memhtml 0.2.4 → 0.2.5

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.
@@ -1 +1 @@
1
- {"version":3,"file":"memhtml.mjs","names":["nowSecond","provenanceOf","ops.writeMemory","ops.batchWrite","ops.readMemory","ops.searchMemories","ops.recallMemories","ops.correctMemory","ops.linkMemories","ops.neighborsOf","ops.archiveMemory","ops.reinforceMemories","ops.listMemories","ops.setTaskStatus","ops.listTasks","ops.indexTraces","ops.searchTraces","ops.traceLinks","ops.statusReport"],"sources":["../../apps/cli/src/serve.ts","../../apps/cli/src/config.ts","../../apps/cli/src/envelope.ts","../../apps/cli/src/extraction.ts","../../apps/cli/src/api-layer.ts","../../apps/cli/src/errors.ts","../../apps/cli/src/operations.ts","../../apps/cli/src/commands.ts","../../apps/cli/src/agents-doc.ts","../../apps/cli/src/prose.ts","../../apps/cli/src/apply.ts","../../apps/cli/src/doctor.ts","../../apps/cli/src/exec.ts","../../apps/cli/src/publish.ts","../../apps/cli/src/state.ts","../../apps/cli/src/views.ts","../../apps/cli/src/run.ts","../../apps/cli/src/bin.ts"],"sourcesContent":["import { spawn } from \"node:child_process\"\nimport { access } from \"node:fs/promises\"\nimport { fileURLToPath } from \"node:url\"\n\nimport { StorageFailure } from \"@memhtml/contracts/errors\"\nimport { Effect } from \"effect\"\n\n/**\n * `memhtml serve mcp`: run the stdio MCP server over the same repo.\n *\n * **The server runs as a child process because of stdout.** The CLI's contract is exactly one JSON\n * envelope on stdout, and a stdio MCP server owns stdout as an NDJSON-RPC stream. Two writers on one\n * file descriptor corrupt the stream for whichever of the two a client is parsing, and no framing\n * makes both readable at once.\n *\n * `stdio: \"inherit\"` hands the child the very descriptors the MCP client opened, so the client talks\n * to `memhtml-mcp` directly and this process is only a supervisor. The child inherits the environment\n * too, which is what makes it build a byte-identical `AppLive`: same region, same credentials.\n * `MEMHTML_ROOT` is passed explicitly on top so a `--repo` override reaches the server, which an\n * inherited environment alone would not carry.\n */\n\n/** What the supervised server's exit looked like. */\nexport interface ServeResult {\n readonly server: string\n readonly exitCode: number\n /** The signal that ended it, when a signal did. */\n readonly signal: string | null\n}\n\n/** An explicit path to the server, for a deployment that does not keep the two apps side by side. */\nexport const MCP_BIN_VAR = \"MEMHTML_MCP_BIN\"\n\n/**\n * Where the `memhtml-mcp` entry point sits relative to this module, in each layout that ships.\n *\n * Resolved by PATH rather than by `require.resolve`, which the dependency direction forces.\n * `@memhtml/mcp` depends on `@memhtml/cli` for the composition root, so `@memhtml/cli` cannot depend on\n * `@memhtml/mcp` without a cycle, and node resolution can only find a package that is a dependency.\n * (`require.resolve(\"@memhtml/mcp/bin\")` from here raises `MODULE_NOT_FOUND`, which is how this was\n * found.)\n *\n * Two candidates, tried in order, because the two apps are one build and where that build puts them\n * differs:\n *\n * - `./memhtml-mcp.mjs` — the PUBLISHED package, where both bins are entry points of one bundle and\n * land beside each other in `dist/`.\n * - `../../mcp/dist/bin.js` — the workspace, where `apps/cli/dist/serve.js` reaches\n * `apps/mcp/dist/bin.js` two directories up and across.\n *\n * Both are real directories rather than pnpm symlinks into the store, so each walk is stable where it\n * applies. {@link MCP_BIN_VAR} still overrides for a deployment that separates them.\n */\nconst MCP_CANDIDATES = [\"./memhtml-mcp.mjs\", \"../../mcp/dist/bin.js\"] as const\n\nexport const mcpEntryPoint = (): Effect.Effect<string, StorageFailure> =>\n Effect.gen(function* () {\n const override = process.env[MCP_BIN_VAR]\n if (override !== undefined && override.trim() !== \"\") return override.trim()\n\n for (const candidate of MCP_CANDIDATES) {\n const path = fileURLToPath(new URL(candidate, import.meta.url))\n const present = yield* Effect.tryPromise({\n try: () => access(path),\n catch: () => \"absent\" as const\n }).pipe(\n Effect.as(true),\n Effect.orElseSucceed(() => false)\n )\n if (present) return path\n }\n\n // A build that produced the CLI but not the server is the one thing that lands here, so the\n // message names the fix rather than the missing path.\n return yield* Effect.fail(\n StorageFailure.make({\n operation: `serve.resolveMcp: run \\`pnpm build\\`, or set ${MCP_BIN_VAR}`\n })\n )\n })\n\nexport const serveMcp = (memhtmlRoot: string): Effect.Effect<ServeResult, StorageFailure> =>\n Effect.gen(function* () {\n const entry = yield* mcpEntryPoint()\n\n return yield* Effect.callback<ServeResult, StorageFailure>((resume) => {\n const child = spawn(process.execPath, [entry], {\n stdio: \"inherit\",\n env: { ...process.env, MEMHTML_ROOT: memhtmlRoot }\n })\n\n child.on(\"error\", () =>\n resume(Effect.fail(StorageFailure.make({ operation: \"serve.spawn\" })))\n )\n child.on(\"exit\", (code, signal) =>\n resume(\n Effect.succeed({\n server: entry,\n exitCode: code ?? 0,\n signal: signal ?? null\n })\n )\n )\n\n // Killing the child on interruption is what keeps a `memhtml serve mcp` that the operator\n // Ctrl-C'd from leaving an orphaned server holding the repo's database open.\n return Effect.sync(() => {\n child.kill()\n })\n })\n })\n","import { homedir } from \"node:os\"\nimport { join } from \"node:path\"\n\nimport { expandRoot } from \"@memhtml/store\"\nimport { Config } from \"effect\"\n\nimport { MCP_BIN_VAR } from \"./serve.js\"\n\n/**\n * The whole environment surface, in one place, so `memhtml manifest` can describe it and a reader\n * does not have to grep for `process.env`.\n *\n * Every variable is read through `effect/Config` rather than `process.env` directly: a missing\n * required value becomes a typed failure with the variable's name in it, and a default is\n * declared next to the name it defaults for.\n */\n\n/** One documented environment variable, for the manifest and the generated agent doc. */\nexport interface ConfigVar {\n readonly name: string\n readonly description: string\n /** The value used when the variable is absent, or `null` when absence is meaningful. */\n readonly fallback: string | null\n}\n\nexport const CONFIG_VARS: ReadonlyArray<ConfigVar> = [\n {\n name: \"MEMHTML_ROOT\",\n description: \"The memory repo's root: a git repository holding the corpus and `.memhtml/`.\",\n fallback: join(\"~\", \"memhtml\")\n },\n {\n name: \"MEMHTML_TRACE_ROOT\",\n description:\n \"Where `memhtml trace index` reads Claude Code transcripts from. Read-only; never written.\",\n fallback: join(\"~\", \".claude\")\n },\n {\n name: \"MEMHTML_AWS_REGION\",\n description: \"The Bedrock region for embeddings and the sleep cycle's four LLM phases.\",\n fallback: \"us-east-1\"\n },\n {\n name: \"AWS_BEARER_TOKEN_BEDROCK\",\n description:\n \"Bedrock bearer token, read by the AWS SDK itself. Absent means the default credential chain; retrieval then degrades to the lexical floor rather than failing.\",\n fallback: null\n },\n {\n name: \"MEMHTML_EMBED\",\n description:\n \"`off` disables the embedder entirely. An explicit opt-out, distinct from a missing credential: a missing credential degrades one search at call time, `off` degrades every search, and an operator reading this manifest needs those to be different states.\",\n fallback: \"on\"\n },\n {\n name: \"MEMHTML_LLM\",\n description:\n \"`off` makes the four LLM sleep phases report `no model bound` and stay `ok`, so a credential-free run is honest rather than red.\",\n fallback: \"on\"\n },\n {\n name: \"MEMHTML_EXTRACT_ENTITIES\",\n description:\n \"`on` adds one GPT-5.6 Luna call per write batch that extracts `memhtml-entity` metas the ops did not declare. Opt-in, unlike MEMHTML_EMBED, because it changes what a write STORES: extracted entities land in the files as if authored, and the write itself never waits on or fails with the model. A failed extraction is a logged warning and an unextracted batch.\",\n fallback: \"off\"\n },\n {\n /**\n * The name is imported rather than retyped: this row and the `process.env` read at serve.ts:50\n * must name the same string, and a literal here would let a rename disclose a variable nothing\n * reads.\n */\n name: MCP_BIN_VAR,\n description:\n \"An explicit path to the `memhtml-mcp` entry point, read only by the `memhtml serve mcp` supervisor. Absent means the sibling-path default. The two apps ship as one build, so `apps/cli/dist/serve.js` finds `apps/mcp/dist/bin.js` two directories over. An operator sets it for a split deployment that does not keep the apps side by side; it locates the server rather than configuring the store, so it changes no retrieval behavior.\",\n fallback: null\n }\n]\n\n/**\n * `MEMHTML_ROOT`. Re-exported from `@memhtml/store`'s own config rather than redeclared, because the\n * store's config expands a leading `~`. This value arrives from a shell profile, an MCP client\n * config, and a cron line, and only the shell expands tildes on its own.\n */\nexport const MemhtmlRoot = Config.string(\"MEMHTML_ROOT\").pipe(\n Config.withDefault(join(\"~\", \"memhtml\")),\n Config.map(expandRoot)\n)\n\n/**\n * `MEMHTML_TRACE_ROOT`, defaulting to `~/.claude`.\n *\n * A parameter rather than a constant so the trace indexer is drivable against a fixture tree and\n * against an archived copy, which is also what keeps real transcripts out of the test suite.\n */\nexport const TraceRoot = Config.string(\"MEMHTML_TRACE_ROOT\").pipe(\n Config.withDefault(join(homedir(), \".claude\")),\n Config.map(expandRoot)\n)\n","/**\n * The machine contract. `apiVersion` lets the envelope evolve without silently\n * breaking parsers, and `type` is a discriminator an agent reads to know the\n * shape of `data` before parsing it.\n */\nexport const API_VERSION = \"1\"\n\n/**\n * Append-only, like `ERROR_CODES`. A discriminator's meaning is fixed once shipped;\n * a new payload shape gets a new discriminator rather than reusing one.\n */\nexport const RESPONSE_TYPES = [\n \"cli.manifest\",\n \"memory.written\",\n \"memory.detail\",\n \"memory.hits\",\n \"recall.pack\",\n \"index.report\",\n \"trace.sessions\",\n \"sleep.report\",\n \"sleep.review\",\n \"eval.discrimination\",\n \"doctor.report\",\n \"status.health\",\n \"repo.init\",\n \"memory.corrected\",\n \"memory.linked\",\n \"memory.neighbors\",\n \"memory.archived\",\n \"memory.reinforced\",\n \"memory.list\",\n \"trace.report\",\n \"trace.links\",\n \"sleep.merge\",\n \"agents.doc\",\n \"serve.exit\",\n \"publish.report\",\n \"state.export\",\n \"state.import\",\n \"task.written\",\n \"task.updated\",\n \"task.list\",\n \"batch.applied\",\n \"exec.report\"\n] as const\n\nexport type ResponseType = (typeof RESPONSE_TYPES)[number]\n\nexport interface Success<A> {\n readonly apiVersion: typeof API_VERSION\n readonly type: ResponseType\n readonly data: A\n}\n\nexport interface Failure {\n readonly apiVersion: typeof API_VERSION\n readonly error: string\n readonly code: ErrorCode\n readonly suggestions: ReadonlyArray<string>\n}\n\n/**\n * Append-only. Once shipped, a code's meaning never changes and a code is never\n * removed; new conditions get new codes. Agents branch on `code`, never on the\n * human `error` string, which changes freely as wording improves.\n */\nexport const ERROR_CODES = [\n \"ERR_UNKNOWN_COMMAND\",\n \"ERR_MISSING_ARGUMENT\",\n \"ERR_INVALID_FLAG\",\n \"ERR_PATH_NOT_FOUND\",\n \"ERR_INVALID_MEMORY\",\n \"ERR_DUPLICATE_CONTENT\",\n \"ERR_WRITE_CONFLICT\",\n \"ERR_DIRTY_TREE\",\n \"ERR_INDEX_STALE\",\n \"ERR_EMBED_MODEL_MISMATCH\",\n \"ERR_MODEL_UNAVAILABLE\",\n \"ERR_STORAGE\",\n \"ERR_GIT\",\n \"ERR_DISCRIMINATION_FAILED\",\n \"ERR_UNKNOWN\"\n] as const\n\nexport type ErrorCode = (typeof ERROR_CODES)[number]\n\n/** Exit codes stay stable so a shell caller can branch without parsing output. */\nexport const EXIT_OK = 0\nexport const EXIT_USAGE = 2\nexport const EXIT_RUNTIME = 1\n\nexport const succeed = <A>(type: ResponseType, data: A): Success<A> => ({\n apiVersion: API_VERSION,\n type,\n data\n})\n\nexport const fail = (\n code: ErrorCode,\n error: string,\n suggestions: ReadonlyArray<string> = []\n): Failure => ({ apiVersion: API_VERSION, error, code, suggestions })\n\n/** Levenshtein distance, used for \"did you mean\" suggestions. */\nconst distance = (a: string, b: string): number => {\n const rows = a.length + 1\n const cols = b.length + 1\n let previous = Array.from({ length: cols }, (_, index) => index)\n\n for (let row = 1; row < rows; row += 1) {\n const current = [row, ...Array.from({ length: cols - 1 }, () => 0)]\n for (let col = 1; col < cols; col += 1) {\n const substitution = (previous[col - 1] as number) + (a[row - 1] === b[col - 1] ? 0 : 1)\n const insertion = (current[col - 1] as number) + 1\n const deletion = (previous[col] as number) + 1\n current[col] = Math.min(substitution, insertion, deletion)\n }\n previous = current\n }\n\n return previous[cols - 1] as number\n}\n\n/** Nearest known names, so an unknown argument returns candidates rather than a dead end. */\nexport const nearest = (\n input: string,\n known: ReadonlyArray<string>,\n limit = 3\n): ReadonlyArray<string> =>\n known\n .map((candidate) => ({\n candidate,\n score: distance(input.toLowerCase(), candidate.toLowerCase())\n }))\n .filter((entry) => entry.score <= Math.max(2, Math.ceil(input.length / 2)))\n .sort((left, right) => left.score - right.score)\n .slice(0, limit)\n .map((entry) => entry.candidate)\n\n/**\n * `--dense` drops nulls and indentation so an agent pasting output into a prompt\n * spends tokens on content rather than decoration.\n */\nconst stripNulls = (value: unknown): unknown => {\n if (Array.isArray(value)) return value.map(stripNulls)\n if (typeof value === \"object\" && value !== null) {\n return Object.fromEntries(\n Object.entries(value)\n .filter(([, entry]) => entry !== null && entry !== undefined)\n .map(([key, entry]) => [key, stripNulls(entry)])\n )\n }\n return value\n}\n\nexport const render = (payload: Success<unknown> | Failure, dense: boolean): string =>\n dense ? JSON.stringify(stripNulls(payload)) : JSON.stringify(payload, null, 2)\n","import { ModelUnavailable } from \"@memhtml/contracts/errors\"\nimport { wrapAsData } from \"@memhtml/llm\"\nimport { Effect } from \"effect\"\n\n/**\n * Write-time entity extraction: one model call per write batch, entities landing as ordinary\n * `memhtml-entity` metas. The git tree stays the system of record and the index only ever sees the\n * rebuildable projection, exactly as if the author had declared them.\n *\n * The port is optional and the default is off (`MEMHTML_EXTRACT_ENTITIES`, config.ts). The write path\n * has never carried a generative call, and the embeddings precedent governs the failure mode: a\n * model that is down costs this batch its extracted entities and nothing else. The write proceeds,\n * the warning is logged, and `entities: []` is what an entity-free write always produced.\n *\n * The model is GPT-5.6 Luna on the Bedrock mantle endpoint, which speaks the OpenAI Responses API\n * over HTTPS and is not reachable through `@memhtml/llm`'s InvokeModel client (the model card lists\n * Invoke and Converse as unsupported; probed 2026-08-09: a strict-json-schema extraction round\n * trip completes in ~1s). The fetch transport therefore lives here rather than as a fourth lane in\n * `packages/llm`, which holds one vendor and one call shape by design. This port's transport is\n * injectable so no test needs the network.\n */\n\n/** One op's text as the extractor sees it: the title plus whichever body form the op carried. */\nexport interface ExtractionItem {\n readonly title: string\n /** `claim` + body prose for prose ops, raw article markup for `article_html` ops. */\n readonly text: string\n}\n\n/**\n * The port `batchWrite` consumes. `undefined` entries are not permitted in the result. The\n * contract is one entity array per input item, index-aligned, empty when the model found nothing.\n */\nexport interface EntityExtractorShape {\n readonly extract: (\n items: ReadonlyArray<ExtractionItem>\n ) => Effect.Effect<ReadonlyArray<ReadonlyArray<string>>, ModelUnavailable>\n}\n\n/** The transport: one Responses-API round trip, body in, decoded JSON out. Injectable for tests. */\nexport interface MantleTransport {\n readonly post: (body: string, signal: AbortSignal) => Promise<unknown>\n}\n\n/**\n * GPT-5.6 Luna, the fast high-volume model on the mantle endpoint. A constant rather than config\n * because the schema below is tested against this model's strict-mode behavior. Changing the model\n * is a code change with a test run, not an env var.\n */\nexport const EXTRACTION_MODEL_ID = \"openai.gpt-5.6-luna\"\n\n/** Entity types the prompt offers. Downstream the vocabulary is open: `unknown:` is a valid store type. */\nconst ENTITY_TYPES = [\"person\", \"org\", \"service\", \"place\", \"work\", \"concept\", \"event\"] as const\n\n/**\n * The strict output schema. `additionalProperties: false` and `required` on every level because\n * the Responses API's `strict: true` demands both, and a lax schema invites the model to answer\n * with prose keys the parser would then be guessing at.\n */\nconst RESPONSE_SCHEMA = {\n type: \"object\",\n properties: {\n items: {\n type: \"array\",\n items: {\n type: \"object\",\n properties: {\n index: { type: \"integer\" },\n entities: {\n type: \"array\",\n items: {\n type: \"object\",\n properties: {\n type: { type: \"string\", enum: [...ENTITY_TYPES] },\n name: { type: \"string\" }\n },\n required: [\"type\", \"name\"],\n additionalProperties: false\n }\n }\n },\n required: [\"index\", \"entities\"],\n additionalProperties: false\n }\n }\n },\n required: [\"items\"],\n additionalProperties: false\n} as const\n\nconst INSTRUCTIONS =\n \"Extract the named entities each memory mentions. \" +\n \"An entity is a specific nameable thing a later search would look up: a person, an \" +\n \"organization, a service or system, a place, a titled work, a defined concept, or a named \" +\n \"event. Skip generic nouns, dates, and quantities. Use the memory's own spelling for the \" +\n \"name. Return one result per input index, with an empty entities array when a memory names \" +\n \"nothing.\"\n\n/** The request body for one batch. Exported for the wire test, where the schema is the contract. */\nexport const requestBodyOf = (modelId: string, items: ReadonlyArray<ExtractionItem>): string =>\n JSON.stringify({\n model: modelId,\n instructions: INSTRUCTIONS,\n input: wrapAsData(\n \"memories\",\n JSON.stringify(items.map((item, index) => ({ index, title: item.title, text: item.text })))\n ),\n text: {\n format: {\n type: \"json_schema\",\n name: \"entities\",\n strict: true,\n schema: RESPONSE_SCHEMA\n }\n }\n })\n\n/**\n * Decode one Responses-API payload into index-aligned `type:name` arrays.\n *\n * Total over unknown input: every malformed shape returns `undefined` and the caller maps that to\n * `ModelUnavailable`. A payload this code cannot read carries no answer, and treating it as\n * \"no entities\" would record a model failure as a fact about the corpus.\n */\nexport const entitiesOf = (\n payload: unknown,\n expected: number\n): ReadonlyArray<ReadonlyArray<string>> | undefined => {\n const text = outputTextOf(payload)\n if (text === undefined) return undefined\n let parsed: unknown\n try {\n parsed = JSON.parse(text)\n } catch {\n return undefined\n }\n const items = (parsed as { items?: unknown }).items\n if (!Array.isArray(items)) return undefined\n\n const results: Array<ReadonlyArray<string>> = Array.from({ length: expected }, () => [])\n for (const item of items) {\n const index = (item as { index?: unknown }).index\n const entities = (item as { entities?: unknown }).entities\n if (typeof index !== \"number\" || !Number.isInteger(index) || index < 0 || index >= expected) {\n continue\n }\n if (!Array.isArray(entities)) continue\n results[index] = entities.flatMap((entity) => {\n const type = (entity as { type?: unknown }).type\n const name = (entity as { name?: unknown }).name\n if (typeof type !== \"string\" || typeof name !== \"string\") return []\n const trimmedName = name.trim()\n return trimmedName === \"\" ? [] : [`${type}:${trimmedName}`]\n })\n }\n return results\n}\n\n/** The assistant message text out of a Responses payload, or `undefined` off-shape. */\nconst outputTextOf = (payload: unknown): string | undefined => {\n const output = (payload as { output?: unknown }).output\n if (!Array.isArray(output)) return undefined\n for (const entry of output) {\n if ((entry as { type?: unknown }).type !== \"message\") continue\n const content = (entry as { content?: unknown }).content\n if (!Array.isArray(content)) continue\n for (const part of content) {\n const text = (part as { text?: unknown }).text\n if ((part as { type?: unknown }).type === \"output_text\" && typeof text === \"string\") {\n return text\n }\n }\n }\n return undefined\n}\n\n/**\n * Per-call ceiling. Generous against the probed ~1s because a batch of 256 ops is a bigger\n * prompt than the probe's one sentence, and a late abort costs only this batch's entities. The\n * write itself is unaffected.\n */\nconst EXTRACT_TIMEOUT_MS = 60_000\n\n/** The extractor over a transport. The transport owns the endpoint; this owns prompt and parse. */\nexport const makeEntityExtractor = (\n transport: MantleTransport,\n modelId: string\n): EntityExtractorShape => ({\n extract: (items) =>\n items.length === 0\n ? Effect.succeed([])\n : Effect.gen(function* () {\n const payload = yield* Effect.tryPromise({\n try: (signal) => {\n const timeout = AbortSignal.timeout(EXTRACT_TIMEOUT_MS)\n return transport.post(\n requestBodyOf(modelId, items),\n AbortSignal.any([signal, timeout])\n )\n },\n catch: (cause) =>\n ModelUnavailable.make({\n modelId,\n reason: cause instanceof Error ? `${cause.name}: ${cause.message}` : String(cause)\n })\n })\n const entities = entitiesOf(payload, items.length)\n if (entities === undefined) {\n return yield* Effect.fail(\n ModelUnavailable.make({ modelId, reason: \"unreadable extraction payload\" })\n )\n }\n return entities\n })\n})\n\n/**\n * The production transport: bearer-token fetch against the mantle endpoint.\n *\n * A non-2xx status is a rejection carrying the status and the body's first line, because mantle\n * reports quota and auth failures as structured JSON the operator needs verbatim. Folding it into\n * a generic message was the mistake the embeddings lane made first.\n */\nexport const fetchMantleTransport = (region: string, token: string): MantleTransport => ({\n post: async (body, signal) => {\n const response = await fetch(`https://bedrock-mantle.${region}.api.aws/openai/v1/responses`, {\n method: \"POST\",\n headers: { Authorization: `Bearer ${token}`, \"Content-Type\": \"application/json\" },\n body,\n signal\n })\n const text = await response.text()\n if (!response.ok) {\n throw new Error(`mantle ${response.status}: ${text.slice(0, 200)}`)\n }\n return JSON.parse(text) as unknown\n }\n})\n","import { readFile } from \"node:fs/promises\"\nimport { join } from \"node:path\"\nimport {\n type ConsolidatorShape,\n hasConsolidatorCredentials,\n makeConsolidator\n} from \"@memhtml/consolidator\"\nimport { StorageFailure } from \"@memhtml/contracts/errors\"\nimport {\n DatabaseService,\n type DatabaseShape,\n type EmbedPort,\n Indexer,\n type IndexerShape,\n IndexGit,\n IndexRecorder,\n type IndexRecorderShape,\n MIGRATIONS_DIR,\n makeDatabase,\n makeGitPort,\n makeIndexer,\n makeIndexRecorder,\n makeRetrieval,\n type QueryEmbedPort,\n Retrieval,\n type RetrievalShape,\n STATE_MIGRATIONS_DIR\n} from \"@memhtml/index\"\nimport {\n EMBED_DIM,\n EMBED_WATERMARK,\n Embeddings,\n EmbeddingsLive,\n type EmbeddingsShape,\n ModelClient,\n ModelClientLive,\n type ModelClientShape\n} from \"@memhtml/llm\"\nimport { makeSleep, Sleep, type SleepShape } from \"@memhtml/sleep\"\nimport {\n Git,\n type GitShape,\n INDEX_DB_PATH,\n makeGit,\n makeStore,\n STATE_DB_PATH,\n Store,\n type StoreShape\n} from \"@memhtml/store\"\nimport { Config, Context, Effect, Layer } from \"effect\"\n\nimport { MemhtmlRoot, TraceRoot } from \"./config.js\"\nimport {\n type EntityExtractorShape,\n EXTRACTION_MODEL_ID,\n fetchMantleTransport,\n makeEntityExtractor\n} from \"./extraction.js\"\n\n/**\n * The service tags, re-exported from the composition root.\n *\n * A handler imports its services from here rather than from six packages, so \"which tag does this\n * come from\" is answered once. `IndexGit` is the case that needs care. `@memhtml/store` publishes\n * `memhtml/Git` for its `GitShape` and `@memhtml/index` publishes `memhtml/IndexGit` for a different\n * shape, and the two appearing side by side in this list keeps them from being confused.\n */\nexport { DatabaseService, Indexer, IndexGit, IndexRecorder, Retrieval } from \"@memhtml/index\"\nexport { Embeddings, ModelClient } from \"@memhtml/llm\"\nexport { Sleep } from \"@memhtml/sleep\"\nexport { Git, Store } from \"@memhtml/store\"\n\n/**\n * `AppLive`: the one place every service is wired to every other.\n *\n * Built bottom-up with `Layer.provideMerge`, so each level both consumes what is below it and\n * stays visible to what is above. Every command handler and every MCP tool then reads the same\n * tags, which keeps a handler down to decode, call, envelope, with no composition logic\n * of its own to drift from its sibling in the other app.\n *\n * Real dependencies force the order:\n *\n * 1. **Root**: `MEMHTML_ROOT`/`MEMHTML_TRACE_ROOT`, needed to open anything.\n * 2. **Database**: `index.db` with `state.db` ATTACHed. `Indexer` and `Retrieval` both need it,\n * and so does the recorder the store's dedupe hook calls.\n * 3. **Git**: the store's subprocess wrapper, plus the indexer's own port over it.\n * 4. **Recorder**: `makeIndexRecorder(db)` supplies both the store's `dedupeLookup` and the\n * session-link writer, which is why the store cannot come before the database.\n * 5. **Store**: over git, with the recorder's hooks attached.\n * 6. **Indexer / Retrieval**: over the database and the git port.\n *\n * The one cycle in the design is broken at step 4. The store needs a SQL lookup to answer \"does\n * this content already exist\", and `@memhtml/store` is SQL-free by design. The lookup arrives as an\n * injected function, so the arrow still points inward and this file is the only module that knows\n * both halves exist.\n */\n\n/** The resolved roots, as a service so a handler reads the repo path without re-reading config. */\nexport interface RootsShape {\n /** `MEMHTML_ROOT`, absolute, `~` expanded. */\n readonly memhtmlRoot: string\n /** `MEMHTML_TRACE_ROOT`, absolute. Read-only, so nothing under it is ever written. */\n readonly traceRoot: string\n}\n\nexport const Roots = Context.Service<RootsShape>(\"memhtml/Roots\")\n\n/**\n * The roots layer. `repoOverride` is `--repo`, and it wins over `MEMHTML_ROOT` so an operator running\n * against a second repo does not have to mutate their environment to do it.\n */\nexport const layerRoots = (repoOverride?: string | undefined): Layer.Layer<RootsShape> =>\n Layer.effect(Roots)(\n Effect.gen(function* () {\n const fromConfig = yield* MemhtmlRoot\n const traceRoot = yield* TraceRoot\n const memhtmlRoot =\n repoOverride !== undefined && repoOverride.trim() !== \"\" ? repoOverride.trim() : fromConfig\n return { memhtmlRoot, traceRoot }\n })\n ).pipe(Layer.orDie)\n\n/**\n * The database, rooted in the repo's `.memhtml/`.\n *\n * Both planes on one connection, always. The salience retrieval arm `LEFT JOIN`s `state.access`\n * in the same statement as `main.files`, so a connection without the attachment silently drops\n * that arm. `DatabaseShape.hasState` is what the arm registry consults, and it is `false` only\n * for a caller that deliberately asked for the index alone.\n */\nexport const layerDatabase: Layer.Layer<DatabaseShape, never, RootsShape> = Layer.effect(\n DatabaseService\n)(\n Effect.gen(function* () {\n const roots = yield* Roots\n return yield* makeDatabase(join(roots.memhtmlRoot, INDEX_DB_PATH), MIGRATIONS_DIR, {\n path: join(roots.memhtmlRoot, STATE_DB_PATH),\n migrationsDir: STATE_MIGRATIONS_DIR\n })\n })\n).pipe(Layer.orDie)\n\n/** Git over the repo root. The store's shape, under the store's own tag. */\nexport const layerGit: Layer.Layer<GitShape, never, RootsShape> = Layer.effect(Git)(\n Effect.gen(function* () {\n const roots = yield* Roots\n return makeGit(roots.memhtmlRoot)\n })\n)\n\n/**\n * The indexer's git port, over the store's git service.\n *\n * `readFile` is `Effect.tryPromise` rather than `Effect.promise`. `Effect.promise` turns an ENOENT\n * into a defect, and a defect travels past the `Effect.catch` the indexer wraps each projection in.\n * An absent path would then kill the fiber mid-update instead of becoming the counted skip the indexer\n * already handles. An agent listing a path it just archived is the normal case, which makes this\n * the difference between a working `index update` and a crash on an ordinary day.\n */\nexport const layerIndexGit: Layer.Layer<\n Context.Service.Identifier<typeof IndexGit>,\n never,\n RootsShape | GitShape\n> = Layer.effect(IndexGit)(\n Effect.gen(function* () {\n const roots = yield* Roots\n const git = yield* Git\n return makeGitPort({\n git,\n readFile: (path) =>\n Effect.tryPromise({\n try: () => readFile(join(roots.memhtmlRoot, path), \"utf8\"),\n catch: (cause) => cause\n }),\n fail: (operation) =>\n Effect.fail(StorageFailure.make({ operation: `git.${operation}` })) as never\n })\n })\n)\n\n/** The recorder: the dedupe lookup the store gates writes on, and the session-link writer. */\nexport const layerRecorder: Layer.Layer<IndexRecorderShape, never, DatabaseShape> = Layer.effect(\n IndexRecorder\n)(\n Effect.gen(function* () {\n const db = yield* DatabaseService\n return makeIndexRecorder(db)\n })\n)\n\n/**\n * The store, with the recorder's dedupe hook attached.\n *\n * `onMove` mirrors `state.access.path` across an archive. Cross-database foreign keys do not\n * exist, so the mirror is an explicit call at the one place a path can change; without it every\n * eviction leaves an orphan access row and the salience arm stops finding the memory it describes.\n */\nexport const layerStore: Layer.Layer<\n StoreShape,\n never,\n GitShape | IndexRecorderShape | DatabaseShape\n> = Layer.effect(Store)(\n Effect.gen(function* () {\n const git = yield* Git\n const recorder = yield* IndexRecorder\n const db = yield* DatabaseService\n return makeStore(git, {\n dedupeLookup: recorder.activePathForHash,\n onMove: (from, to) =>\n db.run(\"UPDATE state.access SET path = ? WHERE path = ?\", [to, from]).pipe(\n // A move whose mirror fails must not fail the move. The archive commit has already\n // landed, and the orphan row is what `memhtml doctor` reports. Losing the commit to a\n // bookkeeping error would be worse than an orphan.\n Effect.catch((error) =>\n Effect.logWarning(`state.access mirror missed ${from} -> ${to}: ${error.operation}`)\n )\n )\n })\n })\n)\n\n/**\n * The embeddings ports, or absent.\n *\n * Absent is a supported configuration rather than an error. `index rebuild --no-embed` and every test\n * run without credentials take this path, and retrieval then assembles without the vector arm and\n * reports `degraded: true`. Making the embedder mandatory would turn a Bedrock outage into a dead\n * CLI, which is the failure the lexical floor exists to prevent.\n */\nexport interface EmbedderShape {\n readonly document: EmbedPort | undefined\n readonly query: QueryEmbedPort | undefined\n}\n\nexport const Embedder = Context.Service<EmbedderShape>(\"memhtml/Embedder\")\n\n/**\n * Bedrock embeddings when the region resolves, absent when `MEMHTML_EMBED` is `off`.\n *\n * The switch is an explicit opt-out rather than credential sniffing. A missing credential is\n * discovered at call time and degrades one search. A deliberate `off` degrades every search, and\n * an operator reading `memhtml manifest` needs those to be different states.\n */\nexport const layerEmbedder: Layer.Layer<EmbedderShape, never, EmbeddingsShape> = Layer.effect(\n Embedder\n)(\n Effect.gen(function* () {\n const enabled = yield* Config.string(\"MEMHTML_EMBED\").pipe(\n Config.withDefault(\"on\"),\n Config.map((value) => value.trim().toLowerCase() !== \"off\")\n )\n if (!enabled) return { document: undefined, query: undefined }\n const embeddings = yield* Embeddings\n return { document: embeddings, query: embeddings }\n })\n).pipe(Layer.orDie)\n\n/** A layer supplying the embedder ports directly, for a test that wants a deterministic vector. */\nexport const layerEmbedderFrom = (embedder: EmbedderShape): Layer.Layer<EmbedderShape> =>\n Layer.succeed(Embedder)(embedder)\n\n/** The indexer, over the database and the git port. */\nexport const layerIndexer: Layer.Layer<\n IndexerShape,\n never,\n DatabaseShape | Context.Service.Identifier<typeof IndexGit> | EmbedderShape\n> = Layer.effect(Indexer)(\n Effect.gen(function* () {\n const db = yield* DatabaseService\n const git = yield* IndexGit\n const embedder = yield* Embedder\n return makeIndexer({\n db,\n git,\n embedWatermark: EMBED_WATERMARK,\n embedDim: EMBED_DIM,\n embeddings: embedder.document,\n // Wall-clock through the Effect clock would need an Effect here; the indexer wants a plain\n // thunk for `indexed_at`. A test that must pin the instant builds the indexer directly.\n now: () => new Date().toISOString()\n })\n })\n)\n\n/** Retrieval, over the database and the query embedder. */\nexport const layerRetrieval: Layer.Layer<RetrievalShape, never, DatabaseShape | EmbedderShape> =\n Layer.effect(Retrieval)(\n Effect.gen(function* () {\n const db = yield* DatabaseService\n const embedder = yield* Embedder\n return makeRetrieval({ db, embeddings: embedder.query })\n })\n )\n\n/**\n * The model behind the four LLM sleep phases, or absent.\n *\n * Absent is a run whose LLM phases report `skipped`, which `@memhtml/sleep` distinguishes from\n * `failed`, because a deterministic run on a fixture without credentials is not a broken run.\n */\nexport interface ModelPortShape {\n readonly model: ModelClientShape | undefined\n}\n\nexport const ModelPort = Context.Service<ModelPortShape>(\"memhtml/ModelPort\")\n\nexport const layerModelPort: Layer.Layer<ModelPortShape, never, ModelClientShape> = Layer.effect(\n ModelPort\n)(\n Effect.gen(function* () {\n const enabled = yield* Config.string(\"MEMHTML_LLM\").pipe(\n Config.withDefault(\"on\"),\n Config.map((value) => value.trim().toLowerCase() !== \"off\")\n )\n if (!enabled) return { model: undefined }\n return { model: yield* ModelClient }\n })\n).pipe(Layer.orDie)\n\n/** A layer supplying the model port directly, for a test that scripts the model's answers. */\nexport const layerModelFrom = (model: ModelClientShape | undefined): Layer.Layer<ModelPortShape> =>\n Layer.succeed(ModelPort)({ model })\n\n/**\n * Write-time entity extraction, or absent. Absent is the default.\n *\n * Opt-in (`MEMHTML_EXTRACT_ENTITIES=on`) where the embedder is opt-out, and the asymmetry is\n * deliberate. The write path has never carried a generative call, extraction changes what a write\n * stores rather than what a search finds, and a default-on model call in every agent's write path\n * is a behavior change an operator must choose. The failure mode does follow the embedder\n * precedent: a bound extractor that fails costs this batch its extracted entities and never the\n * write (`batchWrite` logs and proceeds).\n *\n * The transport is a bearer-token fetch against the Bedrock mantle endpoint rather than a fourth lane\n * in `@memhtml/llm`. GPT-5.6 Luna is mantle-only (no InvokeModel, no Converse), and that package holds\n * one vendor and one call shape by design. The bearer token is the same\n * `AWS_BEARER_TOKEN_BEDROCK` the SDK chain reads. An absent token with the flag on is a configuration\n * the operator asked for and cannot have, so it degrades per batch with a logged warning rather\n * than failing at layer build, matching how a missing embedder credential degrades a search.\n */\nexport interface ExtractorPortShape {\n readonly extractor: EntityExtractorShape | undefined\n}\n\nexport const ExtractorPort = Context.Service<ExtractorPortShape>(\"memhtml/ExtractorPort\")\n\nexport const layerExtractorPort: Layer.Layer<ExtractorPortShape> = Layer.effect(ExtractorPort)(\n Effect.gen(function* () {\n const enabled = yield* Config.string(\"MEMHTML_EXTRACT_ENTITIES\").pipe(\n Config.withDefault(\"off\"),\n Config.map((value) => value.trim().toLowerCase() === \"on\")\n )\n if (!enabled) return { extractor: undefined }\n const region = yield* Config.string(\"MEMHTML_AWS_REGION\").pipe(Config.withDefault(\"us-east-1\"))\n const token = yield* Config.string(\"AWS_BEARER_TOKEN_BEDROCK\").pipe(Config.withDefault(\"\"))\n if (token === \"\") {\n yield* Effect.logWarning(\n \"MEMHTML_EXTRACT_ENTITIES=on but AWS_BEARER_TOKEN_BEDROCK is absent; writes proceed unextracted\"\n )\n return { extractor: undefined }\n }\n return {\n extractor: makeEntityExtractor(fetchMantleTransport(region, token), EXTRACTION_MODEL_ID)\n }\n })\n).pipe(Layer.orDie)\n\n/** A layer supplying the extractor directly, for a test that scripts the extraction answers. */\nexport const layerExtractorFrom = (\n extractor: EntityExtractorShape | undefined\n): Layer.Layer<ExtractorPortShape> => Layer.succeed(ExtractorPort)({ extractor })\n\n/**\n * The consolidator behind trace consolidation, or absent.\n *\n * **This file is the only place that knows both halves exist**, which is why it is\n * here rather than in `@memhtml/sleep`. `apps/consolidator` is an eve agent over the AI SDK Bedrock\n * provider with a `just-bash` sandbox. Sleep declares the shape it consumes\n * (`packages/sleep/src/consolidator.ts`) and never imports any of that. The assignment below needs no\n * adapter and no cast, because TypeScript is structural and `ConsolidatorShape` satisfies\n * `ConsolidatorPort` field for field.\n *\n * **There is no host option, by construction.** The consolidator's eve channel now demands a bearer\n * JWT signed with a per-run secret (`apps/consolidator/agent/channels/eve.ts` via `jwtHmac`), so the\n * bind address is no longer the only thing keeping the agent off the network. It is still not optional,\n * because two layers are only depth while both are in place. `makeConsolidator` exposes no `host`\n * option at all and pins loopback itself (`apps/consolidator/src/client.ts`, `LOOPBACK_HOST`). Nothing\n * here may reintroduce one, and the absence of an option is the mechanism.\n */\nexport interface ConsolidatorPortShape {\n readonly consolidator: ConsolidatorShape | undefined\n}\n\nexport const ConsolidatorPortService = Context.Service<ConsolidatorPortShape>(\n \"memhtml/ConsolidatorPort\"\n)\n\n/**\n * Two gates, both cheap, both before anything is spawned.\n *\n * `MEMHTML_LLM=off` is the same explicit opt-out `layerModelPort` reads, and it covers the consolidator\n * too, because an operator who turned the models off did not mean \"except the expensive agent\".\n *\n * `hasConsolidatorCredentials` is the credential preflight, read here as well as inside the client.\n * The redundancy is deliberate and the two reads do different jobs. This one decides whether the phase\n * sees a consolidator at all, so a credential-free environment gets `detail: \"no consolidator bound\"`,\n * the same shape the other three LLM phases report with no model, rather than a bound port that\n * fails on every call and reports a degradation. CI has no credentials and must read as skipped rather\n * than degraded.\n *\n * The check cannot be skipped in favor of the client's own, because the provider is lazy.\n * `createAmazonBedrock` and `provider(modelId)` both succeed with zero credentials and nothing fails\n * until the first request (verified in T-EVE-1's probe, recorded at\n * `apps/consolidator/src/contract.ts:301-319`).\n *\n * **`env` is a parameter, and it has to be.** `Config` reads its values through a `ConfigProvider`,\n * which a test substitutes, while `hasConsolidatorCredentials` reads `process.env` directly, and\n * effect's default provider snapshots `process.env` at module load (probed 2026-08-08: mutating\n * `process.env.MEMHTML_LLM` after importing `effect` changes nothing `Config.string` returns). A test\n * that set both by mutation would read a stale snapshot for one gate and a live object for the other,\n * and the two gates would disagree about which environment they are in. Threading the credential\n * environment through as an argument makes both injectable from one call. See\n * `apps/cli/tests/consolidator-wiring.test.ts`, where that disagreement produced a false defect\n * before this parameter existed.\n *\n * **It now requires `RootsShape`, for `traceRoot`.** That is how transcripts reach the agent. The\n * consolidator mounts the trace root read-only rather than sending transcripts as a model message\n * (`apps/consolidator/src/client.ts`, `manifestFor`, records what the superseded path actually did).\n * The root is `MEMHTML_TRACE_ROOT` and this file is where config becomes services, so it is read from the\n * same `Roots` service `memhtml trace index` scans with. One resolution of one variable is what\n * keeps the mounted tree and the indexed `traces` rows describing the same directory. A second\n * `Config.string(\"MEMHTML_TRACE_ROOT\")` here would be a second place the `~/.claude` default lives.\n */\nexport const layerConsolidatorPort = (\n env: Record<string, string | undefined> = process.env\n): Layer.Layer<ConsolidatorPortShape, never, RootsShape> =>\n Layer.effect(ConsolidatorPortService)(\n Effect.gen(function* () {\n const roots = yield* Roots\n const enabled = yield* Config.string(\"MEMHTML_LLM\").pipe(\n Config.withDefault(\"on\"),\n Config.map((value) => value.trim().toLowerCase() !== \"off\")\n )\n if (!enabled) return { consolidator: undefined }\n if (!hasConsolidatorCredentials(env)) {\n yield* Effect.logDebug(\n \"trace consolidation unbound: no Bedrock credentials in the environment\"\n )\n return { consolidator: undefined }\n }\n /**\n * The client is built over the same environment the gate just read. A client over ambient\n * `process.env` while the gate read an injected one would pass the gate and fail at the call,\n * which is the degradation-instead-of-skip outcome this gate exists to prevent.\n */\n return { consolidator: makeConsolidator({ env, traceRoot: roots.traceRoot }) }\n })\n ).pipe(Layer.orDie)\n\n/** A layer supplying the consolidator directly, for a test that scripts its candidates. */\nexport const layerConsolidatorFrom = (\n consolidator: ConsolidatorShape | undefined\n): Layer.Layer<ConsolidatorPortShape> => Layer.succeed(ConsolidatorPortService)({ consolidator })\n\n/**\n * The sleep runner over the same services every other command uses.\n *\n * `@memhtml/sleep` deliberately ships no `SleepLive` that resolves its own git, database, and model.\n * A layer that built its own would open a second connection to one database file and a second git\n * wrapper on one root, and the run would then curate a corpus the indexer is not describing.\n */\nexport const layerSleep: Layer.Layer<\n SleepShape,\n never,\n GitShape | StoreShape | DatabaseShape | IndexerShape | ModelPortShape | ConsolidatorPortShape\n> = Layer.effect(Sleep)(\n Effect.gen(function* () {\n const git = yield* Git\n const store = yield* Store\n const db = yield* DatabaseService\n const indexer = yield* Indexer\n const modelPort = yield* ModelPort\n const consolidatorPort = yield* ConsolidatorPortService\n return makeSleep({\n git,\n store,\n db,\n indexer,\n model: modelPort.model,\n consolidator: consolidatorPort.consolidator\n })\n })\n)\n\n/**\n * Everything above the embedder and the model, as one layer requiring only the roots and those two.\n *\n * Written top-down because that is what `Layer.provideMerge(that)` means. It feeds `that`'s output\n * into `self`'s requirements, so the consumer is `self` and each `.pipe` step below adds the level\n * beneath it. Chaining in dependency order instead, with the database first, reads naturally and is\n * wrong. It would provide git to the database and leave `GitShape` in the final requirement set, which\n * typechecks as an unsatisfied layer rather than failing where the mistake is.\n *\n * Split out from `layerApp` so a test provides a deterministic embedder and a real temp repo with\n * no Bedrock anywhere in the graph. The composition under test is then the same composition\n * production runs, which a hand-assembled test wiring would not be.\n */\nexport const layerCore = Layer.mergeAll(layerSleep, layerRetrieval).pipe(\n Layer.provideMerge(Layer.mergeAll(layerIndexer, layerStore)),\n Layer.provideMerge(Layer.mergeAll(layerIndexGit, layerRecorder)),\n Layer.provideMerge(Layer.mergeAll(layerDatabase, layerGit))\n)\n\n/**\n * The production graph: roots from config, Bedrock behind both model ports, everything else over\n * them. `repoOverride` is `--repo`.\n *\n * This is the one composition production runs. `memhtml serve mcp` runs the same one in a child\n * process, so an MCP tool and its CLI twin cannot be looking at different databases.\n */\nexport const layerApp = (repoOverride?: string | undefined) =>\n layerCore.pipe(\n Layer.provideMerge(\n Layer.mergeAll(\n layerRoots(repoOverride),\n layerEmbedder.pipe(Layer.provide(EmbeddingsLive), Layer.orDie),\n layerModelPort.pipe(Layer.provide(ModelClientLive), Layer.orDie),\n layerExtractorPort,\n /**\n * `layerRoots` is provided to the consolidator port explicitly rather than merged beside it.\n * The consolidator needs `traceRoot` to mount, and a sibling in one `mergeAll` is not a\n * dependency. The roots layer is built once with `repoOverride` and fed in, so a `--repo`\n * run and the mounted trace root cannot come from two different resolutions.\n */\n layerConsolidatorPort().pipe(Layer.provide(layerRoots(repoOverride)))\n )\n )\n )\n\n/**\n * The graph a test provides: the real composition, with the embedder and the model injected.\n *\n * Same `layerCore`, so a test exercises the wiring production uses rather than a parallel one. The\n * only substituted edges are the two that reach the network.\n */\nexport const layerAppWith = (options: {\n readonly repo: string\n readonly embedder: EmbedderShape\n readonly model?: ModelClientShape | undefined\n /**\n * Absent leaves trace consolidation skipped, which is the right default for every test that is not\n * about that phase. It is what a credential-free environment produces, and binding a live agent\n * from a test harness would spawn an eve server per case.\n */\n readonly consolidator?: ConsolidatorShape | undefined\n /** Absent leaves writes unextracted, the production default. Only extraction tests bind one. */\n readonly extractor?: EntityExtractorShape | undefined\n}) =>\n layerCore.pipe(\n Layer.provideMerge(\n Layer.mergeAll(\n layerRoots(options.repo),\n layerEmbedderFrom(options.embedder),\n layerModelFrom(options.model),\n layerConsolidatorFrom(options.consolidator),\n layerExtractorFrom(options.extractor)\n )\n )\n )\n","import { type ErrorCode, type Failure, fail } from \"./envelope.js\"\n\n/**\n * The one translation from a typed domain failure to an envelope code.\n *\n * Every failure in the system reaches an agent through this function, and the mapping is total by\n * construction: an unrecognized `_tag` becomes `ERR_UNKNOWN` rather than an empty response, so a\n * new error class added upstream degrades to a documented code instead of a crash.\n *\n * The codes are `ERROR_CODES` and nothing else. An agent branches on `code` and not on the human\n * `error` string, which changes freely as wording improves. The suggestions are therefore part of\n * the contract and the prose is not.\n */\n\n/** A typed failure as it arrives here: a `_tag` plus whatever payload its class carries. */\ninterface TaggedError {\n readonly _tag: string\n readonly [field: string]: unknown\n}\n\nconst isTagged = (value: unknown): value is TaggedError =>\n typeof value === \"object\" &&\n value !== null &&\n typeof (value as { _tag?: unknown })._tag === \"string\"\n\nconst text = (value: unknown): string | undefined => (typeof value === \"string\" ? value : undefined)\n\nconst paths = (value: unknown): ReadonlyArray<string> =>\n Array.isArray(value) ? value.filter((entry): entry is string => typeof entry === \"string\") : []\n\n/**\n * The code for a tag.\n *\n * `GitFailure` lives in `@memhtml/store` rather than `@memhtml/contracts`. It is the one error class\n * outside the shared contracts package, because it carries a git subcommand name and only the store\n * speaks git. It maps to `ERR_GIT` here at the CLI edge, the only place the two vocabularies meet.\n *\n * `EmbedModelMismatch` is a plain class rather than a schema error (it predates the contracts\n * package), so it arrives with the same `_tag` shape and needs no special case.\n */\nexport const codeFor = (error: unknown): ErrorCode => {\n if (!isTagged(error)) return \"ERR_UNKNOWN\"\n switch (error._tag) {\n case \"GitFailure\":\n return \"ERR_GIT\"\n case \"StorageFailure\":\n return \"ERR_STORAGE\"\n case \"InvalidMemory\":\n return \"ERR_INVALID_MEMORY\"\n case \"PathNotFound\":\n return \"ERR_PATH_NOT_FOUND\"\n case \"WriteConflict\":\n return \"ERR_WRITE_CONFLICT\"\n case \"DirtyTree\":\n return \"ERR_DIRTY_TREE\"\n case \"DuplicateContent\":\n return \"ERR_DUPLICATE_CONTENT\"\n case \"ModelUnavailable\":\n return \"ERR_MODEL_UNAVAILABLE\"\n case \"EmbedModelMismatch\":\n return \"ERR_EMBED_MODEL_MISMATCH\"\n case \"DiscriminationFailed\":\n return \"ERR_DISCRIMINATION_FAILED\"\n default:\n return \"ERR_UNKNOWN\"\n }\n}\n\n/**\n * The human message for a failure.\n *\n * Deliberately narrow. Every payload field named here is one a caller can act on: a path to\n * re-read, two shas to reconcile, a model to check. The message omits the driver's own text, the\n * SQL, the git argv, and any memory body. Each typed error class already dropped those at its\n * adapter edge so a tool response could not carry corpus content, and reconstructing them here\n * would undo that.\n */\nexport const messageFor = (error: unknown): string => {\n if (!isTagged(error)) return String(error)\n switch (error._tag) {\n case \"GitFailure\":\n return `git ${text(error.command) ?? \"command\"} failed (exit ${String(error.exitCode)})`\n case \"StorageFailure\":\n return `storage operation failed: ${text(error.operation) ?? \"unknown\"}`\n case \"InvalidMemory\":\n return `invalid memory: ${text(error.reason) ?? \"unstated reason\"}`\n case \"PathNotFound\":\n return `no memory at ${text(error.path) ?? \"the given path\"}`\n case \"WriteConflict\":\n return `write conflict on ${text(error.path) ?? \"a path\"}: ours ${text(error.ourSha) ?? \"?\"}, theirs ${text(error.theirSha) ?? \"?\"}`\n case \"DirtyTree\":\n return `the working tree has uncommitted changes: ${paths(error.paths).join(\", \")}`\n case \"DuplicateContent\":\n return `this content already lives at ${text(error.existingPath) ?? \"another path\"}`\n case \"ModelUnavailable\":\n return `bedrock refused ${text(error.modelId) ?? \"the model\"}: ${text(error.reason) ?? \"no reason given\"}`\n case \"EmbedModelMismatch\":\n return `the index was built in vector space ${text(error.stored) ?? \"?\"}, configured is ${text(error.configured) ?? \"?\"}`\n case \"LlmContractViolation\":\n return `the model broke its structured-output contract: ${text(error.reason) ?? \"no reason given\"}`\n case \"DiscriminationFailed\":\n return text(error.reason) ?? \"the discrimination gate refused\"\n default:\n return `unexpected failure: ${error._tag}`\n }\n}\n\n/** One tag's suggestions, given the failure. Some read a payload field, most ignore it. */\ntype SuggestionsFor = (error: TaggedError) => ReadonlyArray<string>\n\n/**\n * What to do about a failure, as commands the caller can run.\n *\n * A suggestion is part of the contract. An agent that receives `ERR_INDEX_STALE` and a\n * `memhtml index update` suggestion can recover in one step without a round trip to a human. Absent\n * suggestions are an empty array rather than a null, so a parser never branches on presence.\n *\n * A record rather than a `switch`, which is what closes the drift class. Every `memhtml …` string\n * below names a command from the table in `commands.ts`, and a rename there used to leave a stale\n * suggestion here that nothing failed on. A record's keys and arms are both walkable, so the suite\n * can enumerate every tag, run every suggestion through the real `parseArgv`, and fail on a name the\n * table does not hold. A `switch` cannot expose any of that to a test.\n *\n * Validated in the test rather than here on purpose: `errors.ts` importing `commands.ts` closes the\n * cycle `commands.ts` → `operations.ts` → `errors.ts` (commands.ts:8, operations.ts:35) and leaves\n * `AUTHORABLE_RELS` undefined in `commands.ts`'s module body under an operations-first import order.\n */\nexport const SUGGESTIONS: Readonly<Record<string, SuggestionsFor>> = {\n PathNotFound: () => [\"memhtml search <what you were looking for>\", \"memhtml list\"],\n WriteConflict: (error) => [\n `memhtml read ${text(error.path) ?? \"<path>\"}`,\n \"re-apply the change to current content\"\n ],\n DirtyTree: () => [\"git -C $MEMHTML_ROOT status\", \"commit or stash the changes, then retry\"],\n DuplicateContent: (error) => [`memhtml read ${text(error.existingPath) ?? \"<path>\"}`],\n EmbedModelMismatch: () => [\"memhtml index rebuild --embed\"],\n ModelUnavailable: () => [\"retry: search still works on the lexical floor\", \"memhtml status\"],\n InvalidMemory: () => [\"memhtml manifest\"],\n // No `--json`: it is a global flag defaulting to true (commands.ts:36-42), so naming it here only\n // gave the suggestion a second way to go stale.\n DiscriminationFailed: () => [\n \"memhtml eval discriminate\",\n \"memhtml sleep review\",\n \"git branch -D <run-id>\"\n ]\n}\n\nexport const suggestionsFor = (error: unknown): ReadonlyArray<string> => {\n if (!isTagged(error)) return []\n return SUGGESTIONS[error._tag]?.(error) ?? []\n}\n\n/** A typed failure as an envelope. The one call every command's error path makes. */\nexport const failureFor = (error: unknown): Failure =>\n fail(codeFor(error), messageFor(error), suggestionsFor(error))\n","import { isEdgeRel, MEMORY_RELS, relClassFor, TASK_RELS } from \"@memhtml/contracts/edges\"\nimport { InvalidMemory, type StorageFailure } from \"@memhtml/contracts/errors\"\nimport { normalizePath } from \"@memhtml/contracts/paths\"\nimport {\n isTaskStatus,\n isWritableMemoryType,\n type MemoryType,\n TASK_STATUSES,\n type TaskStatus,\n WRITABLE_MEMORY_TYPES\n} from \"@memhtml/contracts/types\"\nimport { frameKeyOf, REINFORCE_SIGNALS, type ReinforceSignal } from \"@memhtml/domain\"\nimport { isValidDatetime, setMeta } from \"@memhtml/html\"\nimport {\n DatabaseService,\n type DatabaseShape,\n type FrameMatch,\n Indexer,\n IndexRecorder,\n type IndexRecorderShape,\n type LinkKind,\n persistScanned,\n Retrieval,\n readIndexState,\n readWatermark,\n reinforce,\n type SearchScope,\n sanitizeFtsQuery,\n type TailMerger\n} from \"@memhtml/index\"\nimport { EMBED_WATERMARK } from \"@memhtml/llm\"\nimport { attemptIo, commitSubject, Store, type WriteInput } from \"@memhtml/store\"\nimport { mergeTailExtract, type SessionExtract, scanTraceRoot } from \"@memhtml/traces\"\nimport { Effect } from \"effect\"\n\nimport { ExtractorPort, Roots } from \"./api-layer.js\"\nimport type { ErrorCode } from \"./envelope.js\"\nimport { codeFor, messageFor } from \"./errors.js\"\nimport type { ExtractionItem } from \"./extraction.js\"\n\n/**\n * The use cases, one per tool. Every CLI command and every MCP tool is a thin adapter over exactly\n * one of these, which makes `memhtml search` and `memory_search` provably the same query\n * rather than two implementations that agree today.\n *\n * Nothing here parses argv or builds an envelope. A function takes decoded parameters, returns a\n * typed result, and fails with a typed error. The adapters own the shape of the wire.\n */\n\n/** Wall-clock as an ISO-8601 UTC second, through the Effect clock so a test can pin it. */\nconst nowSecond = Effect.clockWith((clock) =>\n Effect.map(clock.currentTimeMillis, (millis) => `${new Date(millis).toISOString().slice(0, 19)}Z`)\n)\n\n/** Drop `undefined`-valued keys, so `exactOptionalPropertyTypes` sees an absent key. */\nconst defined = <T extends Record<string, unknown>>(input: T): Partial<T> => {\n const out: Record<string, unknown> = {}\n for (const [key, value] of Object.entries(input)) if (value !== undefined) out[key] = value\n return out as Partial<T>\n}\n\n/**\n * Narrow an untrusted memory-type string.\n *\n * `arc` is refused even though it is a valid storage type. An arc is synthesized by the sleep\n * cycle from many memories, so an agent naming one directly would be asserting a conclusion the\n * corpus has not earned. The vocabulary the tool exposes is therefore narrower than the CHECK\n * constraint by exactly that one value.\n */\nexport const decodeWritableType = (\n value: string\n): Effect.Effect<Exclude<MemoryType, \"arc\">, InvalidMemory> =>\n (WRITABLE_MEMORY_TYPES as ReadonlyArray<string>).includes(value)\n ? Effect.succeed(value as Exclude<MemoryType, \"arc\">)\n : Effect.fail(\n InvalidMemory.make({\n reason: `unknown memory type: ${value}. One of: ${WRITABLE_MEMORY_TYPES.join(\", \")}`\n })\n )\n\n/**\n * The rels a CALLER may author: the nine memory rels plus the two task rels.\n *\n * The two classes the vocabulary withholds are the ones the system mints itself. A `person` edge is\n * written by sleep's person-links phase against `resources/people/*`, and `from_session` is written\n * by the write path from the provenance a caller already supplied. Authoring either by hand would put\n * a hand-guessed row where a derivation belongs.\n */\nexport const AUTHORABLE_RELS = [...MEMORY_RELS, ...TASK_RELS] as const\n\nexport type AuthorableRel = (typeof AUTHORABLE_RELS)[number]\n\n/**\n * Narrow an untrusted rel to one a caller may author.\n *\n * A `blocks` edge between two tasks is a legitimate authored assertion, so the task class is in and\n * refusing it would leave the task graph writable by nothing. Whether the rel agrees with its\n * endpoints is not this function's business. `@memhtml/store`'s `linkMemories` reads both files'\n * `memhtml-type` and refuses a mismatch, and it is the only layer that can see the endpoints at all.\n *\n * `memory_link`'s MCP schema stays memory-rels-only (`MemoryRelSchema`, `apps/mcp/src/tools.ts`) and\n * refuses a task rel at decode. That is one narrow surface for agents and one wider one for the\n * operator, with the store's endpoint guard governing both.\n */\nexport const decodeAuthorableRel = (value: string): Effect.Effect<AuthorableRel, InvalidMemory> =>\n isEdgeRel(value) && (AUTHORABLE_RELS as ReadonlyArray<string>).includes(value)\n ? Effect.succeed(value as AuthorableRel)\n : Effect.fail(\n InvalidMemory.make({\n reason: `unknown rel: ${value}. One of: ${AUTHORABLE_RELS.join(\", \")}`\n })\n )\n\n/** Narrow an untrusted task status. */\nexport const decodeTaskStatus = (value: string): Effect.Effect<TaskStatus, InvalidMemory> =>\n isTaskStatus(value)\n ? Effect.succeed(value)\n : Effect.fail(\n InvalidMemory.make({\n reason: `unknown task status: ${value}. One of: ${TASK_STATUSES.join(\", \")}`\n })\n )\n\n/**\n * Narrow an untrusted due date, using the FORMAT's own validator.\n *\n * `isValidDatetime` rather than a local regex or `Date.parse`, because `files.due_at` is compared and\n * ordered as a string. `2026-8-9` and `Aug 9 2026` both parse as instants and neither sorts alongside\n * `2026-08-09`, so the overdue query would silently miss them. Reusing the parser's own validator is\n * also what keeps this refusal and the parser's violation from drifting apart.\n */\nexport const decodeDueAt = (value: string): Effect.Effect<string, InvalidMemory> =>\n isValidDatetime(value)\n ? Effect.succeed(value)\n : Effect.fail(\n InvalidMemory.make({\n reason: `due date is not an ISO date or datetime: ${value}. Expected YYYY-MM-DD or YYYY-MM-DDThh:mm:ssZ`\n })\n )\n\n/** Narrow an untrusted reinforcement signal. */\nexport const decodeSignal = (value: string): Effect.Effect<ReinforceSignal, InvalidMemory> =>\n (REINFORCE_SIGNALS as ReadonlyArray<string>).includes(value)\n ? Effect.succeed(value as ReinforceSignal)\n : Effect.fail(\n InvalidMemory.make({\n reason: `unknown signal: ${value}. One of: ${REINFORCE_SIGNALS.join(\", \")}`\n })\n )\n\n/** Session provenance, present on any write-path call an agent makes from inside a session. */\nexport interface Provenance {\n readonly sessionId?: string | undefined\n readonly promptId?: string | undefined\n readonly turnUuid?: string | undefined\n}\n\n/**\n * Record the session link for an operation that touched a path.\n *\n * Fire-and-log rather than fail-the-call. The link is a note about what happened, and losing the\n * memory over a failed note about it would invert the priority. The file's own head already\n * carries `memhtml-session`/`memhtml-prompt`/`memhtml-turn`, so the durable half of the link survives even\n * when this row does not.\n */\nconst recordLink = (path: string, linkKind: LinkKind, provenance: Provenance, at: string) =>\n Effect.gen(function* () {\n if (provenance.sessionId === undefined || provenance.sessionId === \"\") return\n const recorder = yield* IndexRecorder\n yield* recorder\n .recordLink({\n path,\n sessionId: provenance.sessionId,\n linkKind,\n at,\n ...defined({ promptId: provenance.promptId, turnUuid: provenance.turnUuid })\n })\n .pipe(\n Effect.catch((error) =>\n Effect.logWarning(`session link not recorded for ${path}: ${error.operation}`)\n )\n )\n })\n\nexport interface WriteParams extends Provenance {\n readonly title: string\n readonly claim: string\n readonly body?: ReadonlyArray<string> | undefined\n /**\n * Pre-authored article markup, used verbatim in place of `claim`/`body`. The caller owns\n * constraint 1 when it supplies this, and the store's render gate is what enforces it. Markup\n * with no `<mark>` fails with `InvalidMemory` before anything is written or committed.\n */\n readonly articleHtml?: string | undefined\n readonly memoryType: string\n readonly path?: string | undefined\n readonly workspace?: string | undefined\n readonly tags?: ReadonlyArray<string> | undefined\n readonly entities?: ReadonlyArray<string> | undefined\n readonly importance?: number | undefined\n readonly confidence?: number | undefined\n /** A task's opening status. Ignored on any other type, which carries no such meta. */\n readonly taskStatus?: string | undefined\n /** A task's deadline, ISO date or datetime. Refused before the write when it is neither. */\n readonly dueAt?: string | undefined\n}\n\n/**\n * Bring the index up to the commit a write just made.\n *\n * `indexer.update()` rather than `indexPaths([…])`, and the difference changes behavior twice:\n *\n * 1. **`indexPaths` cannot express a rename.** Every correction and every archive is a `git mv`, and\n * an index that handled one as \"index the destination\" leaves the source row live. The archived\n * memory stays in `memhtml list`, `files` gains a row the tree does not have, and the chunk rows the\n * move exists to preserve are duplicated under two paths. `update()` reads `diff --name-status -M`,\n * sees the `R`, and re-points the row, which keeps the embedding and drops nothing.\n * 2. **`indexPaths` never records the watermark.** `index_state.head_sha` is what makes\n * \"the index describes the current commit\" answerable at all, so a write path that skipped it\n * would leave `memhtml status` reporting `index_fresh: false` forever and `index update` re-deriving\n * from a stale base.\n *\n * The cost is one `git diff` over one commit, which is what the watermark exists to bound. On the\n * very first write the watermark is absent and `update()` falls through to a full rebuild. That is\n * correct, and cheap on a corpus that has one file in it.\n */\nconst reindex = () =>\n Effect.gen(function* () {\n const indexer = yield* Indexer\n return yield* indexer.update({ embed: true })\n })\n\n/**\n * Decode untrusted write parameters into the store's `WriteInput`.\n *\n * Shared by {@link writeMemory} and {@link batchWrite}, and the sharing matters. A batch that\n * re-derived this would be a second decode of the same vocabulary, and the two would agree today\n * and drift the first time a field is added. This is `symspec`'s lesson stated as code: the batch\n * folds the singular's own decode rather than a parallel one.\n *\n * The two task metas are decoded here, before any file is rendered, and only for a task.\n * `@memhtml/html`'s parser refuses `memhtml-task-status` on a non-task and refuses a `memhtml-due` that is not\n * an ISO datetime, so a bad value passed through would render a file the indexer then declines to\n * project. That file is present in the tree, absent from every search, and visible only as a log\n * line. Deciding here turns it into a typed `InvalidMemory` before the commit.\n */\nconst toWriteInput = (params: WriteParams, at: string): Effect.Effect<WriteInput, InvalidMemory> =>\n Effect.gen(function* () {\n const memoryType = yield* decodeWritableType(params.memoryType)\n const taskStatus =\n memoryType === \"task\" && params.taskStatus !== undefined && params.taskStatus !== \"\"\n ? yield* decodeTaskStatus(params.taskStatus)\n : undefined\n const dueAt =\n memoryType === \"task\" && params.dueAt !== undefined && params.dueAt !== \"\"\n ? yield* decodeDueAt(params.dueAt)\n : undefined\n\n return {\n title: params.title,\n claim: params.claim,\n memoryType,\n at,\n ...defined({\n body: params.body,\n articleHtml: params.articleHtml,\n path: params.path,\n workspace: params.workspace,\n tags: params.tags,\n entities: params.entities,\n importance: params.importance,\n confidence: params.confidence,\n sessionId: params.sessionId,\n promptId: params.promptId,\n turnUuid: params.turnUuid,\n taskStatus,\n dueAt\n })\n }\n })\n\n/**\n * Write one memory: render, dedupe, commit, index.\n *\n * On a dedupe nothing is indexed, because nothing changed. A dedupe writes no file, stages nothing,\n * and commits nothing, so the tree is byte-identical and the index already describes it.\n */\nexport const writeMemory = (params: WriteParams) =>\n Effect.gen(function* () {\n const store = yield* Store\n const at = yield* nowSecond\n const result = yield* store.writeMemory(yield* toWriteInput(params, at))\n\n if (result.created) yield* reindex()\n yield* recordLink(result.path, \"wrote\", params, at)\n return result\n })\n\n/**\n * A frame-match the `detect_conflicts` assist found for one op: something else already occupies this\n * claim's slot.\n *\n * One shape for both kinds of match, with the two source fields nullable, rather than a discriminated\n * union. A caller reads `claim` unconditionally, because that is the disagreement and what a decision\n * is made on, and then reads whichever of `path`/`batchIndex` is non-null to find the other claim. A\n * union would make every consumer branch before it could read the field it actually wants, and the\n * wire form (`Schema.NullOr` per field, per the batch's present-and-nullable rule) would publish the\n * same two nullable fields anyway.\n *\n * Exactly one of the two is non-null, always. A store match names the active memory's `path`. An\n * intra-batch match names the earlier op's `batchIndex`, and has no path because that op's file does\n * not exist yet, since the batch has not been written when the assist runs.\n */\nexport interface FrameConflict {\n /** The active memory already holding this frame key, or null for an intra-batch match. */\n readonly path: string | null\n /** The earlier op in this same batch holding it, or null for a store match. */\n readonly batchIndex: number | null\n /** The other claim's own text. The disagreement itself, which is what a caller decides on. */\n readonly claim: string\n}\n\n/** One op's outcome as the doors report it: the store's own shape, with the envelope's code. */\nexport interface BatchOpReport {\n readonly index: number\n readonly ok: boolean\n readonly path?: string | undefined\n readonly deduped?: boolean | undefined\n readonly existingPath?: string | undefined\n /** The envelope error code for this op's failure, absent when it did not fail. */\n readonly code?: ErrorCode | undefined\n readonly error?: string | undefined\n readonly skipped?: boolean | undefined\n /**\n * What this op's claim contradicts, when `detectConflicts` was on and something matched. Absent\n * when the flag was off, when nothing matched, or when the claim has no frame shape.\n *\n * Propose-only, so the presence of this field never changed what was written. See {@link batchWrite}.\n */\n readonly conflict?: FrameConflict | undefined\n /**\n * Set on a batch-internal loser under `consolidate: \"last-wins\"`: a later restatement of a slot\n * an earlier op already occupied. Its value won the slot, since last wins, but the write landed at\n * the earliest index with that frame key, so this op never got its own file and has no `path`.\n * The number is that slot, the caller-space index whose report carries the surviving write with its\n * path and any `supersededPath`.\n */\n readonly consolidatedInto?: number | undefined\n /**\n * Set on a winner whose write superseded a live stored memory under `consolidate: \"last-wins\"`:\n * the loser's archive path, where its bytes now live. Absent when nothing stored occupied the\n * slot, and also when the supersede itself degraded. The corpus is then merely unconsolidated,\n * which is what every batch produced before this flag existed.\n */\n readonly supersededPath?: string | undefined\n}\n\nexport interface BatchWriteResult {\n readonly results: ReadonlyArray<BatchOpReport>\n readonly summary: {\n readonly total: number\n readonly written: number\n readonly deduped: number\n readonly failed: number\n readonly skipped: number\n /** Batch-internal losers under `consolidate: \"last-wins\"`: ops whose value a later op replaced. */\n readonly consolidated: number\n }\n readonly commitSha: string | null\n}\n\nexport interface BatchWriteParams extends Provenance {\n readonly ops: ReadonlyArray<WriteParams>\n /** Best-effort mode: failed ops are reported and skipped, survivors land in the one commit. */\n readonly continueOnError?: boolean | undefined\n /**\n * Report each op's frame-matches as a per-op `conflict`. Changes nothing about what is written.\n *\n * Off by default, and the default is part of the contract rather than caution. The assist costs one\n * extra query per batch, and a caller that did not ask for the field would be paying for an answer\n * it does not read.\n */\n readonly detectConflicts?: boolean | undefined\n /**\n * Opt-in write-time consolidation: deterministic frame-key (`frameKeyOf`) last-wins.\n *\n * `detectConflicts` reports and leaves the corpus alone. This one acts, on the caller's explicit ask.\n * A later op whose claim occupies the same frame slot as an earlier one replaces it before\n * anything is written, so a batch-internal loser never reaches disk. A surviving op whose slot a\n * live stored memory occupies supersedes it after the commit, archiving the old file with a\n * `supersedes` chain back from the winner. Fail-closed on the rule's own terms: a claim with no\n * frame shape (null key) is never touched, and a failed store lookup degrades to\n * batch-internal-only consolidation through the same `Effect.catch` → `logWarning` → neutral\n * shape {@link detectFrameConflicts} takes, so the flag cannot become a new way to lose writes.\n */\n readonly consolidate?: \"last-wins\" | undefined\n}\n\n/**\n * A typed failure as a per-op report, through the same `codeFor`/`messageFor` every envelope error\n * takes.\n *\n * Mapped here rather than in each door, deliberately. A per-op code is part of the batch's payload\n * rather than of the envelope, so two doors shaping it independently is two mappings that agree today.\n * `memhtml apply` and `memory_write_batch` reporting different codes for the same refused op is\n * the drift the shared-use-case rule exists to prevent.\n */\nconst reportFailure = (index: number, error: unknown): BatchOpReport => ({\n index,\n ok: false,\n code: codeFor(error),\n error: messageFor(error)\n})\n\n/**\n * The `detect_conflicts` assist: which claim, if any, each op's own claim contradicts.\n *\n * **Propose-only, and that is the design rather than a v1 limitation.** The function returns a report\n * per op index and writes nothing, stages nothing, and refuses nothing, because sometimes the\n * contradiction is the answer. A memory recording that a runbook step changed necessarily contradicts\n * the memory stating the old step, and an assist that auto-archived, applied last-wins, or blocked the\n * write would destroy the pair a later reader needs to see the change in. The caller decides: write\n * anyway, `memory_correct` the match, or skip.\n *\n * **One query for the whole batch.** Every op's frame key is collected first and `activeFramesFor` is\n * called once with all of them. The signature takes an array so a caller cannot loop, and a\n * per-op lookup would be the quadratic-write-cost pattern this codebase has already paid for once.\n *\n * **Two match sources, checked in that order.** The store answers for active non-task memories. Its\n * predicate, and 0009's index, exclude archived rows and tasks, because an archived claim is not a\n * competing assertion and an open to-do phrased as a claim is working state rather than knowledge. Then\n * come the batch's own earlier ops, folded as this loop walks them in order. Two ops in one call can\n * occupy the same slot, and neither is in the store yet, so nothing but this fold can see that pair. A\n * store match wins when an op has both, because the store's memory is a fact already in the corpus\n * while the earlier op is one this same call is about to create.\n *\n * **A later op reports on an earlier one, never the reverse.** The fold is asymmetric on purpose. Op 3\n * matching op 1 tells a caller \"you are about to restate something you just said\", which is actionable\n * with op 3 still in hand. Reporting it on op 1 as well would name a conflict with something that did\n * not exist when op 1 was written, and would double one finding into two.\n *\n * **A lookup failure degrades to no conflicts.** The assist is a note about the writes, so losing the\n * memories over a failed note about them would invert the priority as it would for\n * {@link recordLink} and {@link bumpAccess}, with the same `Effect.catch` → `logWarning` → neutral value.\n * The write path never sees this function's failure, which makes \"the assist cannot block a\n * write\" true structurally rather than by review.\n */\nconst detectFrameConflicts = (\n ops: ReadonlyArray<WriteParams>\n): Effect.Effect<ReadonlyMap<number, FrameConflict>, never, IndexRecorderShape> =>\n Effect.gen(function* () {\n /**\n * `frameKeyOf(op.claim)` per op, computed once and kept alongside the index.\n *\n * On the `article_html` path `claim` is `\"\"` by construction, because both doors leave it empty and\n * the `<mark>` inside the markup is the claim. `frameKeyOf` therefore returns null and a markup op\n * gets no assist. Deriving one here would mean parsing every op's article at the ops layer, a second\n * render of bytes the store is about to render anyway. The boundary is stated in the tool\n * description instead of hidden behind a duplicate parse.\n */\n const keyed: Array<{ readonly index: number; readonly key: string; readonly claim: string }> =\n []\n for (const [index, op] of ops.entries()) {\n const key = frameKeyOf(op.claim)\n if (key !== null) keyed.push({ index, key, claim: op.claim })\n }\n if (keyed.length === 0) return new Map<number, FrameConflict>()\n\n const recorder = yield* IndexRecorder\n const live = yield* recorder\n .activeFramesFor(keyed.map((entry) => entry.key))\n .pipe(\n Effect.catch((error) =>\n Effect.logWarning(`conflict assist skipped: ${error.operation}`).pipe(\n Effect.as(new Map<string, ReadonlyArray<FrameMatch>>())\n )\n )\n )\n\n const conflicts = new Map<number, FrameConflict>()\n /** frame key → the first op in this batch to occupy it. Built as the loop walks in order. */\n const seen = new Map<string, { readonly index: number; readonly claim: string }>()\n for (const entry of keyed) {\n const [stored] = live.get(entry.key) ?? []\n const earlier = seen.get(entry.key)\n if (stored !== undefined) {\n conflicts.set(entry.index, {\n path: stored.path,\n batchIndex: null,\n claim: stored.gist\n })\n } else if (earlier !== undefined) {\n conflicts.set(entry.index, {\n path: null,\n batchIndex: earlier.index,\n claim: earlier.claim\n })\n }\n if (earlier === undefined) seen.set(entry.key, { index: entry.index, claim: entry.claim })\n }\n return conflicts\n })\n\n/**\n * The `consolidate: \"last-wins\"` plan: which slots survive, which ops lost to a later restatement,\n * and which stored memories a surviving slot supersedes. Everything is in the caller's index space.\n */\ninterface LastWinsPlan {\n /** The ops the pipeline runs, each at its original slot index. Losers are absent. */\n readonly ops: ReadonlyArray<{ readonly index: number; readonly op: WriteParams }>\n /** Batch-internal loser index → the slot whose position carries the surviving value. */\n readonly losers: ReadonlyMap<number, number>\n /** Surviving slot index → the live stored memory occupying that slot's frame key. */\n readonly pendingSupersede: ReadonlyMap<number, string>\n}\n\n/**\n * Fold last-wins over the caller's op array, before the decode fold, so a batch-internal loser\n * never reaches disk. The surviving value simply occupies the earliest slot with that key.\n *\n * Not derived from {@link detectFrameConflicts}' output, although the walk mirrors it. A store\n * match wins there, masking the batch-internal pair the plan needs, and the plan needs both: the\n * batch collision decides which value writes, and the store match decides what that write supersedes.\n *\n * The slot rule: the first occupant of a key keeps its position and later ops with the same key\n * replace its content (`plannedOps[slot] = laterOp`, provenance and all, since the surviving value\n * is the later op's own statement). The occupant-tracking never moves, so a third restatement\n * replaces the slot again, last wins, at a stable position a caller can index by.\n *\n * Fail-closed on both of the rule's own guards: a null frame key is never consolidated, and a\n * failed store lookup degrades to batch-internal consolidation only, through the same\n * `Effect.catch` → `logWarning` → neutral-shape path the conflict assist takes, because an opt-in\n * consolidation must not become a new way to lose writes.\n */\nconst planLastWins = (\n ops: ReadonlyArray<WriteParams>\n): Effect.Effect<LastWinsPlan, never, IndexRecorderShape> =>\n Effect.gen(function* () {\n /** frame key → the slot (earliest occupant's index) that carries this key's surviving value. */\n const slotOf = new Map<string, number>()\n /** slot index → the op whose value currently occupies it. */\n const content = new Map<number, WriteParams>()\n const losers = new Map<number, number>()\n /** Slot indices in caller order, keyed and keyless alike. */\n const order: Array<number> = []\n\n for (const [index, op] of ops.entries()) {\n const key = frameKeyOf(op.claim)\n if (key === null) {\n // No frame shape, no slot. The rule's guards fail closed, so this op is never touched.\n order.push(index)\n content.set(index, op)\n continue\n }\n const slot = slotOf.get(key)\n if (slot === undefined) {\n slotOf.set(key, index)\n order.push(index)\n content.set(index, op)\n continue\n }\n content.set(slot, op)\n losers.set(index, slot)\n }\n\n const pendingSupersede = new Map<number, string>()\n if (slotOf.size > 0) {\n const recorder = yield* IndexRecorder\n // One query for every surviving key, for detectFrameConflicts' reason: a per-slot lookup is\n // the quadratic-write-cost shape this codebase has already paid for once.\n const live = yield* recorder\n .activeFramesFor([...slotOf.keys()])\n .pipe(\n Effect.catch((error) =>\n Effect.logWarning(`consolidation store lookup skipped: ${error.operation}`).pipe(\n Effect.as(new Map<string, ReadonlyArray<FrameMatch>>())\n )\n )\n )\n for (const [key, slot] of slotOf) {\n const [stored] = live.get(key) ?? []\n if (stored !== undefined) pendingSupersede.set(slot, stored.path)\n }\n }\n\n return {\n ops: order.flatMap((index) => {\n const op = content.get(index)\n return op === undefined ? [] : [{ index, op }]\n }),\n losers,\n pendingSupersede\n }\n })\n\n/**\n * Loser reports for a last-wins plan, derived from the winner slots' own final reports.\n *\n * A loser reports `ok` with `consolidatedInto` only when its slot's write landed, which means the\n * surviving value is on disk and the pointer names where. A slot that was skipped or refused took the\n * loser's value down with it, so the loser reports `skipped`, which is the retryable outcome and\n * the one an atomic abort already means: nothing of this op reached disk.\n */\nconst withConsolidation = (\n results: ReadonlyArray<BatchOpReport>,\n plan: LastWinsPlan | null\n): ReadonlyArray<BatchOpReport> => {\n if (plan === null || plan.losers.size === 0) return results\n return results.map((report, index) => {\n const slot = plan.losers.get(index)\n if (slot === undefined) return report\n const winner = results[slot]\n return winner?.ok === true && winner.skipped !== true\n ? ({ index, ok: true, consolidatedInto: slot } satisfies BatchOpReport)\n : ({ index, ok: false, skipped: true } satisfies BatchOpReport)\n })\n}\n\n/**\n * Write N memories: one commit, one reindex, per-op results in input order.\n *\n * **Two folds, not one.** Decode is the operations layer's job and the store never sees it, so a\n * malformed `memory_type` on op 4 has to be caught here. This function therefore folds decode\n * over the ops and hands the store only what decoded. The store then folds the render gate, dedup,\n * and path claim over that, and this function splices the two result sets back into one array in\n * the caller's index space. Anything less and a decode failure would either be invisible per-op or\n * would shift every later op's index by one.\n *\n * **One reindex, gated on a file having been written** (G4). The indexer's `update()` reads\n * `git diff` over one commit, so a batch that committed once costs one diff. A dedupe-only\n * batch, which commits nothing, skips it entirely, because moving the watermark for a commit that\n * never happened is what `writeMemory`'s own `if (result.created)` guard exists to avoid.\n *\n * **The conflict assist is a third pass and it is read-only** (AC-1-2). It runs before the store's\n * fold, over the ops as the caller sent them, and its findings are merged into the reports at the\n * end, so it observes the batch and never participates in it. Nothing downstream of\n * {@link detectFrameConflicts} branches on its result: the same files are written, the same commit is\n * made, and the same ops are refused whether the flag is on or off. That is what propose-only means,\n * and it is checkable by reading this function rather than by trusting a description.\n */\nexport const batchWrite = (params: BatchWriteParams) =>\n Effect.gen(function* () {\n const continueOnError = params.continueOnError === true\n const store = yield* Store\n const at = yield* nowSecond\n\n /**\n * The assist, over the caller's own op array and before anything is written.\n *\n * Over `params.ops` rather than the decoded `inputs` below, so a conflict is reported in the\n * caller's index space directly and needs no `originOf` translation. An op the store then\n * refuses still gets its finding, which is the more useful order, because a caller told both \"this\n * op is malformed\" and \"it also contradicts X\" fixes one thing.\n *\n * Not gated on the ops being valid, and deliberately so. `frameKeyOf` is a pure lexical function\n * over a string, so it has nothing to refuse and cannot fail on an op the decode is about to reject.\n */\n const conflicts =\n params.detectConflicts === true\n ? yield* detectFrameConflicts(params.ops)\n : new Map<number, FrameConflict>()\n\n /**\n * The consolidation plan, before the decode fold and in the caller's index space. A\n * batch-internal loser is excluded from everything downstream, so its value never earns a file.\n * The surviving value sits at the earliest slot with its key, so every later report and\n * conflict finding stays at the index the caller sent.\n */\n const plan = params.consolidate === \"last-wins\" ? yield* planLastWins(params.ops) : null\n const planned =\n plan === null ? [...params.ops.entries()].map(([index, op]) => ({ index, op })) : plan.ops\n\n /**\n * Fold 1, decode. `Effect.result` rather than letting the failure escape, because a decode\n * refusal is this op's result and not the batch's.\n */\n const reports: Array<BatchOpReport | undefined> = params.ops.map(() => undefined)\n const inputs: Array<WriteInput> = []\n /** Store-result position → caller's op index, since the store never sees a skipped op. */\n const originOf: Array<number> = []\n let decodeAborted = false\n\n for (const { index, op } of planned) {\n const decoded = yield* Effect.result(toWriteInput({ ...op, ...provenanceOf(params, op) }, at))\n if (decoded._tag === \"Failure\") {\n reports[index] = reportFailure(index, decoded.failure)\n if (!continueOnError) {\n decodeAborted = true\n break\n }\n continue\n }\n originOf.push(index)\n inputs.push(decoded.success)\n }\n\n /**\n * An atomic decode abort touches the store at all. Nothing was written, so every other op,\n * including the ones that decoded, reports `skipped`, matching the store's own abort semantics\n * exactly rather than inventing a second one.\n */\n if (decodeAborted) {\n const results = withConsolidation(merged(reports, conflicts), plan)\n return { results, summary: summarize(results), commitSha: null } satisfies BatchWriteResult\n }\n\n /**\n * The extraction assist: one model call over the decoded ops, extracted entities unioned into\n * each op's own `entities` before anything is written, so they land as ordinary `memhtml-entity`\n * metas and the git tree, rather than the index, is what remembers them.\n *\n * After the decode fold because a refused op must not reach the prompt, and before the store\n * because the render is what serializes the metas. Failure costs exactly this batch's\n * extracted entities. The port being absent, the model being down, and an unreadable payload\n * all take the same logged-warning path, and the write itself never waits on a retry.\n * `entities: []` is what every write produced before this assist existed.\n */\n const extractor = (yield* ExtractorPort).extractor\n if (extractor !== undefined && inputs.length > 0) {\n const items: Array<ExtractionItem> = inputs.map((input) => ({\n title: input.title,\n text:\n input.articleHtml !== undefined\n ? input.articleHtml\n : [input.claim, ...(input.body ?? [])].join(\"\\n\")\n }))\n const outcome = yield* Effect.result(extractor.extract(items))\n if (outcome._tag === \"Failure\") {\n yield* Effect.logWarning(\n `entity extraction skipped for this batch: ${outcome.failure.reason}`\n )\n } else {\n for (const [index, extracted] of outcome.success.entries()) {\n const input = inputs[index]\n if (input === undefined || extracted.length === 0) continue\n const declared = input.entities ?? []\n const union = [...declared, ...extracted.filter((entity) => !declared.includes(entity))]\n inputs[index] = { ...input, entities: union }\n }\n }\n }\n\n // Fold 2, the store: render gate, dedup against the folded state, one commit.\n const batch = yield* store.writeMemories(inputs, { continueOnError })\n\n for (const entry of batch.results) {\n const index = originOf[entry.index]\n if (index === undefined) continue\n reports[index] =\n entry.ok || entry.skipped === true\n ? {\n index,\n ok: entry.ok,\n ...defined({\n path: entry.path,\n deduped: entry.deduped,\n existingPath: entry.existingPath,\n skipped: entry.skipped\n })\n }\n : reportFailure(index, entry.error)\n }\n\n // One reindex, after the commit, only when a file was actually written.\n if (batch.writtenPaths.length > 0) yield* reindex()\n for (const path of batch.writtenPaths) yield* recordLink(path, \"wrote\", params, at)\n\n /**\n * The store-supersede pass, after a successful batch commit: every surviving slot whose frame\n * key a live memory occupied archives that memory, in one `supersedeMemories` call.\n *\n * A slot qualifies when its report is `ok` with a path, including a dedupe, where the path is\n * the pre-existing file that already carries this slot's value. The stored occupant still\n * states the losing value, so superseding it is still correct. A slot that failed or was\n * skipped wrote nothing, so there is nothing for its occupant to lose to.\n *\n * `Effect.result` rather than a bare yield, because a failed supersede must not fail a batch whose\n * memories already landed. The degradation is annotate-only: `supersededPath` is omitted, the\n * warning says why, and the corpus is merely unconsolidated, which is what every batch produced\n * before this flag existed. On success there is one extra reindex, because archive paths moved.\n */\n if (plan !== null && plan.pendingSupersede.size > 0) {\n const pairs: Array<{ readonly winnerPath: string; readonly loserPath: string }> = []\n const winnerOf = new Map<string, number>()\n for (const [slot, storedPath] of plan.pendingSupersede) {\n const report = reports[slot]\n if (report === undefined || !report.ok || report.skipped === true) continue\n if (report.path === undefined) continue\n // A slot whose content deduped onto the occupant itself is a restatement rather than a\n // supersession. Winner and loser are one file, and archiving it would lose the value.\n if (report.path === storedPath) continue\n pairs.push({ winnerPath: report.path, loserPath: storedPath })\n winnerOf.set(storedPath, slot)\n }\n if (pairs.length > 0) {\n const outcome = yield* Effect.result(store.supersedeMemories(pairs))\n if (outcome._tag === \"Failure\") {\n yield* Effect.logWarning(\n `consolidation supersede skipped: ${messageFor(outcome.failure)}`\n )\n } else {\n for (const entry of outcome.success.archived) {\n const slot = winnerOf.get(entry.loserPath)\n const report = slot === undefined ? undefined : reports[slot]\n if (slot === undefined || report === undefined) continue\n reports[slot] = { ...report, supersededPath: entry.archivePath }\n }\n if (outcome.success.archived.length > 0) yield* reindex()\n }\n }\n }\n\n /**\n * An op the store aborted before reaching has no result of its own, and neither does one whose\n * decode succeeded in a batch the store then aborted. Both are `skipped`. Losers pick up their\n * `consolidatedInto` pointer last, from their winner slot's own final report.\n */\n const results = withConsolidation(merged(reports, conflicts), plan)\n\n return {\n results,\n summary: summarize(results),\n commitSha: batch.commitSha\n } satisfies BatchWriteResult\n })\n\n/**\n * Per-op provenance falls back to the batch's own.\n *\n * The batch call carries the session the agent is in, and an op may name its own (a `memhtml apply`\n * file replaying a previous session's writes). Per-op wins, because it is the more specific statement\n * about where that one memory came from.\n */\nconst provenanceOf = (params: BatchWriteParams, op: WriteParams): Provenance =>\n defined({\n sessionId: op.sessionId ?? params.sessionId,\n promptId: op.promptId ?? params.promptId,\n turnUuid: op.turnUuid ?? params.turnUuid\n })\n\n/**\n * The reports as their final array: an unreported op becomes `skipped`, and every op picks up the\n * assist's finding for its index.\n *\n * One function for both exit paths, the atomic decode abort and the normal return, because they had\n * already grown two copies of the same `?? skipped` fill and a third responsibility spliced into only\n * one of them is how a batch that aborted would silently lose its conflict findings. The abort path\n * needs them because nothing was written. A caller told \"op 2 is malformed\" and also \"op 0\n * contradicts areas/x.html\" can fix both before retrying, rather than discovering the second on the\n * next round trip.\n *\n * Merging here rather than at each report's construction site also keeps the assist out of the\n * write path. The reports are already final when the conflicts are attached, so there is no point at\n * which a conflict could be read by anything that decides an outcome.\n */\nconst merged = (\n reports: ReadonlyArray<BatchOpReport | undefined>,\n conflicts: ReadonlyMap<number, FrameConflict>\n): ReadonlyArray<BatchOpReport> =>\n reports.map((report, index) => {\n const base = report ?? ({ index, ok: false, skipped: true } satisfies BatchOpReport)\n const conflict = conflicts.get(index)\n return conflict === undefined ? base : { ...base, conflict }\n })\n\n/** The counts, derived from the reports in one pass so they cannot disagree with them. */\nconst summarize = (results: ReadonlyArray<BatchOpReport>): BatchWriteResult[\"summary\"] => {\n let written = 0\n let deduped = 0\n let failed = 0\n let skipped = 0\n let consolidated = 0\n for (const result of results) {\n // A batch-internal loser is neither written nor failed. Its value survived at another slot,\n // and no file of its own was ever attempted, so it partitions into its own count.\n if (result.consolidatedInto !== undefined) consolidated += 1\n else if (result.skipped === true) skipped += 1\n else if (!result.ok) failed += 1\n else if (result.deduped === true) deduped += 1\n else written += 1\n }\n return { total: results.length, written, deduped, failed, skipped, consolidated }\n}\n\n/**\n * Read one memory, optionally recording that the session read it.\n *\n * The access bump lives here and nowhere else on the retrieval side, because salience accumulates\n * evidence that someone chose a memory and a ranker's guess is not a choice. An explicit open names\n * one path, through this call and the `memhtml://file/{path}` resource that funnels through it, which is\n * the strongest signal short of a write. A path merely returned by search or recall was the ranker's own\n * suggestion, and bumping it builds a rich-get-richer loop: today's top five rank higher\n * tomorrow while the memory that should displace them never breaks in to earn a first bump.\n *\n * `bumpAccess` sits beside `recordLink` deliberately. Both are notes about the read, both swallow their\n * own failures, and neither may cost the caller the memory it asked for.\n */\nexport const readMemory = (path: string, provenance: Provenance = {}) =>\n Effect.gen(function* () {\n const store = yield* Store\n const result = yield* store.readMemory(path)\n yield* recordLink(result.path, \"read\", provenance, yield* nowSecond)\n yield* bumpAccess([result.path])\n return result\n })\n\nexport interface SearchParams extends SearchScope {\n readonly query: string\n readonly limit?: number | undefined\n}\n\n/**\n * Ranked search. The retrieval service sanitizes the query text itself in `fts-query.ts`, so this\n * function never MATCHes user prose and neither does any caller of it.\n *\n * **No access bump, and the omission is the rule rather than an oversight.** A hit is the ranker's\n * guess about what the caller wanted, so counting it as salience would let the ranking teach itself.\n * A memory in today's top five would rank higher tomorrow purely for having been listed, and the\n * memory that should displace it never appears and so never earns a first bump. The cooldown does not\n * help, because it bounds one query replayed within 900 seconds, while the drift it would have to\n * bound operates across days. Salience moves when a caller opens a path ({@link readMemory}) or names\n * an outcome ({@link reinforceMemories}).\n */\nexport const searchMemories = (params: SearchParams) =>\n Effect.gen(function* () {\n const retrieval = yield* Retrieval\n return yield* retrieval.search(params)\n })\n\nexport interface RecallParams extends SearchScope {\n readonly query: string\n readonly budgetChars?: number | undefined\n}\n\n/**\n * A context pack under a character budget.\n *\n * No access bump either, for {@link searchMemories}' reason. A disclosed body is still the ranker's\n * choice of what to spend the budget on rather than the caller's choice of what to read.\n */\nexport const recallMemories = (params: RecallParams) =>\n Effect.gen(function* () {\n const retrieval = yield* Retrieval\n return yield* retrieval.recall(params)\n })\n\n/**\n * Bump access bookkeeping for paths a caller chose to open. A missing state plane makes this a no-op.\n *\n * `reinforce` is the one SQL writer for `state.access` and this helper does not become a second one.\n * It moves callers to that writer rather than moving the write here.\n */\nconst bumpAccess = (paths: ReadonlyArray<string>) =>\n Effect.gen(function* () {\n if (paths.length === 0) return\n const db = yield* DatabaseService\n if (!db.hasState) return\n yield* reinforce(db, paths, \"neutral\", yield* nowSecond).pipe(\n Effect.catch((error) =>\n Effect.logWarning(`access bookkeeping missed: ${error.operation}`).pipe(\n Effect.as({ bumped: [], cooledDown: [] })\n )\n )\n )\n })\n\nexport interface CorrectParams extends Provenance {\n readonly targetPath: string\n readonly title: string\n readonly claim: string\n readonly body?: ReadonlyArray<string> | undefined\n /** Pre-authored article markup for the superseding file, used verbatim in place of `claim`/`body`. */\n readonly articleHtml?: string | undefined\n readonly memoryType?: string | undefined\n readonly reason?: string | undefined\n}\n\n/**\n * Supersede a memory: the new file and the archived target land in one commit.\n *\n * The type defaults to the target's own. A correction that silently changed the type would move\n * the memory to a different retention profile and a different PARA directory, and that is a second\n * decision the caller did not make.\n */\nexport const correctMemory = (params: CorrectParams) =>\n Effect.gen(function* () {\n const store = yield* Store\n const target = yield* store.readMemory(params.targetPath)\n const requested = params.memoryType ?? target.doc.metas.memoryType\n const memoryType = yield* decodeWritableType(requested)\n const at = yield* nowSecond\n\n const result = yield* store.correctMemory(params.targetPath, {\n title: params.title,\n claim: params.claim,\n memoryType,\n at,\n ...defined({\n body: params.body,\n articleHtml: params.articleHtml,\n reason: params.reason,\n sessionId: params.sessionId,\n promptId: params.promptId,\n turnUuid: params.turnUuid\n })\n })\n\n // A correction is an add and a rename in one commit, so it needs the diff-driven path. The\n // archived target's row has to move rather than be re-added under a new name beside its old one.\n yield* reindex()\n yield* recordLink(result.path, \"corrected\", params, at)\n return result\n })\n\n/**\n * Add an authored edge. Idempotent on `(rel, href)`, so a re-run commits nothing.\n *\n * The rel is decoded against {@link AUTHORABLE_RELS}, the memory class plus the task class, so\n * `memhtml link a.html blocks b.html` reaches the task graph while a person or provenance rel, both of\n * which the system mints itself, stays unauthorable.\n */\nexport const linkMemories = (srcPath: string, rel: string, dstPath: string) =>\n Effect.gen(function* () {\n const edgeRel = yield* decodeAuthorableRel(rel)\n const store = yield* Store\n const src = normalizePath(srcPath)\n const result = yield* store.linkMemories(src, edgeRel, dstPath)\n // `addLink` is idempotent on the pair, so a re-link commits nothing and there is nothing to\n // index. Re-deriving a diff for a no-op would move the watermark for a commit that never was.\n if (result.commitSha !== null) yield* reindex()\n return { ...result, srcPath: src, dstPath: normalizePath(dstPath), rel: edgeRel }\n })\n\n/** Soft-evict: `git mv` into `archive/<YYYY>/` with the archive stamps. Never a delete. */\nexport const archiveMemory = (path: string, reason: string) =>\n Effect.gen(function* () {\n const store = yield* Store\n const result = yield* store.archiveMemory(path, reason)\n // An archive is a pure rename. Handled as two independent paths it would leave the source row\n // live and duplicate the chunks. The diff path re-points the row and keeps the vector.\n yield* reindex()\n return result\n })\n\n/** Bump access bookkeeping deliberately, with a caller-chosen signal. */\nexport const reinforceMemories = (paths: ReadonlyArray<string>, signal: string) =>\n Effect.gen(function* () {\n const decoded = yield* decodeSignal(signal)\n const db = yield* DatabaseService\n const at = yield* nowSecond\n if (!db.hasState) {\n return { bumped: [] as ReadonlyArray<string>, cooledDown: paths, signal: decoded }\n }\n const result = yield* reinforce(db, paths, decoded, at)\n return { ...result, signal: decoded }\n })\n\nexport interface NeighborsParams {\n readonly path: string\n /** 1 or 2. Clamped rather than refused: a caller asking for 5 wants \"as much as you'll give\". */\n readonly depth?: number | undefined\n readonly rels?: ReadonlyArray<string> | undefined\n}\n\n/** One node in a neighborhood. `hop` is 1-based distance from the center: 1 or 2, never 0. */\nexport interface NeighborNode {\n readonly path: string\n readonly title: string\n readonly hop: number\n readonly rel: string\n}\n\n/**\n * The memory graph around one path, to a fixed depth of at most two hops.\n *\n * **Two fixed-depth joins in a `UNION ALL`, deliberately not a recursive CTE.** The depth is\n * bounded at 2 by the tool's contract, so recursion buys nothing and costs the one thing a graph\n * query must not have here: an unbounded worst case on a corpus whose `relates_to` edges are\n * mined by the sleep cycle and can be dense. A fixed join is also index-covered by `edges_src`\n * and `edges_dst`, which a recursive walk is not.\n *\n * **Both directions, and `derived = 0 ∪ derived = 1`.** An edge is an assertion about a pair, and\n * which file happens to hold the `<link>` is authorship rather than direction of meaning. A\n * neighborhood that read only outbound edges would show a superseding memory its target and hide\n * from the target that it had been superseded. Derived edges are included because lateral retrieval\n * is what they are for. `derived` is still reported per node so a caller can tell a\n * sleep-mined suspicion from an authored assertion.\n *\n * `edge_class = 'memory'` on every join. A person edge entering here would put\n * `resources/people/*` into a memory neighborhood, and the class column exists to make that\n * structurally impossible.\n */\nexport const neighborsOf = (params: NeighborsParams) =>\n Effect.gen(function* () {\n const db = yield* DatabaseService\n const center = normalizePath(params.path)\n const depth = Math.min(2, Math.max(1, Math.trunc(params.depth ?? 1)))\n\n const rels = (params.rels ?? []).filter(\n (rel) => isEdgeRel(rel) && relClassFor(rel) === \"memory\"\n )\n const relFilter = rels.length > 0 ? ` AND e.rel IN (${rels.map(() => \"?\").join(\", \")})` : \"\"\n const relFilter2 = rels.length > 0 ? ` AND e2.rel IN (${rels.map(() => \"?\").join(\", \")})` : \"\"\n\n /**\n * Hop 1 is the center's own edges, either direction. Hop 2 walks one further from each hop-1\n * node and excludes the center, so a two-cycle does not report the center as its own neighbor\n * at distance 2.\n */\n const hopOne = `\n SELECT e.dst_path AS path, e.rel AS rel, e.derived AS derived, 1 AS hop\n FROM edges e\n WHERE e.src_path = ?1 AND e.edge_class = 'memory'${relFilter}\n UNION ALL\n SELECT e.src_path AS path, e.rel AS rel, e.derived AS derived, 1 AS hop\n FROM edges e\n WHERE e.dst_path = ?1 AND e.edge_class = 'memory'${relFilter}`\n\n const hopTwo = `\n SELECT e2.dst_path AS path, e2.rel AS rel, e2.derived AS derived, 2 AS hop\n FROM edges e\n JOIN edges e2 ON e2.src_path = e.dst_path\n WHERE e.src_path = ?1 AND e.edge_class = 'memory' AND e2.edge_class = 'memory'\n AND e2.dst_path <> ?1${relFilter}${relFilter2}\n UNION ALL\n SELECT e2.src_path AS path, e2.rel AS rel, e2.derived AS derived, 2 AS hop\n FROM edges e\n JOIN edges e2 ON e2.dst_path = e.src_path\n WHERE e.dst_path = ?1 AND e.edge_class = 'memory' AND e2.edge_class = 'memory'\n AND e2.src_path <> ?1${relFilter}${relFilter2}`\n\n const walk = depth === 1 ? hopOne : `${hopOne}\\n UNION ALL${hopTwo}`\n\n /**\n * `min(hop)` per path: a node reachable both directly and via a detour is a 1-hop neighbor,\n * and reporting it twice would let one memory occupy two slots in a bounded answer.\n *\n * The join onto `files` is an inner join, so an edge pointing at a path the tree does not hold\n * contributes nothing. A dangling href is `memhtml doctor`'s finding rather than a titleless node.\n */\n const rows = yield* db.all<{\n path: string\n title: string\n rel: string\n derived: number\n hop: number\n }>(\n `SELECT w.path AS path, f.title AS title, min(w.hop) AS hop,\n min(w.rel) AS rel, max(w.derived) AS derived\n FROM (${walk}) w\n JOIN files f ON f.path = w.path\n GROUP BY w.path\n ORDER BY hop ASC, w.path ASC`,\n // The rel list binds once per occurrence of the filter, in textual order: hop 1 uses it\n // twice, hop 2 uses it four times. Getting this count wrong is a bind mismatch rather than a\n // wrong answer, so it fails loudly.\n [\n center,\n ...(depth === 1\n ? [...rels, ...rels]\n : [...rels, ...rels, ...rels, ...rels, ...rels, ...rels])\n ]\n )\n\n const nodes: ReadonlyArray<NeighborNode> = rows.map((row) => ({\n path: row.path,\n title: row.title,\n hop: row.hop,\n rel: row.rel\n }))\n return { center, depth, nodes, edges: nodes.length }\n })\n\nexport interface ListParams {\n readonly memoryType?: string | undefined\n readonly workspace?: string | undefined\n readonly tag?: string | undefined\n readonly entity?: string | undefined\n readonly para?: string | undefined\n readonly limit?: number | undefined\n /** The previous page's `nextCursor`: the last path returned. A keyset rather than an offset. */\n readonly cursor?: string | undefined\n readonly includeArchived?: boolean | undefined\n}\n\n/**\n * Page the corpus by facet.\n *\n * Keyset pagination on `path` rather than `LIMIT/OFFSET`. `files.path` is the primary key and it also\n * moves, because eviction is a `git mv`, so an offset page taken while a sleep cycle archives a file\n * would skip a row or repeat one. A cursor on the path itself is stable against that.\n */\nexport const listMemories = (params: ListParams) =>\n Effect.gen(function* () {\n const db = yield* DatabaseService\n const limit = Math.min(500, Math.max(1, Math.trunc(params.limit ?? 50)))\n const conditions: Array<string> = []\n const values: Array<string | number> = []\n\n if (params.includeArchived !== true) conditions.push(\"f.archived = 0\")\n if (params.memoryType !== undefined && params.memoryType !== \"\") {\n const memoryType = yield* decodeWritableType(params.memoryType)\n conditions.push(\"f.memory_type = ?\")\n values.push(memoryType)\n }\n if (params.workspace !== undefined && params.workspace !== \"\") {\n conditions.push(\"f.workspace = ?\")\n values.push(params.workspace)\n }\n if (params.para !== undefined && params.para !== \"\") {\n conditions.push(\"f.para = ?\")\n values.push(params.para)\n }\n if (params.tag !== undefined && params.tag !== \"\") {\n conditions.push(\"EXISTS (SELECT 1 FROM file_tags t WHERE t.path = f.path AND t.tag = ?)\")\n values.push(params.tag)\n }\n if (params.entity !== undefined && params.entity !== \"\") {\n // The entity arrives as `type:name` and the table splits it at the first colon, so the\n // comparison rebuilds the reference rather than making the caller know the split.\n conditions.push(\n \"EXISTS (SELECT 1 FROM file_entities e WHERE e.path = f.path AND e.entity_type || ':' || e.entity_name = ?)\"\n )\n values.push(params.entity)\n }\n if (params.cursor !== undefined && params.cursor !== \"\") {\n conditions.push(\"f.path > ?\")\n values.push(normalizePath(params.cursor))\n }\n\n const where = conditions.length === 0 ? \"\" : `WHERE ${conditions.join(\" AND \")}`\n const rows = yield* db.all<{\n path: string\n title: string\n memory_type: string\n gist: string\n workspace: string | null\n para: string\n confidence: number\n importance: number\n archived: number\n updated_at: string\n }>(\n `SELECT f.path, f.title, f.memory_type, f.gist, f.workspace, f.para,\n f.confidence, f.importance, f.archived, f.updated_at\n FROM files f ${where} ORDER BY f.path ASC LIMIT ?`,\n [...values, limit + 1]\n )\n\n // One row over the limit is fetched to decide whether a next page exists, then dropped. A\n // separate COUNT would be a second statement over the same predicate and could disagree with\n // this one under a concurrent write.\n const page = rows.slice(0, limit)\n const nextCursor = rows.length > limit ? (page.at(-1)?.path ?? null) : null\n return {\n files: page.map((row) => ({\n path: row.path,\n title: row.title,\n memoryType: row.memory_type,\n gist: row.gist,\n workspace: row.workspace,\n para: row.para,\n confidence: row.confidence,\n importance: row.importance,\n archived: row.archived === 1,\n updatedAt: row.updated_at\n })),\n nextCursor\n }\n })\n\n/**\n * The task surface: CRUDL without retrieval.\n *\n * A task is the 10th `memory_type` and it is default-excluded from search, dedup, and all fifteen\n * sleep phases, so the working set an agent needs is not reachable by ranking. These three\n * functions are how it becomes reachable: `task add` wraps {@link writeMemory}, `task status` is one\n * head meta edited in place, and {@link listTasks} is a direct indexed scan. Reading a directory,\n * grepping a meta, and editing one line remain equally valid, and nothing here is the only path.\n */\n\nexport interface TaskStatusParams {\n readonly path: string\n readonly status: string\n /** Why the task closed. Stamped as the archive reason when the status is `done`. */\n readonly reason?: string | undefined\n}\n\n/** What a status change did. `archived` is true only for the `done` transition. */\nexport interface TaskStatusResult {\n readonly path: string\n readonly taskStatus: TaskStatus\n readonly archived: boolean\n /** The archive path, present iff `archived`. */\n readonly archivePath?: string | undefined\n readonly commitSha: string | null\n /** True when the file already carried this status, so nothing was written. */\n readonly unchanged: boolean\n}\n\n/**\n * Move a task to a new status.\n *\n * **`setMeta`, never parse→serialize.** The editors splice by source offset, so the article's bytes\n * cannot move on a status change, and neither can `memhtml-content-hash`, the dedupe key, or any chunk\n * id hanging off it. A round trip through the serializer drops a `<pre>` newline per write, which\n * would re-embed a task for a one-word edit and break the hash the file claims for itself.\n *\n * **`done` routes through `store.archiveMemory`**, which is a `git mv`. That is the design decision\n * that keeps `done` off the `memhtml-status` axis. Finishing a task stamps the status and moves the file\n * under `archive/<YYYY>/`, so \"what did I finish\" is the archive tree plus `git log` rather than a\n * fifth value every archive, correction, and publish path would have to learn. The stamp is written\n * before the move so both land in one commit and `git log --follow` reads through it.\n *\n * `indexer.update()` afterwards rather than `indexPaths`, because the `done` transition is a rename and\n * `indexPaths` cannot express one. It would leave the pre-archive row live, duplicate the chunks\n * under two paths, and skip the watermark (finding from T9, stated at {@link reindex}).\n */\nexport const setTaskStatus = (params: TaskStatusParams) =>\n Effect.gen(function* () {\n const status = yield* decodeTaskStatus(params.status)\n const store = yield* Store\n const path = normalizePath(params.path)\n const at = yield* nowSecond\n\n // Read through the parser. A `memhtml task status` on a memory file would otherwise stamp a meta the\n // format refuses on that type, producing a file the indexer then declines to project.\n const existing = yield* store.readMemory(path)\n if (existing.doc.metas.memoryType !== \"task\") {\n return yield* Effect.fail(\n InvalidMemory.make({\n reason: `${path} is a ${existing.doc.metas.memoryType} memory, not a task: only a task carries memhtml-task-status`\n })\n )\n }\n\n /**\n * A no-op status change writes nothing and commits nothing, so a re-run is free and the tree\n * stays byte-identical. The `memhtml-updated` stamp is skipped along with it, because a fresh\n * timestamp with no status change would claim the task moved when it did not.\n */\n if (existing.doc.metas.taskStatus === status) {\n return {\n path,\n taskStatus: status,\n archived: false,\n commitSha: null,\n unchanged: true\n } satisfies TaskStatusResult\n }\n\n const stamped = setMeta(\n setMeta(existing.html, \"memhtml-task-status\", status),\n \"memhtml-updated\",\n at\n )\n yield* attemptIo(`task.write:${path}`, async () => {\n const { writeFile } = await import(\"node:fs/promises\")\n const { join } = await import(\"node:path\")\n await writeFile(join(store.root, path), stamped, \"utf8\")\n })\n\n if (status !== \"done\") {\n yield* store.git.add([path])\n const commit = yield* store.git.commit(commitSubject(\"task\", `${status} ${path}`))\n yield* reindex()\n return {\n path,\n taskStatus: status,\n archived: false,\n commitSha: commit.sha,\n unchanged: false\n } satisfies TaskStatusResult\n }\n\n /**\n * `archiveMemory` stages the `git mv` and commits, and it reads the file from disk, so the\n * `memhtml-task-status: done` stamp written just above travels with the move rather than needing a\n * second commit. `git mv` carries a working-tree modification with it (probed live 2026-08-02:\n * the staged blob is the pre-edit content and the worktree keeps the edit), and `archiveMemory`\n * re-writes the stamped bytes at the destination before staging, so the committed file holds\n * both the archive stamps and the done status.\n */\n const archived = yield* store.archiveMemory(path, params.reason ?? `task ${status}`)\n yield* reindex()\n return {\n path,\n taskStatus: status,\n archived: true,\n archivePath: archived.archivePath,\n commitSha: archived.commitSha,\n unchanged: false\n } satisfies TaskStatusResult\n })\n\nexport interface ListTasksParams {\n readonly status?: string | undefined\n readonly workspace?: string | undefined\n /** An ISO date. Returns tasks due strictly before it, so `--due-before today` is \"overdue\". */\n readonly dueBefore?: string | undefined\n readonly limit?: number | undefined\n /** The previous page's `nextCursor`: the last path returned. A keyset rather than an offset. */\n readonly cursor?: string | undefined\n readonly includeArchived?: boolean | undefined\n}\n\n/** One task row as `task list` reports it. */\nexport interface TaskRow {\n readonly path: string\n readonly title: string\n readonly taskStatus: string | null\n readonly dueAt: string | null\n readonly workspace: string | null\n readonly archived: boolean\n readonly updatedAt: string\n /** Every task asserting `blocks` toward this one, path-ordered. Empty when nothing blocks it. */\n readonly blockedBy: ReadonlyArray<string>\n}\n\n/**\n * The task working set: a direct indexed scan, deliberately not retrieval.\n *\n * No RRF, no MMR, no embedding. A to-do list is not a ranking problem. An agent asking \"what is\n * open\" wants every row in a stable order, and a relevance score over working state would make the\n * answer depend on a query the caller does not have. The partial index `files_task_status`\n * (`WHERE memory_type='task' AND archived=0`) is what makes the default scan cheap.\n *\n * `blockedBy` is one correlated subquery over `edges`, filtered to `edge_class='task'` and\n * `rel='blocks'`. **The class filter is redundant with the rel filter today and is kept anyway.**\n * Probed live 2026-08-02: `0008_tasks.sql`'s per-class CHECKs refuse `blocks` under `memory`,\n * `person`, and `provenance`, so `rel='blocks'` already implies the class, and a mutation removing the\n * class predicate leaves every test green. It stays because the class column is what every\n * memory-graph query filters on, and a reader who saw this one query trust the rel alone would learn\n * the wrong rule about how the firewall is enforced.\n *\n * `group_concat` over an ordered subselect, probed 2026-08-12 on node 24.19.0. The inner `ORDER BY`\n * is preserved, and `char(10)` is the separator because a path cannot contain a newline while it can\n * contain a comma.\n *\n * The join is deliberately not an inner join onto `files`. A blocker whose file left the tree still\n * blocks, and hiding it here would make a permanently-blocked task look ready. `memhtml doctor` reports\n * that as a finding, and this function reports the edge as the corpus states it.\n */\nexport const listTasks = (params: ListTasksParams) =>\n Effect.gen(function* () {\n const db = yield* DatabaseService\n const limit = Math.min(500, Math.max(1, Math.trunc(params.limit ?? 50)))\n const conditions: Array<string> = [\"f.memory_type = 'task'\"]\n const values: Array<string | number> = []\n\n if (params.includeArchived !== true) conditions.push(\"f.archived = 0\")\n if (params.status !== undefined && params.status !== \"\") {\n const status = yield* decodeTaskStatus(params.status)\n conditions.push(\"f.task_status = ?\")\n values.push(status)\n }\n if (params.workspace !== undefined && params.workspace !== \"\") {\n conditions.push(\"f.workspace = ?\")\n values.push(params.workspace)\n }\n if (params.dueBefore !== undefined && params.dueBefore !== \"\") {\n const dueBefore = yield* decodeDueAt(params.dueBefore)\n /**\n * `substr(…, 1, 10)` on both sides, so the comparison is one of calendar days.\n *\n * The case it fixes, established by enumeration 2026-08-02: a due date stored as a bare day\n * against a bound carrying a time on that same day. Whole-string,\n * `\"2026-08-25\" < \"2026-08-25T09:00:00Z\"` is true, because the shorter string is a prefix and\n * sorts first, so a task due sometime on the 25th would be reported late at 09:00 on the 25th.\n * A day-granularity deadline is not late until the day is over, and truncating both sides is\n * what says so. Every other combination of the two forms agrees either way.\n */\n conditions.push(\"f.due_at IS NOT NULL AND substr(f.due_at, 1, 10) < substr(?, 1, 10)\")\n values.push(dueBefore)\n }\n if (params.cursor !== undefined && params.cursor !== \"\") {\n conditions.push(\"f.path > ?\")\n values.push(normalizePath(params.cursor))\n }\n\n const rows = yield* db.all<{\n path: string\n title: string\n task_status: string | null\n due_at: string | null\n workspace: string | null\n archived: number\n updated_at: string\n blocked_by: string | null\n }>(\n `SELECT f.path, f.title, f.task_status, f.due_at, f.workspace, f.archived, f.updated_at,\n (SELECT group_concat(b.src_path, char(10)) FROM (\n SELECT e.src_path AS src_path FROM edges e\n WHERE e.dst_path = f.path AND e.edge_class = 'task' AND e.rel = 'blocks'\n ORDER BY e.src_path ASC) b) AS blocked_by\n FROM files f\n WHERE ${conditions.join(\" AND \")}\n ORDER BY f.path ASC LIMIT ?`,\n [...values, limit + 1]\n )\n\n const page = rows.slice(0, limit)\n const nextCursor = rows.length > limit ? (page.at(-1)?.path ?? null) : null\n return {\n tasks: page.map(\n (row): TaskRow => ({\n path: row.path,\n title: row.title,\n taskStatus: row.task_status,\n dueAt: row.due_at,\n workspace: row.workspace,\n archived: row.archived === 1,\n updatedAt: row.updated_at,\n blockedBy: row.blocked_by === null ? [] : row.blocked_by.split(\"\\n\")\n })\n ),\n nextCursor\n }\n })\n\n/**\n * `mergeTailExtract` as the merger `persistScanned` requires.\n *\n * The two shapes differ in exactly one field, and the difference is real rather than cosmetic.\n * `SessionExtract` carries `counters`, the parse bookkeeping of one scan, and the persisted\n * `traces` row does not, because those are facts about a read rather than about the session.\n * `readStoredExtract` therefore cannot reconstruct them, and the merge is handed zeros for the\n * stored side. The merged counters then describe this scan alone, which is the only reading\n * available. Inventing a stored value would produce a number that claims to count lines nobody\n * read.\n *\n * Every other field the merge reads is present on both shapes, so this adapter is total.\n */\nconst ZERO_COUNTERS = {\n parsedLines: 0,\n droppedLines: 0,\n droppedNoSession: 0,\n skippedTypeLines: 0,\n unknownTypeLines: 0\n} as const\n\nconst tailMerger: TailMerger = (stored, tail) =>\n mergeTailExtract(\n { ...stored, counters: ZERO_COUNTERS } as SessionExtract,\n { ...tail, counters: ZERO_COUNTERS } as SessionExtract\n )\n\n/**\n * Scan the trace root and persist what changed.\n *\n * {@link tailMerger} is passed as the tail merger, and this is the only correct way to call\n * `persistScanned` on a `tail` action. A tail's extract describes the appended slice, so its\n * `first_prompt` is a mid-conversation prompt, its `started_at` is later than the session's, and\n * its prompt ordinals restart at 0. `persistScanned` takes the merger as a parameter precisely so\n * that \"never upsert a tail extract directly\" is a type-level obligation rather than a convention.\n */\nexport const indexTraces = () =>\n Effect.gen(function* () {\n const roots = yield* Roots\n const db = yield* DatabaseService\n const at = yield* nowSecond\n\n const report = yield* scanTraceRoot(roots.traceRoot, readWatermark(db))\n\n let sessionsWritten = 0\n let promptsWritten = 0\n let merged = 0\n for (const scanned of report.files) {\n const outcome = yield* persistScanned(db, scanned, tailMerger, at)\n if (outcome.action !== \"skip\") sessionsWritten += 1\n if (outcome.merged) merged += 1\n promptsWritten += outcome.promptsWritten\n }\n\n return {\n traceRoot: roots.traceRoot,\n filesSeen: report.files.length,\n skipped: report.skipped,\n tailed: report.tailed,\n rescanned: report.rescanned,\n bytesRead: report.bytesRead,\n sessionsWritten,\n promptsWritten,\n tailsMerged: merged\n }\n })\n\nexport interface TraceSearchParams {\n readonly query: string\n readonly cwd?: string | undefined\n readonly since?: string | undefined\n readonly limit?: number | undefined\n}\n\n/**\n * FTS over session first-prompts and AI titles.\n *\n * The query goes through the same sanitizer the memory arms use, and it has to. An apostrophe is a\n * hard driver error rather than an empty result, and \"what did I ask about don't-repeat-yourself\"\n * is an ordinary trace query. An empty sanitized query returns the most recent sessions rather\n * than nothing, because a caller with no terms wants a listing and an empty MATCH is not a listing.\n *\n * This is the trace plane and it stops here. No memory table is named, and nothing in the\n * retrieval assembler names `traces`. The firewall is by table name, in both directions.\n */\nexport const searchTraces = (params: TraceSearchParams) =>\n Effect.gen(function* () {\n const db = yield* DatabaseService\n const match = sanitizeFtsQuery(params.query)\n const limit = Math.min(200, Math.max(1, Math.trunc(params.limit ?? 20)))\n\n const conditions: Array<string> = []\n const values: Array<string | number> = []\n /**\n * The MATCH names `traces_fts` rather than a column of `traces`. The index is an external-content\n * FTS5 table, so it is joined in by rowid and only reached when there is something to match. Without\n * a query the statement never mentions it, which is what keeps a bare listing a plain table scan.\n */\n const matched = match !== \"\"\n const from = matched\n ? \"FROM traces_fts JOIN traces t ON t.rowid = traces_fts.rowid\"\n : \"FROM traces t\"\n if (matched) {\n conditions.push(\"traces_fts MATCH ?\")\n values.push(match)\n }\n if (params.cwd !== undefined && params.cwd !== \"\") {\n conditions.push(\"t.cwd = ?\")\n values.push(params.cwd)\n }\n if (params.since !== undefined && params.since !== \"\") {\n conditions.push(\"t.started_at >= ?\")\n values.push(params.since)\n }\n\n const where = conditions.length === 0 ? \"\" : `WHERE ${conditions.join(\" AND \")}`\n // A matched query orders by relevance, ascending because FTS5's bm25 is negative-is-better.\n // Without a match there is no relevance to order by and recency is the useful order.\n const order = matched ? \"ORDER BY bm25(traces_fts)\" : \"ORDER BY t.started_at DESC\"\n const rows = yield* db.all<{\n session_id: string\n slug: string\n cwd: string | null\n started_at: string | null\n prompt_count: number\n first_prompt: string\n ai_title: string | null\n }>(\n `SELECT t.session_id, t.slug, t.cwd, t.started_at, t.prompt_count, t.first_prompt, t.ai_title\n ${from} ${where} ${order} LIMIT ?`,\n [...values, limit]\n )\n\n return {\n sessions: rows.map((row) => ({\n sessionId: row.session_id,\n slug: row.slug,\n cwd: row.cwd,\n startedAt: row.started_at,\n promptCount: row.prompt_count,\n firstPrompt: row.first_prompt,\n aiTitle: row.ai_title\n })),\n degraded: match === \"\"\n }\n })\n\n/**\n * The memory-session links, from either side.\n *\n * Both parameters absent is a refusal rather than an unbounded scan of every link ever recorded. A\n * tool whose no-argument form returns the whole table is a tool an agent calls by accident.\n */\nexport const traceLinks = (params: {\n readonly sessionId?: string | undefined\n readonly path?: string | undefined\n}) =>\n Effect.gen(function* () {\n const hasSession = params.sessionId !== undefined && params.sessionId !== \"\"\n const hasPath = params.path !== undefined && params.path !== \"\"\n if (!hasSession && !hasPath) {\n return yield* Effect.fail(\n InvalidMemory.make({ reason: \"trace links needs a session_id or a path\" })\n )\n }\n\n const db = yield* DatabaseService\n const conditions: Array<string> = []\n const values: Array<string> = []\n if (hasSession) {\n conditions.push(\"l.session_id = ?\")\n values.push(params.sessionId as string)\n }\n if (hasPath) {\n conditions.push(\"l.path = ?\")\n values.push(normalizePath(params.path as string))\n }\n\n const rows = yield* db.all<{\n path: string\n session_id: string\n prompt_id: string | null\n turn_uuid: string | null\n link_kind: string\n at: string\n }>(\n `SELECT l.path, l.session_id, l.prompt_id, l.turn_uuid, l.link_kind, l.at\n FROM memory_session_links l\n WHERE ${conditions.join(\" AND \")}\n ORDER BY l.at DESC, l.path ASC`,\n values\n )\n\n return {\n links: rows.map((row) => ({\n path: row.path,\n sessionId: row.session_id,\n promptId: row.prompt_id,\n turnUuid: row.turn_uuid,\n linkKind: row.link_kind,\n at: row.at\n }))\n }\n })\n\n/**\n * Corpus health, in one call.\n *\n * `indexFresh` compares the recorded watermark to `HEAD`, which is the only answer that means\n * anything. The index is a projection of a commit, so \"fresh\" means \"the commit it describes is the\n * commit we are on\". A count of rows would say the index exists rather than that it is current.\n *\n * `embedderUp` is read off the stored watermark rather than by probing Bedrock. A status call that\n * made a network request would fail for a reason unrelated to the corpus, and what a caller\n * needs to know is whether the vectors in this index are usable.\n */\nexport const statusReport = () =>\n Effect.gen(function* () {\n const store = yield* Store\n const db = yield* DatabaseService\n\n const headSha = yield* store.git.revParseHead()\n const dirty = yield* store.dirtyPaths()\n\n const state = yield* readIndexState(db).pipe(Effect.orElseSucceed(() => undefined))\n\n const byType = yield* countRows(\n db,\n \"SELECT memory_type AS k, count(*) AS n FROM files WHERE archived = 0 GROUP BY memory_type\"\n )\n const archivedCount = yield* countOne(db, \"SELECT count(*) AS n FROM files WHERE archived = 1\")\n const edges = yield* countOne(db, \"SELECT count(*) AS n FROM edges\")\n const derivedEdges = yield* countOne(db, \"SELECT count(*) AS n FROM edges WHERE derived = 1\")\n const embeddings = yield* countOne(db, \"SELECT count(*) AS n FROM embeddings\")\n const chunks = yield* countOne(db, \"SELECT count(*) AS n FROM chunks\")\n const traces = yield* countOne(db, \"SELECT count(*) AS n FROM traces\")\n\n const lastSleep = yield* db\n .get<{ run_id: string; status: string; started_at: string }>(\n \"SELECT run_id, status, started_at FROM sleep_runs ORDER BY started_at DESC LIMIT 1\"\n )\n .pipe(Effect.orElseSucceed(() => undefined))\n\n return {\n root: store.root,\n headSha,\n dirty: dirty.length > 0,\n dirtyPaths: dirty,\n countsByType: byType,\n archivedCount,\n edges,\n derivedEdges,\n chunks,\n embeddings,\n traces,\n indexFresh: state?.head_sha !== null && state?.head_sha === headSha,\n indexHeadSha: state?.head_sha ?? null,\n embedModel: state?.embed_model ?? null,\n // A stored watermark that disagrees with the configured one means every cosine in this index\n // is against a different vector space. Reporting it as \"up\" would be the silent half-migration\n // the indexer refuses at write time.\n embedderUp: state !== undefined && state.embed_model === EMBED_WATERMARK && embeddings > 0,\n hasState: db.hasState,\n lastSleep:\n lastSleep === undefined\n ? null\n : { runId: lastSleep.run_id, status: lastSleep.status, startedAt: lastSleep.started_at }\n }\n })\n\n/** One scalar count, `0` when the table is unreachable. */\nconst countOne = (db: DatabaseShape, sql: string): Effect.Effect<number, StorageFailure> =>\n db.get<{ n: number }>(sql).pipe(Effect.map((row) => row?.n ?? 0))\n\n/** A `GROUP BY` into a record. An absent key means zero, so the caller never reads a null. */\nconst countRows = (\n db: DatabaseShape,\n sql: string\n): Effect.Effect<Readonly<Record<string, number>>, StorageFailure> =>\n db\n .all<{ k: string; n: number }>(sql)\n .pipe(Effect.map((rows) => Object.fromEntries(rows.map((row) => [row.k, row.n]))))\n\n/** Re-exported so the write path's type guard is usable by a caller building tool schemas. */\nexport { isWritableMemoryType }\n","import { MEMORY_RELS } from \"@memhtml/contracts/edges\"\nimport { TASK_STATUSES, WRITABLE_MEMORY_TYPES } from \"@memhtml/contracts/types\"\nimport { REINFORCE_SIGNALS } from \"@memhtml/domain\"\nimport { SLEEP_PHASES } from \"@memhtml/sleep\"\n\nimport { CONFIG_VARS } from \"./config.js\"\nimport { ERROR_CODES, type ResponseType } from \"./envelope.js\"\nimport { AUTHORABLE_RELS } from \"./operations.js\"\n\nexport interface FlagSpec {\n readonly name: string\n readonly type: \"string\" | \"int\" | \"boolean\"\n readonly description: string\n readonly default?: string | number | boolean\n readonly values?: ReadonlyArray<string>\n readonly required?: boolean\n /** True when the flag may be repeated, each occurrence appending a value. */\n readonly repeatable?: boolean\n}\n\nexport interface ArgSpec {\n readonly name: string\n readonly description: string\n readonly required: boolean\n}\n\nexport interface CommandSpec {\n readonly name: string\n readonly summary: string\n readonly args: ReadonlyArray<ArgSpec>\n readonly flags: ReadonlyArray<FlagSpec>\n readonly responseTypes: ReadonlyArray<ResponseType>\n}\n\n/** Flags every command accepts. Listed once so the manifest cannot drift from behavior. */\nexport const GLOBAL_FLAGS: ReadonlyArray<FlagSpec> = [\n {\n name: \"json\",\n type: \"boolean\",\n description: \"Emit the typed JSON envelope on stdout (default; logs go to stderr).\",\n default: true\n },\n {\n name: \"dense\",\n type: \"boolean\",\n description: \"Minify JSON and drop null fields, for pasting into a context window.\",\n default: false\n },\n {\n name: \"repo\",\n type: \"string\",\n description: \"Path to the memory repo. Defaults to $MEMHTML_ROOT.\",\n default: \"\"\n }\n]\n\n/** Flags every retrieval command shares, so `search` and `recall` cannot scope differently. */\nconst SCOPE_FLAGS: ReadonlyArray<FlagSpec> = [\n {\n name: \"type\",\n type: \"string\",\n description: \"Restrict to one memory type. Repeatable; each occurrence broadens (ANY-of).\",\n values: WRITABLE_MEMORY_TYPES,\n repeatable: true\n },\n {\n name: \"workspace\",\n type: \"string\",\n description:\n \"Restrict to one workspace. STRICT: a scoped query never returns a memory with no workspace.\"\n },\n {\n name: \"tag\",\n type: \"string\",\n description: \"Restrict to memories carrying any of these tags. Repeatable; each broadens.\",\n repeatable: true\n },\n {\n name: \"entity\",\n type: \"string\",\n // Singular, unlike --tag, because the scope exists to chain one hop off a hit's own entity list,\n // which is one reference at a time. Same spelling `memhtml list --entity` takes, so the two are\n // one vocabulary rather than two facets that happen to share a word.\n description:\n \"Restrict to memories carrying one `type:name` entity reference, e.g. service:checkout-api, the form a hit's `entities` publishes, so a hop is a copy. A scope matching nothing returns no hits and says so; it never widens.\"\n },\n {\n name: \"include-archived\",\n type: \"boolean\",\n description: \"Include archived memories. Eviction is a `git mv`, so they still exist.\",\n default: false\n },\n {\n name: \"as-of\",\n type: \"string\",\n description:\n \"Point-in-time view: returns what was believed valid at this ISO instant, including since-superseded memories (marked superseded_by). The validity window is coalesce(valid_from, event_at, created_at) <= as-of < valid_until.\"\n }\n]\n\n/**\n * The single source of parsing, validation, and the manifest. A command lands here\n * before it lands anywhere else, so `memhtml manifest` and `memhtml agents-doc` describe\n * what the binary actually accepts rather than what someone remembered to document.\n *\n * A subcommand is one entry with a space in its name (`index rebuild`), not a nested tree.\n * Flattening keeps `nearest()` able to suggest across the whole surface, a typo in the noun\n * (`memhtml indx rebuild`) and a typo in the verb (`memhtml index rebiuld`) both get a candidate, and\n * keeps one table driving parsing, the manifest, and the generated doc.\n */\nexport const COMMANDS: ReadonlyArray<CommandSpec> = [\n {\n name: \"manifest\",\n summary: \"Emit this CLI's full machine-readable contract.\",\n args: [],\n flags: [],\n responseTypes: [\"cli.manifest\"]\n },\n {\n name: \"init\",\n summary: \"Scaffold a memory repo at --repo/$MEMHTML_ROOT: git init, PARA dirs, merge driver.\",\n args: [],\n flags: [],\n responseTypes: [\"repo.init\"]\n },\n {\n name: \"write\",\n summary: \"Write one memory. Content-hash duplicates return the existing path, uncommitted.\",\n args: [],\n flags: [\n {\n name: \"title\",\n type: \"string\",\n description: \"The memory's title. Becomes the <title> and the filename slug.\",\n required: true\n },\n {\n name: \"claim\",\n type: \"string\",\n description:\n \"The one load-bearing sentence. Becomes the <mark> span and files.gist. Exactly one of --claim or --article-html.\"\n },\n {\n name: \"body\",\n type: \"string\",\n description: \"A prose paragraph after the claim. Repeatable, one <p> each.\",\n repeatable: true\n },\n {\n name: \"article-html\",\n type: \"string\",\n description:\n \"Raw <article> markup used verbatim in place of --claim/--body. Must contain exactly one <mark> in the first <p> or <li>; the first <time datetime> becomes the memory's event time. The store refuses format violations before any commit. Exactly one of --claim or --article-html.\"\n },\n {\n name: \"type\",\n type: \"string\",\n description: \"The memory type. `arc` is absent: an arc is synthesized by sleep.\",\n values: WRITABLE_MEMORY_TYPES,\n required: true\n },\n {\n name: \"path\",\n type: \"string\",\n description: \"An explicit path override. Ignored when it is not a valid memory path.\"\n },\n { name: \"workspace\", type: \"string\", description: \"Routes the memory to projects/<slug>/.\" },\n {\n name: \"tag\",\n type: \"string\",\n description: \"A tag. Repeatable; the first one routes an unplaced resource memory.\"\n },\n {\n name: \"entity\",\n type: \"string\",\n description: \"A `type:name` entity reference, e.g. service:checkout-api. Repeatable.\",\n repeatable: true\n },\n {\n name: \"importance\",\n type: \"int\",\n description: \"1-10, a display ordinal. The retention scorer divides by 10.\"\n },\n { name: \"confidence\", type: \"string\", description: \"0-1. 1.0 is an unqualified assertion.\" },\n {\n name: \"session-id\",\n type: \"string\",\n description: \"The Claude Code session. Stamped into the head AND indexed as a link.\"\n },\n { name: \"prompt-id\", type: \"string\", description: \"The prompt within that session.\" },\n { name: \"turn-uuid\", type: \"string\", description: \"The turn within that session.\" }\n ],\n responseTypes: [\"memory.written\"]\n },\n {\n name: \"apply\",\n summary:\n \"Write many memories from a JSONL op stream: ONE commit, ONE index update, per-op results.\",\n args: [],\n flags: [\n {\n name: \"file\",\n type: \"string\",\n description:\n \"The JSONL file to read. One complete JSON object per line. Omit it (or pass `-`) to read the stream from stdin.\"\n },\n {\n name: \"continue-on-error\",\n type: \"boolean\",\n description:\n \"Best-effort: a refused op is reported and skipped while every surviving op lands in the one commit. Atomic by default. The first refused op aborts the batch and nothing is written.\",\n default: false\n },\n {\n name: \"detect-conflicts\",\n type: \"boolean\",\n description:\n \"Report each op's frame-matches as a per-op `conflict`: the ACTIVE memory (or the earlier op) whose claim occupies the same subject-and-relation slot. PROPOSE-ONLY: every op still writes exactly as it would have, because sometimes the contradiction is the answer. You decide: write anyway, `memhtml correct` the match, or drop the line.\",\n default: false\n },\n {\n name: \"consolidate\",\n type: \"string\",\n values: [\"last-wins\"],\n description:\n \"Resolve frame-key matches instead of only reporting them: `--consolidate last-wins` makes the LATER op's value win a shared claim slot (one file, written at the FIRST index that claimed the slot, with each later restatement reporting `consolidated_into` naming that slot) and archives a stored ACTIVE memory a surviving slot displaces, reported as `superseded_path`. Off by default; claims with no frame shape are never consolidated.\"\n },\n {\n name: \"session-id\",\n type: \"string\",\n description:\n \"The Claude Code session for every op that names none. A line's own `session_id` wins over this.\"\n },\n { name: \"prompt-id\", type: \"string\", description: \"The prompt within that session.\" },\n { name: \"turn-uuid\", type: \"string\", description: \"The turn within that session.\" }\n ],\n responseTypes: [\"batch.applied\"]\n },\n {\n name: \"read\",\n summary: \"Read one memory: its metas, links, article, and format warnings.\",\n args: [{ name: \"path\", description: \"Repo-root-relative path to the memory.\", required: true }],\n flags: [\n {\n name: \"session-id\",\n type: \"string\",\n description: \"Records a `read` session link, so provenance is queryable both ways.\"\n }\n ],\n responseTypes: [\"memory.detail\"]\n },\n {\n name: \"search\",\n summary: \"Ranked search: four RRF arms plus MMR. Degrades to the lexical floor.\",\n args: [{ name: \"query\", description: \"Prose. Never a query language.\", required: true }],\n flags: [\n ...SCOPE_FLAGS,\n { name: \"limit\", type: \"int\", description: \"Hits to return.\", default: 10 }\n ],\n responseTypes: [\"memory.hits\"]\n },\n {\n name: \"recall\",\n summary: \"A disclosure pack under a character budget: arcs and memories folded separately.\",\n args: [{ name: \"query\", description: \"Prose.\", required: true }],\n flags: [\n ...SCOPE_FLAGS,\n {\n name: \"budget\",\n type: \"int\",\n description: \"Characters of quoted body. Arcs get their own envelope on top.\",\n default: 16_000\n }\n ],\n responseTypes: [\"recall.pack\"]\n },\n {\n name: \"correct\",\n summary: \"Supersede a memory: write the new file and archive the target in ONE commit.\",\n args: [{ name: \"target\", description: \"The memory being corrected.\", required: true }],\n flags: [\n { name: \"title\", type: \"string\", description: \"The new memory's title.\", required: true },\n {\n name: \"claim\",\n type: \"string\",\n description: \"The corrected claim. Exactly one of --claim or --article-html.\"\n },\n {\n name: \"body\",\n type: \"string\",\n description: \"A prose paragraph. Repeatable.\",\n repeatable: true\n },\n {\n name: \"article-html\",\n type: \"string\",\n description:\n \"Raw <article> markup for the superseding memory, used verbatim in place of --claim/--body. Must contain exactly one <mark> in the first <p> or <li>; the first <time datetime> becomes the memory's event time. The store refuses format violations before any commit. Exactly one of --claim or --article-html.\"\n },\n {\n name: \"type\",\n type: \"string\",\n description: \"The new memory's type. Defaults to the target's.\",\n values: WRITABLE_MEMORY_TYPES\n },\n { name: \"reason\", type: \"string\", description: \"Why the correction was made.\" },\n { name: \"session-id\", type: \"string\", description: \"Records a `corrected` session link.\" }\n ],\n responseTypes: [\"memory.corrected\"]\n },\n {\n name: \"link\",\n summary: \"Add an authored edge to the source file and commit it. Idempotent.\",\n args: [\n { name: \"src\", description: \"The asserting memory or task.\", required: true },\n {\n name: \"rel\",\n // The task rels are authorable here rather than in `memory_link`, because a `blocks` edge\n // between two tasks is a real authored assertion, while a person or provenance rel is minted.\n description: `One of: ${AUTHORABLE_RELS.join(\", \")}. A task rel needs two tasks; a memory rel refuses a task endpoint.`,\n required: true\n },\n { name: \"dst\", description: \"The memory or task being pointed at.\", required: true }\n ],\n flags: [],\n responseTypes: [\"memory.linked\"]\n },\n {\n name: \"neighbors\",\n summary: \"The memory graph around one path, to a fixed depth of at most two hops.\",\n args: [{ name: \"path\", description: \"The center of the neighborhood.\", required: true }],\n flags: [\n { name: \"depth\", type: \"int\", description: \"1 or 2. Never more.\", default: 1 },\n {\n name: \"rel\",\n type: \"string\",\n description: \"Restrict to these rels. Repeatable.\",\n values: MEMORY_RELS,\n repeatable: true\n }\n ],\n responseTypes: [\"memory.neighbors\"]\n },\n {\n name: \"archive\",\n summary: \"Soft-evict: `git mv` into archive/<YYYY>/ with the archive stamps. Never a delete.\",\n args: [{ name: \"path\", description: \"The memory to archive.\", required: true }],\n flags: [{ name: \"reason\", type: \"string\", description: \"Why it was evicted.\", required: true }],\n responseTypes: [\"memory.archived\"]\n },\n {\n name: \"reinforce\",\n summary: \"Bump access bookkeeping, gated by a 900-second per-path cooldown.\",\n args: [\n { name: \"path\", description: \"A memory path. Repeat the argument for more.\", required: true }\n ],\n flags: [\n {\n name: \"signal\",\n type: \"string\",\n description: \"`neutral` bumps access without claiming the memory was right.\",\n values: REINFORCE_SIGNALS,\n default: \"neutral\"\n }\n ],\n responseTypes: [\"memory.reinforced\"]\n },\n {\n name: \"list\",\n summary: \"Page through the corpus by type, workspace, tag, entity, or PARA bucket.\",\n args: [],\n flags: [\n {\n name: \"type\",\n type: \"string\",\n description: \"One memory type.\",\n values: WRITABLE_MEMORY_TYPES\n },\n { name: \"workspace\", type: \"string\", description: \"One workspace.\" },\n { name: \"tag\", type: \"string\", description: \"One tag.\" },\n { name: \"entity\", type: \"string\", description: \"One `type:name` entity reference.\" },\n {\n name: \"para\",\n type: \"string\",\n description: \"One PARA bucket.\",\n values: [\"projects\", \"areas\", \"resources\", \"archive\"]\n },\n { name: \"limit\", type: \"int\", description: \"Rows per page.\", default: 50 },\n {\n name: \"cursor\",\n type: \"string\",\n description: \"The `next_cursor` from the previous page: the last path returned.\"\n },\n {\n name: \"include-archived\",\n type: \"boolean\",\n description: \"Include archived memories.\",\n default: false\n }\n ],\n responseTypes: [\"memory.list\"]\n },\n /**\n * The task family: CRUDL over the 10th memory type, without retrieval.\n *\n * Sugar over the same use cases everything else uses. `task add` is `writeMemory` with\n * `--type task`, and `task status` is one head meta plus (for `done`) the archive machinery. The\n * design intent is that an agent works tasks with `Read`, `Edit`, and `ls` as readily as with these.\n * A task is a file in a directory, and this family exists so the common moves are one call rather\n * than three.\n */\n {\n name: \"task add\",\n summary: \"Open a task: a `task` memory in projects/<ws>/tasks/ or areas/inbox/tasks/.\",\n args: [],\n flags: [\n {\n name: \"title\",\n type: \"string\",\n description: \"What the task is. Becomes the <title> and the filename slug.\",\n required: true\n },\n {\n name: \"claim\",\n type: \"string\",\n description: \"The task statement, as the <mark> span. Defaults to --title.\"\n },\n {\n name: \"body\",\n type: \"string\",\n description: \"A prose paragraph of working notes. Repeatable, one <p> each.\",\n repeatable: true\n },\n {\n name: \"status\",\n type: \"string\",\n description: \"The opening status. `todo` unless you are recording work already underway.\",\n values: TASK_STATUSES,\n default: \"todo\"\n },\n {\n name: \"due\",\n type: \"string\",\n description: \"An ISO date or datetime deadline. Compared as a string, so the form matters.\"\n },\n {\n name: \"workspace\",\n type: \"string\",\n description: \"Routes the task to projects/<slug>/tasks/.\"\n },\n {\n name: \"tag\",\n type: \"string\",\n description: \"A tag. Repeatable; tags scope search but never route a task.\",\n repeatable: true\n },\n {\n name: \"entity\",\n type: \"string\",\n description: \"A `type:name` entity reference. Repeatable.\",\n repeatable: true\n },\n {\n name: \"session-id\",\n type: \"string\",\n description: \"The Claude Code session that opened the task.\"\n },\n { name: \"prompt-id\", type: \"string\", description: \"The prompt within that session.\" },\n { name: \"turn-uuid\", type: \"string\", description: \"The turn within that session.\" }\n ],\n responseTypes: [\"task.written\"]\n },\n {\n name: \"task status\",\n summary: \"Move a task's status. `done` stamps AND archives it, in one commit.\",\n args: [\n { name: \"path\", description: \"The task file.\", required: true },\n { name: \"status\", description: `One of: ${TASK_STATUSES.join(\", \")}.`, required: true }\n ],\n flags: [\n {\n name: \"reason\",\n type: \"string\",\n description: \"Why it closed. Recorded on the archive commit when the status is `done`.\"\n }\n ],\n responseTypes: [\"task.updated\"]\n },\n {\n name: \"task list\",\n summary: \"The task working set: a direct indexed scan with blockers, never ranked retrieval.\",\n args: [],\n flags: [\n {\n name: \"status\",\n type: \"string\",\n description: \"One task status.\",\n values: TASK_STATUSES\n },\n { name: \"workspace\", type: \"string\", description: \"One workspace.\" },\n {\n name: \"due-before\",\n type: \"string\",\n description: \"An ISO date. Returns tasks due strictly before it, by calendar day.\"\n },\n { name: \"limit\", type: \"int\", description: \"Rows per page.\", default: 50 },\n {\n name: \"cursor\",\n type: \"string\",\n description: \"The `next_cursor` from the previous page: the last path returned.\"\n },\n {\n name: \"include-archived\",\n type: \"boolean\",\n description: \"Include finished tasks. `done` archives, so they are otherwise absent.\",\n default: false\n }\n ],\n responseTypes: [\"task.list\"]\n },\n {\n name: \"index rebuild\",\n summary: \"Rebuild index.db from the git tree at HEAD. Destroys nothing outside .memhtml/.\",\n args: [],\n flags: [\n {\n name: \"embed\",\n type: \"boolean\",\n description: \"Fill missing vectors from Bedrock. --no-embed makes the rebuild instant.\",\n default: true\n }\n ],\n responseTypes: [\"index.report\"]\n },\n {\n name: \"index update\",\n summary: \"Index only what moved since the recorded watermark, plus the dirty working tree.\",\n args: [],\n flags: [\n { name: \"embed\", type: \"boolean\", description: \"Fill missing vectors.\", default: true }\n ],\n responseTypes: [\"index.report\"]\n },\n {\n name: \"index status\",\n summary: \"The index watermark, the vector space it was built in, and its row counts.\",\n args: [],\n flags: [],\n responseTypes: [\"index.report\"]\n },\n {\n name: \"trace index\",\n summary: \"Scan $MEMHTML_TRACE_ROOT for Claude Code transcripts, reading only what changed.\",\n args: [],\n flags: [],\n responseTypes: [\"trace.report\"]\n },\n {\n name: \"trace search\",\n summary: \"FTS over session first-prompts and AI titles. Never enters memory retrieval.\",\n args: [{ name: \"query\", description: \"Prose.\", required: true }],\n flags: [\n { name: \"cwd\", type: \"string\", description: \"Restrict to sessions from this directory.\" },\n { name: \"since\", type: \"string\", description: \"ISO-8601 lower bound on started_at.\" },\n { name: \"limit\", type: \"int\", description: \"Sessions to return.\", default: 20 }\n ],\n responseTypes: [\"trace.sessions\"]\n },\n {\n name: \"trace links\",\n summary: \"The memory-session links, from either side.\",\n args: [],\n flags: [\n { name: \"session-id\", type: \"string\", description: \"Every memory this session touched.\" },\n { name: \"path\", type: \"string\", description: \"Every session that touched this memory.\" }\n ],\n responseTypes: [\"trace.links\"]\n },\n {\n name: \"sleep run\",\n summary: \"The nightly curation cycle: 15 phases, each an isolated commit on a review branch.\",\n args: [],\n flags: [\n {\n name: \"date\",\n type: \"string\",\n description: \"The run date, `YYYY-MM-DD`. Defaults to today. Names the branch.\"\n },\n {\n name: \"phases\",\n type: \"string\",\n description: `Comma-separated subset. All 15 by default: ${SLEEP_PHASES.join(\", \")}.`\n },\n {\n name: \"dry-run\",\n type: \"boolean\",\n description: \"Report per-phase counts and commit nothing.\",\n default: false\n }\n ],\n responseTypes: [\"sleep.report\"]\n },\n {\n name: \"sleep resume\",\n summary: \"Re-run only the phases with no Memhtml-Phase trailer on the branch.\",\n args: [{ name: \"run-id\", description: \"The run id, e.g. sleep/2026-08-02.\", required: true }],\n flags: [],\n responseTypes: [\"sleep.report\"]\n },\n {\n name: \"sleep review\",\n summary: \"Per-phase counts, the commit list, diff --stat, and a per-file classification.\",\n args: [{ name: \"run-id\", description: \"The run id.\", required: true }],\n flags: [\n { name: \"diff\", type: \"boolean\", description: \"Include the raw diff.\", default: false }\n ],\n responseTypes: [\"sleep.review\"]\n },\n {\n name: \"sleep merge\",\n summary: \"Fast-forward main to the run's branch, after the discrimination gate passes.\",\n args: [{ name: \"run-id\", description: \"The run id.\", required: true }],\n flags: [\n {\n name: \"skip-gate\",\n type: \"boolean\",\n description:\n \"Merge without re-running discrimination. A deliberate, logged override, never a default.\",\n default: false\n }\n ],\n responseTypes: [\"sleep.merge\"]\n },\n {\n name: \"sleep status\",\n summary: \"The latest sleep run and its per-phase outcomes.\",\n args: [],\n flags: [],\n responseTypes: [\"sleep.report\"]\n },\n {\n name: \"status\",\n summary: \"Corpus health: HEAD, dirty state, counts by type, edges, index freshness.\",\n args: [],\n flags: [],\n responseTypes: [\"status.health\"]\n },\n {\n name: \"publish\",\n summary: \"Regenerate the per-directory index.html listings and sitemap.xml, and commit them.\",\n args: [],\n flags: [],\n responseTypes: [\"publish.report\"]\n },\n {\n name: \"doctor\",\n summary:\n \"Corpus health: dangling hrefs, orphan state rows, inbox depth, vocabulary, staleness.\",\n args: [],\n flags: [\n {\n name: \"fix\",\n type: \"boolean\",\n description:\n \"Repair dangling hrefs and prune orphan access rows. The other findings need a decision.\",\n default: false\n }\n ],\n responseTypes: [\"doctor.report\"]\n },\n {\n name: \"eval discriminate\",\n summary: \"The refusable retrieval gate: every probe must outrank its own wrong-fact twins.\",\n args: [],\n flags: [\n {\n name: \"mode\",\n type: \"string\",\n description:\n \"`fake` is the deterministic embedder CI measures; `live` needs AWS_BEARER_TOKEN_BEDROCK and refuses loudly without it.\",\n values: [\"fake\", \"live\"],\n default: \"fake\"\n },\n {\n name: \"seed\",\n type: \"int\",\n description: \"The fixture corpus seed. A failing run is reproducible from this number.\"\n },\n { name: \"size\", type: \"int\", description: \"Base memories to generate.\", default: 200 },\n {\n name: \"probes\",\n type: \"int\",\n description: \"Probes to run. Design §5 wants ≥30.\",\n default: 36\n },\n {\n name: \"mrr-floor\",\n type: \"string\",\n description: \"Mean-reciprocal-rank floor. Lowering it is a deliberate, visible choice.\",\n default: \"0.85\"\n }\n ],\n responseTypes: [\"eval.discrimination\"]\n },\n /**\n * Code-mode (ROADMAP item 7b): one script, one execution, one envelope.\n *\n * The flag surface answers three questions a script cannot answer for itself, and nothing else.\n *\n * **How does the script arrive?** Three doors, exactly one per call, enforced in `validate` so a\n * wrong combination is exit 2. `--file` for a script under version control, `--script` for the\n * inline one-liner an agent composes, and a bare `memhtml exec` (or `-`) for stdin, which is the same\n * three-door shape and the same `-` spelling `memhtml apply` already uses for its op stream, so an\n * agent that learned one learned both. `--script` rather than a positional argument, because the\n * positional slot on a two-word command is where a run-id or a path goes on every other command\n * here, and a multi-line program in that slot would read as one.\n *\n * **How long may it run?** `--timeout-ms`, bounded and defaulted, because the guest is a QuickJS\n * worker with no reaper of its own and an unbounded script holds the CLI process open. The\n * millisecond unit is in the flag name rather than left to a note, since `--timeout 30` is\n * ambiguous by a factor of a thousand.\n *\n * **Which tree does it see?** `--sha`, defaulting to `HEAD`. Never the live working tree, which is\n * a containment decision rather than a convenience. A mounted `$MEMHTML_ROOT` exposes `.memhtml/index.db`\n * to the guest, whose `sqlite3` reads it happily (probed 2026-08-09: a read-only mount is no barrier\n * to a reader). A gitignored file is absent from a detached worktree, so pinning a commit is what\n * keeps the ranked planes out of reach, and the read-only mount is the second layer rather than\n * the only one. A pin also makes the answer reproducible. `sha` rides back in the envelope, so a\n * rerun is exact.\n *\n * There is deliberately no flag for the guest's own opt-ins. `javascript` is on because `js-exec`\n * is the feature. `python` and `network` are off and unofferable, so no invocation can turn either\n * on. `apps/cli/src/exec.ts` carries the mechanism and the egress probe.\n */\n {\n name: \"exec\",\n summary:\n \"Run a read-only traversal script over the corpus in a sandbox: multi-hop in ONE execution.\",\n args: [],\n flags: [\n {\n name: \"file\",\n type: \"string\",\n description:\n \"The script to run, as a path on the HOST. Omit it (or pass `-`) to read the script from stdin. Mutually exclusive with `--script`.\"\n },\n {\n name: \"script\",\n type: \"string\",\n description:\n \"The script source, inline. Mutually exclusive with `--file` and with reading stdin.\"\n },\n {\n name: \"timeout-ms\",\n type: \"int\",\n description:\n \"Wall-clock bound on the script. Exceeding it is `exitCode` 124 with `timedOut: true`, not an error envelope. Capped at 600000.\",\n default: 30000\n },\n {\n name: \"sha\",\n type: \"string\",\n description:\n \"The commit to mount, materialized as a detached worktree. Defaults to HEAD. Never the live working tree, whose gitignored .memhtml/index.db a worktree omits.\"\n }\n ],\n responseTypes: [\"exec.report\"]\n },\n {\n name: \"state export\",\n summary:\n \"Write .memhtml/state/access.jsonl, the only durable copy of the state plane, and commit.\",\n args: [],\n flags: [],\n responseTypes: [\"state.export\"]\n },\n {\n name: \"state import\",\n summary: \"Replay the committed sidecar into state.db. Counters merge by max, never last-wins.\",\n args: [],\n flags: [],\n responseTypes: [\"state.import\"]\n },\n {\n name: \"agents-doc\",\n summary: \"Regenerate AGENTS.md from this command table. --check fails on drift.\",\n args: [],\n flags: [\n {\n name: \"check\",\n type: \"boolean\",\n description: \"Compare the committed doc to the regenerated one and fail on a difference.\",\n default: false\n },\n { name: \"out\", type: \"string\", description: \"Where to write. Defaults to ./AGENTS.md.\" }\n ],\n responseTypes: [\"agents.doc\"]\n },\n {\n name: \"serve mcp\",\n summary: \"Run the `memhtml-mcp` stdio server: 14 tools and 2 resources over this same repo.\",\n args: [],\n flags: [],\n responseTypes: [\"serve.exit\"]\n }\n]\n\nexport const COMMAND_NAMES = COMMANDS.map((command) => command.name)\n\n/** One prose block of the manifest's guide: a topic key an agent can cite, and the prose. */\nexport interface GuideBlock {\n readonly topic: string\n readonly body: string\n}\n\n/**\n * The example op line, quoted verbatim into the `when-to-batch` block.\n *\n * A constant rather than a literal inside the prose, because a test parses it. An example an agent\n * copies has to be valid JSONL, and it stays valid because the doc and the parser read the\n * same bytes. A prose-only example drifts silently the first time a field is renamed.\n */\nexport const GUIDE_OP_EXAMPLE =\n '{\"op\":\"write\",\"title\":\"One writer and many readers share the index\",\"type\":\"semantic\",\"body\":\"WAL admits a single writer at a time and any number of concurrent readers, so a CLI command and a running `memhtml serve mcp` can work against one store.\",\"tag\":\"infra\"}'\n\n/**\n * The guide: what an agent reads on its first call, before it has written anything.\n *\n * Prose, in a structured field, authored here beside `COMMANDS`, which is the design (spec\n * D8/G6). The manifest carries it on a bare `memhtml`, `memhtml help`, `memhtml --help`, and `memhtml manifest`, and\n * `memhtml agents-doc` renders these same strings into `AGENTS.md`, so the doc and the live answer cannot\n * disagree. Prose kept in a separate Markdown file would be a second copy that drifts, and prose kept\n * only in `AGENTS.md` would be invisible to an agent that never opens the repo.\n *\n * Written for an LLM agent mid-task rather than for an operator browsing: complete sentences, action\n * first, and every claim true of this build rather than of the design. A guide that describes an\n * intention is worse than no guide, because an agent acts on it.\n */\nexport const GUIDE: ReadonlyArray<GuideBlock> = [\n {\n topic: \"first-call\",\n body:\n \"You are reading this CLI's manifest: every command, argument, flag, response type, error code, \" +\n \"and environment variable the binary accepts. A bare `memhtml`, `memhtml help`, `memhtml --help`, and \" +\n \"`memhtml manifest` all return it, and all four answer on a machine with no repo, no database, and \" +\n \"no credentials, so this is also the liveness check when something else has failed. \" +\n \"Every command writes exactly ONE JSON envelope to stdout and nothing else; logs go to stderr. \" +\n \"A success is `{apiVersion, type, data}` and a failure is `{apiVersion, error, code, suggestions}`. \" +\n \"Branch on `code`, never on the `error` prose: the codes and response types are append-only and a \" +\n \"shipped one never changes meaning, while the prose changes freely as wording improves. \" +\n \"Exit 0 is success, exit 2 is a usage error you fix by changing the call, exit 1 is a runtime \" +\n \"failure you fix by changing the repo or the environment. Add `--dense` to any command to get \" +\n \"minified JSON with null fields dropped, which is what you want when the output goes into a prompt.\"\n },\n {\n topic: \"write-surfaces\",\n body:\n \"There are three ways to put a memory into the corpus, and they are all legitimate. \" +\n \"First, this CLI: `memhtml write` for one memory, `memhtml apply` for many. \" +\n \"Second, the MCP server: `memhtml serve mcp` speaks stdio with 14 tools and 2 resources over this \" +\n \"same repo, and it is the door to use when you are already an MCP client. \" +\n \"Third, editing files under $MEMHTML_ROOT directly with your normal file tools: the git tree IS the \" +\n \"system of record and `.memhtml/index.db` is only a projection of it, so a hand-written or hand-edited \" +\n \"memory file is as real as one this CLI wrote. `memhtml index update` projects uncommitted working-tree \" +\n \"changes as well as committed ones, so a dirty edit is searchable before you commit it. \" +\n \"What you take on by editing directly is everything the write path would have done for you: the \" +\n \"file must satisfy the format (run `memhtml doctor`, and `memhtml read <path>` reports per-file format \" +\n \"warnings), you own choosing a path that does not collide, you own noticing that the content \" +\n \"already exists somewhere else, and you own the commit. The nightly `memhtml sleep run` refuses to \" +\n \"start on a dirty tree, so an uncommitted edit blocks curation until it is committed or stashed. \" +\n \"A CLI command and a running `memhtml serve mcp` may share one store: the index is WAL SQLite, \" +\n \"which admits one writer at a time and any number of concurrent readers, so a second writer \" +\n \"waits its turn rather than failing. The one thing to keep clear of is `memhtml sleep run`, and \" +\n \"for a git reason rather than a database one: a run holds a checked-out `sleep/<date>` branch, \" +\n \"so a write landing during it commits onto that branch and is merged as if it were curation or \" +\n \"lost when the branch is dropped.\"\n },\n {\n topic: \"when-to-batch\",\n body:\n \"Writing more than about three memories in one task? Call `memhtml apply` once with a JSONL op stream \" +\n \"instead of running `memhtml write` N times. A batch stages every file, makes ONE commit, and \" +\n \"reindexes ONCE, where N separate writes make N commits and pay N index passes over N diffs. \" +\n \"Pass the stream as `memhtml apply --file ops.jsonl`, or pipe it: `memhtml apply -` and a bare `memhtml apply` \" +\n \"both read stdin. One complete JSON object per line, no wrapping array, no pretty-printing. A \" +\n \"line looks like this:\\n\" +\n `${GUIDE_OP_EXAMPLE}\\n` +\n \"`op` is `write` (the only verb in the vocabulary today), `title` and `type` are required, and each \" +\n \"op carries the same optional fields `memhtml write` takes, in snake_case: `path`, `workspace`, `tag`, \" +\n \"`entity`, `importance`, `confidence`, `session_id`, `prompt_id`, `turn_uuid`. \" +\n \"The whole file is validated for shape before ANY op executes, so a malformed line 7 is exit 2 \" +\n \"naming line 7 with nothing written. A failed apply costs you nothing but the call. \" +\n \"You get one result per op in INPUT ORDER, each naming its own `index`, so you can match results \" +\n \"back to the lines you sent. \" +\n \"A batch is ATOMIC by default: the first refused op aborts the whole batch, no file is written, no \" +\n \"commit is made, and the surviving ops report `skipped: true`. Pass `--continue-on-error` for \" +\n \"best-effort instead, and a refused op comes back as one failed result carrying its own `code` and \" +\n \"`error` while every op that succeeded lands in the one commit. \" +\n \"A duplicate is never an error: an op whose exact content is already stored comes back `ok: true` \" +\n \"with `deduped: true` and the existing path, so re-applying a file you already applied is safe and \" +\n \"writes nothing. `commit_sha` is null exactly when nothing was committed: a batch that only \" +\n \"deduped, or one that aborted.\"\n },\n {\n topic: \"conflicts\",\n body:\n \"Pass `--detect-conflicts` to `memhtml apply` and each result gains a `conflict` field naming what \" +\n \"that op's claim contradicts. Dedupe catches an op whose content is IDENTICAL to something stored; \" +\n \"this catches an op that says something DIFFERENT about the same thing, the case dedupe is blind \" +\n \"to and the one that actually rots a corpus. \" +\n \"The match is grammatical, not semantic: a claim is split into a frame (the subject and relation, \" +\n \"up to its last `of`/`is`/`in`/`to`/`by`/`as`) and a value, and two claims conflict when they share \" +\n \"a frame. `The pool ceiling is 64` and `The pool ceiling is 128` share `the pool ceiling is`. \" +\n \"`conflict.path` names an ACTIVE memory already holding that slot; `conflict.batch_index` names an \" +\n \"EARLIER op in this same call, which is the case nothing else can see because neither op is stored \" +\n \"yet; `conflict.claim` is the other claim's own text, so you can decide without a second read. \" +\n \"It is null when nothing matched, and also when the claim has no frame shape. The rule refuses \" +\n \"frames under three tokens and values over six, so short claims and claims trailed by a clause are \" +\n \"deliberately unmatched rather than loosely matched. On a line using `article_html` instead of \" +\n \"`body` it is always null, because the claim lives inside your markup and is not read until the \" +\n \"store renders it. \" +\n \"THE ASSIST NEVER CHANGES WHAT IS WRITTEN. An op carrying a conflict is written exactly as it \" +\n \"would have been without the flag: nothing is archived, nothing is refused, and later does not win. \" +\n \"That is deliberate, because sometimes the contradiction IS the answer. A memory recording that a \" +\n \"runbook step changed necessarily contradicts the memory stating the old step, and a system that \" +\n \"resolved that for you would delete the pair a reader needs in order to see the change at all. \" +\n \"You decide per conflict: keep both (they are about different things, or both are true), \" +\n \"`memhtml correct <path>` instead (the new claim supersedes the old one, and the old one stays readable \" +\n \"under archive/), or drop the line (you were about to restate something already stored). \" +\n \"Archived memories never match, so a superseded claim stops contradicting the claim that superseded it.\\n\" +\n \"When you have already decided that later wins (a re-scrape, a settings sync, any stream where \" +\n \"each line is the newest statement of its slot), pass `--consolidate last-wins` (the batch tool's \" +\n '`consolidate: \"last-wins\"`) and the batch RESOLVES those matches instead of reporting them. ' +\n \"Ops sharing a frame key write ONE file carrying the LATER value at the FIRST index that claimed \" +\n \"the slot; each later restatement reports `consolidated_into` naming that slot and the summary \" +\n \"counts it under `consolidated`, neither written nor failed. A stored ACTIVE memory occupying a \" +\n \"surviving slot is archived with a supersedes link from the new file, its archive path reported \" +\n \"as `superseded_path`, the same chain `memhtml correct` leaves, so ancestry reads identically. \" +\n \"OFF by default, and the key is the conflict rule's own: the frame split is a rule measured in \" +\n \"the eval harness before it was believed and ported verbatim into `@memhtml/domain`'s frame.ts, \" +\n \"which detection and consolidation share, so anything the rule refuses to key (short frames, \" +\n \"clause values) is never consolidated, and what you saw reported with `--detect-conflicts` is \" +\n \"exactly what this flag would have acted on.\\n\" +\n \"Every supersede, `memhtml correct` and `--consolidate last-wins` alike, also stamps a VALIDITY \" +\n \"WINDOW, in the same one commit. The superseded memory gains `memhtml-valid-until` set to the \" +\n \"moment the new fact became true (the winner's own `memhtml-valid-from`, else its first \" +\n \"`<time datetime>`, else the operation's instant), and the winner gains `memhtml-valid-from` at \" +\n \"that same moment, so one window closes exactly where the next opens. Min-wins: a memory \" +\n \"already stating an EARLIER `memhtml-valid-until` keeps it, because a fact cannot outlive its \" +\n \"earliest stated bound. That is what `--as-of` on `memhtml search` reads: pass an ISO instant and \" +\n \"the result is what was believed valid AT THAT MOMENT. Since-superseded memories return, each \" +\n \"marked `superseded_by` naming what replaced it, and facts not yet valid then are absent. \" +\n \"History is read from the files, not replayed from git, so it survives a full index rebuild.\"\n },\n {\n topic: \"authoring\",\n body:\n \"Every write authors the article in exactly one of two ways, and supplying both or neither is \" +\n \"refused. Either you write prose and the template owns the markup (`--claim` is the one \" +\n \"load-bearing sentence and becomes the `<mark>` claim span and `files.gist`, and each `--body` \" +\n \"is one paragraph after it) or you supply `--article-html` and own the markup yourself. \" +\n \"On a `memhtml apply` line the prose form is the `body` field, whose first sentence becomes the claim, \" +\n \"and the markup form is `article_html`. \" +\n \"When you supply markup you own two constraints. It must contain EXACTLY ONE `<mark>`, and that \" +\n \"`<mark>` must sit in the article's first `<p>` or `<li>` and not inside an `<aside>` or \" +\n \"`<details>`. The claim leads the article and is never a caveat or behind a fold. And the first \" +\n \"`<time datetime>` in your markup becomes the memory's event time, which is what recency ranks \" +\n \"on, so a memory about something that happened last year should say so rather than being ranked \" +\n \"as today's news. \" +\n \"Markup is checked before anything is written: the store renders your article, runs the format \" +\n \"check, and refuses with the list of violations before it creates a file, stages it, or commits. \" +\n \"A refused write leaves the tree byte-identical, so a failed attempt costs nothing and you can fix \" +\n \"the markup and retry. \" +\n \"Code goes in the prose path as a fenced block: a body paragraph that is entirely a ``` fence \" +\n \"becomes <figure><pre><code>, whitespace preserved verbatim, and the fence's info string \" +\n \"(```ts) is stamped as data-lang and promoted to a `lang:ts` entity, so `memhtml list --entity \" +\n \"lang:ts` finds every memory carrying TypeScript. A blank line inside a fence does NOT split \" +\n 'paragraphs. On the markup path write the same <figure><pre><code data-lang=\"ts\"> yourself; ' +\n \"never `class` (forbidden) and never `lang=` (that attribute names human languages).\"\n },\n {\n topic: \"code-mode\",\n body:\n \"Answering a question that takes MORE THAN ONE HOP through the corpus? Write it as a script and \" +\n \"run `memhtml exec` once, instead of spending a tool call per hop. Supersedence ancestry, live \" +\n \"contradiction pairs, orphan census, entity co-occurrence, 'which of these 40 paths has no \" +\n \"backlink': each of those is one traversal in code and N round trips through `memhtml read` and \" +\n \"`memhtml neighbors`. Measured on a 305-file corpus: a full census in 598ms, and 410 edges resolved \" +\n \"into 201 chains, longest 8 hops, in one execution at 430ms. \" +\n \"The script runs under QuickJS in a sandbox with the corpus mounted READ-ONLY at `/mnt/memhtml`, and \" +\n \"a helper is already seeded for you at `/workspace/lib/corpus.mjs`. Import it: \" +\n '`import { corpus, backlinks, chain, edges } from \"/workspace/lib/corpus.mjs\"`. `corpus()` ' +\n \"returns a Map keyed by root-absolute path (the SAME string an edge's href holds, so \" +\n \"`memories.get(link.href)` resolves with no path juggling) and each value carries `claim`, \" +\n \"`memoryType`, `status`, `tags`, `entities`, `links`, `facets`, `citations`, `eventAt`, and a \" +\n \"`document` escape hatch for any selector the fields do not cover. \" +\n \"Print your answer as JSON on stdout with `console.log`; it comes back verbatim in `data.stdout`, \" +\n \"so keep it small and structured rather than dumping the corpus. \" +\n \"THREE THINGS IT CANNOT DO, by design. It cannot write: the corpus is read-only and a write \" +\n \"answers EROFS, so every write still goes through `memhtml write` / `memhtml apply`, which own commits, \" +\n \"dedup, and conflict detection. It cannot rank: no cosine, no RRF, no salience, and no index \" +\n \"database. For ranked retrieval shell out to `memhtml search --json` and parse its envelope, which \" +\n \"the one-envelope-per-command contract already makes a code-mode API. And it cannot reach the \" +\n \"network: there is no curl and the guest's `fetch` refuses on call. \" +\n \"The intended opening move is ranked retrieval FIRST, code-mode second: `memhtml search` or \" +\n \"`memhtml recall` to get the handful of paths the ranking stack says matter, then `memhtml exec` to walk, \" +\n \"join, count, and filter from there. Starting in code-mode means starting with a full-corpus scan \" +\n \"and no relevance signal. \" +\n \"A non-zero `exitCode` in the response is YOUR script failing, not the command failing. Read \" +\n \"`data.stderr` for the diagnostic and the exit code is still 0. A script that runs past \" +\n \"`--timeout-ms` (default 30000) comes back `exitCode: 124` with `timedOut: true`. \" +\n \"The tree you get is a pinned commit, HEAD by default, named in `data.sha`, so an answer is \" +\n \"reproducible with `--sha`, and an uncommitted edit is NOT visible to the script.\"\n }\n]\n\nexport const GUIDE_TOPICS = GUIDE.map((block) => block.topic)\n\n/**\n * Derived from `COMMANDS` and `GLOBAL_FLAGS` by walking them, so adding a flag\n * updates the manifest automatically. A hand-written manifest drifts the first\n * time someone adds a flag and forgets to edit it.\n */\nexport const buildManifest = () => ({\n name: \"memhtml\",\n version: \"0.2.4\", // x-release-please-version\n summary: \"Read, write, and curate the git-backed memory repo.\",\n apiVersion: \"1\",\n /**\n * The prose an agent needs before the command table means anything, so it is listed before it.\n * A manifest that opened with 33 command specifications makes an agent infer the workflow from a\n * surface, while `guide` states it.\n */\n guide: GUIDE,\n globalFlags: GLOBAL_FLAGS,\n errorCodes: ERROR_CODES,\n config: CONFIG_VARS,\n responseTypes: [...new Set(COMMANDS.flatMap((command) => command.responseTypes))],\n commands: COMMANDS.map((command) => ({\n name: command.name,\n summary: command.summary,\n args: command.args,\n flags: command.flags,\n responseTypes: command.responseTypes,\n supportsJson: true,\n supportsDense: true\n }))\n})\n","import { readFile, writeFile } from \"node:fs/promises\"\nimport { resolve } from \"node:path\"\n\nimport { InvalidMemory, StorageFailure } from \"@memhtml/contracts/errors\"\nimport { Effect } from \"effect\"\n\nimport { COMMANDS, GLOBAL_FLAGS, GUIDE } from \"./commands.js\"\nimport { CONFIG_VARS } from \"./config.js\"\nimport { API_VERSION, ERROR_CODES, EXIT_OK, EXIT_RUNTIME, EXIT_USAGE } from \"./envelope.js\"\n\n/**\n * `AGENTS.md`, generated from the same `COMMANDS` array that drives parsing.\n *\n * Generated rather than written, so the doc cannot describe a flag the binary does not accept. A test\n * checks the committed file against a fresh render, and `memhtml agents-doc --check` runs the same\n * comparison as a command, so the drift is catchable in CI and fixable in one call.\n *\n * The rendering is deterministic to the byte: no timestamp, no version of anything but the CLI\n * itself, no iteration over an unordered structure. A generator whose output moved on every run\n * would make the drift check useless.\n */\n\n/** Where the doc lives by default: the repo root, next to `package.json`. */\nexport const AGENTS_DOC_PATH = \"AGENTS.md\"\n\nconst escapeCell = (text: string): string => text.replaceAll(\"|\", \"\\\\|\")\n\nconst flagCell = (flags: ReadonlyArray<{ readonly name: string; readonly required?: boolean }>) =>\n flags.length === 0\n ? \"—\"\n : flags\n .map((flag) => (flag.required === true ? `\\`--${flag.name}\\`*` : `\\`--${flag.name}\\``))\n .join(\" \")\n\nconst argCell = (args: ReadonlyArray<{ readonly name: string; readonly required: boolean }>) =>\n args.length === 0\n ? \"—\"\n : args.map((arg) => (arg.required ? `<${arg.name}>` : `[${arg.name}]`)).join(\" \")\n\n/**\n * The guide blocks as Markdown, each under its own topic heading.\n *\n * The topic is the heading and it is code-quoted, so the key an agent reads from\n * `memhtml manifest`'s `guide[].topic` is greppable in this file. The two projections of one array\n * must name their blocks identically, or the reader cannot cross-reference them.\n *\n * A body line beginning with `{` becomes a fenced JSON block. The `when-to-batch` block carries an\n * example op line an agent copies, and that example is only useful if it survives the trip through\n * Markdown unwrapped and unescaped. The rule is derived from the content's own shape rather than\n * from a per-block flag, so a second example added to a second block needs no edit here.\n */\nconst guideLines = (): ReadonlyArray<string> => {\n const lines: Array<string> = [\"## Guide\", \"\"]\n for (const block of GUIDE) {\n lines.push(`### \\`${block.topic}\\``)\n lines.push(\"\")\n for (const paragraph of block.body.split(\"\\n\")) {\n if (paragraph.startsWith(\"{\")) {\n lines.push(\"```json\")\n lines.push(paragraph)\n lines.push(\"```\")\n } else {\n lines.push(paragraph)\n }\n lines.push(\"\")\n }\n }\n return lines\n}\n\n/** The whole document, as bytes. */\nexport const renderAgentsDoc = (): string => {\n const lines: Array<string> = []\n\n lines.push(\"<!-- Generated by `memhtml agents-doc`. Edit `apps/cli/src/commands.ts` instead. -->\")\n lines.push(\"\")\n lines.push(\"# `memhtml` — agent instructions\")\n lines.push(\"\")\n lines.push(\n \"`memhtml` is the CLI over a git-backed memory repo. Every command writes exactly ONE JSON envelope\"\n )\n lines.push(\"to stdout and nothing else; logs go to stderr.\")\n lines.push(\"\")\n lines.push(\"## The envelope\")\n lines.push(\"\")\n lines.push(\"```json\")\n lines.push(`{ \"apiVersion\": \"${API_VERSION}\", \"type\": \"<response type>\", \"data\": { } }`)\n lines.push(\"```\")\n lines.push(\"\")\n lines.push(\"A failure is a different shape, and `code` is what you branch on:\")\n lines.push(\"\")\n lines.push(\"```json\")\n lines.push(\n `{ \"apiVersion\": \"${API_VERSION}\", \"error\": \"<prose>\", \"code\": \"<ERROR_CODE>\", \"suggestions\": [\"<command>\"] }`\n )\n lines.push(\"```\")\n lines.push(\"\")\n lines.push(\n \"Never branch on the `error` string — it changes freely as wording improves. `code` and `type`\"\n )\n lines.push(\"are append-only: a shipped value never changes meaning and is never removed.\")\n lines.push(\"\")\n lines.push(\n `Exit codes: **${EXIT_OK}** success, **${EXIT_USAGE}** usage error (unknown command, bad flag,`\n )\n lines.push(`missing argument), **${EXIT_RUNTIME}** runtime failure.`)\n lines.push(\"\")\n lines.push(\"## Start here\")\n lines.push(\"\")\n lines.push(\n \"`memhtml manifest` is the first call to make. It answers with every command, argument, flag,\"\n )\n lines.push(\n \"response type, and error code this binary accepts — and it answers on a machine with no repo,\"\n )\n lines.push(\"no database, and no credentials, so it is also the liveness check.\")\n lines.push(\"\")\n /**\n * The guide goes before the command table, because it is what makes the table mean something. The\n * three write doors, when to batch, and the authoring XOR are decisions an agent makes before it\n * picks a command. Rendered from the same `GUIDE` array `memhtml manifest` returns, so an agent that\n * read the doc and an agent that called the binary got the same words.\n */\n lines.push(...guideLines())\n lines.push(\"## Global flags\")\n lines.push(\"\")\n lines.push(\"| Flag | Type | Default | Meaning |\")\n lines.push(\"|---|---|---|---|\")\n for (const flag of GLOBAL_FLAGS) {\n lines.push(\n `| \\`--${flag.name}\\` | ${flag.type} | ${flag.default === \"\" ? \"—\" : String(flag.default)} | ${escapeCell(flag.description)} |`\n )\n }\n lines.push(\"\")\n lines.push(\"## Commands\")\n lines.push(\"\")\n lines.push(\"`<required>` `[optional]`; a flag marked `*` is required.\")\n lines.push(\"\")\n lines.push(\"| Command | Arguments | Flags | Response type |\")\n lines.push(\"|---|---|---|---|\")\n for (const command of COMMANDS) {\n lines.push(\n `| \\`memhtml ${command.name}\\` | ${argCell(command.args)} | ${flagCell(command.flags)} | ${command.responseTypes.map((type) => `\\`${type}\\``).join(\", \")} |`\n )\n }\n lines.push(\"\")\n\n for (const command of COMMANDS) {\n lines.push(`### \\`memhtml ${command.name}\\``)\n lines.push(\"\")\n lines.push(command.summary)\n lines.push(\"\")\n if (command.args.length > 0) {\n for (const arg of command.args) {\n lines.push(\n `- \\`${arg.required ? `<${arg.name}>` : `[${arg.name}]`}\\` — ${escapeCell(arg.description)}`\n )\n }\n lines.push(\"\")\n }\n if (command.flags.length > 0) {\n for (const flag of command.flags) {\n const suffix = [\n flag.required === true ? \"**required**\" : undefined,\n flag.repeatable === true ? \"repeatable\" : undefined,\n flag.default === undefined ? undefined : `default \\`${String(flag.default)}\\``,\n flag.values === undefined\n ? undefined\n : `one of: ${flag.values.map((value) => `\\`${value}\\``).join(\", \")}`\n ]\n .filter((part) => part !== undefined)\n .join(\"; \")\n lines.push(\n `- \\`--${flag.name}\\` (${flag.type}) — ${escapeCell(flag.description)}${suffix === \"\" ? \"\" : ` _(${suffix})_`}`\n )\n }\n lines.push(\"\")\n }\n }\n\n lines.push(\"## Error codes\")\n lines.push(\"\")\n for (const code of ERROR_CODES) lines.push(`- \\`${code}\\``)\n lines.push(\"\")\n lines.push(\"## Configuration\")\n lines.push(\"\")\n lines.push(\"| Variable | Default | Meaning |\")\n lines.push(\"|---|---|---|\")\n for (const variable of CONFIG_VARS) {\n lines.push(\n `| \\`${variable.name}\\` | ${variable.fallback === null ? \"—\" : `\\`${variable.fallback}\\``} | ${escapeCell(variable.description)} |`\n )\n }\n lines.push(\"\")\n\n return `${lines.join(\"\\n\")}\\n`\n}\n\n/** What a generate-or-check pass produced. */\nexport interface AgentsDocResult {\n readonly path: string\n readonly bytes: number\n /** True when the file on disk already matched. `--check` fails when this is false. */\n readonly inSync: boolean\n /** True when this call wrote the file. False under `--check`, which never writes. */\n readonly written: boolean\n}\n\n/**\n * Write the doc, or compare it and fail on drift.\n *\n * `--check` is the CI form and it writes nothing. A check that fixed the drift it found would make\n * a green pipeline out of an uncommitted change.\n */\nexport const runAgentsDoc = (options: {\n readonly check: boolean\n readonly out?: string | undefined\n}): Effect.Effect<AgentsDocResult, InvalidMemory | StorageFailure> =>\n Effect.gen(function* () {\n const path = resolve(options.out ?? AGENTS_DOC_PATH)\n const rendered = renderAgentsDoc()\n\n const existing = yield* Effect.tryPromise({\n try: () => readFile(path, \"utf8\"),\n catch: () => null\n }).pipe(Effect.orElseSucceed(() => null))\n\n const inSync = existing === rendered\n\n if (options.check) {\n if (!inSync) {\n return yield* Effect.fail(\n InvalidMemory.make({\n reason:\n existing === null\n ? `${path} is missing; run \\`memhtml agents-doc\\``\n : `${path} is out of date; run \\`memhtml agents-doc\\``\n })\n )\n }\n return { path, bytes: rendered.length, inSync, written: false }\n }\n\n if (inSync) return { path, bytes: rendered.length, inSync, written: false }\n\n yield* Effect.tryPromise({\n try: () => writeFile(path, rendered, \"utf8\"),\n catch: () => StorageFailure.make({ operation: `agents-doc.write:${path}` })\n })\n return { path, bytes: rendered.length, inSync: false, written: true }\n })\n","/**\n * Prose → claim derivation: the single implementation both write doors use.\n *\n * The tools take `{title, body}` because that is what a model produces, and the format needs a\n * `<mark>` claim plus one `<p>` per paragraph. Turning the first into the second is a text heuristic,\n * and it lives here for two reasons. It was duplicated once, as `claimOf`/`restOf` in `apps/mcp` and\n * `claimFromProse`/`proseTail` in `apps/cli`, the same regex in two packages. A sentence-splitting\n * rule that drifts between the doors also makes `memhtml apply` and `memory_write_batch` derive different\n * claims from the same body, so the gist of a memory would depend on which door wrote it.\n *\n * It does not live in `@memhtml/html`, which owns markup and the format's own rules. \"Where does a\n * sentence end\" is a guess about natural-language prose, and the format states no such constraint. It\n * is not in `operations.ts` either, because that module holds the use cases both doors call, and this\n * is a text helper they apply before calling one.\n *\n * The derivation is defense in depth now; it was once the only guard. `@memhtml/html` constraint 1 now\n * rejects an empty `<mark>` outright, so a door that skipped this would be stopped by the store's\n * render gate instead of landing a file with an empty `files.gist`. What is left here is the\n * authoring convenience the doors exist to provide: a JSONL line and an MCP call carry no `claim`\n * field, so the door derives one instead of asking an author to restate the body's first sentence.\n */\n\nimport { closesFence, fenceOpeningOf } from \"@memhtml/html\"\n\n/**\n * Split prose into paragraphs on blank lines, dropping the empties. Inside a fenced code block a\n * blank line is content, so the split skips it there. Without that carve-out, a snippet containing a\n * blank line splits into two paragraphs, neither of which is a complete fence, and both land as\n * escaped backtick text instead of the `<figure><pre><code>` an intact fence renders as.\n *\n * The fence grammar comes from `@memhtml/html` (`fenceOpeningOf`/`closesFence`) rather than a second\n * copy here. The splitter deciding \"this is one block\" and the template deciding \"this is a fence\"\n * must be the same judgment, or the doors drift the way the claim derivation once did.\n */\nconst paragraphsOf = (prose: string): ReadonlyArray<string> => {\n const parts: Array<Array<string>> = [[]]\n let opening: string | undefined\n for (const line of prose.split(\"\\n\")) {\n const current = parts.at(-1) as Array<string>\n if (opening === undefined && line.trim() === \"\") {\n if (current.length > 0) parts.push([])\n continue\n }\n current.push(line)\n if (opening === undefined) {\n opening = fenceOpeningOf(line)\n } else if (closesFence(line, opening)) {\n opening = undefined\n }\n }\n return parts.map((lines) => lines.join(\"\\n\").trim()).filter((part) => part !== \"\")\n}\n\n/**\n * The claim: the first sentence of the prose.\n *\n * The first sentence is where a model puts the assertion. Taking the title instead would make every\n * gist a restatement of the filename, which is the one thing a Tier-1 disclosure line must not be.\n * Prose with no sentence terminator is its own claim in full. A fragment is still an assertion, and\n * rejecting it would reject the shortest legitimate memory there is.\n */\nexport const claimFromProse = (prose: string): string => {\n const trimmed = prose.trim()\n const match = /^(.*?[.!?])(\\s|$)/s.exec(trimmed)\n return (match?.[1] ?? trimmed).trim()\n}\n\n/**\n * The prose after the claim, as paragraphs. Empty when the claim was the whole body.\n *\n * The first element becomes the claim paragraph's own tail rather than a second `<p>`, which is\n * `articleHtmlFor`'s contract in `@memhtml/html`'s template. A one-paragraph body therefore yields\n * exactly one `<p>` with the `<mark>` inside it, which is what constraint 1 requires.\n */\nexport const proseTail = (prose: string): ReadonlyArray<string> => {\n const remainder = prose.trim().slice(claimFromProse(prose).length).trim()\n return remainder === \"\" ? [] : paragraphsOf(remainder)\n}\n","import { readFile } from \"node:fs/promises\"\n\nimport { type ErrorCode, type Failure, fail } from \"./envelope.js\"\nimport type { BatchOpReport, BatchWriteResult, WriteParams } from \"./operations.js\"\nimport { claimFromProse, proseTail } from \"./prose.js\"\n\n/**\n * `memhtml apply`'s own layer: JSONL text in, decoded ops or a usage failure out.\n *\n * Separated from `run.ts` because everything here is a decision about one untrusted text format, and\n * because AC-6-4's contract is that the whole file is judged before any op executes. That makes\n * this a pure function from text to either an op list or a refusal, testable without a repo.\n *\n * The refusals are `Failure` values rather than thrown errors for the reason `validate` returns one:\n * the exit code is the contract. A usage error is exit 2 and a runtime error is exit 1, and a\n * malformed line is a usage error, because the caller wrote a bad file and the corpus is fine.\n */\n\n/**\n * The op vocabulary, v1.\n *\n * Writes only, per spec D4. `op` is carried on the wire anyway so v2 can add `correct`/`link`/\n * `archive` without a format break. An unknown value is refused with this list attached rather than\n * ignored, because a file of `{\"op\":\"wrote\",…}` lines that applied nothing and exited 0 is the silent\n * failure the whole pre-validation pass exists to prevent.\n */\nexport const APPLY_OPS: ReadonlyArray<string> = [\"write\"]\n\n/**\n * Every field a line may carry, mapped to the `WriteParams` field it becomes.\n *\n * A table rather than a hand-written decode, so the snake_case → camelCase rename is stated once and\n * the unknown-field check below is derived from it. The MCP tool's parameters use exactly these\n * snake_case names (`apps/mcp/src/tools.ts`), so an agent that learned the field names from one door\n * can write a JSONL file for the other without translating.\n */\nconst SCALAR_FIELDS = {\n title: \"title\",\n type: \"memoryType\",\n body: \"body\",\n article_html: \"articleHtml\",\n path: \"path\",\n workspace: \"workspace\",\n importance: \"importance\",\n confidence: \"confidence\",\n session_id: \"sessionId\",\n prompt_id: \"promptId\",\n turn_uuid: \"turnUuid\",\n status: \"taskStatus\",\n due: \"dueAt\"\n} as const\n\n/** Fields that accept a string or an array of strings, and always become an array. */\nconst LIST_FIELDS = { tag: \"tags\", tags: \"tags\", entity: \"entities\", entities: \"entities\" } as const\n\n/** `op` is the discriminator rather than a `WriteParams` field, so it is legal and never mapped. */\nconst KNOWN_FIELDS: ReadonlySet<string> = new Set([\n \"op\",\n ...Object.keys(SCALAR_FIELDS),\n ...Object.keys(LIST_FIELDS)\n])\n\n/** A usage failure naming the offending line, 1-based as a text editor counts. */\nconst lineError = (\n code: ErrorCode,\n line: number,\n reason: string,\n suggestions: ReadonlyArray<string> = []\n): Failure => fail(code, `${APPLY_DOC}: line ${line}: ${reason}`, suggestions)\n\n/** The prefix every apply refusal carries, so a caller can tell a file error from a corpus error. */\nconst APPLY_DOC = \"memhtml apply\"\n\n/** One line's parsed JSON as a record, or the refusal. */\nconst objectAt = (text: string, line: number): Record<string, unknown> | Failure => {\n let value: unknown\n try {\n value = JSON.parse(text)\n } catch (error) {\n return lineError(\n \"ERR_INVALID_FLAG\",\n line,\n `not valid JSON (${error instanceof Error ? error.message : String(error)}). Every line is one complete JSON object; a pretty-printed object spanning several lines is not JSONL`,\n [\n 'memhtml apply --file ops.jsonl, one object per line: {\"op\":\"write\",\"title\":\"…\",\"type\":\"semantic\",\"body\":\"…\"}'\n ]\n )\n }\n if (typeof value !== \"object\" || value === null || Array.isArray(value)) {\n return lineError(\n \"ERR_INVALID_FLAG\",\n line,\n `parsed as ${Array.isArray(value) ? \"an array\" : typeof value}, not a JSON object`\n )\n }\n return value as Record<string, unknown>\n}\n\nconst isFailure = (value: unknown): value is Failure =>\n typeof value === \"object\" && value !== null && \"code\" in value && \"error\" in value\n\n/** A field that must be a non-empty string, or the refusal naming it. */\nconst requiredString = (\n record: Record<string, unknown>,\n field: string,\n line: number\n): string | Failure => {\n const value = record[field]\n if (value === undefined) {\n return lineError(\"ERR_MISSING_ARGUMENT\", line, `missing required field \\`${field}\\``)\n }\n if (typeof value !== \"string\" || value.trim() === \"\") {\n return lineError(\n \"ERR_INVALID_FLAG\",\n line,\n `\\`${field}\\` must be a non-empty string, got ${value === null ? \"null\" : typeof value}`\n )\n }\n return value\n}\n\n/** A list field as an array of strings: a bare string is a one-element list, as `--tag` is. */\nconst strings = (value: unknown, field: string, line: number): Array<string> | Failure => {\n if (typeof value === \"string\") return value === \"\" ? [] : [value]\n if (!Array.isArray(value)) {\n return lineError(\n \"ERR_INVALID_FLAG\",\n line,\n `\\`${field}\\` must be a string or an array of strings, got ${typeof value}`\n )\n }\n const out: Array<string> = []\n for (const entry of value) {\n if (typeof entry !== \"string\") {\n return lineError(\n \"ERR_INVALID_FLAG\",\n line,\n `\\`${field}\\` holds a ${typeof entry} where every element must be a string`\n )\n }\n if (entry !== \"\") out.push(entry)\n }\n return out\n}\n\n/** A numeric field, accepting the JSON number or a numeric string. */\nconst numeric = (value: unknown, field: string, line: number): number | Failure => {\n const parsed = typeof value === \"number\" ? value : Number(value)\n if (typeof value !== \"number\" && typeof value !== \"string\") {\n return lineError(\"ERR_INVALID_FLAG\", line, `\\`${field}\\` must be a number, got ${typeof value}`)\n }\n if (!Number.isFinite(parsed)) {\n return lineError(\n \"ERR_INVALID_FLAG\",\n line,\n `\\`${field}\\` is not a finite number: ${String(value)}`\n )\n }\n return parsed\n}\n\n/**\n * One line as a `WriteParams`, or the refusal naming the line.\n *\n * The shape rules AC-6-4 puts at this door and nowhere else: the line parses, it declares an op in\n * the vocabulary, and it carries `title` and `type` as non-empty strings. Everything past that is\n * the operations layer's decode (is `type` in the vocabulary) or the store's render gate (is the\n * markup valid). Those are checked per op and reported per op, and they are not duplicated here,\n * because a second copy of the type vocabulary is a second thing to update when it moves.\n */\nconst opAt = (record: Record<string, unknown>, line: number): WriteParams | Failure => {\n for (const field of Object.keys(record)) {\n if (!KNOWN_FIELDS.has(field)) {\n return lineError(\n \"ERR_INVALID_FLAG\",\n line,\n `unknown field \\`${field}\\`. Fields: ${[...KNOWN_FIELDS].sort().join(\", \")}`\n )\n }\n }\n\n const op = record.op\n if (op === undefined) {\n return lineError(\n \"ERR_MISSING_ARGUMENT\",\n line,\n `missing required field \\`op\\`. One of: ${APPLY_OPS.join(\", \")}`\n )\n }\n if (typeof op !== \"string\" || !APPLY_OPS.includes(op)) {\n return lineError(\n \"ERR_INVALID_FLAG\",\n line,\n `\\`op\\` must be one of: ${APPLY_OPS.join(\", \")}, got ${JSON.stringify(op)}`\n )\n }\n\n const title = requiredString(record, \"title\", line)\n if (isFailure(title)) return title\n const memoryType = requiredString(record, \"type\", line)\n if (isFailure(memoryType)) return memoryType\n\n const params: Record<string, unknown> = { title, memoryType, claim: \"\" }\n\n for (const [field, target] of Object.entries(SCALAR_FIELDS)) {\n const value = record[field]\n if (value === undefined || value === null) continue\n if (field === \"title\" || field === \"type\") continue\n if (target === \"importance\" || target === \"confidence\") {\n const parsed = numeric(value, field, line)\n if (isFailure(parsed)) return parsed\n params[target] = parsed\n continue\n }\n if (typeof value !== \"string\") {\n return lineError(\n \"ERR_INVALID_FLAG\",\n line,\n `\\`${field}\\` must be a string, got ${typeof value}`\n )\n }\n params[target] = value\n }\n\n for (const [field, target] of Object.entries(LIST_FIELDS)) {\n const value = record[field]\n if (value === undefined || value === null) continue\n const parsed = strings(value, field, line)\n if (isFailure(parsed)) return parsed\n params[target] = [...((params[target] as Array<string> | undefined) ?? []), ...parsed]\n }\n\n /**\n * `body` prose becomes claim + tail; `article_html` is used verbatim and leaves `claim` empty.\n *\n * The XOR itself is not enforced here. The store's render gate owns it per op, so a batch with one\n * bad op reports that op and not the whole file. This branch owns the claim instead: the JSONL wire\n * has no `claim` field, so a prose line's claim is derived rather than restated by its author (see\n * {@link claimFromProse}, the one copy both doors share).\n *\n * Skipping this no longer lands a bad file. `@memhtml/html` constraint 1 rejects an empty `<mark>`, so\n * the render gate would stop the op instead of committing a file with an empty `files.gist`. The\n * derivation is what makes a prose line valid in the first place. It is no longer the only thing\n * standing between a missing claim and a silent write.\n */\n const prose = typeof params.body === \"string\" ? (params.body as string) : undefined\n if (prose !== undefined && prose.trim() !== \"\") {\n params.claim = claimFromProse(prose)\n params.body = proseTail(prose)\n } else if (prose !== undefined) {\n delete params.body\n }\n\n return params as unknown as WriteParams\n}\n\n/** What a whole-file decode produced: the ops, or the first line that refused. */\nexport type ApplyDecode =\n | { readonly ok: true; readonly ops: ReadonlyArray<WriteParams> }\n | { readonly ok: false; readonly failure: Failure }\n\n/**\n * Decode a whole JSONL document, refusing on the first bad line.\n *\n * Every line is judged before any op runs (AC-6-4), and that ordering is the contract rather than an\n * implementation detail. An apply that executed lines 1-6 and then refused line 7 would leave a\n * commit behind for a call that reported failure, and the caller's only recovery would be to work out\n * which prefix landed. Refusing first costs nothing, since no service has been touched yet.\n *\n * Blank lines are skipped rather than refused, because a file written by `printf '%s\\n'` or a heredoc\n * ends in one. The line numbers still count them, so an error naming line 7 means the seventh\n * line of the file the caller can open in an editor.\n */\nexport const decodeApply = (text: string): ApplyDecode => {\n const ops: Array<WriteParams> = []\n const lines = text.split(\"\\n\")\n\n for (const [at, raw] of lines.entries()) {\n const line = at + 1\n if (raw.trim() === \"\") continue\n const record = objectAt(raw, line)\n if (isFailure(record)) return { ok: false, failure: record }\n const op = opAt(record, line)\n if (isFailure(op)) return { ok: false, failure: op }\n ops.push(op)\n }\n\n if (ops.length === 0) {\n return {\n ok: false,\n failure: fail(\n \"ERR_MISSING_ARGUMENT\",\n `${APPLY_DOC}: no ops. The input held no non-blank lines, so there is nothing to write`,\n [\n \"memhtml apply --file ops.jsonl\",\n 'printf \\'%s\\\\n\\' \\'{\"op\":\"write\",\"title\":\"A fact\",\"type\":\"semantic\",\"body\":\"The thing that happened.\"}\\' | memhtml apply -'\n ]\n )\n }\n }\n\n return { ok: true, ops }\n}\n\n/**\n * Read the JSONL text for one invocation: `--file <path>`, or stdin.\n *\n * **The stdin seam.** `run()` takes this reader as an injectable parameter and defaults to\n * {@link readStdin}, so `bin.ts` needs no edit and a test supplies the text directly. Reading stdin\n * in `bin.ts` instead would make the entry point parse argv to discover whether\n * the command it is about to dispatch even wants stdin, and would put an I/O decision in the one file\n * whose whole job is \"call run, write the envelope, exit\".\n */\nexport const applyText = async (\n file: string | undefined,\n stdin: () => Promise<string>\n): Promise<string | Failure> => {\n if (file !== undefined && file.trim() !== \"\") {\n try {\n return await readFile(file, \"utf8\")\n } catch (error) {\n return fail(\n \"ERR_PATH_NOT_FOUND\",\n `${APPLY_DOC}: cannot read --file ${file}: ${error instanceof Error ? error.message : String(error)}`,\n [`ls ${file}`, \"memhtml apply - < ops.jsonl\"]\n )\n }\n }\n return await stdin()\n}\n\n/**\n * `process.stdin` as text, and nothing when a human is at a terminal.\n *\n * The TTY check is what makes a bare `memhtml apply` with no `--file` and no pipe answer with the\n * empty-input usage error instead of hanging forever waiting on a keyboard. An agent invoking this\n * without a pipe gets an envelope; a hang would get a timeout and no diagnosis.\n */\nexport const readStdin = async (): Promise<string> => {\n if (process.stdin.isTTY === true) return \"\"\n const chunks: Array<Buffer> = []\n for await (const chunk of process.stdin) {\n chunks.push(typeof chunk === \"string\" ? Buffer.from(chunk) : (chunk as Buffer))\n }\n return Buffer.concat(chunks).toString(\"utf8\")\n}\n\n/**\n * The `batch.applied` payload: the operation's result, renamed to the wire's snake_case.\n *\n * snake_case here and camelCase in `memory.written` is a real inconsistency, and it comes from the\n * spec (D6 names `commit_sha`). It was taken on purpose, because it makes this payload byte-comparable\n * with `memory_write_batch`'s over MCP. An agent that has parsed one has parsed the other, and a batch\n * result is the payload most likely to be handled by shared code across the two doors.\n *\n * Absent fields are `null` rather than missing. `deduped` and `skipped` are always booleans. An agent\n * branching on `deduped === true` should not have to also handle the key being absent, and `--dense`\n * strips the nulls for the context-window case anyway.\n */\nconst opPayload = (report: BatchOpReport) => ({\n index: report.index,\n ok: report.ok,\n path: report.path ?? null,\n deduped: report.deduped === true,\n existing_path: report.existingPath ?? null,\n code: report.code ?? null,\n error: report.error ?? null,\n skipped: report.skipped === true,\n /**\n * What this op's claim contradicts, when `--detect-conflicts` was passed and something matched.\n *\n * The inner field names are snake_case (`batch_index`) for the same reason the outer ones are: this\n * payload is byte-comparable with `memory_write_batch`'s, so shared code across the two doors reads\n * one shape. Null when the flag was off, when nothing matched, or when the claim has no frame\n * shape. An op carrying a conflict was still written, because the field is a report rather than a\n * refusal.\n */\n conflict:\n report.conflict === undefined\n ? null\n : {\n path: report.conflict.path,\n batch_index: report.conflict.batchIndex,\n claim: report.conflict.claim\n },\n /**\n * The two `--consolidate last-wins` outcomes, null everywhere else, including when the flag was\n * off. That is the same \"absent is null\" rule every field above follows, and the same shape\n * `memory_write_batch` publishes.\n */\n consolidated_into: report.consolidatedInto ?? null,\n superseded_path: report.supersededPath ?? null\n})\n\nexport const applyPayload = (result: BatchWriteResult) => ({\n results: result.results.map(opPayload),\n summary: result.summary,\n commit_sha: result.commitSha\n})\n","import { mkdir, writeFile } from \"node:fs/promises\"\nimport { dirname, join } from \"node:path\"\n\nimport { type EdgeRel, isEdgeRel } from \"@memhtml/contracts/edges\"\nimport { INBOX_DIR, normalizePath, TASKS_SUBDIR } from \"@memhtml/contracts/paths\"\nimport { checkMemory } from \"@memhtml/html\"\nimport { DatabaseService, type DatabaseShape, STATE_SCHEMA } from \"@memhtml/index\"\nimport { EMBED_WATERMARK } from \"@memhtml/llm\"\nimport {\n allPaths,\n applyHeadEdits,\n archivedFormOf,\n danglingEdges,\n hrefFor,\n link,\n meta,\n unlink\n} from \"@memhtml/sleep\"\nimport { attemptIo, commitSubject, readFileOrNull } from \"@memhtml/store\"\nimport { Effect } from \"effect\"\n\nimport { Git, Store } from \"./api-layer.js\"\n\n/**\n * `memhtml doctor`: the corpus's own health check, and `--fix` for the two findings a repair can settle\n * without a judgement call.\n *\n * Eight checks, and each one is a claim the design makes about the corpus rather than a lint:\n *\n * 1. **Dangling `<link>` hrefs**: an authored edge pointing at a path the tree does not hold. Design\n * §2.3 has no foreign key on `edges` deliberately (a `<link>` may name a file the indexer has not\n * reached), so a LEFT JOIN is the only thing that finds these.\n * 2. **Orphan state rows**: a `state.access` row whose path left the tree. There are no\n * cross-database foreign keys, so the store mirrors a move explicitly and an interrupted mirror\n * leaves a row describing nothing.\n * 3. **Inbox depth**: design §2.1 rule 6 routes an unplaceable memory to `areas/inbox/` and says\n * doctor reports the depth as a health signal. A deep inbox is a placement rule that stopped\n * matching what agents write, which nothing else surfaces.\n * 4. **Vocabulary warnings**: format constraint 6. An element outside the closed vocabulary still\n * indexes, so the only way it ever becomes visible is here.\n * 5. **Index staleness**: the index is a projection of a commit, so \"fresh\" means the commit it\n * describes is the commit we are on. Plus the vector-space watermark, because a stored space that\n * differs from the configured one makes every cosine in the index incomparable.\n * 6. **Overdue tasks**: a task is default-excluded from search and skipped by every sleep phase, so\n * nothing else in the system will ever mention that a deadline passed. Doctor is the only surface\n * that reads `due_at`.\n * 7. **Stale task blockers**: a `blocks` edge whose blocker is archived or absent. This is the one\n * task-graph state no single file can reveal, since each file individually is valid and the pair\n * is a task waiting on something that will never move.\n * 8. **Task inbox depth**: a task in `areas/inbox/tasks/` is work with no project, and a task inbox\n * is meant to be drained rather than accumulated.\n *\n * **`--fix` repairs exactly two of the eight, and the repair logic is imported from the sleep\n * integrity phase rather than re-ported.** `archivedFormOf` decides whether a dangling target moved\n * to the archive or is genuinely gone, and `applyHeadEdits`/`link`/`unlink`/`meta` are the byte-splice\n * editors that change one head line without touching the article. A parse→serialize round trip drops\n * a `<pre>` newline per write, so a \"repair\" through the serializer would move the content hash of\n * every file it touched. A second implementation of either would be the consumer-side reimplementation\n * of producer semantics the fleet has paid for repeatedly.\n *\n * The other six report and do not repair. An inbox memory or task needs a human or an agent to decide\n * where it belongs, a vocabulary warning needs the author's intent, and a stale index needs\n * `memhtml index update`, which doctor names in its own suggestions rather than running behind the\n * operator's back. An overdue task needs the work done or the deadline moved, and a stale blocker\n * needs someone to decide whether the blocked task is actually ready.\n */\n\n/** How deep the inbox may get before doctor calls it a finding. */\nexport const INBOX_WARN_DEPTH = 20\n\n/**\n * How many unplaced tasks may sit in `areas/inbox/tasks/` before doctor calls it a finding.\n *\n * Lower than {@link INBOX_WARN_DEPTH} because the two crowds mean different things. An unplaced\n * memory is a placement rule that stopped matching. An unplaced task is work with no project, which\n * is the state a to-do list rots in, and a task inbox is meant to be drained rather than accumulated.\n */\nexport const INBOX_TASK_WARN_DEPTH = 10\n\n/** One dangling href, and what a repair would do about it. */\nexport interface DanglingFinding {\n readonly srcPath: string\n readonly rel: string\n readonly dstPath: string\n /** The archive path the target moved to, or `null` when the target is genuinely gone. */\n readonly rewriteTo: string | null\n}\n\n/** One file carrying vocabulary warnings. */\nexport interface WarningFinding {\n readonly path: string\n readonly warnings: ReadonlyArray<string>\n}\n\n/** One open task past its deadline. */\nexport interface OverdueTaskFinding {\n readonly path: string\n readonly taskStatus: string | null\n /** The `memhtml-due` value, verbatim. An ISO date or datetime. */\n readonly dueAt: string\n}\n\n/** One open task whose blocker can never close it. */\nexport interface StaleBlockerFinding {\n readonly path: string\n readonly blockerPath: string\n /** `archived`: the blocker is finished or evicted. `missing`: no file at that path at all. */\n readonly blockerState: \"archived\" | \"missing\"\n}\n\n/** What a doctor pass found. Every list is present and possibly empty, so a parser never branches. */\nexport interface DoctorReport {\n readonly root: string\n /** True when every check is clean. */\n readonly healthy: boolean\n readonly dangling: ReadonlyArray<DanglingFinding>\n /** `state.access` rows whose path is absent from `files`. */\n readonly orphanAccessRows: ReadonlyArray<string>\n readonly inboxDepth: number\n /** True when the inbox is past {@link INBOX_WARN_DEPTH}. */\n readonly inboxCrowded: boolean\n /** Open tasks in `areas/inbox/tasks/`: work with no project. */\n readonly inboxTaskDepth: number\n /** True when the task inbox is past {@link INBOX_TASK_WARN_DEPTH}. */\n readonly inboxTasksCrowded: boolean\n /** Open tasks whose `memhtml-due` has passed, earliest first. */\n readonly overdueTasks: ReadonlyArray<OverdueTaskFinding>\n /** Open tasks blocked by a task that is archived or absent from the tree. */\n readonly staleBlockers: ReadonlyArray<StaleBlockerFinding>\n readonly warnings: ReadonlyArray<WarningFinding>\n /** Files the index holds that failed to parse when doctor re-read them. */\n readonly unparseable: ReadonlyArray<string>\n readonly indexFresh: boolean\n readonly indexHeadSha: string | null\n readonly headSha: string | null\n /** True when the stored vector space IS the configured one. */\n readonly embedModelMatches: boolean\n readonly storedEmbedModel: string | null\n readonly configuredEmbedModel: string\n readonly dirty: ReadonlyArray<string>\n /** Present under `--fix`: what the repair actually did. */\n readonly repaired?: RepairReport | undefined\n}\n\n/** What `--fix` changed. */\nexport interface RepairReport {\n /** Dangling hrefs rewritten to the target's archive path. */\n readonly rewritten: number\n /** Dangling hrefs dropped because the target has no file anywhere. */\n readonly dropped: number\n /** Orphan `state.access` rows deleted. */\n readonly prunedAccessRows: number\n /** The commit the href repairs landed in, or `null` when nothing was rewritten. */\n readonly commitSha: string | null\n}\n\n/** Every `state.access` path the index has no `files` row for. */\nconst orphanAccess = (db: DatabaseShape): Effect.Effect<ReadonlyArray<string>, never, never> =>\n db.hasState\n ? db\n .all<{ path: string }>(\n `SELECT a.path AS path FROM ${STATE_SCHEMA}.access a\n LEFT JOIN files f ON f.path = a.path\n WHERE f.path IS NULL ORDER BY a.path ASC`\n )\n .pipe(\n Effect.map((rows) => rows.map((row) => row.path)),\n Effect.orElseSucceed(() => [])\n )\n : Effect.succeed([])\n\n/** How many ACTIVE memories sit in the inbox. An archived one is no longer awaiting placement. */\nconst inboxDepth = (db: DatabaseShape): Effect.Effect<number, never, never> =>\n db\n .get<{ n: number }>(\n \"SELECT count(*) AS n FROM files WHERE archived = 0 AND path LIKE ? || '/%'\",\n [INBOX_DIR]\n )\n .pipe(\n Effect.map((row) => row?.n ?? 0),\n Effect.orElseSucceed(() => 0)\n )\n\n/**\n * How many ACTIVE tasks sit in the task inbox.\n *\n * `memory_type = 'task'` as well as the path prefix, because `areas/inbox/tasks/` is a directory and\n * a directory is not a type: a hand-authored memory filed there would inflate the task count and make\n * the finding say something it does not mean.\n */\nconst inboxTaskDepth = (db: DatabaseShape): Effect.Effect<number, never, never> =>\n db\n .get<{ n: number }>(\n `SELECT count(*) AS n FROM files\n WHERE archived = 0 AND memory_type = 'task' AND path LIKE ? || '/%'`,\n [`${INBOX_DIR}/${TASKS_SUBDIR}`]\n )\n .pipe(\n Effect.map((row) => row?.n ?? 0),\n Effect.orElseSucceed(() => 0)\n )\n\n/**\n * Open tasks past their deadline.\n *\n * `substr(due_at, 1, 10)` states that the comparison is one of calendar days. The bound is always a\n * bare `YYYY-MM-DD` (today, from the clock), and enumerated against that bound the truncation changes\n * no answer, because a time-bearing due date on the bound's own day sorts after it either way. It\n * stays as the statement of intent. `listTasks`' `--due-before` takes a caller-supplied bound that may\n * carry a time, where the truncation does change answers, and one form across both queries keeps\n * \"overdue\" meaning the same thing in the two places an operator reads it.\n *\n * **`archived = 0` and `task_status <> 'done'` both change the result** (mutation-verified\n * 2026-08-02). A finished task's deadline is history, and reporting it would make the finding grow\n * forever and never reach zero.\n */\nconst overdueTasks = (\n db: DatabaseShape,\n today: string\n): Effect.Effect<ReadonlyArray<OverdueTaskFinding>, never, never> =>\n db\n .all<{ path: string; task_status: string | null; due_at: string }>(\n `SELECT path, task_status, due_at FROM files\n WHERE memory_type = 'task' AND archived = 0 AND due_at IS NOT NULL\n AND substr(due_at, 1, 10) < ? AND task_status <> 'done'\n ORDER BY due_at ASC, path ASC`,\n [today]\n )\n .pipe(\n Effect.map((rows) =>\n rows.map((row) => ({ path: row.path, taskStatus: row.task_status, dueAt: row.due_at }))\n ),\n Effect.orElseSucceed(() => [])\n )\n\n/**\n * Open tasks whose blocker can never close them.\n *\n * A `blocks` edge points blocker → blocked, so the blocked task is the edge's `dst_path`. A LEFT JOIN\n * rather than an inner one, because the two failure modes differ. An archived blocker is finished work\n * whose edge nobody cleared, and a missing one is an edge whose source has no `files` row. Either way\n * the blocked task waits on something that will never move. This is the one task-graph state no single\n * file can reveal, since each file is individually valid and only the pair is wrong.\n *\n * **The `archived` arm is the reachable one, and `missing` is defense in depth.** Probed and\n * mutation-confirmed 2026-08-02: deleting a blocker's file makes `indexer.update` clear\n * `edges WHERE src_path = ?` in the same batch, so an edge cannot outlive its source file and the\n * `missing` branch has nothing to find. Removing that `DELETE` turns the branch on, and it stays for\n * that reason. `edges` carries no foreign key deliberately, so a future writer of edge rows would not\n * inherit the indexer's discipline.\n *\n * **`edge_class = 'task'` is redundant with `rel = 'blocks'` today.** The migration's per-class CHECKs\n * refuse `blocks` under every other class, so a mutation dropping it leaves the suite green. It is kept\n * because every memory-graph query filters on the class column, and a reader who saw this one trust\n * the rel alone would learn the wrong rule about where the firewall lives.\n *\n * Report-only. Clearing the edge is an authoring decision, since the blocked task may be genuinely\n * ready or the blocker may have been archived prematurely. `--fix` guessing between those would rewrite\n * a plan.\n */\nconst staleBlockers = (\n db: DatabaseShape\n): Effect.Effect<ReadonlyArray<StaleBlockerFinding>, never, never> =>\n db\n .all<{ path: string; blocker_path: string; blocker_state: string }>(\n `SELECT t.path AS path, e.src_path AS blocker_path,\n CASE WHEN b.path IS NULL THEN 'missing' ELSE 'archived' END AS blocker_state\n FROM files t\n JOIN edges e ON e.dst_path = t.path AND e.edge_class = 'task' AND e.rel = 'blocks'\n LEFT JOIN files b ON b.path = e.src_path\n WHERE t.memory_type = 'task' AND t.archived = 0 AND t.task_status <> 'done'\n AND (b.path IS NULL OR b.archived = 1)\n ORDER BY t.path ASC, e.src_path ASC`\n )\n .pipe(\n Effect.map((rows) =>\n rows.map((row) => ({\n path: row.path,\n blockerPath: row.blocker_path,\n blockerState:\n row.blocker_state === \"missing\" ? (\"missing\" as const) : (\"archived\" as const)\n }))\n ),\n Effect.orElseSucceed(() => [])\n )\n\n/**\n * Re-read every active file and collect its format warnings.\n *\n * Re-read rather than taken from the index, because a warning is not a stored column. The indexer\n * counts a parse failure and projects what it can, and constraint 6 is deliberately non-fatal. Doctor\n * is the one caller that wants the list, so it is the one caller that pays for the read.\n */\nconst collectWarnings = (\n root: string,\n paths: ReadonlyArray<string>\n): Effect.Effect<\n { readonly warnings: ReadonlyArray<WarningFinding>; readonly unparseable: ReadonlyArray<string> },\n never,\n never\n> =>\n Effect.gen(function* () {\n const warnings: Array<WarningFinding> = []\n const unparseable: Array<string> = []\n for (const path of paths) {\n const html = yield* readFileOrNull(join(root, path)).pipe(Effect.orElseSucceed(() => null))\n if (html === null) {\n unparseable.push(path)\n continue\n }\n const checked = checkMemory(html)\n if (checked.violations.length > 0) unparseable.push(path)\n if (checked.warnings.length > 0) warnings.push({ path, warnings: checked.warnings })\n }\n return { warnings, unparseable }\n })\n\n/** The year a run's repairs partition archive lookups under: the current calendar year. */\nconst currentYear = Effect.clockWith((clock) =>\n Effect.map(clock.currentTimeMillis, (millis) => new Date(millis).getUTCFullYear())\n)\n\n/** Today as `YYYY-MM-DD`, through the Effect clock so a test can pin what \"overdue\" means. */\nconst todayDate = Effect.clockWith((clock) =>\n Effect.map(clock.currentTimeMillis, (millis) => new Date(millis).toISOString().slice(0, 10))\n)\n\n/** An ISO-8601 UTC second, for the `memhtml-updated` stamp a repair writes. */\nconst nowSecond = Effect.clockWith((clock) =>\n Effect.map(clock.currentTimeMillis, (millis) => `${new Date(millis).toISOString().slice(0, 19)}Z`)\n)\n\n/**\n * Repair the dangling hrefs and prune the orphan access rows.\n *\n * The href repair mirrors the integrity phase exactly, using its own `archivedFormOf` and its own\n * head editors. A dangling target that moved under `archive/<YYYY>/` gets its href rewritten, so the\n * edge still says something true. A target with no file anywhere gets the link dropped with a\n * warning, because the edge asserts a relationship to nothing and leaving it would produce the same\n * finding on every rebuild forever.\n *\n * Remove-then-add on the same file in one pass, so a repair replaces one line rather than dropping a\n * line and appending another elsewhere in the head. A re-run is then a no-op: once the href points at\n * the archive path the removal matches nothing and the addition is already present.\n */\nconst repair = (\n root: string,\n findings: ReadonlyArray<DanglingFinding>,\n orphans: ReadonlyArray<string>\n) =>\n Effect.gen(function* () {\n const git = yield* Git\n const db = yield* DatabaseService\n const at = yield* nowSecond\n\n let rewritten = 0\n let dropped = 0\n const touched: Array<string> = []\n\n for (const finding of findings) {\n if (!isEdgeRel(finding.rel)) continue\n const rel = finding.rel as EdgeRel\n const absolute = join(root, finding.srcPath)\n const html = yield* readFileOrNull(absolute).pipe(Effect.orElseSucceed(() => null))\n if (html === null) continue\n\n const edits =\n finding.rewriteTo === null\n ? [unlink(rel, hrefFor(finding.dstPath)), meta(\"memhtml-updated\", at)]\n : [\n unlink(rel, hrefFor(finding.dstPath)),\n link(rel, hrefFor(finding.rewriteTo)),\n meta(\"memhtml-updated\", at)\n ]\n const edited = applyHeadEdits(html, edits)\n if (edited === html) continue\n\n if (finding.rewriteTo === null) {\n yield* Effect.logWarning(\n `doctor dropped a dangling ${rel} from ${finding.srcPath}: target has no file`\n )\n }\n yield* attemptIo(`doctor.write:${finding.srcPath}`, async () => {\n await mkdir(dirname(absolute), { recursive: true })\n await writeFile(absolute, edited, \"utf8\")\n }).pipe(Effect.orElseSucceed(() => undefined))\n touched.push(finding.srcPath)\n if (finding.rewriteTo === null) dropped += 1\n else rewritten += 1\n }\n\n let prunedAccessRows = 0\n if (orphans.length > 0 && db.hasState) {\n /**\n * One statement per path rather than an `IN` list, because the list is unbounded. A driver\n * parameter limit reached mid-prune would fail the whole batch and leave every row in place.\n */\n for (const path of orphans) {\n const done = yield* db\n .run(`DELETE FROM ${STATE_SCHEMA}.access WHERE path = ?`, [path])\n .pipe(\n Effect.as(true),\n Effect.orElseSucceed(() => false)\n )\n if (done) prunedAccessRows += 1\n }\n }\n\n let commitSha: string | null = null\n if (touched.length > 0) {\n yield* git.add(touched)\n const commit = yield* git.commit(\n commitSubject(\"link\", `repair ${rewritten + dropped} dangling links`)\n )\n commitSha = commit.sha\n }\n\n return { rewritten, dropped, prunedAccessRows, commitSha } satisfies RepairReport\n })\n\n/**\n * Run the health check, optionally repairing.\n *\n * The findings are gathered before any repair and the report carries the pre-repair lists alongside\n * `repaired`, which is what makes a `--fix` run auditable. An operator reads what was wrong and what\n * was done about it in one envelope, rather than a clean report that says nothing happened.\n */\nexport const doctor = (options: { readonly fix: boolean }) =>\n Effect.gen(function* () {\n const git = yield* Git\n const store = yield* Store\n const db = yield* DatabaseService\n\n const headSha = yield* git.revParseHead().pipe(Effect.orElseSucceed(() => null))\n const dirty = yield* store.dirtyPaths().pipe(Effect.orElseSucceed(() => []))\n\n const state = yield* db\n .get<{ head_sha: string | null; embed_model: string }>(\n \"SELECT head_sha, embed_model FROM index_state WHERE id = 1\"\n )\n .pipe(Effect.orElseSucceed(() => undefined))\n\n const known = new Set(\n (yield* allPaths(db).pipe(Effect.orElseSucceed(() => []))).map((row) => row.path)\n )\n const year = yield* currentYear\n const edges = yield* danglingEdges(db).pipe(Effect.orElseSucceed(() => []))\n const dangling: ReadonlyArray<DanglingFinding> = edges.map((edge) => {\n const dstPath = normalizePath(edge.dst_path)\n return {\n srcPath: edge.src_path,\n rel: edge.rel,\n dstPath,\n rewriteTo: archivedFormOf(dstPath, known, year) ?? null\n }\n })\n\n const orphanAccessRows = yield* orphanAccess(db)\n const depth = yield* inboxDepth(db)\n const taskDepth = yield* inboxTaskDepth(db)\n const overdue = yield* overdueTasks(db, yield* todayDate)\n const stale = yield* staleBlockers(db)\n\n const active = yield* db\n .all<{ path: string }>(\"SELECT path FROM files WHERE archived = 0 ORDER BY path ASC\")\n .pipe(Effect.orElseSucceed(() => []))\n const { warnings, unparseable } = yield* collectWarnings(\n git.root,\n active.map((row) => row.path)\n )\n\n const repaired = options.fix ? yield* repair(git.root, dangling, orphanAccessRows) : undefined\n\n const indexFresh = state?.head_sha !== null && state?.head_sha === headSha\n const embedModelMatches = state?.embed_model === EMBED_WATERMARK\n\n return {\n root: git.root,\n /**\n * `healthy` is computed from the findings and not from the repair. A `--fix` run that repaired\n * everything still reports the corpus as it was found. A command that flipped itself green by\n * fixing what it found would make \"doctor is clean\" unfalsifiable.\n */\n healthy:\n dangling.length === 0 &&\n orphanAccessRows.length === 0 &&\n depth <= INBOX_WARN_DEPTH &&\n /**\n * The task inbox counts toward `healthy` for the same reason the memory inbox does: an\n * unplaced item is a routing signal. `overdueTasks` and `staleBlockers` are excluded, because\n * those two are facts about the work rather than defects in the corpus. A repo whose owner is\n * late on a to-do is structurally sound, and folding them in would make `healthy: false` the\n * normal state and stop anyone reading the flag at all. Every other finding here is a defect\n * in the corpus; those two describe work that has fallen behind.\n */\n taskDepth <= INBOX_TASK_WARN_DEPTH &&\n warnings.length === 0 &&\n unparseable.length === 0 &&\n indexFresh &&\n embedModelMatches,\n dangling,\n orphanAccessRows,\n inboxDepth: depth,\n inboxCrowded: depth > INBOX_WARN_DEPTH,\n inboxTaskDepth: taskDepth,\n inboxTasksCrowded: taskDepth > INBOX_TASK_WARN_DEPTH,\n overdueTasks: overdue,\n staleBlockers: stale,\n warnings,\n unparseable,\n indexFresh,\n indexHeadSha: state?.head_sha ?? null,\n headSha,\n embedModelMatches,\n storedEmbedModel: state?.embed_model ?? null,\n configuredEmbedModel: EMBED_WATERMARK,\n dirty,\n ...(repaired === undefined ? {} : { repaired })\n } satisfies DoctorReport\n })\n","import { readFile } from \"node:fs/promises\"\nimport { createRequire } from \"node:module\"\nimport { dirname, resolve } from \"node:path\"\nimport { fileURLToPath } from \"node:url\"\n\nimport { InvalidMemory, StorageFailure } from \"@memhtml/contracts/errors\"\nimport { type GitFailure, makeGit } from \"@memhtml/store\"\nimport { Effect, type Scope } from \"effect\"\n\nimport { type Failure, fail } from \"./envelope.js\"\n\n/**\n * `memhtml exec`, the code-mode runtime: an agent-supplied script, a read-only corpus, one envelope.\n *\n * ROADMAP item 7 is the requirement. A multi-hop traversal written as code answers in one execution\n * what the tool path answers in one round trip per hop, and the closed vocabulary is what makes the\n * tree queryable without a new surface per question. Measured in the 2026-08 spike and\n * re-probed here on 2026-08-09: a 305-file\n * census in 598ms, and an edge walk resolving 410/410 edges into 201 chains, the longest 8 hops, in one\n * execution at 430ms.\n *\n * **Structural and lexical planes only. No index handle.** That is the division item 7 itself draws.\n * `memhtml search` finds entry points, code traverses from there, and a script needing ranked retrieval\n * shells out to `memhtml search` and consumes its envelope. Nothing here opens `index.db`, so CODE-2's\n * index half is satisfied by there being no handle to guard rather than by a guard. If one is ever\n * added, `scripts/probe-sqlite-concurrency.mjs` measures what a second process can do to a live store.\n *\n * **Read-only by contract.** Every write still goes through `memhtml apply` / `memory_write*`, so the\n * one-commit-per-op, dedup, and conflict machinery cannot be bypassed. The mount enforces it, since\n * `readOnly: true` on the `OverlayFs` answers `EROFS`, and this module offers no write path at all.\n */\n\n/** Where the corpus appears in the guest. Matches `ROOT` in `apps/cli/guest/corpus.mjs`. */\nexport const CORPUS_MOUNT = \"/mnt/memhtml\"\n\n/** Where the seeded modules live. `/workspace` is writable; the corpus mount is not. */\nconst GUEST_LIB = \"/workspace/lib\"\nconst GUEST_SCRIPT = \"/workspace/script.mjs\"\n\n/**\n * The default wall-clock bound on the script, in milliseconds.\n *\n * 30s, which is `maxJsTimeoutMs`'s own default in just-bash 3.2.0 (`dist/limits.d.ts:83`). It is named\n * here rather than inherited so the value appears in `memhtml manifest` and in `AGENTS.md`, where an\n * agent budgeting a call can read it. The measured work is far below it: the whole 305-file corpus\n * parses in 640ms, so 30s is roughly 45x the cost of a full-corpus pass.\n */\nexport const DEFAULT_TIMEOUT_MS = 30_000\n\n/**\n * The bound is capped, and the cap is what makes a runaway script terminate.\n *\n * `maxJsTimeoutMs` is the only thing standing between a runaway guest loop and a `memhtml exec` that\n * never returns. The guest is a QuickJS worker with no host-side reaper of its own, and an unbounded\n * script would hold the CLI process open indefinitely. Probed 2026-08-09 with `maxJsTimeoutMs: 700`\n * against `for(;;){n++}`: exit 124 at 724ms, \"js-exec: Execution timeout: exceeded 700ms limit\".\n */\nexport const MAX_TIMEOUT_MS = 600_000\n\n/**\n * How much looser the shell's bound is than the script's, so the script's bound fires first.\n *\n * This is not extra budget for the script, since `maxJsTimeoutMs` still cuts it off at the requested\n * value. It is the margin that decides which of the two bounds reports, and therefore whether `stderr`\n * carries the message naming the limit. See {@link runExec} for the measured table.\n */\nconst SHELL_TIMEOUT_GRACE_MS = 2_000\n\n/**\n * The `atob` shim, installed through just-bash's `javascript.bootstrap` before any guest module loads.\n *\n * QuickJS ships no base64 builtins and `node-html-parser` decodes a base64 entity table at load time,\n * so without this the parser throws \"'atob' is not defined\" at import and every script fails before\n * its first selector. Probed all three placements 2026-08-09: `bootstrap` works, prepending the shim\n * to the parser's own bytes works, and omitting it fails at `decodeBase64`. `bootstrap` is chosen\n * because it leaves the vendored parser byte-identical to the published artifact. A shim spliced into\n * the bundle would make the seeded file something no `pnpm` install reproduces.\n *\n * Base64 only, no `btoa`. The parser decodes and never encodes, and a shim for a capability nothing\n * uses is a capability added to the guest for free.\n */\nconst ATOB_BOOTSTRAP = `globalThis.atob = globalThis.atob || function (encoded) {\n const alphabet = \"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/\"\n let decoded = \"\", bits = 0, accumulator = 0\n for (const character of String(encoded).replace(/=+$/, \"\")) {\n const value = alphabet.indexOf(character)\n if (value < 0) continue\n accumulator = (accumulator << 6) | value\n bits += 6\n if (bits >= 8) { bits -= 8; decoded += String.fromCharCode((accumulator >> bits) & 0xff) }\n }\n return decoded\n}\n`\n\n/**\n * Where the guest-side helper's source lives on the host.\n *\n * `apps/cli/guest/corpus.mjs`, read as bytes at run time and never compiled. It sits outside `src/`\n * so `tsc` does not see it. It is guest source, its imports resolve against guest paths\n * (`/workspace/lib/nhp.mjs`), and a `.ts` file under `src/` would be typechecked against the host's\n * module graph and fail on an import that only exists inside the sandbox.\n *\n * Resolved from `import.meta.url` rather than from `process.cwd()`, so `memhtml exec` works from any\n * directory. `dist/exec.js` sits one level under the package root, which is where `guest/` is.\n */\nconst guestHelperPath = (): string =>\n resolve(dirname(fileURLToPath(import.meta.url)), \"..\", \"guest\", \"corpus.mjs\")\n\n/**\n * The HTML parser's bytes, as published.\n *\n * ## No bundling step, because the published artifact already is one\n *\n * `node-html-parser@9.0.1`'s `dist/index.mjs` is emitted by `tsdown` with its two dependencies\n * (`css-select`, `entities`) inlined: **zero `import` statements, zero `require(` calls, zero `node:`\n * references, 206655 bytes**, verified against the installed file rather than inferred from the\n * package's `sideEffects` field. The file `pnpm` installs is already loadable in the guest verbatim,\n * and there is nothing to regenerate. The reproduction path is `pnpm install`, pinned by\n * `pnpm-lock.yaml`, and a reader can re-verify self-containment with one grep. A checked-in bundle\n * would be a second copy of a published artifact that nobody could tell had drifted.\n *\n * ## Why this parser\n *\n * **cheerio and linkedom cannot load in QuickJS**, measured: `Object.getOwnPropertyDescriptor(\n * Function.prototype, \"toString\").writable === false` there, so `Object.assign(fn, source)` throws\n * whenever `source` carries a `toString`, which is what cheerio does when it attaches its\n * static API to `load`. linkedom fails identically through `cssom`. That is a property of the runtime,\n * so `docs/code-mode.md`'s cheerio examples do not carry over even though every selector does.\n *\n * `createRequire` against this module rather than a static import. The parser is never loaded on the\n * host at all, only read as text, and a static `import` would put a 200 KB module on the graph of\n * every `memhtml` command to obtain a path.\n */\nconst parserSourcePath = (): string =>\n createRequire(import.meta.url)\n .resolve(\"node-html-parser\")\n .replace(/index\\.cjs$/, \"index.mjs\")\n\n/**\n * Did the runtime cut this script off, or did the script exit 124 on its own?\n *\n * Exported, and a pure function of the two observable values, because it is the one piece of\n * classification here that cannot be exercised end-to-end. `runExec` deliberately sets the shell's\n * bound looser than the script's ({@link SHELL_TIMEOUT_GRACE_MS}), so the JS bound always wins and only\n * one of the two wordings ever reaches a live report. That makes the other branch unfalsifiable\n * through the command and therefore a claim rather than a guard. As a function it is testable against\n * both strings just-bash actually produces.\n *\n * Both wordings, measured 2026-08-09 on `for(;;)` at a 400ms bound:\n *\n * - `maxJsTimeoutMs` fires: `js-exec: Execution timeout: exceeded 400ms limit`\n * - `maxExecutionTimeMs` fires: `bash: js-exec exceeded its execution deadline`, with no \"timeout\" in it\n *\n * A pattern matching only `/timeout/` therefore reports `timedOut: false` on a script that was cut off,\n * which is what the first version of this did. `aborted` covers `bash: execution aborted`, which is what\n * an `AbortSignal` produces (probed). This module takes no such path today, and classifying it correctly\n * now is cheap if it ever does.\n *\n * The exit code is required as well as the wording. 124 alone is reachable from a script that exits 124\n * itself, and a caller branching on `timedOut` needs it to mean the bound fired.\n */\nexport const cutOffByTheRuntime = (exitCode: number, stderr: string): boolean =>\n exitCode === 124 && /timeout|deadline|aborted/i.test(stderr)\n\n/**\n * The two phrases just-bash's sandbox bridge speaks when it fails to answer a guest's filesystem call.\n *\n * ## Why this classification exists\n *\n * A guest `fs` call is a synchronous round trip over a `SharedArrayBuffer`: the QuickJS thread parks in\n * `Atomics.wait` while the host thread services the operation and writes a status back. When that\n * handshake does not complete, `SyncBackend.execSync` throws a message of its OWN making rather than the\n * host's — verbatim from `just-bash@3.2.0`'s bundle, byte-identical in 3.3.0:\n *\n * - `Error code: <n>` — the wait returned with a status that is not `SUCCESS` and no error was recorded.\n * - `Operation timed out` — the wait expired without the host answering at all.\n *\n * Neither is a fact about the corpus or the script. Both reach `stderr` as a thrown guest error, which\n * without this check is reported as the SCRIPT's non-zero exit — telling an agent its selector is wrong\n * when the sandbox merely failed to hand back a `stat`. Observed once on a 4-vCPU CI runner (2026-08-14,\n * `memhtml/memhtml` run 31830358200) on a walk of ~900 entries: `at isDirectory\n * (/workspace/lib/corpus.mjs:45:28): Error code: 0`, on a commit whose tree was byte-identical to one\n * that had passed minutes earlier. The bridge kept working afterwards — the guest's own `stderr` write\n * and exit both landed — so the fault is one operation, not a torn-down sandbox, which is what makes\n * re-running the script the right answer.\n *\n * A cut-off script is deliberately NOT a fault here: {@link cutOffByTheRuntime}'s wordings arrive with\n * exit 124 and name a limit, and treating them as a bridge fault would re-run a runaway script until it\n * had burned every attempt's full bound.\n *\n * Returns the phrase it matched, so a caller logs the evidence rather than a boolean.\n */\nexport const bridgeFault = (exitCode: number, stderr: string): string | null => {\n if (exitCode === 0) return null\n const matched = /(?:^|:\\s)(Error code: \\d+|Operation timed out)\\s*$/m.exec(stderr)\n return matched?.[1] ?? null\n}\n\n/**\n * How many times one script is run before a bridge fault is called the runtime's failure.\n *\n * Three, and the retry is sound rather than hopeful: the corpus is mounted read-only, the sandbox has no\n * network client, and every attempt reads the same pinned tree, so a script cannot have committed a\n * partial effect that a second run would double. Nothing about the guest survives an attempt either —\n * each one builds a fresh `Bash`, and therefore a fresh shared buffer and bridge.\n */\nexport const BRIDGE_ATTEMPTS = 3\n\n/**\n * Run one attempt at a time until a report is the script's own answer, or fail as the runtime.\n *\n * Exported and parameterized by `attempt` because that is the only shape this loop can be tested in: a\n * bridge fault is a rare race — 72 executions under 3x CPU oversubscription did not produce one\n * (measured 2026-08-14) — so a test driving the real sandbox could not distinguish a working retry from\n * a fault that never fired. The injected attempt makes the loop's three claims falsifiable: a faulting\n * attempt is re-run, a script's own failure is NOT, and exhaustion is a typed failure.\n *\n * Exhaustion becomes a `StorageFailure`, so it leaves through the error channel as exit 1 and\n * `ERR_STORAGE` rather than as an `exec.report` carrying the guest's confusing diagnostic. That is the\n * split this module already draws: a script's failure is a successful envelope, the runtime's own is not.\n */\nexport const withBridgeRetry = <E>(\n attempt: (attemptIndex: number) => Effect.Effect<ExecReport, E>,\n attempts: number = BRIDGE_ATTEMPTS\n): Effect.Effect<ExecReport, E | StorageFailure> =>\n Effect.gen(function* () {\n let fault = \"no attempt ran\"\n for (let attemptIndex = 1; attemptIndex <= attempts; attemptIndex++) {\n const report = yield* attempt(attemptIndex)\n const faulted = bridgeFault(report.exitCode, report.stderr)\n if (faulted === null) return report\n fault = faulted\n yield* Effect.logWarning(\n `exec.bridge: the sandbox did not answer a guest call (\"${faulted}\") on attempt ${attemptIndex} of ${attempts}; re-running the same script against the same tree`\n )\n }\n return yield* Effect.fail(\n StorageFailure.make({\n operation: `exec.bridge: the sandbox failed to answer a guest filesystem call ${attempts} times (\"${fault}\"), so no report is the script's own answer`\n })\n )\n })\n\n/** What a script produced. `stdout` is the script's own bytes, uninterpreted. */\nexport interface ExecReport {\n /** The guest path the corpus was mounted at, so a script's paths are explainable from the report. */\n readonly corpusMount: string\n /** The commit the mounted tree holds, or `null` when a directory was mounted directly. */\n readonly sha: string | null\n /** The script's exit code. Non-zero is reported rather than raised. See {@link runExec}. */\n readonly exitCode: number\n readonly stdout: string\n readonly stderr: string\n /** Wall-clock milliseconds for the guest execution alone, excluding mount and seeding. */\n readonly durationMs: number\n /** The bound that was in force. Present so a timeout is self-explaining from the envelope. */\n readonly timeoutMs: number\n /** True when the guest hit {@link timeoutMs}. just-bash reports exit 124 and says so on stderr. */\n readonly timedOut: boolean\n}\n\n/** Everything `memhtml exec` needs. `script` is source, already read; this module opens no script file. */\nexport interface ExecInput {\n /** The script's source, as the guest will see it. */\n readonly script: string\n /** An existing host directory holding the corpus. Mounted read-only at {@link CORPUS_MOUNT}. */\n readonly corpusPath: string\n /** Recorded into the report; `null` when the caller mounted a plain directory. */\n readonly sha?: string | null\n readonly timeoutMs?: number | undefined\n}\n\n/**\n * Run one script against a read-only corpus, and report what it printed.\n *\n * ## A non-zero exit is reported rather than raised\n *\n * A script that throws, or that exits 1 deliberately, comes back as a successful envelope carrying\n * `exitCode` and `stderr`. Mapping a guest exit onto the CLI's own exit 1 instead would\n * make `memhtml exec` unable to distinguish \"your script failed\" from \"the runtime could not run it\", and\n * an agent debugging a selector would get an error envelope with the script's real diagnostic buried\n * in an `error` string. The runtime's own failures (an absent corpus, an unreadable helper) do travel\n * the error channel and become exit 1.\n *\n * A sandbox that fails to answer a guest filesystem call is the RUNTIME failing, even though the guest\n * surfaces it as a thrown script error. {@link bridgeFault} names the two phrases that say so, and the\n * script is re-run against the same tree up to {@link BRIDGE_ATTEMPTS} times; only exhaustion becomes a\n * failure, and it becomes the runtime's. `durationMs` is therefore the attempt that answered.\n *\n * ## The sandbox has no network client, and that is this function's choice\n *\n * `new Bash()` is constructed with no `network` and no `fetch` option, so just-bash never registers its\n * network commands at all. Per `Bash.d.ts:80`: \"Network commands (curl, wget) are registered when either\n * `fetch` or `network` is provided.\" Probed 2026-08-09 (`scripts/probe-sandbox-egress.mjs`): `curl` is\n * exit 127 \"command not found\", and the guest's `fetch` refuses on call with \"Network access not\n * configured.\" `fetch` is a function there, so a `typeof` check on the global proves nothing. Eve\n * passes `dangerouslyAllowFullInternetAccess`, so the consolidator's sandbox does reach the network.\n * Whoever calls `new Bash()` decides egress, so it is decided here, for this runtime, by omission.\n *\n * ## Two opt-ins, one taken\n *\n * `javascript` is on because `js-exec` is the feature. `python` is off, and so is `network`. Both\n * are off by default in just-bash. That default is preserved as an explicit decision\n * rather than inherited silently, because a future edit adding `python: true` for one recipe would\n * hand every script a second language runtime.\n */\nexport const runExec = (\n input: ExecInput\n): Effect.Effect<ExecReport, InvalidMemory | StorageFailure> =>\n Effect.gen(function* () {\n const timeoutMs = input.timeoutMs ?? DEFAULT_TIMEOUT_MS\n\n /**\n * `just-bash` and the mount helper arrive by dynamic import, and the reason is measured.\n *\n * `just-bash`'s bundle is ~6 MB across 20 chunks and costs ~160ms to load. `@memhtml/consolidator`'s\n * barrel re-exports `mount.js`, which imports it statically, and `apps/cli/src/api-layer.ts`\n * imports that barrel, so today `just-bash` is already on the graph of every `memhtml read`\n * (20 chunks loaded, traced with `module.registerHooks`). Importing it here as well would add a\n * second static edge that survives any future fix to that one. This form keeps the exec path's own\n * cost on the exec path, which is the standing rule for the eve closure (`api-layer.ts`, where\n * `eve/client` is dynamic for the same reason).\n */\n const { Bash } = yield* Effect.tryPromise({\n try: () => import(\"just-bash\"),\n catch: (cause) => StorageFailure.make({ operation: `exec.sandbox-load: ${String(cause)}` })\n })\n const { mountReadOnlyRoots } = yield* Effect.tryPromise({\n try: () => import(\"@memhtml/consolidator\"),\n catch: (cause) => StorageFailure.make({ operation: `exec.mount-load: ${String(cause)}` })\n })\n\n const helperSource = yield* Effect.tryPromise({\n try: () => readFile(guestHelperPath(), \"utf8\"),\n catch: (cause) => StorageFailure.make({ operation: `exec.guest-helper: ${String(cause)}` })\n })\n const parserSource = yield* Effect.tryPromise({\n try: () => readFile(parserSourcePath(), \"utf8\"),\n catch: (cause) => StorageFailure.make({ operation: `exec.guest-parser: ${String(cause)}` })\n })\n\n /**\n * One attempt: a fresh mount, a fresh sandbox, one execution.\n *\n * Everything the guest touches is built here rather than above, so a retry\n * ({@link withBridgeRetry}) starts from a new shared buffer and a new bridge instead of re-running\n * against the one that just failed to answer. Only the two sources read off the host — the parser\n * and the helper — are hoisted, because they are the same bytes on every attempt.\n */\n const attempt = (): Effect.Effect<ExecReport, InvalidMemory | StorageFailure> =>\n Effect.gen(function* () {\n /**\n * The one composition, from `apps/consolidator/src/mount.ts`.\n *\n * Not re-derived here. That module encodes the `mountPoint: \"/\"` requirement on the nested\n * `OverlayFs`, which a file count cannot catch, because all three spellings expose the same\n * number of files at three different prefixes. It also validates roots eagerly, so a bad\n * `corpusPath` is refused before a sandbox exists.\n */\n const { filesystem } = yield* Effect.try({\n try: () =>\n mountReadOnlyRoots({\n roots: [{ mountPath: CORPUS_MOUNT, hostPath: input.corpusPath }]\n }),\n catch: (cause) =>\n InvalidMemory.make({ reason: `exec cannot mount the corpus: ${String(cause)}` })\n })\n\n /**\n * Two bounds, and the shell's is deliberately the looser one.\n *\n * `maxJsTimeoutMs` bounds the `js-exec` call and `maxExecutionTimeMs` bounds the whole shell\n * invocation, so both are needed. A script cannot outlive its budget by spending the time\n * outside the JS worker. Which one fires first changes the diagnostic, probed 2026-08-09 on a\n * `for(;;)` loop at a 400ms bound:\n *\n * | limits | exit | stderr |\n * | --- | --- | --- |\n * | `maxJsTimeoutMs` alone | 124 | `js-exec: Execution timeout: exceeded 400ms limit` |\n * | both equal | 124 | `bash: js-exec exceeded its execution deadline` |\n * | shell bound looser | 124 | `js-exec: execution timeout exceeded` + the limit-naming line |\n *\n * Setting them equal is a race whose winner decides whether the operator is told the number\n * they set. The shell's bound gets a small margin so the JS bound wins and its message, the one\n * naming the limit, is what reaches `stderr`. The margin is a grace period rather than extra\n * budget. The script is already cut off at `timeoutMs`, and the shell's bound exists only to\n * catch the case where `js-exec` itself fails to stop.\n */\n const bash = new Bash({\n fs: filesystem,\n javascript: { bootstrap: ATOB_BOOTSTRAP },\n executionLimits: {\n maxJsTimeoutMs: timeoutMs,\n maxExecutionTimeMs: timeoutMs + SHELL_TIMEOUT_GRACE_MS\n }\n })\n\n yield* Effect.tryPromise({\n try: async () => {\n await filesystem.mkdir(GUEST_LIB, { recursive: true })\n await filesystem.writeFile(`${GUEST_LIB}/nhp.mjs`, parserSource)\n await filesystem.writeFile(`${GUEST_LIB}/corpus.mjs`, helperSource)\n // Written through the filesystem rather than passed as `bash -c` text. A script arriving as\n // a shell argument would be subject to the shell's own quoting, and an agent's traversal is\n // full of `$`, backticks, and quotes that a heredoc mangles differently than a file does.\n await filesystem.writeFile(GUEST_SCRIPT, input.script)\n },\n catch: (cause) => StorageFailure.make({ operation: `exec.seed: ${String(cause)}` })\n })\n\n const started = Date.now()\n const result = yield* Effect.tryPromise({\n try: () => bash.exec(`js-exec ${GUEST_SCRIPT}`),\n // A thrown failure from `bash.exec` is the runtime's rather than the script's. just-bash\n // reports a script's own non-zero exit through `exitCode`, and throws only when it could not\n // run at all.\n catch: (cause) => StorageFailure.make({ operation: `exec.run: ${String(cause)}` })\n })\n const durationMs = Date.now() - started\n\n const stderr = String(result.stderr ?? \"\")\n return {\n corpusMount: CORPUS_MOUNT,\n sha: input.sha ?? null,\n exitCode: result.exitCode,\n stdout: String(result.stdout ?? \"\"),\n stderr,\n durationMs,\n timeoutMs,\n timedOut: cutOffByTheRuntime(result.exitCode, stderr)\n }\n })\n\n return yield* withBridgeRetry(attempt)\n })\n\n/**\n * `--file`'s bytes, or the usage failure for an unreadable path.\n *\n * A `Failure` return rather than a raised error, for the reason `applyText` has one. An unreadable\n * input path is a usage error the caller fixes by changing the call, so it must reach exit 2, and only\n * `validate`'s return path and this pre-dispatch read produce that code.\n */\nexport const readScript = async (file: string): Promise<string | Failure> => {\n try {\n return await readFile(file, \"utf8\")\n } catch (cause) {\n return fail(\n \"ERR_PATH_NOT_FOUND\",\n `exec cannot read --file ${file}: ${cause instanceof Error ? cause.message : String(cause)}`,\n [`ls ${file}`, \"cat script.mjs | memhtml exec\"]\n )\n }\n}\n\n/**\n * The whole command: pin a commit, mount it, run the script, release the worktree.\n *\n * ## Why a pinned worktree and not `$MEMHTML_ROOT` itself\n *\n * A live `$MEMHTML_ROOT` contains `.memhtml/index.db`, and the guest ships `sqlite3`. Probed 2026-08-09\n * against a read-only `OverlayFs` over a directory holding a real database: `sqlite3\n * /mnt/memhtml/.memhtml/index.db 'select count(*) …'` returned the row, exit 0. Read-only is therefore no\n * barrier to a reader, and mounting the live root would hand every script the ranked planes this command\n * is scoped to exclude, through a door no `memhtml exec` flag opens.\n *\n * `git worktree add --detach` is what closes it. Both databases are gitignored\n * (`packages/store/src/layout.ts`, `GITIGNORE`), and a gitignored file is absent from a checkout of a\n * commit. This is verified rather than argued: the worktree probe in\n * `apps/cli/tests/exec.test.ts` asserts `.memhtml` is not present and that the guest's own `sqlite3` finds\n * nothing to open. Containment is therefore a property of what is mounted, with the read-only flag as a\n * second layer, rather than resting on a flag that a reader can read straight through.\n *\n * The pin also makes an answer reproducible. `sha` rides back in the report, so the same\n * traversal over the same tree is one `--sha` away, and an uncommitted edit is invisible. That is\n * the right behavior for a command whose whole output is a claim about a corpus state.\n *\n * Cost measured: `git worktree add --detach` on the 305-file fixture is 31ms (three runs: 31/30/31),\n * against a 640ms full-corpus parse. The pin is ~5% of the work it makes correct.\n */\nexport const execCommand = (input: {\n readonly script: string\n readonly memhtmlRoot: string\n readonly sha?: string | undefined\n readonly timeoutMs?: number | undefined\n}): Effect.Effect<ExecReport, InvalidMemory | StorageFailure | GitFailure, Scope.Scope> =>\n Effect.gen(function* () {\n const git = makeGit(input.memhtmlRoot)\n\n const requested = input.sha\n const sha =\n requested !== undefined && requested.trim() !== \"\"\n ? requested.trim()\n : yield* git.revParseHead()\n if (sha === null) {\n return yield* Effect.fail(\n InvalidMemory.make({\n reason: `${input.memhtmlRoot} has no commit to mount: exec reads a committed tree, so an unborn HEAD has nothing to traverse`\n })\n )\n }\n\n /**\n * `pinCorpusSnapshot` from the shared mount module, released through `Effect.acquireRelease`.\n *\n * A worktree is an entry in the repo's own `.git/worktrees`, so a leaked one is durable state left\n * in the operator's repository rather than a temp directory the OS reclaims. The release runs on\n * the script's failure, on a timeout, and on an interrupt, which a `finally` around the happy path\n * would not cover.\n */\n const { pinCorpusSnapshot } = yield* Effect.tryPromise({\n try: () => import(\"@memhtml/consolidator\"),\n catch: (cause) => StorageFailure.make({ operation: `exec.mount-load: ${String(cause)}` })\n })\n\n const snapshot = yield* Effect.acquireRelease(\n Effect.tryPromise({\n try: () => pinCorpusSnapshot({ repoRoot: input.memhtmlRoot, sha }),\n catch: (cause) =>\n InvalidMemory.make({\n reason: `exec cannot materialize ${sha}: ${String(cause)}`\n })\n }),\n (pinned) => Effect.promise(() => pinned.release())\n )\n\n return yield* runExec({\n script: input.script,\n corpusPath: snapshot.hostPath,\n sha,\n timeoutMs: input.timeoutMs\n })\n })\n","import { mkdir, writeFile } from \"node:fs/promises\"\nimport { dirname, join } from \"node:path\"\nimport { DatabaseService } from \"@memhtml/index\"\nimport { type GeneratedFile, generateArtifacts, publishRows } from \"@memhtml/sleep\"\nimport { attemptIo, commitSubject, readFileOrNull } from \"@memhtml/store\"\nimport { Effect } from \"effect\"\n\nimport { Git } from \"./api-layer.js\"\n\n/**\n * `memhtml publish`: regenerate the per-directory `index.html` listings and the root `sitemap.xml`, and\n * commit whatever changed.\n *\n * **The generator is imported from `@memhtml/sleep` and never re-derived.** `generateArtifacts` lives\n * there because a listing needs `files.title`/`gist`/`updated_at`, all of them index projections, and\n * `@memhtml/store` is SQL-free by design. Two generators would produce two byte sequences for one tree,\n * and these files are the design's one merge-conflict source. `.gitattributes` marks them\n * `merge=ours` and a conflict is resolved by regenerating, which only works if regeneration is\n * unambiguous. The sleep integrity phase and this command therefore call the same function, and the\n * only difference between them is which commit the result lands in.\n *\n * The output is deterministic to the byte: the rows arrive path-ordered from SQL, every string is\n * escaped, and no timestamp of generation appears anywhere. Two runs over an unchanged corpus write\n * nothing and commit nothing, which also makes the command safe to run after every merge.\n */\n\n/** What a publish did. `written: 0` means the artifacts already matched the corpus. */\nexport interface PublishReport {\n readonly root: string\n /** Artifacts the generator produced: one listing per directory plus the sitemap. */\n readonly artifacts: number\n /** Artifacts whose bytes differed from what was on disk, and were therefore rewritten. */\n readonly written: number\n readonly paths: ReadonlyArray<string>\n /** The commit, or `null` when nothing changed. */\n readonly commitSha: string | null\n}\n\n/** Write one artifact if its bytes differ. Returns true when the file was rewritten. */\nconst writeIfChanged = (root: string, artifact: GeneratedFile) =>\n Effect.gen(function* () {\n const absolute = join(root, artifact.path)\n const existing = yield* readFileOrNull(absolute)\n if (existing === artifact.html) return false\n yield* attemptIo(`publish.write:${artifact.path}`, async () => {\n await mkdir(dirname(absolute), { recursive: true })\n await writeFile(absolute, artifact.html, \"utf8\")\n })\n return true\n })\n\n/**\n * Regenerate and commit.\n *\n * The whole artifact set is staged rather than only the rewritten files, because a listing that was\n * hand-edited and then regenerated to its correct bytes is a change git already knows about. `commit`\n * no-ops on an index matching HEAD, so staging everything costs nothing when nothing moved.\n */\nexport const publish = () =>\n Effect.gen(function* () {\n const git = yield* Git\n const db = yield* DatabaseService\n const rows = yield* publishRows(db)\n const artifacts = generateArtifacts(rows)\n\n const written: Array<string> = []\n for (const artifact of artifacts) {\n if (yield* writeIfChanged(git.root, artifact)) written.push(artifact.path)\n }\n\n yield* git.add(artifacts.map((artifact) => artifact.path))\n const commit = yield* git.commit(\n commitSubject(\"publish\", `regenerate ${artifacts.length} generated artifacts`)\n )\n\n return {\n root: git.root,\n artifacts: artifacts.length,\n written: written.length,\n paths: written,\n commitSha: commit.sha\n } satisfies PublishReport\n })\n","import { mkdir, writeFile } from \"node:fs/promises\"\nimport { dirname, join } from \"node:path\"\n\nimport { DatabaseService, STATE_SCHEMA } from \"@memhtml/index\"\nimport { accessRows, parseSidecar, renderSidecar } from \"@memhtml/sleep\"\nimport { attemptIo, commitSubject, readFileOrNull, STATE_SIDECAR_PATH } from \"@memhtml/store\"\nimport { Effect } from \"effect\"\n\nimport { Git } from \"./api-layer.js\"\n\n/**\n * `memhtml state export|import`: the state plane's only durability story.\n *\n * `state.db` is gitignored and cannot be rebuilt from git. Access counts, reinforcement counts, and\n * the outcome EWMA are the one set of facts the tree cannot reproduce. `.memhtml/state/access.jsonl` is\n * the committed sidecar that survives, so a fresh clone plus `memhtml state import` plus\n * `memhtml index rebuild` reproduces the whole system rather than a system with amnesia.\n *\n * Both halves reuse `@memhtml/sleep`'s own functions, `renderSidecar` for the export and `parseSidecar`\n * for the import, because the sleep cycle's state-export phase writes this file every night and two\n * writers producing two byte sequences for one plane would churn the file on alternating nights. The\n * only difference between this command and that phase is which commit the result lands in.\n */\n\n/** What an export wrote. `written: false` means the sidecar already matched the plane. */\nexport interface StateExportReport {\n readonly path: string\n readonly rows: number\n readonly bytes: number\n readonly written: boolean\n readonly commitSha: string | null\n}\n\n/** What an import restored. */\nexport interface StateImportReport {\n readonly path: string\n /** Rows the sidecar held. */\n readonly rows: number\n /** Rows actually written into `state.access`. */\n readonly restored: number\n /** Sidecar lines that did not parse. Counted and not fatal: a partial file restores what it holds. */\n readonly skipped: number\n readonly hasState: boolean\n}\n\n/**\n * Write the sidecar and commit it.\n *\n * The output is byte-stable, so an unchanged plane commits nothing. Rows arrive path-ordered from SQL\n * and floats are rounded to the domain's four-decimal grid, so an unchanged plane produces an\n * identical file and `git commit` no-ops on an index matching HEAD. Without that, the widest-churn\n * table in the system would produce a commit every time an operator ran this.\n */\nexport const stateExport = () =>\n Effect.gen(function* () {\n const git = yield* Git\n const db = yield* DatabaseService\n const rows = yield* accessRows(db)\n const contents = renderSidecar(rows)\n const absolute = join(git.root, STATE_SIDECAR_PATH)\n\n const existing = yield* readFileOrNull(absolute).pipe(Effect.orElseSucceed(() => null))\n if (existing === contents) {\n return {\n path: STATE_SIDECAR_PATH,\n rows: rows.length,\n bytes: contents.length,\n written: false,\n commitSha: null\n } satisfies StateExportReport\n }\n\n yield* attemptIo(`state.write:${STATE_SIDECAR_PATH}`, async () => {\n await mkdir(dirname(absolute), { recursive: true })\n await writeFile(absolute, contents, \"utf8\")\n })\n yield* git.add([STATE_SIDECAR_PATH])\n const commit = yield* git.commit(\n commitSubject(\"state\", `export ${rows.length} access rows to the committed sidecar`)\n )\n\n return {\n path: STATE_SIDECAR_PATH,\n rows: rows.length,\n bytes: contents.length,\n written: true,\n commitSha: commit.sha\n } satisfies StateExportReport\n })\n\n/**\n * Replay the sidecar into `state.access`.\n *\n * An upsert per row rather than a truncate-and-load, because an import onto a live plane must not\n * discard counters the sidecar predates. The sidecar is refreshed once per night, and a retrieval an\n * hour later is real state. The upsert takes the maximum of the two counts for the reason design §9's\n * multi-machine note gives: these columns are monotone, so max-of is the merge that cannot lose a\n * bump, while last-writer-wins can.\n *\n * `parseSidecar` is defensive per line, so a file truncated by an interrupted write restores every row\n * it does hold. Rejecting the whole file would turn a partial loss into a total one.\n */\nexport const stateImport = () =>\n Effect.gen(function* () {\n const git = yield* Git\n const db = yield* DatabaseService\n const absolute = join(git.root, STATE_SIDECAR_PATH)\n const contents = yield* readFileOrNull(absolute).pipe(Effect.orElseSucceed(() => null))\n\n if (contents === null) {\n return {\n path: STATE_SIDECAR_PATH,\n rows: 0,\n restored: 0,\n skipped: 0,\n hasState: db.hasState\n } satisfies StateImportReport\n }\n\n const { entries, skipped } = parseSidecar(contents)\n if (!db.hasState || entries.length === 0) {\n return {\n path: STATE_SIDECAR_PATH,\n rows: entries.length,\n restored: 0,\n skipped,\n hasState: db.hasState\n } satisfies StateImportReport\n }\n\n yield* db.writeAll(\n entries.map((entry) => ({\n sql: `INSERT INTO ${STATE_SCHEMA}.access\n (path, access_count, reinforcement_count, outcome_score,\n last_accessed_at, last_reinforced_at, updated_at)\n VALUES (?, ?, ?, ?, ?, ?, ?)\n ON CONFLICT(path) DO UPDATE SET\n access_count = max(access_count, excluded.access_count),\n reinforcement_count = max(reinforcement_count, excluded.reinforcement_count),\n outcome_score = excluded.outcome_score,\n last_accessed_at = max(coalesce(last_accessed_at, ''), coalesce(excluded.last_accessed_at, '')),\n last_reinforced_at = max(coalesce(last_reinforced_at, ''), coalesce(excluded.last_reinforced_at, '')),\n updated_at = excluded.updated_at`,\n params: [\n entry.path,\n entry.accessCount,\n entry.reinforcementCount,\n entry.outcomeScore,\n entry.lastAccessedAt,\n entry.lastReinforcedAt,\n entry.updatedAt\n ]\n }))\n )\n\n return {\n path: STATE_SIDECAR_PATH,\n rows: entries.length,\n restored: entries.length,\n skipped,\n hasState: true\n } satisfies StateImportReport\n })\n","import { InvalidMemory } from \"@memhtml/contracts/errors\"\nimport { DatabaseService, type DatabaseShape, readIndexState } from \"@memhtml/index\"\nimport { EMBED_WATERMARK } from \"@memhtml/llm\"\nimport { isSleepPhase, type RunReport, SLEEP_PHASES, type SleepPhase } from \"@memhtml/sleep\"\nimport { Effect } from \"effect\"\n\n/**\n * Response shaping: the few places a payload is not simply the use case's own return value.\n *\n * Kept out of the dispatcher so an arm stays one call. Each function here exists because a wire\n * shape and an internal shape differ. One is a report that must not carry an unbounded field. The\n * other is a flag list that must be validated against a closed vocabulary before it reaches a runner.\n */\n\n/**\n * The index's own report of itself: the watermark, the vector space, and the row counts.\n *\n * `memhtml index status` reads this rather than running an indexer method, because \"what does the index\n * currently contain\" must be answerable without the git subprocess an `update` would spawn. An\n * operator asking about a stale index is frequently asking because something is wrong with the repo.\n */\nexport const indexReport = () =>\n Effect.gen(function* () {\n const db = yield* DatabaseService\n const state = yield* readIndexState(db).pipe(Effect.orElseSucceed(() => undefined))\n\n return {\n mode: \"status\",\n headSha: state?.head_sha ?? null,\n embedModel: state?.embed_model ?? null,\n embedDim: state?.embed_dim ?? null,\n /**\n * True when the stored vector space IS the configured one. On a mismatch the indexer stops\n * instead of writing, so reporting the two values separately lets an operator see which side\n * to change.\n */\n embedModelMatches: state?.embed_model === EMBED_WATERMARK,\n configuredEmbedModel: EMBED_WATERMARK,\n rebuiltAt: state?.rebuilt_at ?? null,\n updatedAt: state?.updated_at ?? null,\n files: yield* count(db, \"SELECT count(*) AS n FROM files\"),\n activeFiles: yield* count(db, \"SELECT count(*) AS n FROM files WHERE archived = 0\"),\n chunks: yield* count(db, \"SELECT count(*) AS n FROM chunks\"),\n embeddings: yield* count(db, \"SELECT count(*) AS n FROM embeddings\"),\n edges: yield* count(db, \"SELECT count(*) AS n FROM edges\"),\n derivedEdges: yield* count(db, \"SELECT count(*) AS n FROM edges WHERE derived = 1\"),\n tags: yield* count(db, \"SELECT count(DISTINCT tag) AS n FROM file_tags\"),\n entities: yield* count(\n db,\n \"SELECT count(DISTINCT entity_type || ':' || entity_name) AS n FROM file_entities\"\n ),\n traces: yield* count(db, \"SELECT count(*) AS n FROM traces\"),\n hasState: db.hasState\n }\n })\n\nconst count = (db: DatabaseShape, sql: string) =>\n db.get<{ n: number }>(sql).pipe(\n Effect.map((row) => row?.n ?? 0),\n Effect.orElseSucceed(() => 0)\n )\n\n/**\n * A `--phases` value as a validated phase list, or `undefined` for \"all fifteen\".\n *\n * An unknown phase is rejected instead of dropped silently. A run asked for `--phases dedup,compress`\n * with a typo in the first name would otherwise execute only the second. `dedup-merge` is a hard\n * prerequisite of `compress`, so the typo would produce a compress pass over a corpus that still\n * holds its duplicates.\n */\nexport const sleepPhases = (\n raw: string | undefined\n): Effect.Effect<ReadonlyArray<SleepPhase> | undefined, InvalidMemory> => {\n if (raw === undefined || raw.trim() === \"\") return Effect.succeed(undefined)\n const names = raw\n .split(\",\")\n .map((name) => name.trim())\n .filter((name) => name !== \"\")\n\n const unknown = names.filter((name) => !isSleepPhase(name))\n if (unknown.length > 0) {\n return Effect.fail(\n InvalidMemory.make({\n reason: `unknown sleep phase: ${unknown.join(\", \")}. One of: ${SLEEP_PHASES.join(\", \")}`\n })\n )\n }\n\n // Canonical order, not the caller's. The order encodes real dependencies: decay runs before triage\n // so triage scores the decayed value. Honoring a caller's ordering would let a `--phases` value\n // silently invert them.\n return Effect.succeed(SLEEP_PHASES.filter((phase) => names.includes(phase)))\n}\n\n/**\n * A run report on the wire.\n *\n * Identical to the internal shape except for `llmCalls`, which is summed per phase and totalled. A\n * caller auditing Bedrock spend reads the total, and one debugging a phase reads the per-phase\n * number. Deriving either from the other at the call site is how two consumers end up disagreeing\n * about what a number counts.\n */\nexport const sleepRunReport = (report: RunReport) => ({\n runId: report.runId,\n branch: report.branch,\n baseSha: report.baseSha,\n headSha: report.headSha,\n dryRun: report.dryRun,\n llmCalls: report.llmCalls,\n phases: report.phases,\n /** Phases that ended `failed`. Present so a caller does not have to filter to know. */\n failedPhases: report.phases.flatMap((phase) => (phase.status === \"failed\" ? [phase.phase] : [])),\n commits: report.phases.flatMap((phase) => (phase.commitSha === null ? [] : [phase.commitSha]))\n})\n","import { discriminationGate, type EvalMode, runDiscrimination } from \"@memhtml/eval\"\nimport { initRepo } from \"@memhtml/store\"\nimport { Effect, type Layer, Logger } from \"effect\"\nimport { runAgentsDoc } from \"./agents-doc.js\"\nimport { Git, Indexer, layerApp, Sleep } from \"./api-layer.js\"\nimport { applyPayload, applyText, decodeApply, readStdin } from \"./apply.js\"\nimport { buildManifest, COMMAND_NAMES, COMMANDS, GLOBAL_FLAGS } from \"./commands.js\"\nimport { MemhtmlRoot } from \"./config.js\"\nimport { doctor } from \"./doctor.js\"\nimport {\n API_VERSION,\n EXIT_OK,\n EXIT_RUNTIME,\n EXIT_USAGE,\n type Failure,\n fail,\n nearest,\n render,\n type Success,\n succeed\n} from \"./envelope.js\"\nimport { failureFor } from \"./errors.js\"\nimport { DEFAULT_TIMEOUT_MS, execCommand, MAX_TIMEOUT_MS, readScript } from \"./exec.js\"\nimport * as ops from \"./operations.js\"\nimport { publish } from \"./publish.js\"\nimport { serveMcp } from \"./serve.js\"\nimport { stateExport, stateImport } from \"./state.js\"\nimport { indexReport, sleepPhases, sleepRunReport } from \"./views.js\"\n\nexport interface Parsed {\n readonly command: string\n readonly positional: ReadonlyArray<string>\n readonly flags: ReadonlyMap<string, ReadonlyArray<string | boolean>>\n}\n\nconst KNOWN_FLAGS = new Set([\n ...GLOBAL_FLAGS.map((flag) => flag.name),\n ...COMMANDS.flatMap((command) => command.flags.map((flag) => flag.name))\n])\n\n/**\n * The two-word command names, longest first.\n *\n * A subcommand is matched greedily so `index status` beats `index`, and the leftover tokens become\n * positionals. Matching the shorter name first would make `memhtml index status` a call to a\n * hypothetical `index` command with `status` as an argument, which is a wrong answer rather than an\n * error.\n */\nconst COMPOUND_NAMES = COMMAND_NAMES.filter((name) => name.includes(\" \")).sort(\n (left, right) => right.length - left.length\n)\n\n/**\n * `--flag value`, `--flag=value`, `--no-flag`, and bare `--flag`.\n *\n * Every flag's value is an array, because several flags are repeatable (`--tag`, `--entity`,\n * `--body`) and a map of scalars would silently keep only the last occurrence, so a write with three\n * entities would store one. Non-repeatable flags read `.at(-1)`, so a duplicate is last-wins rather\n * than an error, which is what a shell user retyping a flag expects.\n */\nexport const parseArgv = (argv: ReadonlyArray<string>): Parsed => {\n const positional: Array<string> = []\n const flags = new Map<string, Array<string | boolean>>()\n\n const push = (name: string, value: string | boolean): void => {\n const existing = flags.get(name)\n if (existing === undefined) flags.set(name, [value])\n else existing.push(value)\n }\n\n let index = 0\n while (index < argv.length) {\n const token = argv[index] as string\n if (token.startsWith(\"--\")) {\n const body = token.slice(2)\n const eq = body.indexOf(\"=\")\n if (eq !== -1) {\n push(body.slice(0, eq), body.slice(eq + 1))\n index += 1\n continue\n }\n // `--no-embed` is how a boolean defaulting to true is turned off. Without it, a flag whose\n // default is `true` would be unsettable from a shell.\n if (body.startsWith(\"no-\") && KNOWN_FLAGS.has(body.slice(3))) {\n push(body.slice(3), false)\n index += 1\n continue\n }\n const next = argv[index + 1]\n if (next !== undefined && !next.startsWith(\"--\")) {\n push(body, next)\n index += 2\n continue\n }\n push(body, true)\n index += 1\n continue\n }\n positional.push(token)\n index += 1\n }\n\n const joined = positional.join(\" \")\n const compound = COMPOUND_NAMES.find((name) => joined === name || joined.startsWith(`${name} `))\n if (compound !== undefined) {\n const consumed = compound.split(\" \").length\n return { command: compound, positional: positional.slice(consumed), flags }\n }\n\n return { command: positional[0] ?? \"\", positional: positional.slice(1), flags }\n}\n\n/** A flag's last value as a string, or `undefined` when it was not given. */\nconst str = (parsed: Parsed, name: string): string | undefined => {\n const value = parsed.flags.get(name)?.at(-1)\n return value === undefined || typeof value === \"boolean\" ? undefined : value\n}\n\n/** Every value a repeatable flag was given, in order. Empty when absent. */\nconst list = (parsed: Parsed, name: string): ReadonlyArray<string> =>\n (parsed.flags.get(name) ?? []).flatMap((value) =>\n typeof value === \"string\" && value !== \"\" ? [value] : []\n )\n\n/** A flag as a boolean: bare `--flag` is true, `--no-flag` is false, `--flag=false` is false. */\nconst bool = (parsed: Parsed, name: string, fallback: boolean): boolean => {\n const value = parsed.flags.get(name)?.at(-1)\n if (value === undefined) return fallback\n if (typeof value === \"boolean\") return value\n return value !== \"false\" && value !== \"0\" && value !== \"no\"\n}\n\n/** A flag as an integer, or `undefined` when absent or unparseable. */\nconst int = (parsed: Parsed, name: string): number | undefined => {\n const raw = str(parsed, name)\n if (raw === undefined) return undefined\n const value = Number.parseInt(raw, 10)\n return Number.isFinite(value) ? value : undefined\n}\n\n/** A flag as a finite number in a range, or `undefined`. */\nconst num = (parsed: Parsed, name: string): number | undefined => {\n const raw = str(parsed, name)\n if (raw === undefined) return undefined\n const value = Number.parseFloat(raw)\n return Number.isFinite(value) ? value : undefined\n}\n\n/** The scope every retrieval command shares, so `search` and `recall` cannot diverge. */\nconst scopeOf = (parsed: Parsed) => ({\n memoryTypes: list(parsed, \"type\") as ReadonlyArray<never>,\n workspace: str(parsed, \"workspace\"),\n tags: list(parsed, \"tag\"),\n entity: str(parsed, \"entity\"),\n includeArchived: bool(parsed, \"include-archived\", false),\n asOf: str(parsed, \"as-of\")\n})\n\n/** Session provenance, from the three flags every write-path command accepts. */\nconst provenanceOf = (parsed: Parsed) => ({\n sessionId: str(parsed, \"session-id\"),\n promptId: str(parsed, \"prompt-id\"),\n turnUuid: str(parsed, \"turn-uuid\")\n})\n\nexport interface RunResult {\n readonly stdout: string\n readonly exitCode: number\n}\n\n/** What a handler returns: a response type and its payload. The envelope is added once, below. */\ntype Handled = readonly [Success<unknown>[\"type\"], unknown]\n\n/**\n * Dispatch one parsed invocation against the provided services.\n *\n * Every arm is decode → call → name the response type. No arm builds an envelope, catches an error,\n * or writes to a stream. Those happen once in {@link run}, which keeps thirty-one commands\n * from having thirty-one slightly different failure shapes.\n *\n * `applyOps` is the one piece of state an arm cannot derive from `parsed`. Reading a file or draining\n * stdin is async I/O whose failures are usage errors (exit 2), and `run` has already done it and\n * refused before reaching here. It is passed in rather than read here, so the `apply` arm stays what\n * every other arm is: one call to a shared use case.\n */\nconst dispatch = (\n parsed: Parsed,\n applyOps: ReadonlyArray<ops.WriteParams> = []\n): Effect.Effect<Handled, unknown, DispatchServices> => {\n switch (parsed.command) {\n case \"manifest\":\n return Effect.succeed([\"cli.manifest\", buildManifest()])\n\n case \"init\":\n return Effect.gen(function* () {\n const git = yield* Git\n const result = yield* initRepo(git)\n return [\"repo.init\", result] as const\n })\n\n case \"write\":\n return Effect.gen(function* () {\n const result = yield* ops.writeMemory({\n title: str(parsed, \"title\") ?? \"\",\n // `claim` is \"\" exactly when `--article-html` supplied the article instead, which\n // `validate` has already proven is the only way to get here without a claim. The\n // template ignores `claim` entirely on that branch (`@memhtml/html` template.ts:88-91).\n claim: str(parsed, \"claim\") ?? \"\",\n body: list(parsed, \"body\"),\n articleHtml: str(parsed, \"article-html\"),\n memoryType: str(parsed, \"type\") ?? \"\",\n path: str(parsed, \"path\"),\n workspace: str(parsed, \"workspace\"),\n tags: list(parsed, \"tag\"),\n entities: list(parsed, \"entity\"),\n importance: int(parsed, \"importance\"),\n confidence: num(parsed, \"confidence\"),\n ...provenanceOf(parsed)\n })\n return [\"memory.written\", result] as const\n })\n\n /**\n * The batch door. One call to the shared `batchWrite`, and the per-op `code`/`error` it returns\n * are not re-mapped here. The operation already ran them through the same `codeFor`/`messageFor`\n * every envelope error takes, so this door and `memory_write_batch` cannot report\n * different codes for one refused op.\n */\n case \"apply\":\n return Effect.gen(function* () {\n const result = yield* ops.batchWrite({\n ops: applyOps,\n continueOnError: bool(parsed, \"continue-on-error\", false),\n detectConflicts: bool(parsed, \"detect-conflicts\", false),\n // `validate` has already refused any value outside the flag's closed vocabulary, so the\n // narrowing here cannot silently drop a caller's ask.\n ...(str(parsed, \"consolidate\") === \"last-wins\"\n ? { consolidate: \"last-wins\" as const }\n : {}),\n ...provenanceOf(parsed)\n })\n return [\"batch.applied\", applyPayload(result)] as const\n })\n\n case \"read\":\n return Effect.gen(function* () {\n const result = yield* ops.readMemory(parsed.positional[0] ?? \"\", provenanceOf(parsed))\n return [\n \"memory.detail\",\n {\n path: result.path,\n title: result.doc.title,\n metas: result.doc.metas,\n entities: result.doc.entities,\n tags: result.doc.tags,\n links: result.doc.links,\n gist: result.doc.article.gist,\n body: result.doc.article.bodyText,\n html: result.doc.article.html,\n archived: result.doc.metas.status === \"archived\",\n warnings: result.doc.warnings\n }\n ] as const\n })\n\n case \"search\":\n return Effect.gen(function* () {\n const result = yield* ops.searchMemories({\n query: parsed.positional[0] ?? \"\",\n limit: int(parsed, \"limit\"),\n ...scopeOf(parsed)\n })\n return [\"memory.hits\", result] as const\n })\n\n case \"recall\":\n return Effect.gen(function* () {\n const pack = yield* ops.recallMemories({\n query: parsed.positional[0] ?? \"\",\n budgetChars: int(parsed, \"budget\"),\n ...scopeOf(parsed)\n })\n return [\"recall.pack\", pack] as const\n })\n\n case \"correct\":\n return Effect.gen(function* () {\n const result = yield* ops.correctMemory({\n targetPath: parsed.positional[0] ?? \"\",\n title: str(parsed, \"title\") ?? \"\",\n claim: str(parsed, \"claim\") ?? \"\",\n body: list(parsed, \"body\"),\n articleHtml: str(parsed, \"article-html\"),\n memoryType: str(parsed, \"type\"),\n reason: str(parsed, \"reason\"),\n ...provenanceOf(parsed)\n })\n return [\"memory.corrected\", result] as const\n })\n\n case \"link\":\n return Effect.gen(function* () {\n const result = yield* ops.linkMemories(\n parsed.positional[0] ?? \"\",\n parsed.positional[1] ?? \"\",\n parsed.positional[2] ?? \"\"\n )\n return [\"memory.linked\", result] as const\n })\n\n case \"neighbors\":\n return Effect.gen(function* () {\n const result = yield* ops.neighborsOf({\n path: parsed.positional[0] ?? \"\",\n depth: int(parsed, \"depth\"),\n rels: list(parsed, \"rel\")\n })\n return [\"memory.neighbors\", result] as const\n })\n\n case \"archive\":\n return Effect.gen(function* () {\n const result = yield* ops.archiveMemory(\n parsed.positional[0] ?? \"\",\n str(parsed, \"reason\") ?? \"\"\n )\n return [\"memory.archived\", result] as const\n })\n\n case \"reinforce\":\n return Effect.gen(function* () {\n // Every positional is a path: `memhtml reinforce a.html b.html --signal positive` is the shape\n // an agent reaching for the MCP tool's `paths` array writes on a command line.\n const result = yield* ops.reinforceMemories(\n parsed.positional,\n str(parsed, \"signal\") ?? \"neutral\"\n )\n return [\"memory.reinforced\", result] as const\n })\n\n case \"list\":\n return Effect.gen(function* () {\n const result = yield* ops.listMemories({\n memoryType: str(parsed, \"type\"),\n workspace: str(parsed, \"workspace\"),\n tag: str(parsed, \"tag\"),\n entity: str(parsed, \"entity\"),\n para: str(parsed, \"para\"),\n limit: int(parsed, \"limit\"),\n cursor: str(parsed, \"cursor\"),\n includeArchived: bool(parsed, \"include-archived\", false)\n })\n return [\"memory.list\", result] as const\n })\n\n case \"task add\":\n return Effect.gen(function* () {\n const title = str(parsed, \"title\") ?? \"\"\n const result = yield* ops.writeMemory({\n title,\n // The claim defaults to the title, because a task's statement and its name are usually the\n // same sentence, and a required second phrasing would be restated verbatim every time.\n claim: str(parsed, \"claim\") ?? title,\n body: list(parsed, \"body\"),\n memoryType: \"task\",\n workspace: str(parsed, \"workspace\"),\n tags: list(parsed, \"tag\"),\n entities: list(parsed, \"entity\"),\n taskStatus: str(parsed, \"status\"),\n dueAt: str(parsed, \"due\"),\n ...provenanceOf(parsed)\n })\n return [\n \"task.written\",\n {\n path: result.path,\n created: result.created,\n deduped: result.deduped,\n // Two open tasks with identical bodies are two real work items, so the dedup carve-out\n // means this is normally false. It is reported anyway, because a caller cannot tell a\n // fresh file from a returned one without it.\n existingPath: result.existingPath ?? null,\n taskStatus: str(parsed, \"status\") ?? \"todo\",\n dueAt: str(parsed, \"due\") ?? null,\n commitSha: result.commitSha\n }\n ] as const\n })\n\n case \"task status\":\n return Effect.gen(function* () {\n const result = yield* ops.setTaskStatus({\n path: parsed.positional[0] ?? \"\",\n status: parsed.positional[1] ?? \"\",\n reason: str(parsed, \"reason\")\n })\n return [\"task.updated\", { ...result, archivePath: result.archivePath ?? null }] as const\n })\n\n case \"task list\":\n return Effect.gen(function* () {\n const result = yield* ops.listTasks({\n status: str(parsed, \"status\"),\n workspace: str(parsed, \"workspace\"),\n dueBefore: str(parsed, \"due-before\"),\n limit: int(parsed, \"limit\"),\n cursor: str(parsed, \"cursor\"),\n includeArchived: bool(parsed, \"include-archived\", false)\n })\n return [\"task.list\", result] as const\n })\n\n case \"index rebuild\":\n return Effect.gen(function* () {\n const indexer = yield* Indexer\n const report = yield* indexer.rebuild({ embed: bool(parsed, \"embed\", true) })\n return [\"index.report\", { mode: \"rebuild\", ...report }] as const\n })\n\n case \"index update\":\n return Effect.gen(function* () {\n const indexer = yield* Indexer\n const report = yield* indexer.update({ embed: bool(parsed, \"embed\", true) })\n return [\"index.report\", { mode: \"update\", ...report }] as const\n })\n\n case \"index status\":\n return Effect.gen(function* () {\n const report = yield* indexReport()\n return [\"index.report\", report] as const\n })\n\n case \"trace index\":\n return Effect.gen(function* () {\n const report = yield* ops.indexTraces()\n return [\"trace.report\", report] as const\n })\n\n case \"trace search\":\n return Effect.gen(function* () {\n const result = yield* ops.searchTraces({\n query: parsed.positional[0] ?? \"\",\n cwd: str(parsed, \"cwd\"),\n since: str(parsed, \"since\"),\n limit: int(parsed, \"limit\")\n })\n return [\"trace.sessions\", result] as const\n })\n\n case \"trace links\":\n return Effect.gen(function* () {\n const result = yield* ops.traceLinks({\n sessionId: str(parsed, \"session-id\"),\n path: str(parsed, \"path\")\n })\n return [\"trace.links\", result] as const\n })\n\n case \"sleep run\":\n return Effect.gen(function* () {\n const sleep = yield* Sleep\n const phases = yield* sleepPhases(str(parsed, \"phases\"))\n const report = yield* sleep.run({\n date: str(parsed, \"date\") ?? (yield* today),\n ...(phases === undefined ? {} : { phases }),\n dryRun: bool(parsed, \"dry-run\", false)\n })\n return [\"sleep.report\", sleepRunReport(report)] as const\n })\n\n case \"sleep resume\":\n return Effect.gen(function* () {\n const sleep = yield* Sleep\n const report = yield* sleep.resume(parsed.positional[0] ?? \"\")\n return [\"sleep.report\", sleepRunReport(report)] as const\n })\n\n case \"sleep review\":\n return Effect.gen(function* () {\n const sleep = yield* Sleep\n const report = yield* sleep.review(parsed.positional[0])\n const withDiff = bool(parsed, \"diff\", false)\n if (!withDiff) return [\"sleep.review\", report] as const\n // The raw diff is fetched here rather than inside `review`, because it is the one field whose\n // size is unbounded, and a review that always carried it would make the default response\n // unusable in a context window.\n const git = yield* Git\n const diff = yield* git\n .run([\"diff\", `${report.baseSha}..${report.headSha}`])\n .pipe(Effect.orElseSucceed(() => \"\"))\n return [\"sleep.review\", { ...report, diff }] as const\n })\n\n case \"sleep merge\":\n return Effect.gen(function* () {\n const sleep = yield* Sleep\n const skipGate = bool(parsed, \"skip-gate\", false)\n if (skipGate) {\n yield* Effect.logWarning(\n \"sleep merge --skip-gate: merging without re-running discrimination\"\n )\n }\n /**\n * **The discrimination gate, composed here.** A sleep run that degrades retrieval quality\n * cannot land. `@memhtml/sleep` takes the gate as a parameter and supplies none, so a package\n * that cannot import the eval also cannot silently default it. The composition is visible in\n * this wiring or it does not exist.\n *\n * `discriminationGate` fails on an inversion, `merge` wraps it in `Effect.result`, and the\n * failure becomes `refusal: \"gate-failed\"` with `main` never moving.\n *\n * `fake` mode, always. The gate measures the ranking stack against its own generated fixture\n * corpus, so a live-Bedrock run would make a nightly merge conditional on a network call and\n * on credentials being present at 3am. The deterministic embedder's cosine relations are\n * a pure function of the text, which is the property a regression gate needs. A\n * cron whose merge silently skipped its gate because a token expired is the failure this\n * arrangement prevents.\n */\n const report = yield* sleep.merge(\n parsed.positional[0] ?? \"\",\n skipGate ? {} : { preMergeGate: discriminationGate().pipe(Effect.asVoid) }\n )\n return [\"sleep.merge\", report] as const\n })\n\n case \"publish\":\n return Effect.gen(function* () {\n const report = yield* publish()\n return [\"publish.report\", report] as const\n })\n\n case \"doctor\":\n return Effect.gen(function* () {\n const report = yield* doctor({ fix: bool(parsed, \"fix\", false) })\n return [\"doctor.report\", report] as const\n })\n\n case \"state export\":\n return Effect.gen(function* () {\n const report = yield* stateExport()\n return [\"state.export\", report] as const\n })\n\n case \"state import\":\n return Effect.gen(function* () {\n const report = yield* stateImport()\n return [\"state.import\", report] as const\n })\n\n case \"sleep status\":\n return Effect.gen(function* () {\n const sleep = yield* Sleep\n const report = yield* sleep.review()\n return [\n \"sleep.report\",\n {\n runId: report.runId,\n branch: report.branch,\n baseSha: report.baseSha,\n headSha: report.headSha,\n phases: report.phases,\n commits: report.commits.length\n }\n ] as const\n })\n\n case \"status\":\n return Effect.gen(function* () {\n const report = yield* ops.statusReport()\n return [\"status.health\", report] as const\n })\n\n default:\n // Unreachable while every COMMANDS entry has a case. A new spec with no handler surfaces\n // here as a usage error rather than an empty stdout.\n return Effect.fail({ _tag: \"UnhandledCommand\", command: parsed.command })\n }\n}\n\n/** Today as `YYYY-MM-DD`, through the Effect clock so a test can pin the run date. */\nconst today = Effect.clockWith((clock) =>\n Effect.map(clock.currentTimeMillis, (millis) => new Date(millis).toISOString().slice(0, 10))\n)\n\n/**\n * The services `dispatch` may reach for, derived from the app layer's own output.\n *\n * Derived rather than listed. A service added to `layerCore` becomes available to a handler with no\n * edit here, and a service removed from the layer becomes a compile error at\n * the handler that reads it, rather than a runtime \"service not found\" at the one moment an operator\n * is running the command.\n */\ntype DispatchServices = Layer.Success<ReturnType<typeof layerApp>>\n\n/**\n * An unknown command, with candidates measured against the whole typed invocation.\n *\n * `parseArgv` only matches a compound name exactly, so a typo in either word of `memhtml index rebuild`\n * leaves `command` holding the first token alone and every remaining token in `positional`.\n * Measuring `\"index\"` against the flat name list scores `init` at 2 and `index rebuild` at 8, so the\n * suggestion an operator needs loses to one they did not ask for. Re-joining the tokens makes\n * the distance a comparison of the two things: `\"index rebiuld\"` is 2 from `index rebuild` and 12\n * from `init`.\n *\n * Both are offered, the joined form first, because the typo could be in either half. A one-word\n * invocation joins to itself, so the single-command path is unchanged.\n */\nconst unknownCommand = (parsed: Parsed): Failure => {\n const typed = [parsed.command, ...parsed.positional].join(\" \").trim()\n const candidates = [\n ...nearest(typed, COMMAND_NAMES),\n ...nearest(parsed.command, COMMAND_NAMES)\n ].filter((name, at, all) => all.indexOf(name) === at)\n return fail(\n \"ERR_UNKNOWN_COMMAND\",\n `unknown command: ${typed === \"\" ? parsed.command : typed}`,\n candidates.slice(0, 3)\n )\n}\n\n/**\n * The commands where the article body comes from either a claim or pre-authored markup, never both.\n *\n * Listed here rather than expressed in `FlagSpec`, because `FlagSpec` has one `required: boolean` and\n * no notion of a conditional. Inventing a table field for a rule that holds on two commands\n * would put a second, weaker copy of this check into the manifest for every command that does not\n * need it. Both flag descriptions state the rule, so `memhtml manifest` still carries it.\n */\nconst EITHER_CLAIM_OR_ARTICLE: ReadonlySet<string> = new Set([\"write\", \"correct\"])\n\n/**\n * `memhtml exec` takes at most one script door, and a bound inside the cap.\n *\n * Here for the reason `claimOrArticle` is: `validate`'s return becomes exit 2 and a failure raised in\n * `dispatch` becomes exit 1, so \"you passed the wrong flags\" must be decided before any service is\n * built. `.erpaval/solutions/api-patterns/xor-params-and-mcp-error-masking.md` records the rule.\n *\n * At most one rather than exactly one, because zero doors is legal and means stdin, the same shape\n * `memhtml apply` has, where a bare invocation drains the pipe. A missing script is not a usage error\n * here. An empty one is, and that check sits beside the read in {@link run} because reading is async.\n *\n * `--timeout-ms` is checked for a positive integer within the cap. Zero and negatives are refused\n * rather than clamped, because just-bash treats a non-positive `maxJsTimeoutMs` as no bound at all, so\n * `--timeout-ms 0` would read as \"be quick\" and mean \"run forever\".\n */\nconst execFlags = (parsed: Parsed): Failure | undefined => {\n if (parsed.command !== \"exec\") return undefined\n\n const doors = [\n str(parsed, \"file\") === undefined ? undefined : \"--file\",\n str(parsed, \"script\") === undefined ? undefined : \"--script\"\n ].filter((door) => door !== undefined)\n if (doors.length > 1) {\n return fail(\n \"ERR_INVALID_FLAG\",\n \"exec takes at most one of --file or --script, not both: two scripts cannot both be the one that runs\",\n [\n \"memhtml exec --file traverse.mjs\",\n \"memhtml exec --script 'console.log(1)'\",\n \"cat s.mjs | memhtml exec\"\n ]\n )\n }\n // A `-` positional is the explicit stdin spelling, so it cannot sit beside a door either.\n if (doors.length === 1 && parsed.positional[0] === \"-\") {\n return fail(\n \"ERR_INVALID_FLAG\",\n `exec cannot read stdin and ${doors[0]} in the same call: \\`-\\` names stdin as the script source`,\n [\"cat s.mjs | memhtml exec\", `memhtml exec ${doors[0]} …`]\n )\n }\n\n const raw = str(parsed, \"timeout-ms\")\n if (raw !== undefined) {\n const timeout = int(parsed, \"timeout-ms\")\n if (timeout === undefined || timeout <= 0 || timeout > MAX_TIMEOUT_MS) {\n return fail(\n \"ERR_INVALID_FLAG\",\n `--timeout-ms must be a positive integer of at most ${MAX_TIMEOUT_MS}: a non-positive bound is no bound at all, which is the one thing a sandbox may not be`,\n [`memhtml exec --timeout-ms ${DEFAULT_TIMEOUT_MS}`]\n )\n }\n }\n\n return undefined\n}\n\n/**\n * Exactly one of `--claim` / `--article-html`.\n *\n * Checked here rather than in the dispatch arm, because the exit code is the contract. `validate`'s\n * return is emitted as exit 2 ({@link EXIT_USAGE}), while a failure raised inside `dispatch` travels\n * through `failureFor` and becomes exit 1. Supplying the wrong flags is a usage error, and a shell\n * caller branching on the code must not see it as a runtime one.\n *\n * Two codes for two conditions, each following the convention already in this function. An absent\n * required flag is `ERR_MISSING_ARGUMENT` (as below), and a flag present but unusable as given is\n * `ERR_INVALID_FLAG` (as above, and in the closed-vocabulary check). Neither is newly minted.\n */\nconst claimOrArticle = (parsed: Parsed): Failure | undefined => {\n if (!EITHER_CLAIM_OR_ARTICLE.has(parsed.command)) return undefined\n const hasClaim = str(parsed, \"claim\") !== undefined\n const hasArticle = str(parsed, \"article-html\") !== undefined\n if (hasClaim && hasArticle) {\n return fail(\n \"ERR_INVALID_FLAG\",\n `${parsed.command} takes exactly one of --claim or --article-html, not both: --article-html is the whole article, so a --claim beside it would be silently discarded`,\n [\n `memhtml ${parsed.command} --claim <sentence>`,\n `memhtml ${parsed.command} --article-html '<p>…</p>'`\n ]\n )\n }\n if (!hasClaim && !hasArticle) {\n return fail(\n \"ERR_MISSING_ARGUMENT\",\n `${parsed.command} requires exactly one of --claim or --article-html`,\n [\n `memhtml ${parsed.command} --claim <sentence>`,\n `memhtml ${parsed.command} --article-html '<p>…</p>'`\n ]\n )\n }\n return undefined\n}\n\n/**\n * Validate a parsed invocation against its spec. Usage errors only; nothing here touches a service.\n *\n * Returning the failure rather than throwing keeps the exit code decision in one place. A usage\n * error is exit 2 and a runtime error is exit 1, and a validator that emitted its own envelope would\n * have to know that too.\n */\nconst validate = (parsed: Parsed): Failure | undefined => {\n for (const name of parsed.flags.keys()) {\n if (!KNOWN_FLAGS.has(name)) {\n return fail(\"ERR_INVALID_FLAG\", `unknown flag: --${name}`, nearest(name, [...KNOWN_FLAGS]))\n }\n }\n\n const spec = COMMANDS.find((command) => command.name === parsed.command)\n if (spec === undefined) return unknownCommand(parsed)\n\n const missingArgs = spec.args.filter(\n (arg, position) => arg.required && parsed.positional[position] === undefined\n )\n if (missingArgs.length > 0) {\n return fail(\n \"ERR_MISSING_ARGUMENT\",\n `${spec.name} requires: ${missingArgs.map((arg) => arg.name).join(\", \")}`,\n [`memhtml ${spec.name} <${missingArgs[0]?.name}>`]\n )\n }\n\n const missingFlags = spec.flags.filter(\n (flag) => flag.required === true && parsed.flags.get(flag.name) === undefined\n )\n if (missingFlags.length > 0) {\n return fail(\n \"ERR_MISSING_ARGUMENT\",\n `${spec.name} requires: ${missingFlags.map((flag) => `--${flag.name}`).join(\", \")}`,\n missingFlags.map((flag) => `memhtml ${spec.name} --${flag.name} <value>`)\n )\n }\n\n // Presence rules together: the unconditionally-required flags above, then the two conditional\n // rules the table cannot express, then the value checks below.\n const eitherOr = claimOrArticle(parsed)\n if (eitherOr !== undefined) return eitherOr\n\n const exec = execFlags(parsed)\n if (exec !== undefined) return exec\n\n /**\n * A closed-vocabulary flag is checked here rather than at the service, so a typo answers with the\n * whole vocabulary and never touches the database. Every value of a repeatable flag is checked, not\n * only the last one, so a `--type` list with one bad entry is a usage error rather than a silently\n * narrowed search.\n */\n for (const flag of spec.flags) {\n if (flag.values === undefined) continue\n for (const value of parsed.flags.get(flag.name) ?? []) {\n if (typeof value !== \"string\") continue\n if (!flag.values.includes(value)) {\n return fail(\n \"ERR_INVALID_FLAG\",\n `--${flag.name} must be one of: ${flag.values.join(\", \")}`,\n nearest(value, flag.values)\n )\n }\n }\n }\n\n return undefined\n}\n\n/**\n * Returns the rendered envelope and an exit code rather than writing to the process, so tests\n * assert on the exact bytes an agent would parse.\n *\n * `layer` is injectable for that reason. A test supplies the real composition over a temp\n * repo and a deterministic embedder, and every assertion below then describes the shipped path.\n *\n * `stdin` is injectable for the same reason one step further out. `memhtml apply` reads a JSONL stream\n * from a pipe, and a test that had to spawn a process and write to its descriptor to exercise the\n * stdin path would be an integration test of the shell rather than of this function. The default\n * reads `process.stdin`, so `bin.ts` needs no knowledge of which commands want input.\n */\nexport const run = async (\n argv: ReadonlyArray<string>,\n layer?: Layer.Layer<DispatchServices>,\n stdin: () => Promise<string> = readStdin\n): Promise<RunResult> => {\n const parsed = parseArgv(argv)\n const dense = bool(parsed, \"dense\", false)\n\n const emit = (payload: Success<unknown> | Failure, exitCode: number): RunResult => ({\n stdout: render(payload, dense),\n exitCode\n })\n\n if (parsed.command === \"\" || parsed.command === \"help\") {\n return emit(succeed(\"cli.manifest\", buildManifest()), EXIT_OK)\n }\n\n const invalid = validate(parsed)\n if (invalid !== undefined) return emit(invalid, EXIT_USAGE)\n\n /**\n * The two self-describing commands answer without building the app layer.\n *\n * `manifest` matters most here. It is the first call an agent makes and it must answer on a\n * machine with no repo, no database, and no credentials. Building the layer first would make the\n * self-description conditional on the thing it describes being already working.\n *\n * `agents-doc` is here because building the layer has a side effect. `layerDatabase` opens\n * `$MEMHTML_ROOT/.memhtml/index.db`, creating the directory and running every migration. A doc generator\n * that scaffolded a memory repo as a side effect of rendering Markdown would create `~/memhtml`\n * on any machine that ran `memhtml agents-doc --check` in CI. It reads only the command table, so it\n * has no reason to touch the app graph at all.\n */\n if (parsed.command === \"manifest\") {\n return emit(succeed(\"cli.manifest\", buildManifest()), EXIT_OK)\n }\n\n if (parsed.command === \"agents-doc\") {\n return Effect.runPromise(\n runAgentsDoc({ check: bool(parsed, \"check\", false), out: str(parsed, \"out\") }).pipe(\n Effect.map((data) => emit(succeed(\"agents.doc\", data), EXIT_OK)),\n Effect.catch((error) => Effect.succeed(emit(failureFor(error), EXIT_RUNTIME))),\n Effect.provideService(Logger.LogToStderr, true)\n )\n )\n }\n\n /**\n * `serve mcp` must not build the app layer either, and here the reason is the database.\n *\n * The supervisor's only job is to spawn the server and wait. Building `layerApp` first would open\n * `$MEMHTML_ROOT/.memhtml/index.db` and run its migrations in the parent. That is a second writer\n * against the store the child exists to serve, held open for as long as the child lives, by a process\n * that never issues a query. The parent needs the resolved repo root, which is config rather than a\n * service.\n *\n * Nothing is emitted until the child exits, because stdout belongs to the child from the moment it\n * is spawned. The `serve.exit` envelope describes how the server ended, and it is written after\n * the descriptors are the parent's again.\n */\n if (parsed.command === \"serve mcp\") {\n return Effect.runPromise(\n Effect.gen(function* () {\n const override = str(parsed, \"repo\")\n const configured = yield* MemhtmlRoot\n const memhtmlRoot =\n override !== undefined && override.trim() !== \"\" ? override.trim() : configured\n return yield* serveMcp(memhtmlRoot)\n }).pipe(\n Effect.map((data) => emit(succeed(\"serve.exit\", data), EXIT_OK)),\n Effect.catch((error) => Effect.succeed(emit(failureFor(error), EXIT_RUNTIME))),\n Effect.catchCause((cause) =>\n Effect.succeed(\n emit(fail(\"ERR_UNKNOWN\", `unexpected failure: ${String(cause)}`, []), EXIT_RUNTIME)\n )\n ),\n Effect.provideService(Logger.LogToStderr, true)\n )\n )\n }\n\n /**\n * `eval discriminate` does not build the app layer either, for the reason the command above gives.\n * The gate measures the ranking stack against its own generated fixture corpus in a temp directory\n * with an in-memory database, and reads the operator's `index.db` not at all. Building `layerApp`\n * would open and migrate a store this command never queries, and an operator checking the gate is\n * typically doing it while `memhtml-mcp` serves that store.\n *\n * **Exit 1 on a failed gate**, with `ERR_DISCRIMINATION_FAILED`. A gate that exited 0 and\n * left the verdict inside the payload would be a gate every shell caller forgets to read. The\n * exit code is what stops a pipeline.\n */\n if (parsed.command === \"eval discriminate\") {\n const requested = (str(parsed, \"mode\") ?? \"fake\") as EvalMode\n return Effect.runPromise(\n runDiscrimination({\n mode: requested,\n ...(int(parsed, \"seed\") === undefined ? {} : { seed: int(parsed, \"seed\") }),\n ...(int(parsed, \"size\") === undefined ? {} : { size: int(parsed, \"size\") }),\n ...(int(parsed, \"probes\") === undefined ? {} : { probes: int(parsed, \"probes\") }),\n ...(num(parsed, \"mrr-floor\") === undefined ? {} : { mrrFloor: num(parsed, \"mrr-floor\") })\n }).pipe(\n Effect.map((outcome) =>\n outcome.passed\n ? emit(succeed(\"eval.discrimination\", outcome), EXIT_OK)\n : {\n stdout: render(succeed(\"eval.discrimination\", outcome), dense),\n exitCode: EXIT_RUNTIME\n }\n ),\n Effect.catchCause((cause) =>\n Effect.succeed(\n emit(fail(\"ERR_UNKNOWN\", `unexpected failure: ${String(cause)}`, []), EXIT_RUNTIME)\n )\n ),\n Effect.provideService(Logger.LogToStderr, true)\n )\n )\n }\n\n /**\n * `memhtml exec` does not build the app layer either, for the reason two commands over.\n *\n * The command reads a git tree and nothing else. It materializes a commit as a detached worktree and\n * mounts that directory read-only. It never queries `index.db`, so building `layerApp` would open and\n * migrate a database it does not use, on the path an agent reaches for while `memhtml serve mcp` is\n * serving the repo. Nothing here can be reached through `dispatch`, because `dispatch`'s service set\n * is the app layer's.\n *\n * **Non-zero `exitCode` in the payload is still exit 0 for the process**, and that split is the\n * contract. A failing script is a report with `stderr` an agent reads and fixes. The CLI's exit 1 is\n * reserved for the runtime failing to run the script at all (no repo, unreadable sha, absent helper).\n * Collapsing the two would make an agent unable to tell a bad selector from a broken install, and\n * would bury the script's own diagnostic inside an `error` string.\n *\n * The script is read here rather than in `runExec`, so a missing or empty script is exit 2 like every\n * other input error. `runExec` takes source, never a path.\n */\n if (parsed.command === \"exec\") {\n const inline = str(parsed, \"script\")\n const file = parsed.positional[0] === \"-\" ? undefined : str(parsed, \"file\")\n const script =\n inline !== undefined ? inline : file === undefined ? await stdin() : await readScript(file)\n if (typeof script !== \"string\") return emit(script, EXIT_USAGE)\n if (script.trim() === \"\") {\n return emit(\n fail(\n \"ERR_MISSING_ARGUMENT\",\n \"exec needs a script: a blank one would report an empty answer rather than an error\",\n [\n \"memhtml exec --script 'console.log(1)'\",\n \"memhtml exec --file traverse.mjs\",\n \"cat s.mjs | memhtml exec\"\n ]\n ),\n EXIT_USAGE\n )\n }\n\n const override = str(parsed, \"repo\")\n return Effect.runPromise(\n Effect.gen(function* () {\n const configured = yield* MemhtmlRoot\n const memhtmlRoot =\n override !== undefined && override.trim() !== \"\" ? override.trim() : configured\n return yield* execCommand({\n script,\n memhtmlRoot,\n sha: str(parsed, \"sha\"),\n timeoutMs: int(parsed, \"timeout-ms\")\n })\n }).pipe(\n Effect.map((report) => emit(succeed(\"exec.report\", report), EXIT_OK)),\n Effect.catch((error) => Effect.succeed(emit(failureFor(error), EXIT_RUNTIME))),\n Effect.catchCause((cause) =>\n Effect.succeed(\n emit(fail(\"ERR_UNKNOWN\", `unexpected failure: ${String(cause)}`, []), EXIT_RUNTIME)\n )\n ),\n Effect.provideService(Logger.LogToStderr, true),\n Effect.scoped\n )\n )\n }\n\n /**\n * `memhtml apply` checks the shape of its whole op stream before any service is built (AC-6-4).\n *\n * Here rather than in `validate` because reading a file is async and `validate` is a pure synchronous\n * function of the parsed argv. Here rather than in the dispatch arm because a refusal raised inside\n * `dispatch` travels through `failureFor` and becomes exit 1, while a malformed input file is a usage\n * error and must be exit 2. The caller wrote a bad file, and the corpus is fine.\n *\n * The ordering is the observable contract. Nothing is written for a file with a bad line, and at this\n * point nothing can have been, because the app layer has not been built, so no database is open and\n * no git command has run.\n */\n let applyOps: ReadonlyArray<ops.WriteParams> = []\n if (parsed.command === \"apply\") {\n // `memhtml apply -` is the explicit \"read stdin\" spelling, and the dash is not a path.\n const file = parsed.positional[0] === \"-\" ? undefined : str(parsed, \"file\")\n const text = await applyText(file, stdin)\n if (typeof text !== \"string\") return emit(text, EXIT_USAGE)\n const decoded = decodeApply(text)\n if (!decoded.ok) return emit(decoded.failure, EXIT_USAGE)\n applyOps = decoded.ops\n }\n\n const program = dispatch(parsed, applyOps).pipe(\n Effect.map(([type, data]) => emit(succeed(type, data), EXIT_OK)),\n Effect.catch((error) => Effect.succeed(emit(failureFor(error), EXIT_RUNTIME))),\n // A defect is still an answer. An unexpected throw anywhere below would otherwise reach the\n // process as an unhandled rejection and print a stack trace onto stdout. Stdout is a parse\n // target, so it carries the envelope and nothing else.\n Effect.catchCause((cause) =>\n Effect.succeed(\n emit(fail(\"ERR_UNKNOWN\", `unexpected failure: ${String(cause)}`, []), EXIT_RUNTIME)\n )\n ),\n Effect.provide(layer ?? layerApp(str(parsed, \"repo\"))),\n // Logs go to stderr, always. Effect's default logger writes to stdout, which would interleave\n // log lines with the envelope and break every parser.\n Effect.provideService(Logger.LogToStderr, true),\n Effect.scoped\n )\n\n return Effect.runPromise(program)\n}\n\n/** The envelope's api version, re-exported so a caller can assert on it without a second import. */\nexport { API_VERSION }\n","#!/usr/bin/env node\nimport { run } from \"./run.js\"\n\n// stdout carries only the envelope so it stays a clean parse target.\nconst result = await run(process.argv.slice(2))\nprocess.stdout.write(`${result.stdout}\\n`)\nprocess.exit(result.exitCode)\n"],"mappings":"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N,MAAM;EACN,aAAa;EACb,YAAY;CACd;CACA;EACE,MAAM;EACN,MAAM;EAIN,aACE;CACJ;CACA;EACE,MAAM;EACN,MAAM;EACN,aAAa;EACb,SAAS;CACX;CACA;EACE,MAAM;EACN,MAAM;EACN,aACE;CACJ;AACF;;;;;;;;;;;AAYA,MAAa,WAAuC;CAClD;EACE,MAAM;EACN,SAAS;EACT,MAAM,CAAC;EACP,OAAO,CAAC;EACR,eAAe,CAAC,cAAc;CAChC;CACA;EACE,MAAM;EACN,SAAS;EACT,MAAM,CAAC;EACP,OAAO,CAAC;EACR,eAAe,CAAC,WAAW;CAC7B;CACA;EACE,MAAM;EACN,SAAS;EACT,MAAM,CAAC;EACP,OAAO;GACL;IACE,MAAM;IACN,MAAM;IACN,aAAa;IACb,UAAU;GACZ;GACA;IACE,MAAM;IACN,MAAM;IACN,aACE;GACJ;GACA;IACE,MAAM;IACN,MAAM;IACN,aAAa;IACb,YAAY;GACd;GACA;IACE,MAAM;IACN,MAAM;IACN,aACE;GACJ;GACA;IACE,MAAM;IACN,MAAM;IACN,aAAa;IACb,QAAQ;IACR,UAAU;GACZ;GACA;IACE,MAAM;IACN,MAAM;IACN,aAAa;GACf;GACA;IAAE,MAAM;IAAa,MAAM;IAAU,aAAa;GAAyC;GAC3F;IACE,MAAM;IACN,MAAM;IACN,aAAa;GACf;GACA;IACE,MAAM;IACN,MAAM;IACN,aAAa;IACb,YAAY;GACd;GACA;IACE,MAAM;IACN,MAAM;IACN,aAAa;GACf;GACA;IAAE,MAAM;IAAc,MAAM;IAAU,aAAa;GAAwC;GAC3F;IACE,MAAM;IACN,MAAM;IACN,aAAa;GACf;GACA;IAAE,MAAM;IAAa,MAAM;IAAU,aAAa;GAAkC;GACpF;IAAE,MAAM;IAAa,MAAM;IAAU,aAAa;GAAgC;EACpF;EACA,eAAe,CAAC,gBAAgB;CAClC;CACA;EACE,MAAM;EACN,SACE;EACF,MAAM,CAAC;EACP,OAAO;GACL;IACE,MAAM;IACN,MAAM;IACN,aACE;GACJ;GACA;IACE,MAAM;IACN,MAAM;IACN,aACE;IACF,SAAS;GACX;GAC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"}
1
+ {"version":3,"file":"memhtml.mjs","names":["nowSecond","provenanceOf","ops.writeMemory","ops.batchWrite","ops.readMemory","ops.searchMemories","ops.recallMemories","ops.correctMemory","ops.linkMemories","ops.neighborsOf","ops.archiveMemory","ops.reinforceMemories","ops.listMemories","ops.setTaskStatus","ops.listTasks","ops.indexTraces","ops.searchTraces","ops.traceLinks","ops.statusReport"],"sources":["../../apps/cli/src/serve.ts","../../apps/cli/src/config.ts","../../apps/cli/src/envelope.ts","../../apps/cli/src/extraction.ts","../../apps/cli/src/api-layer.ts","../../apps/cli/src/errors.ts","../../apps/cli/src/operations.ts","../../apps/cli/src/commands.ts","../../apps/cli/src/agents-doc.ts","../../apps/cli/src/prose.ts","../../apps/cli/src/apply.ts","../../apps/cli/src/doctor.ts","../../apps/cli/src/exec.ts","../../apps/cli/src/publish.ts","../../apps/cli/src/state.ts","../../apps/cli/src/views.ts","../../apps/cli/src/run.ts","../../apps/cli/src/bin.ts"],"sourcesContent":["import { spawn } from \"node:child_process\"\nimport { access } from \"node:fs/promises\"\nimport { fileURLToPath } from \"node:url\"\n\nimport { StorageFailure } from \"@memhtml/contracts/errors\"\nimport { Effect } from \"effect\"\n\n/**\n * `memhtml serve mcp`: run the stdio MCP server over the same repo.\n *\n * **The server runs as a child process because of stdout.** The CLI's contract is exactly one JSON\n * envelope on stdout, and a stdio MCP server owns stdout as an NDJSON-RPC stream. Two writers on one\n * file descriptor corrupt the stream for whichever of the two a client is parsing, and no framing\n * makes both readable at once.\n *\n * `stdio: \"inherit\"` hands the child the very descriptors the MCP client opened, so the client talks\n * to `memhtml-mcp` directly and this process is only a supervisor. The child inherits the environment\n * too, which is what makes it build a byte-identical `AppLive`: same region, same credentials.\n * `MEMHTML_ROOT` is passed explicitly on top so a `--repo` override reaches the server, which an\n * inherited environment alone would not carry.\n */\n\n/** What the supervised server's exit looked like. */\nexport interface ServeResult {\n readonly server: string\n readonly exitCode: number\n /** The signal that ended it, when a signal did. */\n readonly signal: string | null\n}\n\n/** An explicit path to the server, for a deployment that does not keep the two apps side by side. */\nexport const MCP_BIN_VAR = \"MEMHTML_MCP_BIN\"\n\n/**\n * Where the `memhtml-mcp` entry point sits relative to this module, in each layout that ships.\n *\n * Resolved by PATH rather than by `require.resolve`, which the dependency direction forces.\n * `@memhtml/mcp` depends on `@memhtml/cli` for the composition root, so `@memhtml/cli` cannot depend on\n * `@memhtml/mcp` without a cycle, and node resolution can only find a package that is a dependency.\n * (`require.resolve(\"@memhtml/mcp/bin\")` from here raises `MODULE_NOT_FOUND`, which is how this was\n * found.)\n *\n * Two candidates, tried in order, because the two apps are one build and where that build puts them\n * differs:\n *\n * - `./memhtml-mcp.mjs` — the PUBLISHED package, where both bins are entry points of one bundle and\n * land beside each other in `dist/`.\n * - `../../mcp/dist/bin.js` — the workspace, where `apps/cli/dist/serve.js` reaches\n * `apps/mcp/dist/bin.js` two directories up and across.\n *\n * Both are real directories rather than pnpm symlinks into the store, so each walk is stable where it\n * applies. {@link MCP_BIN_VAR} still overrides for a deployment that separates them.\n */\nconst MCP_CANDIDATES = [\"./memhtml-mcp.mjs\", \"../../mcp/dist/bin.js\"] as const\n\nexport const mcpEntryPoint = (): Effect.Effect<string, StorageFailure> =>\n Effect.gen(function* () {\n const override = process.env[MCP_BIN_VAR]\n if (override !== undefined && override.trim() !== \"\") return override.trim()\n\n for (const candidate of MCP_CANDIDATES) {\n const path = fileURLToPath(new URL(candidate, import.meta.url))\n const present = yield* Effect.tryPromise({\n try: () => access(path),\n catch: () => \"absent\" as const\n }).pipe(\n Effect.as(true),\n Effect.orElseSucceed(() => false)\n )\n if (present) return path\n }\n\n // A build that produced the CLI but not the server is the one thing that lands here, so the\n // message names the fix rather than the missing path.\n return yield* Effect.fail(\n StorageFailure.make({\n operation: `serve.resolveMcp: run \\`pnpm build\\`, or set ${MCP_BIN_VAR}`\n })\n )\n })\n\nexport const serveMcp = (memhtmlRoot: string): Effect.Effect<ServeResult, StorageFailure> =>\n Effect.gen(function* () {\n const entry = yield* mcpEntryPoint()\n\n return yield* Effect.callback<ServeResult, StorageFailure>((resume) => {\n const child = spawn(process.execPath, [entry], {\n stdio: \"inherit\",\n env: { ...process.env, MEMHTML_ROOT: memhtmlRoot }\n })\n\n child.on(\"error\", () =>\n resume(Effect.fail(StorageFailure.make({ operation: \"serve.spawn\" })))\n )\n child.on(\"exit\", (code, signal) =>\n resume(\n Effect.succeed({\n server: entry,\n exitCode: code ?? 0,\n signal: signal ?? null\n })\n )\n )\n\n // Killing the child on interruption is what keeps a `memhtml serve mcp` that the operator\n // Ctrl-C'd from leaving an orphaned server holding the repo's database open.\n return Effect.sync(() => {\n child.kill()\n })\n })\n })\n","import { homedir } from \"node:os\"\nimport { join } from \"node:path\"\n\nimport { expandRoot } from \"@memhtml/store\"\nimport { Config } from \"effect\"\n\nimport { MCP_BIN_VAR } from \"./serve.js\"\n\n/**\n * The whole environment surface, in one place, so `memhtml manifest` can describe it and a reader\n * does not have to grep for `process.env`.\n *\n * Every variable is read through `effect/Config` rather than `process.env` directly: a missing\n * required value becomes a typed failure with the variable's name in it, and a default is\n * declared next to the name it defaults for.\n */\n\n/** One documented environment variable, for the manifest and the generated agent doc. */\nexport interface ConfigVar {\n readonly name: string\n readonly description: string\n /** The value used when the variable is absent, or `null` when absence is meaningful. */\n readonly fallback: string | null\n}\n\nexport const CONFIG_VARS: ReadonlyArray<ConfigVar> = [\n {\n name: \"MEMHTML_ROOT\",\n description: \"The memory repo's root: a git repository holding the corpus and `.memhtml/`.\",\n fallback: join(\"~\", \"memhtml\")\n },\n {\n name: \"MEMHTML_TRACE_ROOT\",\n description:\n \"Where `memhtml trace index` reads Claude Code transcripts from. Read-only; never written.\",\n fallback: join(\"~\", \".claude\")\n },\n {\n name: \"MEMHTML_AWS_REGION\",\n description: \"The Bedrock region for embeddings and the sleep cycle's four LLM phases.\",\n fallback: \"us-east-1\"\n },\n {\n name: \"AWS_BEARER_TOKEN_BEDROCK\",\n description:\n \"Bedrock bearer token, read by the AWS SDK itself. Absent means the default credential chain; retrieval then degrades to the lexical floor rather than failing.\",\n fallback: null\n },\n {\n name: \"MEMHTML_EMBED\",\n description:\n \"`off` disables the embedder entirely. An explicit opt-out, distinct from a missing credential: a missing credential degrades one search at call time, `off` degrades every search, and an operator reading this manifest needs those to be different states.\",\n fallback: \"on\"\n },\n {\n name: \"MEMHTML_LLM\",\n description:\n \"`off` makes the four LLM sleep phases report `no model bound` and stay `ok`, so a credential-free run is honest rather than red.\",\n fallback: \"on\"\n },\n {\n name: \"MEMHTML_EXTRACT_ENTITIES\",\n description:\n \"`on` adds one GPT-5.6 Luna call per write batch that extracts `memhtml-entity` metas the ops did not declare. Opt-in, unlike MEMHTML_EMBED, because it changes what a write STORES: extracted entities land in the files as if authored, and the write itself never waits on or fails with the model. A failed extraction is a logged warning and an unextracted batch.\",\n fallback: \"off\"\n },\n {\n /**\n * The name is imported rather than retyped: this row and the `process.env` read at serve.ts:50\n * must name the same string, and a literal here would let a rename disclose a variable nothing\n * reads.\n */\n name: MCP_BIN_VAR,\n description:\n \"An explicit path to the `memhtml-mcp` entry point, read only by the `memhtml serve mcp` supervisor. Absent means the sibling-path default. The two apps ship as one build, so `apps/cli/dist/serve.js` finds `apps/mcp/dist/bin.js` two directories over. An operator sets it for a split deployment that does not keep the apps side by side; it locates the server rather than configuring the store, so it changes no retrieval behavior.\",\n fallback: null\n }\n]\n\n/**\n * `MEMHTML_ROOT`. Re-exported from `@memhtml/store`'s own config rather than redeclared, because the\n * store's config expands a leading `~`. This value arrives from a shell profile, an MCP client\n * config, and a cron line, and only the shell expands tildes on its own.\n */\nexport const MemhtmlRoot = Config.string(\"MEMHTML_ROOT\").pipe(\n Config.withDefault(join(\"~\", \"memhtml\")),\n Config.map(expandRoot)\n)\n\n/**\n * `MEMHTML_TRACE_ROOT`, defaulting to `~/.claude`.\n *\n * A parameter rather than a constant so the trace indexer is drivable against a fixture tree and\n * against an archived copy, which is also what keeps real transcripts out of the test suite.\n */\nexport const TraceRoot = Config.string(\"MEMHTML_TRACE_ROOT\").pipe(\n Config.withDefault(join(homedir(), \".claude\")),\n Config.map(expandRoot)\n)\n","/**\n * The machine contract. `apiVersion` lets the envelope evolve without silently\n * breaking parsers, and `type` is a discriminator an agent reads to know the\n * shape of `data` before parsing it.\n */\nexport const API_VERSION = \"1\"\n\n/**\n * Append-only, like `ERROR_CODES`. A discriminator's meaning is fixed once shipped;\n * a new payload shape gets a new discriminator rather than reusing one.\n */\nexport const RESPONSE_TYPES = [\n \"cli.manifest\",\n \"memory.written\",\n \"memory.detail\",\n \"memory.hits\",\n \"recall.pack\",\n \"index.report\",\n \"trace.sessions\",\n \"sleep.report\",\n \"sleep.review\",\n \"eval.discrimination\",\n \"doctor.report\",\n \"status.health\",\n \"repo.init\",\n \"memory.corrected\",\n \"memory.linked\",\n \"memory.neighbors\",\n \"memory.archived\",\n \"memory.reinforced\",\n \"memory.list\",\n \"trace.report\",\n \"trace.links\",\n \"sleep.merge\",\n \"agents.doc\",\n \"serve.exit\",\n \"publish.report\",\n \"state.export\",\n \"state.import\",\n \"task.written\",\n \"task.updated\",\n \"task.list\",\n \"batch.applied\",\n \"exec.report\"\n] as const\n\nexport type ResponseType = (typeof RESPONSE_TYPES)[number]\n\nexport interface Success<A> {\n readonly apiVersion: typeof API_VERSION\n readonly type: ResponseType\n readonly data: A\n}\n\nexport interface Failure {\n readonly apiVersion: typeof API_VERSION\n readonly error: string\n readonly code: ErrorCode\n readonly suggestions: ReadonlyArray<string>\n}\n\n/**\n * Append-only. Once shipped, a code's meaning never changes and a code is never\n * removed; new conditions get new codes. Agents branch on `code`, never on the\n * human `error` string, which changes freely as wording improves.\n */\nexport const ERROR_CODES = [\n \"ERR_UNKNOWN_COMMAND\",\n \"ERR_MISSING_ARGUMENT\",\n \"ERR_INVALID_FLAG\",\n \"ERR_PATH_NOT_FOUND\",\n \"ERR_INVALID_MEMORY\",\n \"ERR_DUPLICATE_CONTENT\",\n \"ERR_WRITE_CONFLICT\",\n \"ERR_DIRTY_TREE\",\n \"ERR_INDEX_STALE\",\n \"ERR_EMBED_MODEL_MISMATCH\",\n \"ERR_MODEL_UNAVAILABLE\",\n \"ERR_STORAGE\",\n \"ERR_GIT\",\n \"ERR_DISCRIMINATION_FAILED\",\n \"ERR_UNKNOWN\"\n] as const\n\nexport type ErrorCode = (typeof ERROR_CODES)[number]\n\n/** Exit codes stay stable so a shell caller can branch without parsing output. */\nexport const EXIT_OK = 0\nexport const EXIT_USAGE = 2\nexport const EXIT_RUNTIME = 1\n\nexport const succeed = <A>(type: ResponseType, data: A): Success<A> => ({\n apiVersion: API_VERSION,\n type,\n data\n})\n\nexport const fail = (\n code: ErrorCode,\n error: string,\n suggestions: ReadonlyArray<string> = []\n): Failure => ({ apiVersion: API_VERSION, error, code, suggestions })\n\n/** Levenshtein distance, used for \"did you mean\" suggestions. */\nconst distance = (a: string, b: string): number => {\n const rows = a.length + 1\n const cols = b.length + 1\n let previous = Array.from({ length: cols }, (_, index) => index)\n\n for (let row = 1; row < rows; row += 1) {\n const current = [row, ...Array.from({ length: cols - 1 }, () => 0)]\n for (let col = 1; col < cols; col += 1) {\n const substitution = (previous[col - 1] as number) + (a[row - 1] === b[col - 1] ? 0 : 1)\n const insertion = (current[col - 1] as number) + 1\n const deletion = (previous[col] as number) + 1\n current[col] = Math.min(substitution, insertion, deletion)\n }\n previous = current\n }\n\n return previous[cols - 1] as number\n}\n\n/** Nearest known names, so an unknown argument returns candidates rather than a dead end. */\nexport const nearest = (\n input: string,\n known: ReadonlyArray<string>,\n limit = 3\n): ReadonlyArray<string> =>\n known\n .map((candidate) => ({\n candidate,\n score: distance(input.toLowerCase(), candidate.toLowerCase())\n }))\n .filter((entry) => entry.score <= Math.max(2, Math.ceil(input.length / 2)))\n .sort((left, right) => left.score - right.score)\n .slice(0, limit)\n .map((entry) => entry.candidate)\n\n/**\n * `--dense` drops nulls and indentation so an agent pasting output into a prompt\n * spends tokens on content rather than decoration.\n */\nconst stripNulls = (value: unknown): unknown => {\n if (Array.isArray(value)) return value.map(stripNulls)\n if (typeof value === \"object\" && value !== null) {\n return Object.fromEntries(\n Object.entries(value)\n .filter(([, entry]) => entry !== null && entry !== undefined)\n .map(([key, entry]) => [key, stripNulls(entry)])\n )\n }\n return value\n}\n\nexport const render = (payload: Success<unknown> | Failure, dense: boolean): string =>\n dense ? JSON.stringify(stripNulls(payload)) : JSON.stringify(payload, null, 2)\n","import { ModelUnavailable } from \"@memhtml/contracts/errors\"\nimport { wrapAsData } from \"@memhtml/llm\"\nimport { Effect } from \"effect\"\n\n/**\n * Write-time entity extraction: one model call per write batch, entities landing as ordinary\n * `memhtml-entity` metas. The git tree stays the system of record and the index only ever sees the\n * rebuildable projection, exactly as if the author had declared them.\n *\n * The port is optional and the default is off (`MEMHTML_EXTRACT_ENTITIES`, config.ts). The write path\n * has never carried a generative call, and the embeddings precedent governs the failure mode: a\n * model that is down costs this batch its extracted entities and nothing else. The write proceeds,\n * the warning is logged, and `entities: []` is what an entity-free write always produced.\n *\n * The model is GPT-5.6 Luna on the Bedrock mantle endpoint, which speaks the OpenAI Responses API\n * over HTTPS and is not reachable through `@memhtml/llm`'s InvokeModel client (the model card lists\n * Invoke and Converse as unsupported; probed 2026-08-09: a strict-json-schema extraction round\n * trip completes in ~1s). The fetch transport therefore lives here rather than as a fourth lane in\n * `packages/llm`, which holds one vendor and one call shape by design. This port's transport is\n * injectable so no test needs the network.\n */\n\n/** One op's text as the extractor sees it: the title plus whichever body form the op carried. */\nexport interface ExtractionItem {\n readonly title: string\n /** `claim` + body prose for prose ops, raw article markup for `article_html` ops. */\n readonly text: string\n}\n\n/**\n * The port `batchWrite` consumes. `undefined` entries are not permitted in the result. The\n * contract is one entity array per input item, index-aligned, empty when the model found nothing.\n */\nexport interface EntityExtractorShape {\n readonly extract: (\n items: ReadonlyArray<ExtractionItem>\n ) => Effect.Effect<ReadonlyArray<ReadonlyArray<string>>, ModelUnavailable>\n}\n\n/** The transport: one Responses-API round trip, body in, decoded JSON out. Injectable for tests. */\nexport interface MantleTransport {\n readonly post: (body: string, signal: AbortSignal) => Promise<unknown>\n}\n\n/**\n * GPT-5.6 Luna, the fast high-volume model on the mantle endpoint. A constant rather than config\n * because the schema below is tested against this model's strict-mode behavior. Changing the model\n * is a code change with a test run, not an env var.\n */\nexport const EXTRACTION_MODEL_ID = \"openai.gpt-5.6-luna\"\n\n/** Entity types the prompt offers. Downstream the vocabulary is open: `unknown:` is a valid store type. */\nconst ENTITY_TYPES = [\"person\", \"org\", \"service\", \"place\", \"work\", \"concept\", \"event\"] as const\n\n/**\n * The strict output schema. `additionalProperties: false` and `required` on every level because\n * the Responses API's `strict: true` demands both, and a lax schema invites the model to answer\n * with prose keys the parser would then be guessing at.\n */\nconst RESPONSE_SCHEMA = {\n type: \"object\",\n properties: {\n items: {\n type: \"array\",\n items: {\n type: \"object\",\n properties: {\n index: { type: \"integer\" },\n entities: {\n type: \"array\",\n items: {\n type: \"object\",\n properties: {\n type: { type: \"string\", enum: [...ENTITY_TYPES] },\n name: { type: \"string\" }\n },\n required: [\"type\", \"name\"],\n additionalProperties: false\n }\n }\n },\n required: [\"index\", \"entities\"],\n additionalProperties: false\n }\n }\n },\n required: [\"items\"],\n additionalProperties: false\n} as const\n\nconst INSTRUCTIONS =\n \"Extract the named entities each memory mentions. \" +\n \"An entity is a specific nameable thing a later search would look up: a person, an \" +\n \"organization, a service or system, a place, a titled work, a defined concept, or a named \" +\n \"event. Skip generic nouns, dates, and quantities. Use the memory's own spelling for the \" +\n \"name. Return one result per input index, with an empty entities array when a memory names \" +\n \"nothing.\"\n\n/** The request body for one batch. Exported for the wire test, where the schema is the contract. */\nexport const requestBodyOf = (modelId: string, items: ReadonlyArray<ExtractionItem>): string =>\n JSON.stringify({\n model: modelId,\n instructions: INSTRUCTIONS,\n input: wrapAsData(\n \"memories\",\n JSON.stringify(items.map((item, index) => ({ index, title: item.title, text: item.text })))\n ),\n text: {\n format: {\n type: \"json_schema\",\n name: \"entities\",\n strict: true,\n schema: RESPONSE_SCHEMA\n }\n }\n })\n\n/**\n * Decode one Responses-API payload into index-aligned `type:name` arrays.\n *\n * Total over unknown input: every malformed shape returns `undefined` and the caller maps that to\n * `ModelUnavailable`. A payload this code cannot read carries no answer, and treating it as\n * \"no entities\" would record a model failure as a fact about the corpus.\n */\nexport const entitiesOf = (\n payload: unknown,\n expected: number\n): ReadonlyArray<ReadonlyArray<string>> | undefined => {\n const text = outputTextOf(payload)\n if (text === undefined) return undefined\n let parsed: unknown\n try {\n parsed = JSON.parse(text)\n } catch {\n return undefined\n }\n const items = (parsed as { items?: unknown }).items\n if (!Array.isArray(items)) return undefined\n\n const results: Array<ReadonlyArray<string>> = Array.from({ length: expected }, () => [])\n for (const item of items) {\n const index = (item as { index?: unknown }).index\n const entities = (item as { entities?: unknown }).entities\n if (typeof index !== \"number\" || !Number.isInteger(index) || index < 0 || index >= expected) {\n continue\n }\n if (!Array.isArray(entities)) continue\n results[index] = entities.flatMap((entity) => {\n const type = (entity as { type?: unknown }).type\n const name = (entity as { name?: unknown }).name\n if (typeof type !== \"string\" || typeof name !== \"string\") return []\n const trimmedName = name.trim()\n return trimmedName === \"\" ? [] : [`${type}:${trimmedName}`]\n })\n }\n return results\n}\n\n/** The assistant message text out of a Responses payload, or `undefined` off-shape. */\nconst outputTextOf = (payload: unknown): string | undefined => {\n const output = (payload as { output?: unknown }).output\n if (!Array.isArray(output)) return undefined\n for (const entry of output) {\n if ((entry as { type?: unknown }).type !== \"message\") continue\n const content = (entry as { content?: unknown }).content\n if (!Array.isArray(content)) continue\n for (const part of content) {\n const text = (part as { text?: unknown }).text\n if ((part as { type?: unknown }).type === \"output_text\" && typeof text === \"string\") {\n return text\n }\n }\n }\n return undefined\n}\n\n/**\n * Per-call ceiling. Generous against the probed ~1s because a batch of 256 ops is a bigger\n * prompt than the probe's one sentence, and a late abort costs only this batch's entities. The\n * write itself is unaffected.\n */\nconst EXTRACT_TIMEOUT_MS = 60_000\n\n/** The extractor over a transport. The transport owns the endpoint; this owns prompt and parse. */\nexport const makeEntityExtractor = (\n transport: MantleTransport,\n modelId: string\n): EntityExtractorShape => ({\n extract: (items) =>\n items.length === 0\n ? Effect.succeed([])\n : Effect.gen(function* () {\n const payload = yield* Effect.tryPromise({\n try: (signal) => {\n const timeout = AbortSignal.timeout(EXTRACT_TIMEOUT_MS)\n return transport.post(\n requestBodyOf(modelId, items),\n AbortSignal.any([signal, timeout])\n )\n },\n catch: (cause) =>\n ModelUnavailable.make({\n modelId,\n reason: cause instanceof Error ? `${cause.name}: ${cause.message}` : String(cause)\n })\n })\n const entities = entitiesOf(payload, items.length)\n if (entities === undefined) {\n return yield* Effect.fail(\n ModelUnavailable.make({ modelId, reason: \"unreadable extraction payload\" })\n )\n }\n return entities\n })\n})\n\n/**\n * The production transport: bearer-token fetch against the mantle endpoint.\n *\n * A non-2xx status is a rejection carrying the status and the body's first line, because mantle\n * reports quota and auth failures as structured JSON the operator needs verbatim. Folding it into\n * a generic message was the mistake the embeddings lane made first.\n */\nexport const fetchMantleTransport = (region: string, token: string): MantleTransport => ({\n post: async (body, signal) => {\n const response = await fetch(`https://bedrock-mantle.${region}.api.aws/openai/v1/responses`, {\n method: \"POST\",\n headers: { Authorization: `Bearer ${token}`, \"Content-Type\": \"application/json\" },\n body,\n signal\n })\n const text = await response.text()\n if (!response.ok) {\n throw new Error(`mantle ${response.status}: ${text.slice(0, 200)}`)\n }\n return JSON.parse(text) as unknown\n }\n})\n","import { readFile } from \"node:fs/promises\"\nimport { join } from \"node:path\"\nimport {\n type ConsolidatorShape,\n hasConsolidatorCredentials,\n makeConsolidator\n} from \"@memhtml/consolidator\"\nimport { StorageFailure } from \"@memhtml/contracts/errors\"\nimport {\n DatabaseService,\n type DatabaseShape,\n type EmbedPort,\n Indexer,\n type IndexerShape,\n IndexGit,\n IndexRecorder,\n type IndexRecorderShape,\n MIGRATIONS_DIR,\n makeDatabase,\n makeGitPort,\n makeIndexer,\n makeIndexRecorder,\n makeRetrieval,\n type QueryEmbedPort,\n Retrieval,\n type RetrievalShape,\n STATE_MIGRATIONS_DIR\n} from \"@memhtml/index\"\nimport {\n EMBED_DIM,\n EMBED_WATERMARK,\n Embeddings,\n EmbeddingsLive,\n type EmbeddingsShape,\n ModelClient,\n ModelClientLive,\n type ModelClientShape\n} from \"@memhtml/llm\"\nimport { makeSleep, Sleep, type SleepShape } from \"@memhtml/sleep\"\nimport {\n Git,\n type GitShape,\n INDEX_DB_PATH,\n makeGit,\n makeStore,\n STATE_DB_PATH,\n Store,\n type StoreShape\n} from \"@memhtml/store\"\nimport { Config, Context, Effect, Layer } from \"effect\"\n\nimport { MemhtmlRoot, TraceRoot } from \"./config.js\"\nimport {\n type EntityExtractorShape,\n EXTRACTION_MODEL_ID,\n fetchMantleTransport,\n makeEntityExtractor\n} from \"./extraction.js\"\n\n/**\n * The service tags, re-exported from the composition root.\n *\n * A handler imports its services from here rather than from six packages, so \"which tag does this\n * come from\" is answered once. `IndexGit` is the case that needs care. `@memhtml/store` publishes\n * `memhtml/Git` for its `GitShape` and `@memhtml/index` publishes `memhtml/IndexGit` for a different\n * shape, and the two appearing side by side in this list keeps them from being confused.\n */\nexport { DatabaseService, Indexer, IndexGit, IndexRecorder, Retrieval } from \"@memhtml/index\"\nexport { Embeddings, ModelClient } from \"@memhtml/llm\"\nexport { Sleep } from \"@memhtml/sleep\"\nexport { Git, Store } from \"@memhtml/store\"\n\n/**\n * `AppLive`: the one place every service is wired to every other.\n *\n * Built bottom-up with `Layer.provideMerge`, so each level both consumes what is below it and\n * stays visible to what is above. Every command handler and every MCP tool then reads the same\n * tags, which keeps a handler down to decode, call, envelope, with no composition logic\n * of its own to drift from its sibling in the other app.\n *\n * Real dependencies force the order:\n *\n * 1. **Root**: `MEMHTML_ROOT`/`MEMHTML_TRACE_ROOT`, needed to open anything.\n * 2. **Database**: `index.db` with `state.db` ATTACHed. `Indexer` and `Retrieval` both need it,\n * and so does the recorder the store's dedupe hook calls.\n * 3. **Git**: the store's subprocess wrapper, plus the indexer's own port over it.\n * 4. **Recorder**: `makeIndexRecorder(db)` supplies both the store's `dedupeLookup` and the\n * session-link writer, which is why the store cannot come before the database.\n * 5. **Store**: over git, with the recorder's hooks attached.\n * 6. **Indexer / Retrieval**: over the database and the git port.\n *\n * The one cycle in the design is broken at step 4. The store needs a SQL lookup to answer \"does\n * this content already exist\", and `@memhtml/store` is SQL-free by design. The lookup arrives as an\n * injected function, so the arrow still points inward and this file is the only module that knows\n * both halves exist.\n */\n\n/** The resolved roots, as a service so a handler reads the repo path without re-reading config. */\nexport interface RootsShape {\n /** `MEMHTML_ROOT`, absolute, `~` expanded. */\n readonly memhtmlRoot: string\n /** `MEMHTML_TRACE_ROOT`, absolute. Read-only, so nothing under it is ever written. */\n readonly traceRoot: string\n}\n\nexport const Roots = Context.Service<RootsShape>(\"memhtml/Roots\")\n\n/**\n * The roots layer. `repoOverride` is `--repo`, and it wins over `MEMHTML_ROOT` so an operator running\n * against a second repo does not have to mutate their environment to do it.\n */\nexport const layerRoots = (repoOverride?: string | undefined): Layer.Layer<RootsShape> =>\n Layer.effect(Roots)(\n Effect.gen(function* () {\n const fromConfig = yield* MemhtmlRoot\n const traceRoot = yield* TraceRoot\n const memhtmlRoot =\n repoOverride !== undefined && repoOverride.trim() !== \"\" ? repoOverride.trim() : fromConfig\n return { memhtmlRoot, traceRoot }\n })\n ).pipe(Layer.orDie)\n\n/**\n * The database, rooted in the repo's `.memhtml/`.\n *\n * Both planes on one connection, always. The salience retrieval arm `LEFT JOIN`s `state.access`\n * in the same statement as `main.files`, so a connection without the attachment silently drops\n * that arm. `DatabaseShape.hasState` is what the arm registry consults, and it is `false` only\n * for a caller that deliberately asked for the index alone.\n */\nexport const layerDatabase: Layer.Layer<DatabaseShape, never, RootsShape> = Layer.effect(\n DatabaseService\n)(\n Effect.gen(function* () {\n const roots = yield* Roots\n return yield* makeDatabase(join(roots.memhtmlRoot, INDEX_DB_PATH), MIGRATIONS_DIR, {\n path: join(roots.memhtmlRoot, STATE_DB_PATH),\n migrationsDir: STATE_MIGRATIONS_DIR\n })\n })\n).pipe(Layer.orDie)\n\n/** Git over the repo root. The store's shape, under the store's own tag. */\nexport const layerGit: Layer.Layer<GitShape, never, RootsShape> = Layer.effect(Git)(\n Effect.gen(function* () {\n const roots = yield* Roots\n return makeGit(roots.memhtmlRoot)\n })\n)\n\n/**\n * The indexer's git port, over the store's git service.\n *\n * `readFile` is `Effect.tryPromise` rather than `Effect.promise`. `Effect.promise` turns an ENOENT\n * into a defect, and a defect travels past the `Effect.catch` the indexer wraps each projection in.\n * An absent path would then kill the fiber mid-update instead of becoming the counted skip the indexer\n * already handles. An agent listing a path it just archived is the normal case, which makes this\n * the difference between a working `index update` and a crash on an ordinary day.\n */\nexport const layerIndexGit: Layer.Layer<\n Context.Service.Identifier<typeof IndexGit>,\n never,\n RootsShape | GitShape\n> = Layer.effect(IndexGit)(\n Effect.gen(function* () {\n const roots = yield* Roots\n const git = yield* Git\n return makeGitPort({\n git,\n readFile: (path) =>\n Effect.tryPromise({\n try: () => readFile(join(roots.memhtmlRoot, path), \"utf8\"),\n catch: (cause) => cause\n }),\n fail: (operation) =>\n Effect.fail(StorageFailure.make({ operation: `git.${operation}` })) as never\n })\n })\n)\n\n/** The recorder: the dedupe lookup the store gates writes on, and the session-link writer. */\nexport const layerRecorder: Layer.Layer<IndexRecorderShape, never, DatabaseShape> = Layer.effect(\n IndexRecorder\n)(\n Effect.gen(function* () {\n const db = yield* DatabaseService\n return makeIndexRecorder(db)\n })\n)\n\n/**\n * The store, with the recorder's dedupe hook attached.\n *\n * `onMove` mirrors `state.access.path` across an archive. Cross-database foreign keys do not\n * exist, so the mirror is an explicit call at the one place a path can change; without it every\n * eviction leaves an orphan access row and the salience arm stops finding the memory it describes.\n */\nexport const layerStore: Layer.Layer<\n StoreShape,\n never,\n GitShape | IndexRecorderShape | DatabaseShape\n> = Layer.effect(Store)(\n Effect.gen(function* () {\n const git = yield* Git\n const recorder = yield* IndexRecorder\n const db = yield* DatabaseService\n return makeStore(git, {\n dedupeLookup: recorder.activePathForHash,\n onMove: (from, to) =>\n db.run(\"UPDATE state.access SET path = ? WHERE path = ?\", [to, from]).pipe(\n // A move whose mirror fails must not fail the move. The archive commit has already\n // landed, and the orphan row is what `memhtml doctor` reports. Losing the commit to a\n // bookkeeping error would be worse than an orphan.\n Effect.catch((error) =>\n Effect.logWarning(`state.access mirror missed ${from} -> ${to}: ${error.operation}`)\n )\n )\n })\n })\n)\n\n/**\n * The embeddings ports, or absent.\n *\n * Absent is a supported configuration rather than an error. `index rebuild --no-embed` and every test\n * run without credentials take this path, and retrieval then assembles without the vector arm and\n * reports `degraded: true`. Making the embedder mandatory would turn a Bedrock outage into a dead\n * CLI, which is the failure the lexical floor exists to prevent.\n */\nexport interface EmbedderShape {\n readonly document: EmbedPort | undefined\n readonly query: QueryEmbedPort | undefined\n}\n\nexport const Embedder = Context.Service<EmbedderShape>(\"memhtml/Embedder\")\n\n/**\n * Bedrock embeddings when the region resolves, absent when `MEMHTML_EMBED` is `off`.\n *\n * The switch is an explicit opt-out rather than credential sniffing. A missing credential is\n * discovered at call time and degrades one search. A deliberate `off` degrades every search, and\n * an operator reading `memhtml manifest` needs those to be different states.\n */\nexport const layerEmbedder: Layer.Layer<EmbedderShape, never, EmbeddingsShape> = Layer.effect(\n Embedder\n)(\n Effect.gen(function* () {\n const enabled = yield* Config.string(\"MEMHTML_EMBED\").pipe(\n Config.withDefault(\"on\"),\n Config.map((value) => value.trim().toLowerCase() !== \"off\")\n )\n if (!enabled) return { document: undefined, query: undefined }\n const embeddings = yield* Embeddings\n return { document: embeddings, query: embeddings }\n })\n).pipe(Layer.orDie)\n\n/** A layer supplying the embedder ports directly, for a test that wants a deterministic vector. */\nexport const layerEmbedderFrom = (embedder: EmbedderShape): Layer.Layer<EmbedderShape> =>\n Layer.succeed(Embedder)(embedder)\n\n/** The indexer, over the database and the git port. */\nexport const layerIndexer: Layer.Layer<\n IndexerShape,\n never,\n DatabaseShape | Context.Service.Identifier<typeof IndexGit> | EmbedderShape\n> = Layer.effect(Indexer)(\n Effect.gen(function* () {\n const db = yield* DatabaseService\n const git = yield* IndexGit\n const embedder = yield* Embedder\n return makeIndexer({\n db,\n git,\n embedWatermark: EMBED_WATERMARK,\n embedDim: EMBED_DIM,\n embeddings: embedder.document,\n // Wall-clock through the Effect clock would need an Effect here; the indexer wants a plain\n // thunk for `indexed_at`. A test that must pin the instant builds the indexer directly.\n now: () => new Date().toISOString()\n })\n })\n)\n\n/** Retrieval, over the database and the query embedder. */\nexport const layerRetrieval: Layer.Layer<RetrievalShape, never, DatabaseShape | EmbedderShape> =\n Layer.effect(Retrieval)(\n Effect.gen(function* () {\n const db = yield* DatabaseService\n const embedder = yield* Embedder\n return makeRetrieval({ db, embeddings: embedder.query })\n })\n )\n\n/**\n * The model behind the four LLM sleep phases, or absent.\n *\n * Absent is a run whose LLM phases report `skipped`, which `@memhtml/sleep` distinguishes from\n * `failed`, because a deterministic run on a fixture without credentials is not a broken run.\n */\nexport interface ModelPortShape {\n readonly model: ModelClientShape | undefined\n}\n\nexport const ModelPort = Context.Service<ModelPortShape>(\"memhtml/ModelPort\")\n\nexport const layerModelPort: Layer.Layer<ModelPortShape, never, ModelClientShape> = Layer.effect(\n ModelPort\n)(\n Effect.gen(function* () {\n const enabled = yield* Config.string(\"MEMHTML_LLM\").pipe(\n Config.withDefault(\"on\"),\n Config.map((value) => value.trim().toLowerCase() !== \"off\")\n )\n if (!enabled) return { model: undefined }\n return { model: yield* ModelClient }\n })\n).pipe(Layer.orDie)\n\n/** A layer supplying the model port directly, for a test that scripts the model's answers. */\nexport const layerModelFrom = (model: ModelClientShape | undefined): Layer.Layer<ModelPortShape> =>\n Layer.succeed(ModelPort)({ model })\n\n/**\n * Write-time entity extraction, or absent. Absent is the default.\n *\n * Opt-in (`MEMHTML_EXTRACT_ENTITIES=on`) where the embedder is opt-out, and the asymmetry is\n * deliberate. The write path has never carried a generative call, extraction changes what a write\n * stores rather than what a search finds, and a default-on model call in every agent's write path\n * is a behavior change an operator must choose. The failure mode does follow the embedder\n * precedent: a bound extractor that fails costs this batch its extracted entities and never the\n * write (`batchWrite` logs and proceeds).\n *\n * The transport is a bearer-token fetch against the Bedrock mantle endpoint rather than a fourth lane\n * in `@memhtml/llm`. GPT-5.6 Luna is mantle-only (no InvokeModel, no Converse), and that package holds\n * one vendor and one call shape by design. The bearer token is the same\n * `AWS_BEARER_TOKEN_BEDROCK` the SDK chain reads. An absent token with the flag on is a configuration\n * the operator asked for and cannot have, so it degrades per batch with a logged warning rather\n * than failing at layer build, matching how a missing embedder credential degrades a search.\n */\nexport interface ExtractorPortShape {\n readonly extractor: EntityExtractorShape | undefined\n}\n\nexport const ExtractorPort = Context.Service<ExtractorPortShape>(\"memhtml/ExtractorPort\")\n\nexport const layerExtractorPort: Layer.Layer<ExtractorPortShape> = Layer.effect(ExtractorPort)(\n Effect.gen(function* () {\n const enabled = yield* Config.string(\"MEMHTML_EXTRACT_ENTITIES\").pipe(\n Config.withDefault(\"off\"),\n Config.map((value) => value.trim().toLowerCase() === \"on\")\n )\n if (!enabled) return { extractor: undefined }\n const region = yield* Config.string(\"MEMHTML_AWS_REGION\").pipe(Config.withDefault(\"us-east-1\"))\n const token = yield* Config.string(\"AWS_BEARER_TOKEN_BEDROCK\").pipe(Config.withDefault(\"\"))\n if (token === \"\") {\n yield* Effect.logWarning(\n \"MEMHTML_EXTRACT_ENTITIES=on but AWS_BEARER_TOKEN_BEDROCK is absent; writes proceed unextracted\"\n )\n return { extractor: undefined }\n }\n return {\n extractor: makeEntityExtractor(fetchMantleTransport(region, token), EXTRACTION_MODEL_ID)\n }\n })\n).pipe(Layer.orDie)\n\n/** A layer supplying the extractor directly, for a test that scripts the extraction answers. */\nexport const layerExtractorFrom = (\n extractor: EntityExtractorShape | undefined\n): Layer.Layer<ExtractorPortShape> => Layer.succeed(ExtractorPort)({ extractor })\n\n/**\n * The consolidator behind trace consolidation, or absent.\n *\n * **This file is the only place that knows both halves exist**, which is why it is\n * here rather than in `@memhtml/sleep`. `apps/consolidator` is an eve agent over the AI SDK Bedrock\n * provider with a `just-bash` sandbox. Sleep declares the shape it consumes\n * (`packages/sleep/src/consolidator.ts`) and never imports any of that. The assignment below needs no\n * adapter and no cast, because TypeScript is structural and `ConsolidatorShape` satisfies\n * `ConsolidatorPort` field for field.\n *\n * **There is no host option, by construction.** The consolidator's eve channel now demands a bearer\n * JWT signed with a per-run secret (`apps/consolidator/agent/channels/eve.ts` via `jwtHmac`), so the\n * bind address is no longer the only thing keeping the agent off the network. It is still not optional,\n * because two layers are only depth while both are in place. `makeConsolidator` exposes no `host`\n * option at all and pins loopback itself (`apps/consolidator/src/client.ts`, `LOOPBACK_HOST`). Nothing\n * here may reintroduce one, and the absence of an option is the mechanism.\n */\nexport interface ConsolidatorPortShape {\n readonly consolidator: ConsolidatorShape | undefined\n}\n\nexport const ConsolidatorPortService = Context.Service<ConsolidatorPortShape>(\n \"memhtml/ConsolidatorPort\"\n)\n\n/**\n * Two gates, both cheap, both before anything is spawned.\n *\n * `MEMHTML_LLM=off` is the same explicit opt-out `layerModelPort` reads, and it covers the consolidator\n * too, because an operator who turned the models off did not mean \"except the expensive agent\".\n *\n * `hasConsolidatorCredentials` is the credential preflight, read here as well as inside the client.\n * The redundancy is deliberate and the two reads do different jobs. This one decides whether the phase\n * sees a consolidator at all, so a credential-free environment gets `detail: \"no consolidator bound\"`,\n * the same shape the other three LLM phases report with no model, rather than a bound port that\n * fails on every call and reports a degradation. CI has no credentials and must read as skipped rather\n * than degraded.\n *\n * The check cannot be skipped in favor of the client's own, because the provider is lazy.\n * `createAmazonBedrock` and `provider(modelId)` both succeed with zero credentials and nothing fails\n * until the first request (verified in T-EVE-1's probe, recorded at\n * `apps/consolidator/src/contract.ts:301-319`).\n *\n * **`env` is a parameter, and it has to be.** `Config` reads its values through a `ConfigProvider`,\n * which a test substitutes, while `hasConsolidatorCredentials` reads `process.env` directly, and\n * effect's default provider snapshots `process.env` at module load (probed 2026-08-08: mutating\n * `process.env.MEMHTML_LLM` after importing `effect` changes nothing `Config.string` returns). A test\n * that set both by mutation would read a stale snapshot for one gate and a live object for the other,\n * and the two gates would disagree about which environment they are in. Threading the credential\n * environment through as an argument makes both injectable from one call. See\n * `apps/cli/tests/consolidator-wiring.test.ts`, where that disagreement produced a false defect\n * before this parameter existed.\n *\n * **It now requires `RootsShape`, for `traceRoot`.** That is how transcripts reach the agent. The\n * consolidator mounts the trace root read-only rather than sending transcripts as a model message\n * (`apps/consolidator/src/client.ts`, `manifestFor`, records what the superseded path actually did).\n * The root is `MEMHTML_TRACE_ROOT` and this file is where config becomes services, so it is read from the\n * same `Roots` service `memhtml trace index` scans with. One resolution of one variable is what\n * keeps the mounted tree and the indexed `traces` rows describing the same directory. A second\n * `Config.string(\"MEMHTML_TRACE_ROOT\")` here would be a second place the `~/.claude` default lives.\n */\nexport const layerConsolidatorPort = (\n env: Record<string, string | undefined> = process.env\n): Layer.Layer<ConsolidatorPortShape, never, RootsShape> =>\n Layer.effect(ConsolidatorPortService)(\n Effect.gen(function* () {\n const roots = yield* Roots\n const enabled = yield* Config.string(\"MEMHTML_LLM\").pipe(\n Config.withDefault(\"on\"),\n Config.map((value) => value.trim().toLowerCase() !== \"off\")\n )\n if (!enabled) return { consolidator: undefined }\n if (!hasConsolidatorCredentials(env)) {\n yield* Effect.logDebug(\n \"trace consolidation unbound: no Bedrock credentials in the environment\"\n )\n return { consolidator: undefined }\n }\n /**\n * The client is built over the same environment the gate just read. A client over ambient\n * `process.env` while the gate read an injected one would pass the gate and fail at the call,\n * which is the degradation-instead-of-skip outcome this gate exists to prevent.\n */\n return { consolidator: makeConsolidator({ env, traceRoot: roots.traceRoot }) }\n })\n ).pipe(Layer.orDie)\n\n/** A layer supplying the consolidator directly, for a test that scripts its candidates. */\nexport const layerConsolidatorFrom = (\n consolidator: ConsolidatorShape | undefined\n): Layer.Layer<ConsolidatorPortShape> => Layer.succeed(ConsolidatorPortService)({ consolidator })\n\n/**\n * The sleep runner over the same services every other command uses.\n *\n * `@memhtml/sleep` deliberately ships no `SleepLive` that resolves its own git, database, and model.\n * A layer that built its own would open a second connection to one database file and a second git\n * wrapper on one root, and the run would then curate a corpus the indexer is not describing.\n */\nexport const layerSleep: Layer.Layer<\n SleepShape,\n never,\n GitShape | StoreShape | DatabaseShape | IndexerShape | ModelPortShape | ConsolidatorPortShape\n> = Layer.effect(Sleep)(\n Effect.gen(function* () {\n const git = yield* Git\n const store = yield* Store\n const db = yield* DatabaseService\n const indexer = yield* Indexer\n const modelPort = yield* ModelPort\n const consolidatorPort = yield* ConsolidatorPortService\n return makeSleep({\n git,\n store,\n db,\n indexer,\n model: modelPort.model,\n consolidator: consolidatorPort.consolidator\n })\n })\n)\n\n/**\n * Everything above the embedder and the model, as one layer requiring only the roots and those two.\n *\n * Written top-down because that is what `Layer.provideMerge(that)` means. It feeds `that`'s output\n * into `self`'s requirements, so the consumer is `self` and each `.pipe` step below adds the level\n * beneath it. Chaining in dependency order instead, with the database first, reads naturally and is\n * wrong. It would provide git to the database and leave `GitShape` in the final requirement set, which\n * typechecks as an unsatisfied layer rather than failing where the mistake is.\n *\n * Split out from `layerApp` so a test provides a deterministic embedder and a real temp repo with\n * no Bedrock anywhere in the graph. The composition under test is then the same composition\n * production runs, which a hand-assembled test wiring would not be.\n */\nexport const layerCore = Layer.mergeAll(layerSleep, layerRetrieval).pipe(\n Layer.provideMerge(Layer.mergeAll(layerIndexer, layerStore)),\n Layer.provideMerge(Layer.mergeAll(layerIndexGit, layerRecorder)),\n Layer.provideMerge(Layer.mergeAll(layerDatabase, layerGit))\n)\n\n/**\n * The production graph: roots from config, Bedrock behind both model ports, everything else over\n * them. `repoOverride` is `--repo`.\n *\n * This is the one composition production runs. `memhtml serve mcp` runs the same one in a child\n * process, so an MCP tool and its CLI twin cannot be looking at different databases.\n */\nexport const layerApp = (repoOverride?: string | undefined) =>\n layerCore.pipe(\n Layer.provideMerge(\n Layer.mergeAll(\n layerRoots(repoOverride),\n layerEmbedder.pipe(Layer.provide(EmbeddingsLive), Layer.orDie),\n layerModelPort.pipe(Layer.provide(ModelClientLive), Layer.orDie),\n layerExtractorPort,\n /**\n * `layerRoots` is provided to the consolidator port explicitly rather than merged beside it.\n * The consolidator needs `traceRoot` to mount, and a sibling in one `mergeAll` is not a\n * dependency. The roots layer is built once with `repoOverride` and fed in, so a `--repo`\n * run and the mounted trace root cannot come from two different resolutions.\n */\n layerConsolidatorPort().pipe(Layer.provide(layerRoots(repoOverride)))\n )\n )\n )\n\n/**\n * The graph a test provides: the real composition, with the embedder and the model injected.\n *\n * Same `layerCore`, so a test exercises the wiring production uses rather than a parallel one. The\n * only substituted edges are the two that reach the network.\n */\nexport const layerAppWith = (options: {\n readonly repo: string\n readonly embedder: EmbedderShape\n readonly model?: ModelClientShape | undefined\n /**\n * Absent leaves trace consolidation skipped, which is the right default for every test that is not\n * about that phase. It is what a credential-free environment produces, and binding a live agent\n * from a test harness would spawn an eve server per case.\n */\n readonly consolidator?: ConsolidatorShape | undefined\n /** Absent leaves writes unextracted, the production default. Only extraction tests bind one. */\n readonly extractor?: EntityExtractorShape | undefined\n}) =>\n layerCore.pipe(\n Layer.provideMerge(\n Layer.mergeAll(\n layerRoots(options.repo),\n layerEmbedderFrom(options.embedder),\n layerModelFrom(options.model),\n layerConsolidatorFrom(options.consolidator),\n layerExtractorFrom(options.extractor)\n )\n )\n )\n","import { type ErrorCode, type Failure, fail } from \"./envelope.js\"\n\n/**\n * The one translation from a typed domain failure to an envelope code.\n *\n * Every failure in the system reaches an agent through this function, and the mapping is total by\n * construction: an unrecognized `_tag` becomes `ERR_UNKNOWN` rather than an empty response, so a\n * new error class added upstream degrades to a documented code instead of a crash.\n *\n * The codes are `ERROR_CODES` and nothing else. An agent branches on `code` and not on the human\n * `error` string, which changes freely as wording improves. The suggestions are therefore part of\n * the contract and the prose is not.\n */\n\n/** A typed failure as it arrives here: a `_tag` plus whatever payload its class carries. */\ninterface TaggedError {\n readonly _tag: string\n readonly [field: string]: unknown\n}\n\nconst isTagged = (value: unknown): value is TaggedError =>\n typeof value === \"object\" &&\n value !== null &&\n typeof (value as { _tag?: unknown })._tag === \"string\"\n\nconst text = (value: unknown): string | undefined => (typeof value === \"string\" ? value : undefined)\n\nconst paths = (value: unknown): ReadonlyArray<string> =>\n Array.isArray(value) ? value.filter((entry): entry is string => typeof entry === \"string\") : []\n\n/**\n * The code for a tag.\n *\n * `GitFailure` lives in `@memhtml/store` rather than `@memhtml/contracts`. It is the one error class\n * outside the shared contracts package, because it carries a git subcommand name and only the store\n * speaks git. It maps to `ERR_GIT` here at the CLI edge, the only place the two vocabularies meet.\n *\n * `EmbedModelMismatch` is a plain class rather than a schema error (it predates the contracts\n * package), so it arrives with the same `_tag` shape and needs no special case.\n */\nexport const codeFor = (error: unknown): ErrorCode => {\n if (!isTagged(error)) return \"ERR_UNKNOWN\"\n switch (error._tag) {\n case \"GitFailure\":\n return \"ERR_GIT\"\n case \"StorageFailure\":\n return \"ERR_STORAGE\"\n case \"InvalidMemory\":\n return \"ERR_INVALID_MEMORY\"\n case \"PathNotFound\":\n return \"ERR_PATH_NOT_FOUND\"\n case \"WriteConflict\":\n return \"ERR_WRITE_CONFLICT\"\n case \"DirtyTree\":\n return \"ERR_DIRTY_TREE\"\n case \"DuplicateContent\":\n return \"ERR_DUPLICATE_CONTENT\"\n case \"ModelUnavailable\":\n return \"ERR_MODEL_UNAVAILABLE\"\n case \"EmbedModelMismatch\":\n return \"ERR_EMBED_MODEL_MISMATCH\"\n case \"DiscriminationFailed\":\n return \"ERR_DISCRIMINATION_FAILED\"\n default:\n return \"ERR_UNKNOWN\"\n }\n}\n\n/**\n * The human message for a failure.\n *\n * Deliberately narrow. Every payload field named here is one a caller can act on: a path to\n * re-read, two shas to reconcile, a model to check. The message omits the driver's own text, the\n * SQL, the git argv, and any memory body. Each typed error class already dropped those at its\n * adapter edge so a tool response could not carry corpus content, and reconstructing them here\n * would undo that.\n */\nexport const messageFor = (error: unknown): string => {\n if (!isTagged(error)) return String(error)\n switch (error._tag) {\n case \"GitFailure\":\n return `git ${text(error.command) ?? \"command\"} failed (exit ${String(error.exitCode)})`\n case \"StorageFailure\":\n return `storage operation failed: ${text(error.operation) ?? \"unknown\"}`\n case \"InvalidMemory\":\n return `invalid memory: ${text(error.reason) ?? \"unstated reason\"}`\n case \"PathNotFound\":\n return `no memory at ${text(error.path) ?? \"the given path\"}`\n case \"WriteConflict\":\n return `write conflict on ${text(error.path) ?? \"a path\"}: ours ${text(error.ourSha) ?? \"?\"}, theirs ${text(error.theirSha) ?? \"?\"}`\n case \"DirtyTree\":\n return `the working tree has uncommitted changes: ${paths(error.paths).join(\", \")}`\n case \"DuplicateContent\":\n return `this content already lives at ${text(error.existingPath) ?? \"another path\"}`\n case \"ModelUnavailable\":\n return `bedrock refused ${text(error.modelId) ?? \"the model\"}: ${text(error.reason) ?? \"no reason given\"}`\n case \"EmbedModelMismatch\":\n return `the index was built in vector space ${text(error.stored) ?? \"?\"}, configured is ${text(error.configured) ?? \"?\"}`\n case \"LlmContractViolation\":\n return `the model broke its structured-output contract: ${text(error.reason) ?? \"no reason given\"}`\n case \"DiscriminationFailed\":\n return text(error.reason) ?? \"the discrimination gate refused\"\n default:\n return `unexpected failure: ${error._tag}`\n }\n}\n\n/** One tag's suggestions, given the failure. Some read a payload field, most ignore it. */\ntype SuggestionsFor = (error: TaggedError) => ReadonlyArray<string>\n\n/**\n * What to do about a failure, as commands the caller can run.\n *\n * A suggestion is part of the contract. An agent that receives `ERR_INDEX_STALE` and a\n * `memhtml index update` suggestion can recover in one step without a round trip to a human. Absent\n * suggestions are an empty array rather than a null, so a parser never branches on presence.\n *\n * A record rather than a `switch`, which is what closes the drift class. Every `memhtml …` string\n * below names a command from the table in `commands.ts`, and a rename there used to leave a stale\n * suggestion here that nothing failed on. A record's keys and arms are both walkable, so the suite\n * can enumerate every tag, run every suggestion through the real `parseArgv`, and fail on a name the\n * table does not hold. A `switch` cannot expose any of that to a test.\n *\n * Validated in the test rather than here on purpose: `errors.ts` importing `commands.ts` closes the\n * cycle `commands.ts` → `operations.ts` → `errors.ts` (commands.ts:8, operations.ts:35) and leaves\n * `AUTHORABLE_RELS` undefined in `commands.ts`'s module body under an operations-first import order.\n */\nexport const SUGGESTIONS: Readonly<Record<string, SuggestionsFor>> = {\n PathNotFound: () => [\"memhtml search <what you were looking for>\", \"memhtml list\"],\n WriteConflict: (error) => [\n `memhtml read ${text(error.path) ?? \"<path>\"}`,\n \"re-apply the change to current content\"\n ],\n DirtyTree: () => [\"git -C $MEMHTML_ROOT status\", \"commit or stash the changes, then retry\"],\n DuplicateContent: (error) => [`memhtml read ${text(error.existingPath) ?? \"<path>\"}`],\n EmbedModelMismatch: () => [\"memhtml index rebuild --embed\"],\n ModelUnavailable: () => [\"retry: search still works on the lexical floor\", \"memhtml status\"],\n InvalidMemory: () => [\"memhtml manifest\"],\n // No `--json`: it is a global flag defaulting to true (commands.ts:36-42), so naming it here only\n // gave the suggestion a second way to go stale.\n DiscriminationFailed: () => [\n \"memhtml eval discriminate\",\n \"memhtml sleep review\",\n \"git branch -D <run-id>\"\n ]\n}\n\nexport const suggestionsFor = (error: unknown): ReadonlyArray<string> => {\n if (!isTagged(error)) return []\n return SUGGESTIONS[error._tag]?.(error) ?? []\n}\n\n/** A typed failure as an envelope. The one call every command's error path makes. */\nexport const failureFor = (error: unknown): Failure =>\n fail(codeFor(error), messageFor(error), suggestionsFor(error))\n","import { isEdgeRel, MEMORY_RELS, relClassFor, TASK_RELS } from \"@memhtml/contracts/edges\"\nimport { InvalidMemory, type StorageFailure } from \"@memhtml/contracts/errors\"\nimport { normalizePath } from \"@memhtml/contracts/paths\"\nimport {\n isTaskStatus,\n isWritableMemoryType,\n type MemoryType,\n TASK_STATUSES,\n type TaskStatus,\n WRITABLE_MEMORY_TYPES\n} from \"@memhtml/contracts/types\"\nimport { frameKeyOf, REINFORCE_SIGNALS, type ReinforceSignal } from \"@memhtml/domain\"\nimport { isValidDatetime, setMeta } from \"@memhtml/html\"\nimport {\n DatabaseService,\n type DatabaseShape,\n type FrameMatch,\n Indexer,\n IndexRecorder,\n type IndexRecorderShape,\n type LinkKind,\n persistScanned,\n Retrieval,\n readIndexState,\n readWatermark,\n reinforce,\n type SearchScope,\n sanitizeFtsQuery,\n type TailMerger\n} from \"@memhtml/index\"\nimport { EMBED_WATERMARK } from \"@memhtml/llm\"\nimport { attemptIo, commitSubject, Store, type WriteInput } from \"@memhtml/store\"\nimport { mergeTailExtract, type SessionExtract, scanTraceRoot } from \"@memhtml/traces\"\nimport { Effect } from \"effect\"\n\nimport { ExtractorPort, Roots } from \"./api-layer.js\"\nimport type { ErrorCode } from \"./envelope.js\"\nimport { codeFor, messageFor } from \"./errors.js\"\nimport type { ExtractionItem } from \"./extraction.js\"\n\n/**\n * The use cases, one per tool. Every CLI command and every MCP tool is a thin adapter over exactly\n * one of these, which makes `memhtml search` and `memory_search` provably the same query\n * rather than two implementations that agree today.\n *\n * Nothing here parses argv or builds an envelope. A function takes decoded parameters, returns a\n * typed result, and fails with a typed error. The adapters own the shape of the wire.\n */\n\n/** Wall-clock as an ISO-8601 UTC second, through the Effect clock so a test can pin it. */\nconst nowSecond = Effect.clockWith((clock) =>\n Effect.map(clock.currentTimeMillis, (millis) => `${new Date(millis).toISOString().slice(0, 19)}Z`)\n)\n\n/** Drop `undefined`-valued keys, so `exactOptionalPropertyTypes` sees an absent key. */\nconst defined = <T extends Record<string, unknown>>(input: T): Partial<T> => {\n const out: Record<string, unknown> = {}\n for (const [key, value] of Object.entries(input)) if (value !== undefined) out[key] = value\n return out as Partial<T>\n}\n\n/**\n * Narrow an untrusted memory-type string.\n *\n * `arc` is refused even though it is a valid storage type. An arc is synthesized by the sleep\n * cycle from many memories, so an agent naming one directly would be asserting a conclusion the\n * corpus has not earned. The vocabulary the tool exposes is therefore narrower than the CHECK\n * constraint by exactly that one value.\n */\nexport const decodeWritableType = (\n value: string\n): Effect.Effect<Exclude<MemoryType, \"arc\">, InvalidMemory> =>\n (WRITABLE_MEMORY_TYPES as ReadonlyArray<string>).includes(value)\n ? Effect.succeed(value as Exclude<MemoryType, \"arc\">)\n : Effect.fail(\n InvalidMemory.make({\n reason: `unknown memory type: ${value}. One of: ${WRITABLE_MEMORY_TYPES.join(\", \")}`\n })\n )\n\n/**\n * The rels a CALLER may author: the nine memory rels plus the two task rels.\n *\n * The two classes the vocabulary withholds are the ones the system mints itself. A `person` edge is\n * written by sleep's person-links phase against `resources/people/*`, and `from_session` is written\n * by the write path from the provenance a caller already supplied. Authoring either by hand would put\n * a hand-guessed row where a derivation belongs.\n */\nexport const AUTHORABLE_RELS = [...MEMORY_RELS, ...TASK_RELS] as const\n\nexport type AuthorableRel = (typeof AUTHORABLE_RELS)[number]\n\n/**\n * Narrow an untrusted rel to one a caller may author.\n *\n * A `blocks` edge between two tasks is a legitimate authored assertion, so the task class is in and\n * refusing it would leave the task graph writable by nothing. Whether the rel agrees with its\n * endpoints is not this function's business. `@memhtml/store`'s `linkMemories` reads both files'\n * `memhtml-type` and refuses a mismatch, and it is the only layer that can see the endpoints at all.\n *\n * `memory_link`'s MCP schema stays memory-rels-only (`MemoryRelSchema`, `apps/mcp/src/tools.ts`) and\n * refuses a task rel at decode. That is one narrow surface for agents and one wider one for the\n * operator, with the store's endpoint guard governing both.\n */\nexport const decodeAuthorableRel = (value: string): Effect.Effect<AuthorableRel, InvalidMemory> =>\n isEdgeRel(value) && (AUTHORABLE_RELS as ReadonlyArray<string>).includes(value)\n ? Effect.succeed(value as AuthorableRel)\n : Effect.fail(\n InvalidMemory.make({\n reason: `unknown rel: ${value}. One of: ${AUTHORABLE_RELS.join(\", \")}`\n })\n )\n\n/** Narrow an untrusted task status. */\nexport const decodeTaskStatus = (value: string): Effect.Effect<TaskStatus, InvalidMemory> =>\n isTaskStatus(value)\n ? Effect.succeed(value)\n : Effect.fail(\n InvalidMemory.make({\n reason: `unknown task status: ${value}. One of: ${TASK_STATUSES.join(\", \")}`\n })\n )\n\n/**\n * Narrow an untrusted due date, using the FORMAT's own validator.\n *\n * `isValidDatetime` rather than a local regex or `Date.parse`, because `files.due_at` is compared and\n * ordered as a string. `2026-8-9` and `Aug 9 2026` both parse as instants and neither sorts alongside\n * `2026-08-09`, so the overdue query would silently miss them. Reusing the parser's own validator is\n * also what keeps this refusal and the parser's violation from drifting apart.\n */\nexport const decodeDueAt = (value: string): Effect.Effect<string, InvalidMemory> =>\n isValidDatetime(value)\n ? Effect.succeed(value)\n : Effect.fail(\n InvalidMemory.make({\n reason: `due date is not an ISO date or datetime: ${value}. Expected YYYY-MM-DD or YYYY-MM-DDThh:mm:ssZ`\n })\n )\n\n/** Narrow an untrusted reinforcement signal. */\nexport const decodeSignal = (value: string): Effect.Effect<ReinforceSignal, InvalidMemory> =>\n (REINFORCE_SIGNALS as ReadonlyArray<string>).includes(value)\n ? Effect.succeed(value as ReinforceSignal)\n : Effect.fail(\n InvalidMemory.make({\n reason: `unknown signal: ${value}. One of: ${REINFORCE_SIGNALS.join(\", \")}`\n })\n )\n\n/** Session provenance, present on any write-path call an agent makes from inside a session. */\nexport interface Provenance {\n readonly sessionId?: string | undefined\n readonly promptId?: string | undefined\n readonly turnUuid?: string | undefined\n}\n\n/**\n * Record the session link for an operation that touched a path.\n *\n * Fire-and-log rather than fail-the-call. The link is a note about what happened, and losing the\n * memory over a failed note about it would invert the priority. The file's own head already\n * carries `memhtml-session`/`memhtml-prompt`/`memhtml-turn`, so the durable half of the link survives even\n * when this row does not.\n */\nconst recordLink = (path: string, linkKind: LinkKind, provenance: Provenance, at: string) =>\n Effect.gen(function* () {\n if (provenance.sessionId === undefined || provenance.sessionId === \"\") return\n const recorder = yield* IndexRecorder\n yield* recorder\n .recordLink({\n path,\n sessionId: provenance.sessionId,\n linkKind,\n at,\n ...defined({ promptId: provenance.promptId, turnUuid: provenance.turnUuid })\n })\n .pipe(\n Effect.catch((error) =>\n Effect.logWarning(`session link not recorded for ${path}: ${error.operation}`)\n )\n )\n })\n\nexport interface WriteParams extends Provenance {\n readonly title: string\n readonly claim: string\n readonly body?: ReadonlyArray<string> | undefined\n /**\n * Pre-authored article markup, used verbatim in place of `claim`/`body`. The caller owns\n * constraint 1 when it supplies this, and the store's render gate is what enforces it. Markup\n * with no `<mark>` fails with `InvalidMemory` before anything is written or committed.\n */\n readonly articleHtml?: string | undefined\n readonly memoryType: string\n readonly path?: string | undefined\n readonly workspace?: string | undefined\n readonly tags?: ReadonlyArray<string> | undefined\n readonly entities?: ReadonlyArray<string> | undefined\n readonly importance?: number | undefined\n readonly confidence?: number | undefined\n /** A task's opening status. Ignored on any other type, which carries no such meta. */\n readonly taskStatus?: string | undefined\n /** A task's deadline, ISO date or datetime. Refused before the write when it is neither. */\n readonly dueAt?: string | undefined\n}\n\n/**\n * Bring the index up to the commit a write just made.\n *\n * `indexer.update()` rather than `indexPaths([…])`, and the difference changes behavior twice:\n *\n * 1. **`indexPaths` cannot express a rename.** Every correction and every archive is a `git mv`, and\n * an index that handled one as \"index the destination\" leaves the source row live. The archived\n * memory stays in `memhtml list`, `files` gains a row the tree does not have, and the chunk rows the\n * move exists to preserve are duplicated under two paths. `update()` reads `diff --name-status -M`,\n * sees the `R`, and re-points the row, which keeps the embedding and drops nothing.\n * 2. **`indexPaths` never records the watermark.** `index_state.head_sha` is what makes\n * \"the index describes the current commit\" answerable at all, so a write path that skipped it\n * would leave `memhtml status` reporting `index_fresh: false` forever and `index update` re-deriving\n * from a stale base.\n *\n * The cost is one `git diff` over one commit, which is what the watermark exists to bound. On the\n * very first write the watermark is absent and `update()` falls through to a full rebuild. That is\n * correct, and cheap on a corpus that has one file in it.\n */\nconst reindex = () =>\n Effect.gen(function* () {\n const indexer = yield* Indexer\n return yield* indexer.update({ embed: true })\n })\n\n/**\n * Decode untrusted write parameters into the store's `WriteInput`.\n *\n * Shared by {@link writeMemory} and {@link batchWrite}, and the sharing matters. A batch that\n * re-derived this would be a second decode of the same vocabulary, and the two would agree today\n * and drift the first time a field is added. This is `symspec`'s lesson stated as code: the batch\n * folds the singular's own decode rather than a parallel one.\n *\n * The two task metas are decoded here, before any file is rendered, and only for a task.\n * `@memhtml/html`'s parser refuses `memhtml-task-status` on a non-task and refuses a `memhtml-due` that is not\n * an ISO datetime, so a bad value passed through would render a file the indexer then declines to\n * project. That file is present in the tree, absent from every search, and visible only as a log\n * line. Deciding here turns it into a typed `InvalidMemory` before the commit.\n */\nconst toWriteInput = (params: WriteParams, at: string): Effect.Effect<WriteInput, InvalidMemory> =>\n Effect.gen(function* () {\n const memoryType = yield* decodeWritableType(params.memoryType)\n const taskStatus =\n memoryType === \"task\" && params.taskStatus !== undefined && params.taskStatus !== \"\"\n ? yield* decodeTaskStatus(params.taskStatus)\n : undefined\n const dueAt =\n memoryType === \"task\" && params.dueAt !== undefined && params.dueAt !== \"\"\n ? yield* decodeDueAt(params.dueAt)\n : undefined\n\n return {\n title: params.title,\n claim: params.claim,\n memoryType,\n at,\n ...defined({\n body: params.body,\n articleHtml: params.articleHtml,\n path: params.path,\n workspace: params.workspace,\n tags: params.tags,\n entities: params.entities,\n importance: params.importance,\n confidence: params.confidence,\n sessionId: params.sessionId,\n promptId: params.promptId,\n turnUuid: params.turnUuid,\n taskStatus,\n dueAt\n })\n }\n })\n\n/**\n * Write one memory: render, dedupe, commit, index.\n *\n * On a dedupe nothing is indexed, because nothing changed. A dedupe writes no file, stages nothing,\n * and commits nothing, so the tree is byte-identical and the index already describes it.\n */\nexport const writeMemory = (params: WriteParams) =>\n Effect.gen(function* () {\n const store = yield* Store\n const at = yield* nowSecond\n const result = yield* store.writeMemory(yield* toWriteInput(params, at))\n\n if (result.created) yield* reindex()\n yield* recordLink(result.path, \"wrote\", params, at)\n return result\n })\n\n/**\n * A frame-match the `detect_conflicts` assist found for one op: something else already occupies this\n * claim's slot.\n *\n * One shape for both kinds of match, with the two source fields nullable, rather than a discriminated\n * union. A caller reads `claim` unconditionally, because that is the disagreement and what a decision\n * is made on, and then reads whichever of `path`/`batchIndex` is non-null to find the other claim. A\n * union would make every consumer branch before it could read the field it actually wants, and the\n * wire form (`Schema.NullOr` per field, per the batch's present-and-nullable rule) would publish the\n * same two nullable fields anyway.\n *\n * Exactly one of the two is non-null, always. A store match names the active memory's `path`. An\n * intra-batch match names the earlier op's `batchIndex`, and has no path because that op's file does\n * not exist yet, since the batch has not been written when the assist runs.\n */\nexport interface FrameConflict {\n /** The active memory already holding this frame key, or null for an intra-batch match. */\n readonly path: string | null\n /** The earlier op in this same batch holding it, or null for a store match. */\n readonly batchIndex: number | null\n /** The other claim's own text. The disagreement itself, which is what a caller decides on. */\n readonly claim: string\n}\n\n/** One op's outcome as the doors report it: the store's own shape, with the envelope's code. */\nexport interface BatchOpReport {\n readonly index: number\n readonly ok: boolean\n readonly path?: string | undefined\n readonly deduped?: boolean | undefined\n readonly existingPath?: string | undefined\n /** The envelope error code for this op's failure, absent when it did not fail. */\n readonly code?: ErrorCode | undefined\n readonly error?: string | undefined\n readonly skipped?: boolean | undefined\n /**\n * What this op's claim contradicts, when `detectConflicts` was on and something matched. Absent\n * when the flag was off, when nothing matched, or when the claim has no frame shape.\n *\n * Propose-only, so the presence of this field never changed what was written. See {@link batchWrite}.\n */\n readonly conflict?: FrameConflict | undefined\n /**\n * Set on a batch-internal loser under `consolidate: \"last-wins\"`: a later restatement of a slot\n * an earlier op already occupied. Its value won the slot, since last wins, but the write landed at\n * the earliest index with that frame key, so this op never got its own file and has no `path`.\n * The number is that slot, the caller-space index whose report carries the surviving write with its\n * path and any `supersededPath`.\n */\n readonly consolidatedInto?: number | undefined\n /**\n * Set on a winner whose write superseded a live stored memory under `consolidate: \"last-wins\"`:\n * the loser's archive path, where its bytes now live. Absent when nothing stored occupied the\n * slot, and also when the supersede itself degraded. The corpus is then merely unconsolidated,\n * which is what every batch produced before this flag existed.\n */\n readonly supersededPath?: string | undefined\n}\n\nexport interface BatchWriteResult {\n readonly results: ReadonlyArray<BatchOpReport>\n readonly summary: {\n readonly total: number\n readonly written: number\n readonly deduped: number\n readonly failed: number\n readonly skipped: number\n /** Batch-internal losers under `consolidate: \"last-wins\"`: ops whose value a later op replaced. */\n readonly consolidated: number\n }\n readonly commitSha: string | null\n}\n\nexport interface BatchWriteParams extends Provenance {\n readonly ops: ReadonlyArray<WriteParams>\n /** Best-effort mode: failed ops are reported and skipped, survivors land in the one commit. */\n readonly continueOnError?: boolean | undefined\n /**\n * Report each op's frame-matches as a per-op `conflict`. Changes nothing about what is written.\n *\n * Off by default, and the default is part of the contract rather than caution. The assist costs one\n * extra query per batch, and a caller that did not ask for the field would be paying for an answer\n * it does not read.\n */\n readonly detectConflicts?: boolean | undefined\n /**\n * Opt-in write-time consolidation: deterministic frame-key (`frameKeyOf`) last-wins.\n *\n * `detectConflicts` reports and leaves the corpus alone. This one acts, on the caller's explicit ask.\n * A later op whose claim occupies the same frame slot as an earlier one replaces it before\n * anything is written, so a batch-internal loser never reaches disk. A surviving op whose slot a\n * live stored memory occupies supersedes it after the commit, archiving the old file with a\n * `supersedes` chain back from the winner. Fail-closed on the rule's own terms: a claim with no\n * frame shape (null key) is never touched, and a failed store lookup degrades to\n * batch-internal-only consolidation through the same `Effect.catch` → `logWarning` → neutral\n * shape {@link detectFrameConflicts} takes, so the flag cannot become a new way to lose writes.\n */\n readonly consolidate?: \"last-wins\" | undefined\n}\n\n/**\n * A typed failure as a per-op report, through the same `codeFor`/`messageFor` every envelope error\n * takes.\n *\n * Mapped here rather than in each door, deliberately. A per-op code is part of the batch's payload\n * rather than of the envelope, so two doors shaping it independently is two mappings that agree today.\n * `memhtml apply` and `memory_write_batch` reporting different codes for the same refused op is\n * the drift the shared-use-case rule exists to prevent.\n */\nconst reportFailure = (index: number, error: unknown): BatchOpReport => ({\n index,\n ok: false,\n code: codeFor(error),\n error: messageFor(error)\n})\n\n/**\n * The `detect_conflicts` assist: which claim, if any, each op's own claim contradicts.\n *\n * **Propose-only, and that is the design rather than a v1 limitation.** The function returns a report\n * per op index and writes nothing, stages nothing, and refuses nothing, because sometimes the\n * contradiction is the answer. A memory recording that a runbook step changed necessarily contradicts\n * the memory stating the old step, and an assist that auto-archived, applied last-wins, or blocked the\n * write would destroy the pair a later reader needs to see the change in. The caller decides: write\n * anyway, `memory_correct` the match, or skip.\n *\n * **One query for the whole batch.** Every op's frame key is collected first and `activeFramesFor` is\n * called once with all of them. The signature takes an array so a caller cannot loop, and a\n * per-op lookup would be the quadratic-write-cost pattern this codebase has already paid for once.\n *\n * **Two match sources, checked in that order.** The store answers for active non-task memories. Its\n * predicate, and 0009's index, exclude archived rows and tasks, because an archived claim is not a\n * competing assertion and an open to-do phrased as a claim is working state rather than knowledge. Then\n * come the batch's own earlier ops, folded as this loop walks them in order. Two ops in one call can\n * occupy the same slot, and neither is in the store yet, so nothing but this fold can see that pair. A\n * store match wins when an op has both, because the store's memory is a fact already in the corpus\n * while the earlier op is one this same call is about to create.\n *\n * **A later op reports on an earlier one, never the reverse.** The fold is asymmetric on purpose. Op 3\n * matching op 1 tells a caller \"you are about to restate something you just said\", which is actionable\n * with op 3 still in hand. Reporting it on op 1 as well would name a conflict with something that did\n * not exist when op 1 was written, and would double one finding into two.\n *\n * **A lookup failure degrades to no conflicts.** The assist is a note about the writes, so losing the\n * memories over a failed note about them would invert the priority as it would for\n * {@link recordLink} and {@link bumpAccess}, with the same `Effect.catch` → `logWarning` → neutral value.\n * The write path never sees this function's failure, which makes \"the assist cannot block a\n * write\" true structurally rather than by review.\n */\nconst detectFrameConflicts = (\n ops: ReadonlyArray<WriteParams>\n): Effect.Effect<ReadonlyMap<number, FrameConflict>, never, IndexRecorderShape> =>\n Effect.gen(function* () {\n /**\n * `frameKeyOf(op.claim)` per op, computed once and kept alongside the index.\n *\n * On the `article_html` path `claim` is `\"\"` by construction, because both doors leave it empty and\n * the `<mark>` inside the markup is the claim. `frameKeyOf` therefore returns null and a markup op\n * gets no assist. Deriving one here would mean parsing every op's article at the ops layer, a second\n * render of bytes the store is about to render anyway. The boundary is stated in the tool\n * description instead of hidden behind a duplicate parse.\n */\n const keyed: Array<{ readonly index: number; readonly key: string; readonly claim: string }> =\n []\n for (const [index, op] of ops.entries()) {\n const key = frameKeyOf(op.claim)\n if (key !== null) keyed.push({ index, key, claim: op.claim })\n }\n if (keyed.length === 0) return new Map<number, FrameConflict>()\n\n const recorder = yield* IndexRecorder\n const live = yield* recorder\n .activeFramesFor(keyed.map((entry) => entry.key))\n .pipe(\n Effect.catch((error) =>\n Effect.logWarning(`conflict assist skipped: ${error.operation}`).pipe(\n Effect.as(new Map<string, ReadonlyArray<FrameMatch>>())\n )\n )\n )\n\n const conflicts = new Map<number, FrameConflict>()\n /** frame key → the first op in this batch to occupy it. Built as the loop walks in order. */\n const seen = new Map<string, { readonly index: number; readonly claim: string }>()\n for (const entry of keyed) {\n const [stored] = live.get(entry.key) ?? []\n const earlier = seen.get(entry.key)\n if (stored !== undefined) {\n conflicts.set(entry.index, {\n path: stored.path,\n batchIndex: null,\n claim: stored.gist\n })\n } else if (earlier !== undefined) {\n conflicts.set(entry.index, {\n path: null,\n batchIndex: earlier.index,\n claim: earlier.claim\n })\n }\n if (earlier === undefined) seen.set(entry.key, { index: entry.index, claim: entry.claim })\n }\n return conflicts\n })\n\n/**\n * The `consolidate: \"last-wins\"` plan: which slots survive, which ops lost to a later restatement,\n * and which stored memories a surviving slot supersedes. Everything is in the caller's index space.\n */\ninterface LastWinsPlan {\n /** The ops the pipeline runs, each at its original slot index. Losers are absent. */\n readonly ops: ReadonlyArray<{ readonly index: number; readonly op: WriteParams }>\n /** Batch-internal loser index → the slot whose position carries the surviving value. */\n readonly losers: ReadonlyMap<number, number>\n /** Surviving slot index → the live stored memory occupying that slot's frame key. */\n readonly pendingSupersede: ReadonlyMap<number, string>\n}\n\n/**\n * Fold last-wins over the caller's op array, before the decode fold, so a batch-internal loser\n * never reaches disk. The surviving value simply occupies the earliest slot with that key.\n *\n * Not derived from {@link detectFrameConflicts}' output, although the walk mirrors it. A store\n * match wins there, masking the batch-internal pair the plan needs, and the plan needs both: the\n * batch collision decides which value writes, and the store match decides what that write supersedes.\n *\n * The slot rule: the first occupant of a key keeps its position and later ops with the same key\n * replace its content (`plannedOps[slot] = laterOp`, provenance and all, since the surviving value\n * is the later op's own statement). The occupant-tracking never moves, so a third restatement\n * replaces the slot again, last wins, at a stable position a caller can index by.\n *\n * Fail-closed on both of the rule's own guards: a null frame key is never consolidated, and a\n * failed store lookup degrades to batch-internal consolidation only, through the same\n * `Effect.catch` → `logWarning` → neutral-shape path the conflict assist takes, because an opt-in\n * consolidation must not become a new way to lose writes.\n */\nconst planLastWins = (\n ops: ReadonlyArray<WriteParams>\n): Effect.Effect<LastWinsPlan, never, IndexRecorderShape> =>\n Effect.gen(function* () {\n /** frame key → the slot (earliest occupant's index) that carries this key's surviving value. */\n const slotOf = new Map<string, number>()\n /** slot index → the op whose value currently occupies it. */\n const content = new Map<number, WriteParams>()\n const losers = new Map<number, number>()\n /** Slot indices in caller order, keyed and keyless alike. */\n const order: Array<number> = []\n\n for (const [index, op] of ops.entries()) {\n const key = frameKeyOf(op.claim)\n if (key === null) {\n // No frame shape, no slot. The rule's guards fail closed, so this op is never touched.\n order.push(index)\n content.set(index, op)\n continue\n }\n const slot = slotOf.get(key)\n if (slot === undefined) {\n slotOf.set(key, index)\n order.push(index)\n content.set(index, op)\n continue\n }\n content.set(slot, op)\n losers.set(index, slot)\n }\n\n const pendingSupersede = new Map<number, string>()\n if (slotOf.size > 0) {\n const recorder = yield* IndexRecorder\n // One query for every surviving key, for detectFrameConflicts' reason: a per-slot lookup is\n // the quadratic-write-cost shape this codebase has already paid for once.\n const live = yield* recorder\n .activeFramesFor([...slotOf.keys()])\n .pipe(\n Effect.catch((error) =>\n Effect.logWarning(`consolidation store lookup skipped: ${error.operation}`).pipe(\n Effect.as(new Map<string, ReadonlyArray<FrameMatch>>())\n )\n )\n )\n for (const [key, slot] of slotOf) {\n const [stored] = live.get(key) ?? []\n if (stored !== undefined) pendingSupersede.set(slot, stored.path)\n }\n }\n\n return {\n ops: order.flatMap((index) => {\n const op = content.get(index)\n return op === undefined ? [] : [{ index, op }]\n }),\n losers,\n pendingSupersede\n }\n })\n\n/**\n * Loser reports for a last-wins plan, derived from the winner slots' own final reports.\n *\n * A loser reports `ok` with `consolidatedInto` only when its slot's write landed, which means the\n * surviving value is on disk and the pointer names where. A slot that was skipped or refused took the\n * loser's value down with it, so the loser reports `skipped`, which is the retryable outcome and\n * the one an atomic abort already means: nothing of this op reached disk.\n */\nconst withConsolidation = (\n results: ReadonlyArray<BatchOpReport>,\n plan: LastWinsPlan | null\n): ReadonlyArray<BatchOpReport> => {\n if (plan === null || plan.losers.size === 0) return results\n return results.map((report, index) => {\n const slot = plan.losers.get(index)\n if (slot === undefined) return report\n const winner = results[slot]\n return winner?.ok === true && winner.skipped !== true\n ? ({ index, ok: true, consolidatedInto: slot } satisfies BatchOpReport)\n : ({ index, ok: false, skipped: true } satisfies BatchOpReport)\n })\n}\n\n/**\n * Write N memories: one commit, one reindex, per-op results in input order.\n *\n * **Two folds, not one.** Decode is the operations layer's job and the store never sees it, so a\n * malformed `memory_type` on op 4 has to be caught here. This function therefore folds decode\n * over the ops and hands the store only what decoded. The store then folds the render gate, dedup,\n * and path claim over that, and this function splices the two result sets back into one array in\n * the caller's index space. Anything less and a decode failure would either be invisible per-op or\n * would shift every later op's index by one.\n *\n * **One reindex, gated on a file having been written** (G4). The indexer's `update()` reads\n * `git diff` over one commit, so a batch that committed once costs one diff. A dedupe-only\n * batch, which commits nothing, skips it entirely, because moving the watermark for a commit that\n * never happened is what `writeMemory`'s own `if (result.created)` guard exists to avoid.\n *\n * **The conflict assist is a third pass and it is read-only** (AC-1-2). It runs before the store's\n * fold, over the ops as the caller sent them, and its findings are merged into the reports at the\n * end, so it observes the batch and never participates in it. Nothing downstream of\n * {@link detectFrameConflicts} branches on its result: the same files are written, the same commit is\n * made, and the same ops are refused whether the flag is on or off. That is what propose-only means,\n * and it is checkable by reading this function rather than by trusting a description.\n */\nexport const batchWrite = (params: BatchWriteParams) =>\n Effect.gen(function* () {\n const continueOnError = params.continueOnError === true\n const store = yield* Store\n const at = yield* nowSecond\n\n /**\n * The assist, over the caller's own op array and before anything is written.\n *\n * Over `params.ops` rather than the decoded `inputs` below, so a conflict is reported in the\n * caller's index space directly and needs no `originOf` translation. An op the store then\n * refuses still gets its finding, which is the more useful order, because a caller told both \"this\n * op is malformed\" and \"it also contradicts X\" fixes one thing.\n *\n * Not gated on the ops being valid, and deliberately so. `frameKeyOf` is a pure lexical function\n * over a string, so it has nothing to refuse and cannot fail on an op the decode is about to reject.\n */\n const conflicts =\n params.detectConflicts === true\n ? yield* detectFrameConflicts(params.ops)\n : new Map<number, FrameConflict>()\n\n /**\n * The consolidation plan, before the decode fold and in the caller's index space. A\n * batch-internal loser is excluded from everything downstream, so its value never earns a file.\n * The surviving value sits at the earliest slot with its key, so every later report and\n * conflict finding stays at the index the caller sent.\n */\n const plan = params.consolidate === \"last-wins\" ? yield* planLastWins(params.ops) : null\n const planned =\n plan === null ? [...params.ops.entries()].map(([index, op]) => ({ index, op })) : plan.ops\n\n /**\n * Fold 1, decode. `Effect.result` rather than letting the failure escape, because a decode\n * refusal is this op's result and not the batch's.\n */\n const reports: Array<BatchOpReport | undefined> = params.ops.map(() => undefined)\n const inputs: Array<WriteInput> = []\n /** Store-result position → caller's op index, since the store never sees a skipped op. */\n const originOf: Array<number> = []\n let decodeAborted = false\n\n for (const { index, op } of planned) {\n const decoded = yield* Effect.result(toWriteInput({ ...op, ...provenanceOf(params, op) }, at))\n if (decoded._tag === \"Failure\") {\n reports[index] = reportFailure(index, decoded.failure)\n if (!continueOnError) {\n decodeAborted = true\n break\n }\n continue\n }\n originOf.push(index)\n inputs.push(decoded.success)\n }\n\n /**\n * An atomic decode abort touches the store at all. Nothing was written, so every other op,\n * including the ones that decoded, reports `skipped`, matching the store's own abort semantics\n * exactly rather than inventing a second one.\n */\n if (decodeAborted) {\n const results = withConsolidation(merged(reports, conflicts), plan)\n return { results, summary: summarize(results), commitSha: null } satisfies BatchWriteResult\n }\n\n /**\n * The extraction assist: one model call over the decoded ops, extracted entities unioned into\n * each op's own `entities` before anything is written, so they land as ordinary `memhtml-entity`\n * metas and the git tree, rather than the index, is what remembers them.\n *\n * After the decode fold because a refused op must not reach the prompt, and before the store\n * because the render is what serializes the metas. Failure costs exactly this batch's\n * extracted entities. The port being absent, the model being down, and an unreadable payload\n * all take the same logged-warning path, and the write itself never waits on a retry.\n * `entities: []` is what every write produced before this assist existed.\n */\n const extractor = (yield* ExtractorPort).extractor\n if (extractor !== undefined && inputs.length > 0) {\n const items: Array<ExtractionItem> = inputs.map((input) => ({\n title: input.title,\n text:\n input.articleHtml !== undefined\n ? input.articleHtml\n : [input.claim, ...(input.body ?? [])].join(\"\\n\")\n }))\n const outcome = yield* Effect.result(extractor.extract(items))\n if (outcome._tag === \"Failure\") {\n yield* Effect.logWarning(\n `entity extraction skipped for this batch: ${outcome.failure.reason}`\n )\n } else {\n for (const [index, extracted] of outcome.success.entries()) {\n const input = inputs[index]\n if (input === undefined || extracted.length === 0) continue\n const declared = input.entities ?? []\n const union = [...declared, ...extracted.filter((entity) => !declared.includes(entity))]\n inputs[index] = { ...input, entities: union }\n }\n }\n }\n\n // Fold 2, the store: render gate, dedup against the folded state, one commit.\n const batch = yield* store.writeMemories(inputs, { continueOnError })\n\n for (const entry of batch.results) {\n const index = originOf[entry.index]\n if (index === undefined) continue\n reports[index] =\n entry.ok || entry.skipped === true\n ? {\n index,\n ok: entry.ok,\n ...defined({\n path: entry.path,\n deduped: entry.deduped,\n existingPath: entry.existingPath,\n skipped: entry.skipped\n })\n }\n : reportFailure(index, entry.error)\n }\n\n // One reindex, after the commit, only when a file was actually written.\n if (batch.writtenPaths.length > 0) yield* reindex()\n for (const path of batch.writtenPaths) yield* recordLink(path, \"wrote\", params, at)\n\n /**\n * The store-supersede pass, after a successful batch commit: every surviving slot whose frame\n * key a live memory occupied archives that memory, in one `supersedeMemories` call.\n *\n * A slot qualifies when its report is `ok` with a path, including a dedupe, where the path is\n * the pre-existing file that already carries this slot's value. The stored occupant still\n * states the losing value, so superseding it is still correct. A slot that failed or was\n * skipped wrote nothing, so there is nothing for its occupant to lose to.\n *\n * `Effect.result` rather than a bare yield, because a failed supersede must not fail a batch whose\n * memories already landed. The degradation is annotate-only: `supersededPath` is omitted, the\n * warning says why, and the corpus is merely unconsolidated, which is what every batch produced\n * before this flag existed. On success there is one extra reindex, because archive paths moved.\n */\n if (plan !== null && plan.pendingSupersede.size > 0) {\n const pairs: Array<{ readonly winnerPath: string; readonly loserPath: string }> = []\n const winnerOf = new Map<string, number>()\n for (const [slot, storedPath] of plan.pendingSupersede) {\n const report = reports[slot]\n if (report === undefined || !report.ok || report.skipped === true) continue\n if (report.path === undefined) continue\n // A slot whose content deduped onto the occupant itself is a restatement rather than a\n // supersession. Winner and loser are one file, and archiving it would lose the value.\n if (report.path === storedPath) continue\n pairs.push({ winnerPath: report.path, loserPath: storedPath })\n winnerOf.set(storedPath, slot)\n }\n if (pairs.length > 0) {\n const outcome = yield* Effect.result(store.supersedeMemories(pairs))\n if (outcome._tag === \"Failure\") {\n yield* Effect.logWarning(\n `consolidation supersede skipped: ${messageFor(outcome.failure)}`\n )\n } else {\n for (const entry of outcome.success.archived) {\n const slot = winnerOf.get(entry.loserPath)\n const report = slot === undefined ? undefined : reports[slot]\n if (slot === undefined || report === undefined) continue\n reports[slot] = { ...report, supersededPath: entry.archivePath }\n }\n if (outcome.success.archived.length > 0) yield* reindex()\n }\n }\n }\n\n /**\n * An op the store aborted before reaching has no result of its own, and neither does one whose\n * decode succeeded in a batch the store then aborted. Both are `skipped`. Losers pick up their\n * `consolidatedInto` pointer last, from their winner slot's own final report.\n */\n const results = withConsolidation(merged(reports, conflicts), plan)\n\n return {\n results,\n summary: summarize(results),\n commitSha: batch.commitSha\n } satisfies BatchWriteResult\n })\n\n/**\n * Per-op provenance falls back to the batch's own.\n *\n * The batch call carries the session the agent is in, and an op may name its own (a `memhtml apply`\n * file replaying a previous session's writes). Per-op wins, because it is the more specific statement\n * about where that one memory came from.\n */\nconst provenanceOf = (params: BatchWriteParams, op: WriteParams): Provenance =>\n defined({\n sessionId: op.sessionId ?? params.sessionId,\n promptId: op.promptId ?? params.promptId,\n turnUuid: op.turnUuid ?? params.turnUuid\n })\n\n/**\n * The reports as their final array: an unreported op becomes `skipped`, and every op picks up the\n * assist's finding for its index.\n *\n * One function for both exit paths, the atomic decode abort and the normal return, because they had\n * already grown two copies of the same `?? skipped` fill and a third responsibility spliced into only\n * one of them is how a batch that aborted would silently lose its conflict findings. The abort path\n * needs them because nothing was written. A caller told \"op 2 is malformed\" and also \"op 0\n * contradicts areas/x.html\" can fix both before retrying, rather than discovering the second on the\n * next round trip.\n *\n * Merging here rather than at each report's construction site also keeps the assist out of the\n * write path. The reports are already final when the conflicts are attached, so there is no point at\n * which a conflict could be read by anything that decides an outcome.\n */\nconst merged = (\n reports: ReadonlyArray<BatchOpReport | undefined>,\n conflicts: ReadonlyMap<number, FrameConflict>\n): ReadonlyArray<BatchOpReport> =>\n reports.map((report, index) => {\n const base = report ?? ({ index, ok: false, skipped: true } satisfies BatchOpReport)\n const conflict = conflicts.get(index)\n return conflict === undefined ? base : { ...base, conflict }\n })\n\n/** The counts, derived from the reports in one pass so they cannot disagree with them. */\nconst summarize = (results: ReadonlyArray<BatchOpReport>): BatchWriteResult[\"summary\"] => {\n let written = 0\n let deduped = 0\n let failed = 0\n let skipped = 0\n let consolidated = 0\n for (const result of results) {\n // A batch-internal loser is neither written nor failed. Its value survived at another slot,\n // and no file of its own was ever attempted, so it partitions into its own count.\n if (result.consolidatedInto !== undefined) consolidated += 1\n else if (result.skipped === true) skipped += 1\n else if (!result.ok) failed += 1\n else if (result.deduped === true) deduped += 1\n else written += 1\n }\n return { total: results.length, written, deduped, failed, skipped, consolidated }\n}\n\n/**\n * Read one memory, optionally recording that the session read it.\n *\n * The access bump lives here and nowhere else on the retrieval side, because salience accumulates\n * evidence that someone chose a memory and a ranker's guess is not a choice. An explicit open names\n * one path, through this call and the `memhtml://file/{path}` resource that funnels through it, which is\n * the strongest signal short of a write. A path merely returned by search or recall was the ranker's own\n * suggestion, and bumping it builds a rich-get-richer loop: today's top five rank higher\n * tomorrow while the memory that should displace them never breaks in to earn a first bump.\n *\n * `bumpAccess` sits beside `recordLink` deliberately. Both are notes about the read, both swallow their\n * own failures, and neither may cost the caller the memory it asked for.\n */\nexport const readMemory = (path: string, provenance: Provenance = {}) =>\n Effect.gen(function* () {\n const store = yield* Store\n const result = yield* store.readMemory(path)\n yield* recordLink(result.path, \"read\", provenance, yield* nowSecond)\n yield* bumpAccess([result.path])\n return result\n })\n\nexport interface SearchParams extends SearchScope {\n readonly query: string\n readonly limit?: number | undefined\n}\n\n/**\n * Ranked search. The retrieval service sanitizes the query text itself in `fts-query.ts`, so this\n * function never MATCHes user prose and neither does any caller of it.\n *\n * **No access bump, and the omission is the rule rather than an oversight.** A hit is the ranker's\n * guess about what the caller wanted, so counting it as salience would let the ranking teach itself.\n * A memory in today's top five would rank higher tomorrow purely for having been listed, and the\n * memory that should displace it never appears and so never earns a first bump. The cooldown does not\n * help, because it bounds one query replayed within 900 seconds, while the drift it would have to\n * bound operates across days. Salience moves when a caller opens a path ({@link readMemory}) or names\n * an outcome ({@link reinforceMemories}).\n */\nexport const searchMemories = (params: SearchParams) =>\n Effect.gen(function* () {\n const retrieval = yield* Retrieval\n return yield* retrieval.search(params)\n })\n\nexport interface RecallParams extends SearchScope {\n readonly query: string\n readonly budgetChars?: number | undefined\n}\n\n/**\n * A context pack under a character budget.\n *\n * No access bump either, for {@link searchMemories}' reason. A disclosed body is still the ranker's\n * choice of what to spend the budget on rather than the caller's choice of what to read.\n */\nexport const recallMemories = (params: RecallParams) =>\n Effect.gen(function* () {\n const retrieval = yield* Retrieval\n return yield* retrieval.recall(params)\n })\n\n/**\n * Bump access bookkeeping for paths a caller chose to open. A missing state plane makes this a no-op.\n *\n * `reinforce` is the one SQL writer for `state.access` and this helper does not become a second one.\n * It moves callers to that writer rather than moving the write here.\n */\nconst bumpAccess = (paths: ReadonlyArray<string>) =>\n Effect.gen(function* () {\n if (paths.length === 0) return\n const db = yield* DatabaseService\n if (!db.hasState) return\n yield* reinforce(db, paths, \"neutral\", yield* nowSecond).pipe(\n Effect.catch((error) =>\n Effect.logWarning(`access bookkeeping missed: ${error.operation}`).pipe(\n Effect.as({ bumped: [], cooledDown: [] })\n )\n )\n )\n })\n\nexport interface CorrectParams extends Provenance {\n readonly targetPath: string\n readonly title: string\n readonly claim: string\n readonly body?: ReadonlyArray<string> | undefined\n /** Pre-authored article markup for the superseding file, used verbatim in place of `claim`/`body`. */\n readonly articleHtml?: string | undefined\n readonly memoryType?: string | undefined\n readonly reason?: string | undefined\n}\n\n/**\n * Supersede a memory: the new file and the archived target land in one commit.\n *\n * The type defaults to the target's own. A correction that silently changed the type would move\n * the memory to a different retention profile and a different PARA directory, and that is a second\n * decision the caller did not make.\n */\nexport const correctMemory = (params: CorrectParams) =>\n Effect.gen(function* () {\n const store = yield* Store\n const target = yield* store.readMemory(params.targetPath)\n const requested = params.memoryType ?? target.doc.metas.memoryType\n const memoryType = yield* decodeWritableType(requested)\n const at = yield* nowSecond\n\n const result = yield* store.correctMemory(params.targetPath, {\n title: params.title,\n claim: params.claim,\n memoryType,\n at,\n ...defined({\n body: params.body,\n articleHtml: params.articleHtml,\n reason: params.reason,\n sessionId: params.sessionId,\n promptId: params.promptId,\n turnUuid: params.turnUuid\n })\n })\n\n // A correction is an add and a rename in one commit, so it needs the diff-driven path. The\n // archived target's row has to move rather than be re-added under a new name beside its old one.\n yield* reindex()\n yield* recordLink(result.path, \"corrected\", params, at)\n return result\n })\n\n/**\n * Add an authored edge. Idempotent on `(rel, href)`, so a re-run commits nothing.\n *\n * The rel is decoded against {@link AUTHORABLE_RELS}, the memory class plus the task class, so\n * `memhtml link a.html blocks b.html` reaches the task graph while a person or provenance rel, both of\n * which the system mints itself, stays unauthorable.\n */\nexport const linkMemories = (srcPath: string, rel: string, dstPath: string) =>\n Effect.gen(function* () {\n const edgeRel = yield* decodeAuthorableRel(rel)\n const store = yield* Store\n const src = normalizePath(srcPath)\n const result = yield* store.linkMemories(src, edgeRel, dstPath)\n // `addLink` is idempotent on the pair, so a re-link commits nothing and there is nothing to\n // index. Re-deriving a diff for a no-op would move the watermark for a commit that never was.\n if (result.commitSha !== null) yield* reindex()\n return { ...result, srcPath: src, dstPath: normalizePath(dstPath), rel: edgeRel }\n })\n\n/** Soft-evict: `git mv` into `archive/<YYYY>/` with the archive stamps. Never a delete. */\nexport const archiveMemory = (path: string, reason: string) =>\n Effect.gen(function* () {\n const store = yield* Store\n const result = yield* store.archiveMemory(path, reason)\n // An archive is a pure rename. Handled as two independent paths it would leave the source row\n // live and duplicate the chunks. The diff path re-points the row and keeps the vector.\n yield* reindex()\n return result\n })\n\n/** Bump access bookkeeping deliberately, with a caller-chosen signal. */\nexport const reinforceMemories = (paths: ReadonlyArray<string>, signal: string) =>\n Effect.gen(function* () {\n const decoded = yield* decodeSignal(signal)\n const db = yield* DatabaseService\n const at = yield* nowSecond\n if (!db.hasState) {\n return { bumped: [] as ReadonlyArray<string>, cooledDown: paths, signal: decoded }\n }\n const result = yield* reinforce(db, paths, decoded, at)\n return { ...result, signal: decoded }\n })\n\nexport interface NeighborsParams {\n readonly path: string\n /** 1 or 2. Clamped rather than refused: a caller asking for 5 wants \"as much as you'll give\". */\n readonly depth?: number | undefined\n readonly rels?: ReadonlyArray<string> | undefined\n}\n\n/** One node in a neighborhood. `hop` is 1-based distance from the center: 1 or 2, never 0. */\nexport interface NeighborNode {\n readonly path: string\n readonly title: string\n readonly hop: number\n readonly rel: string\n}\n\n/**\n * The memory graph around one path, to a fixed depth of at most two hops.\n *\n * **Two fixed-depth joins in a `UNION ALL`, deliberately not a recursive CTE.** The depth is\n * bounded at 2 by the tool's contract, so recursion buys nothing and costs the one thing a graph\n * query must not have here: an unbounded worst case on a corpus whose `relates_to` edges are\n * mined by the sleep cycle and can be dense. A fixed join is also index-covered by `edges_src`\n * and `edges_dst`, which a recursive walk is not.\n *\n * **Both directions, and `derived = 0 ∪ derived = 1`.** An edge is an assertion about a pair, and\n * which file happens to hold the `<link>` is authorship rather than direction of meaning. A\n * neighborhood that read only outbound edges would show a superseding memory its target and hide\n * from the target that it had been superseded. Derived edges are included because lateral retrieval\n * is what they are for. `derived` is still reported per node so a caller can tell a\n * sleep-mined suspicion from an authored assertion.\n *\n * `edge_class = 'memory'` on every join. A person edge entering here would put\n * `resources/people/*` into a memory neighborhood, and the class column exists to make that\n * structurally impossible.\n */\nexport const neighborsOf = (params: NeighborsParams) =>\n Effect.gen(function* () {\n const db = yield* DatabaseService\n const center = normalizePath(params.path)\n const depth = Math.min(2, Math.max(1, Math.trunc(params.depth ?? 1)))\n\n const rels = (params.rels ?? []).filter(\n (rel) => isEdgeRel(rel) && relClassFor(rel) === \"memory\"\n )\n const relFilter = rels.length > 0 ? ` AND e.rel IN (${rels.map(() => \"?\").join(\", \")})` : \"\"\n const relFilter2 = rels.length > 0 ? ` AND e2.rel IN (${rels.map(() => \"?\").join(\", \")})` : \"\"\n\n /**\n * Hop 1 is the center's own edges, either direction. Hop 2 walks one further from each hop-1\n * node and excludes the center, so a two-cycle does not report the center as its own neighbor\n * at distance 2.\n */\n const hopOne = `\n SELECT e.dst_path AS path, e.rel AS rel, e.derived AS derived, 1 AS hop\n FROM edges e\n WHERE e.src_path = ?1 AND e.edge_class = 'memory'${relFilter}\n UNION ALL\n SELECT e.src_path AS path, e.rel AS rel, e.derived AS derived, 1 AS hop\n FROM edges e\n WHERE e.dst_path = ?1 AND e.edge_class = 'memory'${relFilter}`\n\n const hopTwo = `\n SELECT e2.dst_path AS path, e2.rel AS rel, e2.derived AS derived, 2 AS hop\n FROM edges e\n JOIN edges e2 ON e2.src_path = e.dst_path\n WHERE e.src_path = ?1 AND e.edge_class = 'memory' AND e2.edge_class = 'memory'\n AND e2.dst_path <> ?1${relFilter}${relFilter2}\n UNION ALL\n SELECT e2.src_path AS path, e2.rel AS rel, e2.derived AS derived, 2 AS hop\n FROM edges e\n JOIN edges e2 ON e2.dst_path = e.src_path\n WHERE e.dst_path = ?1 AND e.edge_class = 'memory' AND e2.edge_class = 'memory'\n AND e2.src_path <> ?1${relFilter}${relFilter2}`\n\n const walk = depth === 1 ? hopOne : `${hopOne}\\n UNION ALL${hopTwo}`\n\n /**\n * `min(hop)` per path: a node reachable both directly and via a detour is a 1-hop neighbor,\n * and reporting it twice would let one memory occupy two slots in a bounded answer.\n *\n * The join onto `files` is an inner join, so an edge pointing at a path the tree does not hold\n * contributes nothing. A dangling href is `memhtml doctor`'s finding rather than a titleless node.\n */\n const rows = yield* db.all<{\n path: string\n title: string\n rel: string\n derived: number\n hop: number\n }>(\n `SELECT w.path AS path, f.title AS title, min(w.hop) AS hop,\n min(w.rel) AS rel, max(w.derived) AS derived\n FROM (${walk}) w\n JOIN files f ON f.path = w.path\n GROUP BY w.path\n ORDER BY hop ASC, w.path ASC`,\n // The rel list binds once per occurrence of the filter, in textual order: hop 1 uses it\n // twice, hop 2 uses it four times. Getting this count wrong is a bind mismatch rather than a\n // wrong answer, so it fails loudly.\n [\n center,\n ...(depth === 1\n ? [...rels, ...rels]\n : [...rels, ...rels, ...rels, ...rels, ...rels, ...rels])\n ]\n )\n\n const nodes: ReadonlyArray<NeighborNode> = rows.map((row) => ({\n path: row.path,\n title: row.title,\n hop: row.hop,\n rel: row.rel\n }))\n return { center, depth, nodes, edges: nodes.length }\n })\n\nexport interface ListParams {\n readonly memoryType?: string | undefined\n readonly workspace?: string | undefined\n readonly tag?: string | undefined\n readonly entity?: string | undefined\n readonly para?: string | undefined\n readonly limit?: number | undefined\n /** The previous page's `nextCursor`: the last path returned. A keyset rather than an offset. */\n readonly cursor?: string | undefined\n readonly includeArchived?: boolean | undefined\n}\n\n/**\n * Page the corpus by facet.\n *\n * Keyset pagination on `path` rather than `LIMIT/OFFSET`. `files.path` is the primary key and it also\n * moves, because eviction is a `git mv`, so an offset page taken while a sleep cycle archives a file\n * would skip a row or repeat one. A cursor on the path itself is stable against that.\n */\nexport const listMemories = (params: ListParams) =>\n Effect.gen(function* () {\n const db = yield* DatabaseService\n const limit = Math.min(500, Math.max(1, Math.trunc(params.limit ?? 50)))\n const conditions: Array<string> = []\n const values: Array<string | number> = []\n\n if (params.includeArchived !== true) conditions.push(\"f.archived = 0\")\n if (params.memoryType !== undefined && params.memoryType !== \"\") {\n const memoryType = yield* decodeWritableType(params.memoryType)\n conditions.push(\"f.memory_type = ?\")\n values.push(memoryType)\n }\n if (params.workspace !== undefined && params.workspace !== \"\") {\n conditions.push(\"f.workspace = ?\")\n values.push(params.workspace)\n }\n if (params.para !== undefined && params.para !== \"\") {\n conditions.push(\"f.para = ?\")\n values.push(params.para)\n }\n if (params.tag !== undefined && params.tag !== \"\") {\n conditions.push(\"EXISTS (SELECT 1 FROM file_tags t WHERE t.path = f.path AND t.tag = ?)\")\n values.push(params.tag)\n }\n if (params.entity !== undefined && params.entity !== \"\") {\n // The entity arrives as `type:name` and the table splits it at the first colon, so the\n // comparison rebuilds the reference rather than making the caller know the split.\n conditions.push(\n \"EXISTS (SELECT 1 FROM file_entities e WHERE e.path = f.path AND e.entity_type || ':' || e.entity_name = ?)\"\n )\n values.push(params.entity)\n }\n if (params.cursor !== undefined && params.cursor !== \"\") {\n conditions.push(\"f.path > ?\")\n values.push(normalizePath(params.cursor))\n }\n\n const where = conditions.length === 0 ? \"\" : `WHERE ${conditions.join(\" AND \")}`\n const rows = yield* db.all<{\n path: string\n title: string\n memory_type: string\n gist: string\n workspace: string | null\n para: string\n confidence: number\n importance: number\n archived: number\n updated_at: string\n }>(\n `SELECT f.path, f.title, f.memory_type, f.gist, f.workspace, f.para,\n f.confidence, f.importance, f.archived, f.updated_at\n FROM files f ${where} ORDER BY f.path ASC LIMIT ?`,\n [...values, limit + 1]\n )\n\n // One row over the limit is fetched to decide whether a next page exists, then dropped. A\n // separate COUNT would be a second statement over the same predicate and could disagree with\n // this one under a concurrent write.\n const page = rows.slice(0, limit)\n const nextCursor = rows.length > limit ? (page.at(-1)?.path ?? null) : null\n return {\n files: page.map((row) => ({\n path: row.path,\n title: row.title,\n memoryType: row.memory_type,\n gist: row.gist,\n workspace: row.workspace,\n para: row.para,\n confidence: row.confidence,\n importance: row.importance,\n archived: row.archived === 1,\n updatedAt: row.updated_at\n })),\n nextCursor\n }\n })\n\n/**\n * The task surface: CRUDL without retrieval.\n *\n * A task is the 10th `memory_type` and it is default-excluded from search, dedup, and all fifteen\n * sleep phases, so the working set an agent needs is not reachable by ranking. These three\n * functions are how it becomes reachable: `task add` wraps {@link writeMemory}, `task status` is one\n * head meta edited in place, and {@link listTasks} is a direct indexed scan. Reading a directory,\n * grepping a meta, and editing one line remain equally valid, and nothing here is the only path.\n */\n\nexport interface TaskStatusParams {\n readonly path: string\n readonly status: string\n /** Why the task closed. Stamped as the archive reason when the status is `done`. */\n readonly reason?: string | undefined\n}\n\n/** What a status change did. `archived` is true only for the `done` transition. */\nexport interface TaskStatusResult {\n readonly path: string\n readonly taskStatus: TaskStatus\n readonly archived: boolean\n /** The archive path, present iff `archived`. */\n readonly archivePath?: string | undefined\n readonly commitSha: string | null\n /** True when the file already carried this status, so nothing was written. */\n readonly unchanged: boolean\n}\n\n/**\n * Move a task to a new status.\n *\n * **`setMeta`, never parse→serialize.** The editors splice by source offset, so the article's bytes\n * cannot move on a status change, and neither can `memhtml-content-hash`, the dedupe key, or any chunk\n * id hanging off it. A round trip through the serializer drops a `<pre>` newline per write, which\n * would re-embed a task for a one-word edit and break the hash the file claims for itself.\n *\n * **`done` routes through `store.archiveMemory`**, which is a `git mv`. That is the design decision\n * that keeps `done` off the `memhtml-status` axis. Finishing a task stamps the status and moves the file\n * under `archive/<YYYY>/`, so \"what did I finish\" is the archive tree plus `git log` rather than a\n * fifth value every archive, correction, and publish path would have to learn. The stamp is written\n * before the move so both land in one commit and `git log --follow` reads through it.\n *\n * `indexer.update()` afterwards rather than `indexPaths`, because the `done` transition is a rename and\n * `indexPaths` cannot express one. It would leave the pre-archive row live, duplicate the chunks\n * under two paths, and skip the watermark (finding from T9, stated at {@link reindex}).\n */\nexport const setTaskStatus = (params: TaskStatusParams) =>\n Effect.gen(function* () {\n const status = yield* decodeTaskStatus(params.status)\n const store = yield* Store\n const path = normalizePath(params.path)\n const at = yield* nowSecond\n\n // Read through the parser. A `memhtml task status` on a memory file would otherwise stamp a meta the\n // format refuses on that type, producing a file the indexer then declines to project.\n const existing = yield* store.readMemory(path)\n if (existing.doc.metas.memoryType !== \"task\") {\n return yield* Effect.fail(\n InvalidMemory.make({\n reason: `${path} is a ${existing.doc.metas.memoryType} memory, not a task: only a task carries memhtml-task-status`\n })\n )\n }\n\n /**\n * A no-op status change writes nothing and commits nothing, so a re-run is free and the tree\n * stays byte-identical. The `memhtml-updated` stamp is skipped along with it, because a fresh\n * timestamp with no status change would claim the task moved when it did not.\n */\n if (existing.doc.metas.taskStatus === status) {\n return {\n path,\n taskStatus: status,\n archived: false,\n commitSha: null,\n unchanged: true\n } satisfies TaskStatusResult\n }\n\n const stamped = setMeta(\n setMeta(existing.html, \"memhtml-task-status\", status),\n \"memhtml-updated\",\n at\n )\n yield* attemptIo(`task.write:${path}`, async () => {\n const { writeFile } = await import(\"node:fs/promises\")\n const { join } = await import(\"node:path\")\n await writeFile(join(store.root, path), stamped, \"utf8\")\n })\n\n if (status !== \"done\") {\n yield* store.git.add([path])\n const commit = yield* store.git.commit(commitSubject(\"task\", `${status} ${path}`))\n yield* reindex()\n return {\n path,\n taskStatus: status,\n archived: false,\n commitSha: commit.sha,\n unchanged: false\n } satisfies TaskStatusResult\n }\n\n /**\n * `archiveMemory` stages the `git mv` and commits, and it reads the file from disk, so the\n * `memhtml-task-status: done` stamp written just above travels with the move rather than needing a\n * second commit. `git mv` carries a working-tree modification with it (probed live 2026-08-02:\n * the staged blob is the pre-edit content and the worktree keeps the edit), and `archiveMemory`\n * re-writes the stamped bytes at the destination before staging, so the committed file holds\n * both the archive stamps and the done status.\n */\n const archived = yield* store.archiveMemory(path, params.reason ?? `task ${status}`)\n yield* reindex()\n return {\n path,\n taskStatus: status,\n archived: true,\n archivePath: archived.archivePath,\n commitSha: archived.commitSha,\n unchanged: false\n } satisfies TaskStatusResult\n })\n\nexport interface ListTasksParams {\n readonly status?: string | undefined\n readonly workspace?: string | undefined\n /** An ISO date. Returns tasks due strictly before it, so `--due-before today` is \"overdue\". */\n readonly dueBefore?: string | undefined\n readonly limit?: number | undefined\n /** The previous page's `nextCursor`: the last path returned. A keyset rather than an offset. */\n readonly cursor?: string | undefined\n readonly includeArchived?: boolean | undefined\n}\n\n/** One task row as `task list` reports it. */\nexport interface TaskRow {\n readonly path: string\n readonly title: string\n readonly taskStatus: string | null\n readonly dueAt: string | null\n readonly workspace: string | null\n readonly archived: boolean\n readonly updatedAt: string\n /** Every task asserting `blocks` toward this one, path-ordered. Empty when nothing blocks it. */\n readonly blockedBy: ReadonlyArray<string>\n}\n\n/**\n * The task working set: a direct indexed scan, deliberately not retrieval.\n *\n * No RRF, no MMR, no embedding. A to-do list is not a ranking problem. An agent asking \"what is\n * open\" wants every row in a stable order, and a relevance score over working state would make the\n * answer depend on a query the caller does not have. The partial index `files_task_status`\n * (`WHERE memory_type='task' AND archived=0`) is what makes the default scan cheap.\n *\n * `blockedBy` is one correlated subquery over `edges`, filtered to `edge_class='task'` and\n * `rel='blocks'`. **The class filter is redundant with the rel filter today and is kept anyway.**\n * Probed live 2026-08-02: `0008_tasks.sql`'s per-class CHECKs refuse `blocks` under `memory`,\n * `person`, and `provenance`, so `rel='blocks'` already implies the class, and a mutation removing the\n * class predicate leaves every test green. It stays because the class column is what every\n * memory-graph query filters on, and a reader who saw this one query trust the rel alone would learn\n * the wrong rule about how the firewall is enforced.\n *\n * `group_concat` over an ordered subselect, probed 2026-08-12 on node 24.19.0. The inner `ORDER BY`\n * is preserved, and `char(10)` is the separator because a path cannot contain a newline while it can\n * contain a comma.\n *\n * The join is deliberately not an inner join onto `files`. A blocker whose file left the tree still\n * blocks, and hiding it here would make a permanently-blocked task look ready. `memhtml doctor` reports\n * that as a finding, and this function reports the edge as the corpus states it.\n */\nexport const listTasks = (params: ListTasksParams) =>\n Effect.gen(function* () {\n const db = yield* DatabaseService\n const limit = Math.min(500, Math.max(1, Math.trunc(params.limit ?? 50)))\n const conditions: Array<string> = [\"f.memory_type = 'task'\"]\n const values: Array<string | number> = []\n\n if (params.includeArchived !== true) conditions.push(\"f.archived = 0\")\n if (params.status !== undefined && params.status !== \"\") {\n const status = yield* decodeTaskStatus(params.status)\n conditions.push(\"f.task_status = ?\")\n values.push(status)\n }\n if (params.workspace !== undefined && params.workspace !== \"\") {\n conditions.push(\"f.workspace = ?\")\n values.push(params.workspace)\n }\n if (params.dueBefore !== undefined && params.dueBefore !== \"\") {\n const dueBefore = yield* decodeDueAt(params.dueBefore)\n /**\n * `substr(…, 1, 10)` on both sides, so the comparison is one of calendar days.\n *\n * The case it fixes, established by enumeration 2026-08-02: a due date stored as a bare day\n * against a bound carrying a time on that same day. Whole-string,\n * `\"2026-08-25\" < \"2026-08-25T09:00:00Z\"` is true, because the shorter string is a prefix and\n * sorts first, so a task due sometime on the 25th would be reported late at 09:00 on the 25th.\n * A day-granularity deadline is not late until the day is over, and truncating both sides is\n * what says so. Every other combination of the two forms agrees either way.\n */\n conditions.push(\"f.due_at IS NOT NULL AND substr(f.due_at, 1, 10) < substr(?, 1, 10)\")\n values.push(dueBefore)\n }\n if (params.cursor !== undefined && params.cursor !== \"\") {\n conditions.push(\"f.path > ?\")\n values.push(normalizePath(params.cursor))\n }\n\n const rows = yield* db.all<{\n path: string\n title: string\n task_status: string | null\n due_at: string | null\n workspace: string | null\n archived: number\n updated_at: string\n blocked_by: string | null\n }>(\n `SELECT f.path, f.title, f.task_status, f.due_at, f.workspace, f.archived, f.updated_at,\n (SELECT group_concat(b.src_path, char(10)) FROM (\n SELECT e.src_path AS src_path FROM edges e\n WHERE e.dst_path = f.path AND e.edge_class = 'task' AND e.rel = 'blocks'\n ORDER BY e.src_path ASC) b) AS blocked_by\n FROM files f\n WHERE ${conditions.join(\" AND \")}\n ORDER BY f.path ASC LIMIT ?`,\n [...values, limit + 1]\n )\n\n const page = rows.slice(0, limit)\n const nextCursor = rows.length > limit ? (page.at(-1)?.path ?? null) : null\n return {\n tasks: page.map(\n (row): TaskRow => ({\n path: row.path,\n title: row.title,\n taskStatus: row.task_status,\n dueAt: row.due_at,\n workspace: row.workspace,\n archived: row.archived === 1,\n updatedAt: row.updated_at,\n blockedBy: row.blocked_by === null ? [] : row.blocked_by.split(\"\\n\")\n })\n ),\n nextCursor\n }\n })\n\n/**\n * `mergeTailExtract` as the merger `persistScanned` requires.\n *\n * The two shapes differ in exactly one field, and the difference is real rather than cosmetic.\n * `SessionExtract` carries `counters`, the parse bookkeeping of one scan, and the persisted\n * `traces` row does not, because those are facts about a read rather than about the session.\n * `readStoredExtract` therefore cannot reconstruct them, and the merge is handed zeros for the\n * stored side. The merged counters then describe this scan alone, which is the only reading\n * available. Inventing a stored value would produce a number that claims to count lines nobody\n * read.\n *\n * Every other field the merge reads is present on both shapes, so this adapter is total.\n */\nconst ZERO_COUNTERS = {\n parsedLines: 0,\n droppedLines: 0,\n droppedNoSession: 0,\n skippedTypeLines: 0,\n unknownTypeLines: 0\n} as const\n\nconst tailMerger: TailMerger = (stored, tail) =>\n mergeTailExtract(\n { ...stored, counters: ZERO_COUNTERS } as SessionExtract,\n { ...tail, counters: ZERO_COUNTERS } as SessionExtract\n )\n\n/**\n * Scan the trace root and persist what changed.\n *\n * {@link tailMerger} is passed as the tail merger, and this is the only correct way to call\n * `persistScanned` on a `tail` action. A tail's extract describes the appended slice, so its\n * `first_prompt` is a mid-conversation prompt, its `started_at` is later than the session's, and\n * its prompt ordinals restart at 0. `persistScanned` takes the merger as a parameter precisely so\n * that \"never upsert a tail extract directly\" is a type-level obligation rather than a convention.\n */\nexport const indexTraces = () =>\n Effect.gen(function* () {\n const roots = yield* Roots\n const db = yield* DatabaseService\n const at = yield* nowSecond\n\n const report = yield* scanTraceRoot(roots.traceRoot, readWatermark(db))\n\n let sessionsWritten = 0\n let promptsWritten = 0\n let merged = 0\n for (const scanned of report.files) {\n const outcome = yield* persistScanned(db, scanned, tailMerger, at)\n if (outcome.action !== \"skip\") sessionsWritten += 1\n if (outcome.merged) merged += 1\n promptsWritten += outcome.promptsWritten\n }\n\n return {\n traceRoot: roots.traceRoot,\n filesSeen: report.files.length,\n skipped: report.skipped,\n tailed: report.tailed,\n rescanned: report.rescanned,\n bytesRead: report.bytesRead,\n sessionsWritten,\n promptsWritten,\n tailsMerged: merged\n }\n })\n\nexport interface TraceSearchParams {\n readonly query: string\n readonly cwd?: string | undefined\n readonly since?: string | undefined\n readonly limit?: number | undefined\n}\n\n/**\n * FTS over session first-prompts and AI titles.\n *\n * The query goes through the same sanitizer the memory arms use, and it has to. An apostrophe is a\n * hard driver error rather than an empty result, and \"what did I ask about don't-repeat-yourself\"\n * is an ordinary trace query. An empty sanitized query returns the most recent sessions rather\n * than nothing, because a caller with no terms wants a listing and an empty MATCH is not a listing.\n *\n * This is the trace plane and it stops here. No memory table is named, and nothing in the\n * retrieval assembler names `traces`. The firewall is by table name, in both directions.\n */\nexport const searchTraces = (params: TraceSearchParams) =>\n Effect.gen(function* () {\n const db = yield* DatabaseService\n const match = sanitizeFtsQuery(params.query)\n const limit = Math.min(200, Math.max(1, Math.trunc(params.limit ?? 20)))\n\n const conditions: Array<string> = []\n const values: Array<string | number> = []\n /**\n * The MATCH names `traces_fts` rather than a column of `traces`. The index is an external-content\n * FTS5 table, so it is joined in by rowid and only reached when there is something to match. Without\n * a query the statement never mentions it, which is what keeps a bare listing a plain table scan.\n */\n const matched = match !== \"\"\n const from = matched\n ? \"FROM traces_fts JOIN traces t ON t.rowid = traces_fts.rowid\"\n : \"FROM traces t\"\n if (matched) {\n conditions.push(\"traces_fts MATCH ?\")\n values.push(match)\n }\n if (params.cwd !== undefined && params.cwd !== \"\") {\n conditions.push(\"t.cwd = ?\")\n values.push(params.cwd)\n }\n if (params.since !== undefined && params.since !== \"\") {\n conditions.push(\"t.started_at >= ?\")\n values.push(params.since)\n }\n\n const where = conditions.length === 0 ? \"\" : `WHERE ${conditions.join(\" AND \")}`\n // A matched query orders by relevance, ascending because FTS5's bm25 is negative-is-better.\n // Without a match there is no relevance to order by and recency is the useful order.\n const order = matched ? \"ORDER BY bm25(traces_fts)\" : \"ORDER BY t.started_at DESC\"\n const rows = yield* db.all<{\n session_id: string\n slug: string\n cwd: string | null\n started_at: string | null\n prompt_count: number\n first_prompt: string\n ai_title: string | null\n }>(\n `SELECT t.session_id, t.slug, t.cwd, t.started_at, t.prompt_count, t.first_prompt, t.ai_title\n ${from} ${where} ${order} LIMIT ?`,\n [...values, limit]\n )\n\n return {\n sessions: rows.map((row) => ({\n sessionId: row.session_id,\n slug: row.slug,\n cwd: row.cwd,\n startedAt: row.started_at,\n promptCount: row.prompt_count,\n firstPrompt: row.first_prompt,\n aiTitle: row.ai_title\n })),\n degraded: match === \"\"\n }\n })\n\n/**\n * The memory-session links, from either side.\n *\n * Both parameters absent is a refusal rather than an unbounded scan of every link ever recorded. A\n * tool whose no-argument form returns the whole table is a tool an agent calls by accident.\n */\nexport const traceLinks = (params: {\n readonly sessionId?: string | undefined\n readonly path?: string | undefined\n}) =>\n Effect.gen(function* () {\n const hasSession = params.sessionId !== undefined && params.sessionId !== \"\"\n const hasPath = params.path !== undefined && params.path !== \"\"\n if (!hasSession && !hasPath) {\n return yield* Effect.fail(\n InvalidMemory.make({ reason: \"trace links needs a session_id or a path\" })\n )\n }\n\n const db = yield* DatabaseService\n const conditions: Array<string> = []\n const values: Array<string> = []\n if (hasSession) {\n conditions.push(\"l.session_id = ?\")\n values.push(params.sessionId as string)\n }\n if (hasPath) {\n conditions.push(\"l.path = ?\")\n values.push(normalizePath(params.path as string))\n }\n\n const rows = yield* db.all<{\n path: string\n session_id: string\n prompt_id: string | null\n turn_uuid: string | null\n link_kind: string\n at: string\n }>(\n `SELECT l.path, l.session_id, l.prompt_id, l.turn_uuid, l.link_kind, l.at\n FROM memory_session_links l\n WHERE ${conditions.join(\" AND \")}\n ORDER BY l.at DESC, l.path ASC`,\n values\n )\n\n return {\n links: rows.map((row) => ({\n path: row.path,\n sessionId: row.session_id,\n promptId: row.prompt_id,\n turnUuid: row.turn_uuid,\n linkKind: row.link_kind,\n at: row.at\n }))\n }\n })\n\n/**\n * Corpus health, in one call.\n *\n * `indexFresh` compares the recorded watermark to `HEAD`, which is the only answer that means\n * anything. The index is a projection of a commit, so \"fresh\" means \"the commit it describes is the\n * commit we are on\". A count of rows would say the index exists rather than that it is current.\n *\n * `embedderUp` is read off the stored watermark rather than by probing Bedrock. A status call that\n * made a network request would fail for a reason unrelated to the corpus, and what a caller\n * needs to know is whether the vectors in this index are usable.\n */\nexport const statusReport = () =>\n Effect.gen(function* () {\n const store = yield* Store\n const db = yield* DatabaseService\n\n const headSha = yield* store.git.revParseHead()\n const dirty = yield* store.dirtyPaths()\n\n const state = yield* readIndexState(db).pipe(Effect.orElseSucceed(() => undefined))\n\n const byType = yield* countRows(\n db,\n \"SELECT memory_type AS k, count(*) AS n FROM files WHERE archived = 0 GROUP BY memory_type\"\n )\n const archivedCount = yield* countOne(db, \"SELECT count(*) AS n FROM files WHERE archived = 1\")\n const edges = yield* countOne(db, \"SELECT count(*) AS n FROM edges\")\n const derivedEdges = yield* countOne(db, \"SELECT count(*) AS n FROM edges WHERE derived = 1\")\n const embeddings = yield* countOne(db, \"SELECT count(*) AS n FROM embeddings\")\n const chunks = yield* countOne(db, \"SELECT count(*) AS n FROM chunks\")\n const traces = yield* countOne(db, \"SELECT count(*) AS n FROM traces\")\n\n const lastSleep = yield* db\n .get<{ run_id: string; status: string; started_at: string }>(\n \"SELECT run_id, status, started_at FROM sleep_runs ORDER BY started_at DESC LIMIT 1\"\n )\n .pipe(Effect.orElseSucceed(() => undefined))\n\n return {\n root: store.root,\n headSha,\n dirty: dirty.length > 0,\n dirtyPaths: dirty,\n countsByType: byType,\n archivedCount,\n edges,\n derivedEdges,\n chunks,\n embeddings,\n traces,\n indexFresh: state?.head_sha !== null && state?.head_sha === headSha,\n indexHeadSha: state?.head_sha ?? null,\n embedModel: state?.embed_model ?? null,\n // A stored watermark that disagrees with the configured one means every cosine in this index\n // is against a different vector space. Reporting it as \"up\" would be the silent half-migration\n // the indexer refuses at write time.\n embedderUp: state !== undefined && state.embed_model === EMBED_WATERMARK && embeddings > 0,\n hasState: db.hasState,\n lastSleep:\n lastSleep === undefined\n ? null\n : { runId: lastSleep.run_id, status: lastSleep.status, startedAt: lastSleep.started_at }\n }\n })\n\n/** One scalar count, `0` when the table is unreachable. */\nconst countOne = (db: DatabaseShape, sql: string): Effect.Effect<number, StorageFailure> =>\n db.get<{ n: number }>(sql).pipe(Effect.map((row) => row?.n ?? 0))\n\n/** A `GROUP BY` into a record. An absent key means zero, so the caller never reads a null. */\nconst countRows = (\n db: DatabaseShape,\n sql: string\n): Effect.Effect<Readonly<Record<string, number>>, StorageFailure> =>\n db\n .all<{ k: string; n: number }>(sql)\n .pipe(Effect.map((rows) => Object.fromEntries(rows.map((row) => [row.k, row.n]))))\n\n/** Re-exported so the write path's type guard is usable by a caller building tool schemas. */\nexport { isWritableMemoryType }\n","import { MEMORY_RELS } from \"@memhtml/contracts/edges\"\nimport { TASK_STATUSES, WRITABLE_MEMORY_TYPES } from \"@memhtml/contracts/types\"\nimport { REINFORCE_SIGNALS } from \"@memhtml/domain\"\nimport { SLEEP_PHASES } from \"@memhtml/sleep\"\n\nimport { CONFIG_VARS } from \"./config.js\"\nimport { ERROR_CODES, type ResponseType } from \"./envelope.js\"\nimport { AUTHORABLE_RELS } from \"./operations.js\"\n\nexport interface FlagSpec {\n readonly name: string\n readonly type: \"string\" | \"int\" | \"boolean\"\n readonly description: string\n readonly default?: string | number | boolean\n readonly values?: ReadonlyArray<string>\n readonly required?: boolean\n /** True when the flag may be repeated, each occurrence appending a value. */\n readonly repeatable?: boolean\n}\n\nexport interface ArgSpec {\n readonly name: string\n readonly description: string\n readonly required: boolean\n}\n\nexport interface CommandSpec {\n readonly name: string\n readonly summary: string\n readonly args: ReadonlyArray<ArgSpec>\n readonly flags: ReadonlyArray<FlagSpec>\n readonly responseTypes: ReadonlyArray<ResponseType>\n}\n\n/** Flags every command accepts. Listed once so the manifest cannot drift from behavior. */\nexport const GLOBAL_FLAGS: ReadonlyArray<FlagSpec> = [\n {\n name: \"json\",\n type: \"boolean\",\n description: \"Emit the typed JSON envelope on stdout (default; logs go to stderr).\",\n default: true\n },\n {\n name: \"dense\",\n type: \"boolean\",\n description: \"Minify JSON and drop null fields, for pasting into a context window.\",\n default: false\n },\n {\n name: \"repo\",\n type: \"string\",\n description: \"Path to the memory repo. Defaults to $MEMHTML_ROOT.\",\n default: \"\"\n }\n]\n\n/** Flags every retrieval command shares, so `search` and `recall` cannot scope differently. */\nconst SCOPE_FLAGS: ReadonlyArray<FlagSpec> = [\n {\n name: \"type\",\n type: \"string\",\n description: \"Restrict to one memory type. Repeatable; each occurrence broadens (ANY-of).\",\n values: WRITABLE_MEMORY_TYPES,\n repeatable: true\n },\n {\n name: \"workspace\",\n type: \"string\",\n description:\n \"Restrict to one workspace. STRICT: a scoped query never returns a memory with no workspace.\"\n },\n {\n name: \"tag\",\n type: \"string\",\n description: \"Restrict to memories carrying any of these tags. Repeatable; each broadens.\",\n repeatable: true\n },\n {\n name: \"entity\",\n type: \"string\",\n // Singular, unlike --tag, because the scope exists to chain one hop off a hit's own entity list,\n // which is one reference at a time. Same spelling `memhtml list --entity` takes, so the two are\n // one vocabulary rather than two facets that happen to share a word.\n description:\n \"Restrict to memories carrying one `type:name` entity reference, e.g. service:checkout-api, the form a hit's `entities` publishes, so a hop is a copy. A scope matching nothing returns no hits and says so; it never widens.\"\n },\n {\n name: \"include-archived\",\n type: \"boolean\",\n description: \"Include archived memories. Eviction is a `git mv`, so they still exist.\",\n default: false\n },\n {\n name: \"as-of\",\n type: \"string\",\n description:\n \"Point-in-time view: returns what was believed valid at this ISO instant, including since-superseded memories (marked superseded_by). The validity window is coalesce(valid_from, event_at, created_at) <= as-of < valid_until.\"\n }\n]\n\n/**\n * The single source of parsing, validation, and the manifest. A command lands here\n * before it lands anywhere else, so `memhtml manifest` and `memhtml agents-doc` describe\n * what the binary actually accepts rather than what someone remembered to document.\n *\n * A subcommand is one entry with a space in its name (`index rebuild`), not a nested tree.\n * Flattening keeps `nearest()` able to suggest across the whole surface, a typo in the noun\n * (`memhtml indx rebuild`) and a typo in the verb (`memhtml index rebiuld`) both get a candidate, and\n * keeps one table driving parsing, the manifest, and the generated doc.\n */\nexport const COMMANDS: ReadonlyArray<CommandSpec> = [\n {\n name: \"manifest\",\n summary: \"Emit this CLI's full machine-readable contract.\",\n args: [],\n flags: [],\n responseTypes: [\"cli.manifest\"]\n },\n {\n name: \"init\",\n summary: \"Scaffold a memory repo at --repo/$MEMHTML_ROOT: git init, PARA dirs, merge driver.\",\n args: [],\n flags: [],\n responseTypes: [\"repo.init\"]\n },\n {\n name: \"write\",\n summary: \"Write one memory. Content-hash duplicates return the existing path, uncommitted.\",\n args: [],\n flags: [\n {\n name: \"title\",\n type: \"string\",\n description: \"The memory's title. Becomes the <title> and the filename slug.\",\n required: true\n },\n {\n name: \"claim\",\n type: \"string\",\n description:\n \"The one load-bearing sentence. Becomes the <mark> span and files.gist. Exactly one of --claim or --article-html.\"\n },\n {\n name: \"body\",\n type: \"string\",\n description: \"A prose paragraph after the claim. Repeatable, one <p> each.\",\n repeatable: true\n },\n {\n name: \"article-html\",\n type: \"string\",\n description:\n \"Raw <article> markup used verbatim in place of --claim/--body. Must contain exactly one <mark> in the first <p> or <li>; the first <time datetime> becomes the memory's event time. The store refuses format violations before any commit. Exactly one of --claim or --article-html.\"\n },\n {\n name: \"type\",\n type: \"string\",\n description: \"The memory type. `arc` is absent: an arc is synthesized by sleep.\",\n values: WRITABLE_MEMORY_TYPES,\n required: true\n },\n {\n name: \"path\",\n type: \"string\",\n description: \"An explicit path override. Ignored when it is not a valid memory path.\"\n },\n { name: \"workspace\", type: \"string\", description: \"Routes the memory to projects/<slug>/.\" },\n {\n name: \"tag\",\n type: \"string\",\n description: \"A tag. Repeatable; the first one routes an unplaced resource memory.\"\n },\n {\n name: \"entity\",\n type: \"string\",\n description: \"A `type:name` entity reference, e.g. service:checkout-api. Repeatable.\",\n repeatable: true\n },\n {\n name: \"importance\",\n type: \"int\",\n description: \"1-10, a display ordinal. The retention scorer divides by 10.\"\n },\n { name: \"confidence\", type: \"string\", description: \"0-1. 1.0 is an unqualified assertion.\" },\n {\n name: \"session-id\",\n type: \"string\",\n description: \"The Claude Code session. Stamped into the head AND indexed as a link.\"\n },\n { name: \"prompt-id\", type: \"string\", description: \"The prompt within that session.\" },\n { name: \"turn-uuid\", type: \"string\", description: \"The turn within that session.\" }\n ],\n responseTypes: [\"memory.written\"]\n },\n {\n name: \"apply\",\n summary:\n \"Write many memories from a JSONL op stream: ONE commit, ONE index update, per-op results.\",\n args: [],\n flags: [\n {\n name: \"file\",\n type: \"string\",\n description:\n \"The JSONL file to read. One complete JSON object per line. Omit it (or pass `-`) to read the stream from stdin.\"\n },\n {\n name: \"continue-on-error\",\n type: \"boolean\",\n description:\n \"Best-effort: a refused op is reported and skipped while every surviving op lands in the one commit. Atomic by default. The first refused op aborts the batch and nothing is written.\",\n default: false\n },\n {\n name: \"detect-conflicts\",\n type: \"boolean\",\n description:\n \"Report each op's frame-matches as a per-op `conflict`: the ACTIVE memory (or the earlier op) whose claim occupies the same subject-and-relation slot. PROPOSE-ONLY: every op still writes exactly as it would have, because sometimes the contradiction is the answer. You decide: write anyway, `memhtml correct` the match, or drop the line.\",\n default: false\n },\n {\n name: \"consolidate\",\n type: \"string\",\n values: [\"last-wins\"],\n description:\n \"Resolve frame-key matches instead of only reporting them: `--consolidate last-wins` makes the LATER op's value win a shared claim slot (one file, written at the FIRST index that claimed the slot, with each later restatement reporting `consolidated_into` naming that slot) and archives a stored ACTIVE memory a surviving slot displaces, reported as `superseded_path`. Off by default; claims with no frame shape are never consolidated.\"\n },\n {\n name: \"session-id\",\n type: \"string\",\n description:\n \"The Claude Code session for every op that names none. A line's own `session_id` wins over this.\"\n },\n { name: \"prompt-id\", type: \"string\", description: \"The prompt within that session.\" },\n { name: \"turn-uuid\", type: \"string\", description: \"The turn within that session.\" }\n ],\n responseTypes: [\"batch.applied\"]\n },\n {\n name: \"read\",\n summary: \"Read one memory: its metas, links, article, and format warnings.\",\n args: [{ name: \"path\", description: \"Repo-root-relative path to the memory.\", required: true }],\n flags: [\n {\n name: \"session-id\",\n type: \"string\",\n description: \"Records a `read` session link, so provenance is queryable both ways.\"\n }\n ],\n responseTypes: [\"memory.detail\"]\n },\n {\n name: \"search\",\n summary: \"Ranked search: four RRF arms plus MMR. Degrades to the lexical floor.\",\n args: [{ name: \"query\", description: \"Prose. Never a query language.\", required: true }],\n flags: [\n ...SCOPE_FLAGS,\n { name: \"limit\", type: \"int\", description: \"Hits to return.\", default: 10 }\n ],\n responseTypes: [\"memory.hits\"]\n },\n {\n name: \"recall\",\n summary: \"A disclosure pack under a character budget: arcs and memories folded separately.\",\n args: [{ name: \"query\", description: \"Prose.\", required: true }],\n flags: [\n ...SCOPE_FLAGS,\n {\n name: \"budget\",\n type: \"int\",\n description: \"Characters of quoted body. Arcs get their own envelope on top.\",\n default: 16_000\n }\n ],\n responseTypes: [\"recall.pack\"]\n },\n {\n name: \"correct\",\n summary: \"Supersede a memory: write the new file and archive the target in ONE commit.\",\n args: [{ name: \"target\", description: \"The memory being corrected.\", required: true }],\n flags: [\n { name: \"title\", type: \"string\", description: \"The new memory's title.\", required: true },\n {\n name: \"claim\",\n type: \"string\",\n description: \"The corrected claim. Exactly one of --claim or --article-html.\"\n },\n {\n name: \"body\",\n type: \"string\",\n description: \"A prose paragraph. Repeatable.\",\n repeatable: true\n },\n {\n name: \"article-html\",\n type: \"string\",\n description:\n \"Raw <article> markup for the superseding memory, used verbatim in place of --claim/--body. Must contain exactly one <mark> in the first <p> or <li>; the first <time datetime> becomes the memory's event time. The store refuses format violations before any commit. Exactly one of --claim or --article-html.\"\n },\n {\n name: \"type\",\n type: \"string\",\n description: \"The new memory's type. Defaults to the target's.\",\n values: WRITABLE_MEMORY_TYPES\n },\n { name: \"reason\", type: \"string\", description: \"Why the correction was made.\" },\n { name: \"session-id\", type: \"string\", description: \"Records a `corrected` session link.\" }\n ],\n responseTypes: [\"memory.corrected\"]\n },\n {\n name: \"link\",\n summary: \"Add an authored edge to the source file and commit it. Idempotent.\",\n args: [\n { name: \"src\", description: \"The asserting memory or task.\", required: true },\n {\n name: \"rel\",\n // The task rels are authorable here rather than in `memory_link`, because a `blocks` edge\n // between two tasks is a real authored assertion, while a person or provenance rel is minted.\n description: `One of: ${AUTHORABLE_RELS.join(\", \")}. A task rel needs two tasks; a memory rel refuses a task endpoint.`,\n required: true\n },\n { name: \"dst\", description: \"The memory or task being pointed at.\", required: true }\n ],\n flags: [],\n responseTypes: [\"memory.linked\"]\n },\n {\n name: \"neighbors\",\n summary: \"The memory graph around one path, to a fixed depth of at most two hops.\",\n args: [{ name: \"path\", description: \"The center of the neighborhood.\", required: true }],\n flags: [\n { name: \"depth\", type: \"int\", description: \"1 or 2. Never more.\", default: 1 },\n {\n name: \"rel\",\n type: \"string\",\n description: \"Restrict to these rels. Repeatable.\",\n values: MEMORY_RELS,\n repeatable: true\n }\n ],\n responseTypes: [\"memory.neighbors\"]\n },\n {\n name: \"archive\",\n summary: \"Soft-evict: `git mv` into archive/<YYYY>/ with the archive stamps. Never a delete.\",\n args: [{ name: \"path\", description: \"The memory to archive.\", required: true }],\n flags: [{ name: \"reason\", type: \"string\", description: \"Why it was evicted.\", required: true }],\n responseTypes: [\"memory.archived\"]\n },\n {\n name: \"reinforce\",\n summary: \"Bump access bookkeeping, gated by a 900-second per-path cooldown.\",\n args: [\n { name: \"path\", description: \"A memory path. Repeat the argument for more.\", required: true }\n ],\n flags: [\n {\n name: \"signal\",\n type: \"string\",\n description: \"`neutral` bumps access without claiming the memory was right.\",\n values: REINFORCE_SIGNALS,\n default: \"neutral\"\n }\n ],\n responseTypes: [\"memory.reinforced\"]\n },\n {\n name: \"list\",\n summary: \"Page through the corpus by type, workspace, tag, entity, or PARA bucket.\",\n args: [],\n flags: [\n {\n name: \"type\",\n type: \"string\",\n description: \"One memory type.\",\n values: WRITABLE_MEMORY_TYPES\n },\n { name: \"workspace\", type: \"string\", description: \"One workspace.\" },\n { name: \"tag\", type: \"string\", description: \"One tag.\" },\n { name: \"entity\", type: \"string\", description: \"One `type:name` entity reference.\" },\n {\n name: \"para\",\n type: \"string\",\n description: \"One PARA bucket.\",\n values: [\"projects\", \"areas\", \"resources\", \"archive\"]\n },\n { name: \"limit\", type: \"int\", description: \"Rows per page.\", default: 50 },\n {\n name: \"cursor\",\n type: \"string\",\n description: \"The `next_cursor` from the previous page: the last path returned.\"\n },\n {\n name: \"include-archived\",\n type: \"boolean\",\n description: \"Include archived memories.\",\n default: false\n }\n ],\n responseTypes: [\"memory.list\"]\n },\n /**\n * The task family: CRUDL over the 10th memory type, without retrieval.\n *\n * Sugar over the same use cases everything else uses. `task add` is `writeMemory` with\n * `--type task`, and `task status` is one head meta plus (for `done`) the archive machinery. The\n * design intent is that an agent works tasks with `Read`, `Edit`, and `ls` as readily as with these.\n * A task is a file in a directory, and this family exists so the common moves are one call rather\n * than three.\n */\n {\n name: \"task add\",\n summary: \"Open a task: a `task` memory in projects/<ws>/tasks/ or areas/inbox/tasks/.\",\n args: [],\n flags: [\n {\n name: \"title\",\n type: \"string\",\n description: \"What the task is. Becomes the <title> and the filename slug.\",\n required: true\n },\n {\n name: \"claim\",\n type: \"string\",\n description: \"The task statement, as the <mark> span. Defaults to --title.\"\n },\n {\n name: \"body\",\n type: \"string\",\n description: \"A prose paragraph of working notes. Repeatable, one <p> each.\",\n repeatable: true\n },\n {\n name: \"status\",\n type: \"string\",\n description: \"The opening status. `todo` unless you are recording work already underway.\",\n values: TASK_STATUSES,\n default: \"todo\"\n },\n {\n name: \"due\",\n type: \"string\",\n description: \"An ISO date or datetime deadline. Compared as a string, so the form matters.\"\n },\n {\n name: \"workspace\",\n type: \"string\",\n description: \"Routes the task to projects/<slug>/tasks/.\"\n },\n {\n name: \"tag\",\n type: \"string\",\n description: \"A tag. Repeatable; tags scope search but never route a task.\",\n repeatable: true\n },\n {\n name: \"entity\",\n type: \"string\",\n description: \"A `type:name` entity reference. Repeatable.\",\n repeatable: true\n },\n {\n name: \"session-id\",\n type: \"string\",\n description: \"The Claude Code session that opened the task.\"\n },\n { name: \"prompt-id\", type: \"string\", description: \"The prompt within that session.\" },\n { name: \"turn-uuid\", type: \"string\", description: \"The turn within that session.\" }\n ],\n responseTypes: [\"task.written\"]\n },\n {\n name: \"task status\",\n summary: \"Move a task's status. `done` stamps AND archives it, in one commit.\",\n args: [\n { name: \"path\", description: \"The task file.\", required: true },\n { name: \"status\", description: `One of: ${TASK_STATUSES.join(\", \")}.`, required: true }\n ],\n flags: [\n {\n name: \"reason\",\n type: \"string\",\n description: \"Why it closed. Recorded on the archive commit when the status is `done`.\"\n }\n ],\n responseTypes: [\"task.updated\"]\n },\n {\n name: \"task list\",\n summary: \"The task working set: a direct indexed scan with blockers, never ranked retrieval.\",\n args: [],\n flags: [\n {\n name: \"status\",\n type: \"string\",\n description: \"One task status.\",\n values: TASK_STATUSES\n },\n { name: \"workspace\", type: \"string\", description: \"One workspace.\" },\n {\n name: \"due-before\",\n type: \"string\",\n description: \"An ISO date. Returns tasks due strictly before it, by calendar day.\"\n },\n { name: \"limit\", type: \"int\", description: \"Rows per page.\", default: 50 },\n {\n name: \"cursor\",\n type: \"string\",\n description: \"The `next_cursor` from the previous page: the last path returned.\"\n },\n {\n name: \"include-archived\",\n type: \"boolean\",\n description: \"Include finished tasks. `done` archives, so they are otherwise absent.\",\n default: false\n }\n ],\n responseTypes: [\"task.list\"]\n },\n {\n name: \"index rebuild\",\n summary: \"Rebuild index.db from the git tree at HEAD. Destroys nothing outside .memhtml/.\",\n args: [],\n flags: [\n {\n name: \"embed\",\n type: \"boolean\",\n description: \"Fill missing vectors from Bedrock. --no-embed makes the rebuild instant.\",\n default: true\n }\n ],\n responseTypes: [\"index.report\"]\n },\n {\n name: \"index update\",\n summary: \"Index only what moved since the recorded watermark, plus the dirty working tree.\",\n args: [],\n flags: [\n { name: \"embed\", type: \"boolean\", description: \"Fill missing vectors.\", default: true }\n ],\n responseTypes: [\"index.report\"]\n },\n {\n name: \"index status\",\n summary: \"The index watermark, the vector space it was built in, and its row counts.\",\n args: [],\n flags: [],\n responseTypes: [\"index.report\"]\n },\n {\n name: \"trace index\",\n summary: \"Scan $MEMHTML_TRACE_ROOT for Claude Code transcripts, reading only what changed.\",\n args: [],\n flags: [],\n responseTypes: [\"trace.report\"]\n },\n {\n name: \"trace search\",\n summary: \"FTS over session first-prompts and AI titles. Never enters memory retrieval.\",\n args: [{ name: \"query\", description: \"Prose.\", required: true }],\n flags: [\n { name: \"cwd\", type: \"string\", description: \"Restrict to sessions from this directory.\" },\n { name: \"since\", type: \"string\", description: \"ISO-8601 lower bound on started_at.\" },\n { name: \"limit\", type: \"int\", description: \"Sessions to return.\", default: 20 }\n ],\n responseTypes: [\"trace.sessions\"]\n },\n {\n name: \"trace links\",\n summary: \"The memory-session links, from either side.\",\n args: [],\n flags: [\n { name: \"session-id\", type: \"string\", description: \"Every memory this session touched.\" },\n { name: \"path\", type: \"string\", description: \"Every session that touched this memory.\" }\n ],\n responseTypes: [\"trace.links\"]\n },\n {\n name: \"sleep run\",\n summary: \"The nightly curation cycle: 15 phases, each an isolated commit on a review branch.\",\n args: [],\n flags: [\n {\n name: \"date\",\n type: \"string\",\n description: \"The run date, `YYYY-MM-DD`. Defaults to today. Names the branch.\"\n },\n {\n name: \"phases\",\n type: \"string\",\n description: `Comma-separated subset. All 15 by default: ${SLEEP_PHASES.join(\", \")}.`\n },\n {\n name: \"dry-run\",\n type: \"boolean\",\n description: \"Report per-phase counts and commit nothing.\",\n default: false\n }\n ],\n responseTypes: [\"sleep.report\"]\n },\n {\n name: \"sleep resume\",\n summary: \"Re-run only the phases with no Memhtml-Phase trailer on the branch.\",\n args: [{ name: \"run-id\", description: \"The run id, e.g. sleep/2026-08-02.\", required: true }],\n flags: [],\n responseTypes: [\"sleep.report\"]\n },\n {\n name: \"sleep review\",\n summary: \"Per-phase counts, the commit list, diff --stat, and a per-file classification.\",\n args: [{ name: \"run-id\", description: \"The run id.\", required: true }],\n flags: [\n { name: \"diff\", type: \"boolean\", description: \"Include the raw diff.\", default: false }\n ],\n responseTypes: [\"sleep.review\"]\n },\n {\n name: \"sleep merge\",\n summary: \"Fast-forward main to the run's branch, after the discrimination gate passes.\",\n args: [{ name: \"run-id\", description: \"The run id.\", required: true }],\n flags: [\n {\n name: \"skip-gate\",\n type: \"boolean\",\n description:\n \"Merge without re-running discrimination. A deliberate, logged override, never a default.\",\n default: false\n }\n ],\n responseTypes: [\"sleep.merge\"]\n },\n {\n name: \"sleep status\",\n summary: \"The latest sleep run and its per-phase outcomes.\",\n args: [],\n flags: [],\n responseTypes: [\"sleep.report\"]\n },\n {\n name: \"status\",\n summary: \"Corpus health: HEAD, dirty state, counts by type, edges, index freshness.\",\n args: [],\n flags: [],\n responseTypes: [\"status.health\"]\n },\n {\n name: \"publish\",\n summary: \"Regenerate the per-directory index.html listings and sitemap.xml, and commit them.\",\n args: [],\n flags: [],\n responseTypes: [\"publish.report\"]\n },\n {\n name: \"doctor\",\n summary:\n \"Corpus health: dangling hrefs, orphan state rows, inbox depth, vocabulary, staleness.\",\n args: [],\n flags: [\n {\n name: \"fix\",\n type: \"boolean\",\n description:\n \"Repair dangling hrefs and prune orphan access rows. The other findings need a decision.\",\n default: false\n }\n ],\n responseTypes: [\"doctor.report\"]\n },\n {\n name: \"eval discriminate\",\n summary: \"The refusable retrieval gate: every probe must outrank its own wrong-fact twins.\",\n args: [],\n flags: [\n {\n name: \"mode\",\n type: \"string\",\n description:\n \"`fake` is the deterministic embedder CI measures; `live` needs AWS_BEARER_TOKEN_BEDROCK and refuses loudly without it.\",\n values: [\"fake\", \"live\"],\n default: \"fake\"\n },\n {\n name: \"seed\",\n type: \"int\",\n description: \"The fixture corpus seed. A failing run is reproducible from this number.\"\n },\n { name: \"size\", type: \"int\", description: \"Base memories to generate.\", default: 200 },\n {\n name: \"probes\",\n type: \"int\",\n description: \"Probes to run. Design §5 wants ≥30.\",\n default: 36\n },\n {\n name: \"mrr-floor\",\n type: \"string\",\n description: \"Mean-reciprocal-rank floor. Lowering it is a deliberate, visible choice.\",\n default: \"0.85\"\n }\n ],\n responseTypes: [\"eval.discrimination\"]\n },\n /**\n * Code-mode (ROADMAP item 7b): one script, one execution, one envelope.\n *\n * The flag surface answers three questions a script cannot answer for itself, and nothing else.\n *\n * **How does the script arrive?** Three doors, exactly one per call, enforced in `validate` so a\n * wrong combination is exit 2. `--file` for a script under version control, `--script` for the\n * inline one-liner an agent composes, and a bare `memhtml exec` (or `-`) for stdin, which is the same\n * three-door shape and the same `-` spelling `memhtml apply` already uses for its op stream, so an\n * agent that learned one learned both. `--script` rather than a positional argument, because the\n * positional slot on a two-word command is where a run-id or a path goes on every other command\n * here, and a multi-line program in that slot would read as one.\n *\n * **How long may it run?** `--timeout-ms`, bounded and defaulted, because the guest is a QuickJS\n * worker with no reaper of its own and an unbounded script holds the CLI process open. The\n * millisecond unit is in the flag name rather than left to a note, since `--timeout 30` is\n * ambiguous by a factor of a thousand.\n *\n * **Which tree does it see?** `--sha`, defaulting to `HEAD`. Never the live working tree, which is\n * a containment decision rather than a convenience. A mounted `$MEMHTML_ROOT` exposes `.memhtml/index.db`\n * to the guest, whose `sqlite3` reads it happily (probed 2026-08-09: a read-only mount is no barrier\n * to a reader). A gitignored file is absent from a detached worktree, so pinning a commit is what\n * keeps the ranked planes out of reach, and the read-only mount is the second layer rather than\n * the only one. A pin also makes the answer reproducible. `sha` rides back in the envelope, so a\n * rerun is exact.\n *\n * There is deliberately no flag for the guest's own opt-ins. `javascript` is on because `js-exec`\n * is the feature. `python` and `network` are off and unofferable, so no invocation can turn either\n * on. `apps/cli/src/exec.ts` carries the mechanism and the egress probe.\n */\n {\n name: \"exec\",\n summary:\n \"Run a read-only traversal script over the corpus in a sandbox: multi-hop in ONE execution.\",\n args: [],\n flags: [\n {\n name: \"file\",\n type: \"string\",\n description:\n \"The script to run, as a path on the HOST. Omit it (or pass `-`) to read the script from stdin. Mutually exclusive with `--script`.\"\n },\n {\n name: \"script\",\n type: \"string\",\n description:\n \"The script source, inline. Mutually exclusive with `--file` and with reading stdin.\"\n },\n {\n name: \"timeout-ms\",\n type: \"int\",\n description:\n \"Wall-clock bound on the script. Exceeding it is `exitCode` 124 with `timedOut: true`, not an error envelope. Capped at 600000.\",\n default: 30000\n },\n {\n name: \"sha\",\n type: \"string\",\n description:\n \"The commit to mount, materialized as a detached worktree. Defaults to HEAD. Never the live working tree, whose gitignored .memhtml/index.db a worktree omits.\"\n }\n ],\n responseTypes: [\"exec.report\"]\n },\n {\n name: \"state export\",\n summary:\n \"Write .memhtml/state/access.jsonl, the only durable copy of the state plane, and commit.\",\n args: [],\n flags: [],\n responseTypes: [\"state.export\"]\n },\n {\n name: \"state import\",\n summary: \"Replay the committed sidecar into state.db. Counters merge by max, never last-wins.\",\n args: [],\n flags: [],\n responseTypes: [\"state.import\"]\n },\n {\n name: \"agents-doc\",\n summary: \"Regenerate AGENTS.md from this command table. --check fails on drift.\",\n args: [],\n flags: [\n {\n name: \"check\",\n type: \"boolean\",\n description: \"Compare the committed doc to the regenerated one and fail on a difference.\",\n default: false\n },\n { name: \"out\", type: \"string\", description: \"Where to write. Defaults to ./AGENTS.md.\" }\n ],\n responseTypes: [\"agents.doc\"]\n },\n {\n name: \"serve mcp\",\n summary: \"Run the `memhtml-mcp` stdio server: 14 tools and 2 resources over this same repo.\",\n args: [],\n flags: [],\n responseTypes: [\"serve.exit\"]\n }\n]\n\nexport const COMMAND_NAMES = COMMANDS.map((command) => command.name)\n\n/** One prose block of the manifest's guide: a topic key an agent can cite, and the prose. */\nexport interface GuideBlock {\n readonly topic: string\n readonly body: string\n}\n\n/**\n * The example op line, quoted verbatim into the `when-to-batch` block.\n *\n * A constant rather than a literal inside the prose, because a test parses it. An example an agent\n * copies has to be valid JSONL, and it stays valid because the doc and the parser read the\n * same bytes. A prose-only example drifts silently the first time a field is renamed.\n */\nexport const GUIDE_OP_EXAMPLE =\n '{\"op\":\"write\",\"title\":\"One writer and many readers share the index\",\"type\":\"semantic\",\"body\":\"WAL admits a single writer at a time and any number of concurrent readers, so a CLI command and a running `memhtml serve mcp` can work against one store.\",\"tag\":\"infra\"}'\n\n/**\n * The guide: what an agent reads on its first call, before it has written anything.\n *\n * Prose, in a structured field, authored here beside `COMMANDS`, which is the design (spec\n * D8/G6). The manifest carries it on a bare `memhtml`, `memhtml help`, `memhtml --help`, and `memhtml manifest`, and\n * `memhtml agents-doc` renders these same strings into `AGENTS.md`, so the doc and the live answer cannot\n * disagree. Prose kept in a separate Markdown file would be a second copy that drifts, and prose kept\n * only in `AGENTS.md` would be invisible to an agent that never opens the repo.\n *\n * Written for an LLM agent mid-task rather than for an operator browsing: complete sentences, action\n * first, and every claim true of this build rather than of the design. A guide that describes an\n * intention is worse than no guide, because an agent acts on it.\n */\nexport const GUIDE: ReadonlyArray<GuideBlock> = [\n {\n topic: \"first-call\",\n body:\n \"You are reading this CLI's manifest: every command, argument, flag, response type, error code, \" +\n \"and environment variable the binary accepts. A bare `memhtml`, `memhtml help`, `memhtml --help`, and \" +\n \"`memhtml manifest` all return it, and all four answer on a machine with no repo, no database, and \" +\n \"no credentials, so this is also the liveness check when something else has failed. \" +\n \"Every command writes exactly ONE JSON envelope to stdout and nothing else; logs go to stderr. \" +\n \"A success is `{apiVersion, type, data}` and a failure is `{apiVersion, error, code, suggestions}`. \" +\n \"Branch on `code`, never on the `error` prose: the codes and response types are append-only and a \" +\n \"shipped one never changes meaning, while the prose changes freely as wording improves. \" +\n \"Exit 0 is success, exit 2 is a usage error you fix by changing the call, exit 1 is a runtime \" +\n \"failure you fix by changing the repo or the environment. Add `--dense` to any command to get \" +\n \"minified JSON with null fields dropped, which is what you want when the output goes into a prompt.\"\n },\n {\n topic: \"write-surfaces\",\n body:\n \"There are three ways to put a memory into the corpus, and they are all legitimate. \" +\n \"First, this CLI: `memhtml write` for one memory, `memhtml apply` for many. \" +\n \"Second, the MCP server: `memhtml serve mcp` speaks stdio with 14 tools and 2 resources over this \" +\n \"same repo, and it is the door to use when you are already an MCP client. \" +\n \"Third, editing files under $MEMHTML_ROOT directly with your normal file tools: the git tree IS the \" +\n \"system of record and `.memhtml/index.db` is only a projection of it, so a hand-written or hand-edited \" +\n \"memory file is as real as one this CLI wrote. `memhtml index update` projects uncommitted working-tree \" +\n \"changes as well as committed ones, so a dirty edit is searchable before you commit it. \" +\n \"What you take on by editing directly is everything the write path would have done for you: the \" +\n \"file must satisfy the format (run `memhtml doctor`, and `memhtml read <path>` reports per-file format \" +\n \"warnings), you own choosing a path that does not collide, you own noticing that the content \" +\n \"already exists somewhere else, and you own the commit. The nightly `memhtml sleep run` refuses to \" +\n \"start on a dirty tree, so an uncommitted edit blocks curation until it is committed or stashed. \" +\n \"A CLI command and a running `memhtml serve mcp` may share one store: the index is WAL SQLite, \" +\n \"which admits one writer at a time and any number of concurrent readers, so a second writer \" +\n \"waits its turn rather than failing. The one thing to keep clear of is `memhtml sleep run`, and \" +\n \"for a git reason rather than a database one: a run holds a checked-out `sleep/<date>` branch, \" +\n \"so a write landing during it commits onto that branch and is merged as if it were curation or \" +\n \"lost when the branch is dropped.\"\n },\n {\n topic: \"when-to-batch\",\n body:\n \"Writing more than about three memories in one task? Call `memhtml apply` once with a JSONL op stream \" +\n \"instead of running `memhtml write` N times. A batch stages every file, makes ONE commit, and \" +\n \"reindexes ONCE, where N separate writes make N commits and pay N index passes over N diffs. \" +\n \"Pass the stream as `memhtml apply --file ops.jsonl`, or pipe it: `memhtml apply -` and a bare `memhtml apply` \" +\n \"both read stdin. One complete JSON object per line, no wrapping array, no pretty-printing. A \" +\n \"line looks like this:\\n\" +\n `${GUIDE_OP_EXAMPLE}\\n` +\n \"`op` is `write` (the only verb in the vocabulary today), `title` and `type` are required, and each \" +\n \"op carries the same optional fields `memhtml write` takes, in snake_case: `path`, `workspace`, `tag`, \" +\n \"`entity`, `importance`, `confidence`, `session_id`, `prompt_id`, `turn_uuid`. \" +\n \"The whole file is validated for shape before ANY op executes, so a malformed line 7 is exit 2 \" +\n \"naming line 7 with nothing written. A failed apply costs you nothing but the call. \" +\n \"You get one result per op in INPUT ORDER, each naming its own `index`, so you can match results \" +\n \"back to the lines you sent. \" +\n \"A batch is ATOMIC by default: the first refused op aborts the whole batch, no file is written, no \" +\n \"commit is made, and the surviving ops report `skipped: true`. Pass `--continue-on-error` for \" +\n \"best-effort instead, and a refused op comes back as one failed result carrying its own `code` and \" +\n \"`error` while every op that succeeded lands in the one commit. \" +\n \"A duplicate is never an error: an op whose exact content is already stored comes back `ok: true` \" +\n \"with `deduped: true` and the existing path, so re-applying a file you already applied is safe and \" +\n \"writes nothing. `commit_sha` is null exactly when nothing was committed: a batch that only \" +\n \"deduped, or one that aborted.\"\n },\n {\n topic: \"conflicts\",\n body:\n \"Pass `--detect-conflicts` to `memhtml apply` and each result gains a `conflict` field naming what \" +\n \"that op's claim contradicts. Dedupe catches an op whose content is IDENTICAL to something stored; \" +\n \"this catches an op that says something DIFFERENT about the same thing, the case dedupe is blind \" +\n \"to and the one that actually rots a corpus. \" +\n \"The match is grammatical, not semantic: a claim is split into a frame (the subject and relation, \" +\n \"up to its last `of`/`is`/`in`/`to`/`by`/`as`) and a value, and two claims conflict when they share \" +\n \"a frame. `The pool ceiling is 64` and `The pool ceiling is 128` share `the pool ceiling is`. \" +\n \"`conflict.path` names an ACTIVE memory already holding that slot; `conflict.batch_index` names an \" +\n \"EARLIER op in this same call, which is the case nothing else can see because neither op is stored \" +\n \"yet; `conflict.claim` is the other claim's own text, so you can decide without a second read. \" +\n \"It is null when nothing matched, and also when the claim has no frame shape. The rule refuses \" +\n \"frames under three tokens and values over six, so short claims and claims trailed by a clause are \" +\n \"deliberately unmatched rather than loosely matched. On a line using `article_html` instead of \" +\n \"`body` it is always null, because the claim lives inside your markup and is not read until the \" +\n \"store renders it. \" +\n \"THE ASSIST NEVER CHANGES WHAT IS WRITTEN. An op carrying a conflict is written exactly as it \" +\n \"would have been without the flag: nothing is archived, nothing is refused, and later does not win. \" +\n \"That is deliberate, because sometimes the contradiction IS the answer. A memory recording that a \" +\n \"runbook step changed necessarily contradicts the memory stating the old step, and a system that \" +\n \"resolved that for you would delete the pair a reader needs in order to see the change at all. \" +\n \"You decide per conflict: keep both (they are about different things, or both are true), \" +\n \"`memhtml correct <path>` instead (the new claim supersedes the old one, and the old one stays readable \" +\n \"under archive/), or drop the line (you were about to restate something already stored). \" +\n \"Archived memories never match, so a superseded claim stops contradicting the claim that superseded it.\\n\" +\n \"When you have already decided that later wins (a re-scrape, a settings sync, any stream where \" +\n \"each line is the newest statement of its slot), pass `--consolidate last-wins` (the batch tool's \" +\n '`consolidate: \"last-wins\"`) and the batch RESOLVES those matches instead of reporting them. ' +\n \"Ops sharing a frame key write ONE file carrying the LATER value at the FIRST index that claimed \" +\n \"the slot; each later restatement reports `consolidated_into` naming that slot and the summary \" +\n \"counts it under `consolidated`, neither written nor failed. A stored ACTIVE memory occupying a \" +\n \"surviving slot is archived with a supersedes link from the new file, its archive path reported \" +\n \"as `superseded_path`, the same chain `memhtml correct` leaves, so ancestry reads identically. \" +\n \"OFF by default, and the key is the conflict rule's own: the frame split is a rule measured in \" +\n \"the eval harness before it was believed and ported verbatim into `@memhtml/domain`'s frame.ts, \" +\n \"which detection and consolidation share, so anything the rule refuses to key (short frames, \" +\n \"clause values) is never consolidated, and what you saw reported with `--detect-conflicts` is \" +\n \"exactly what this flag would have acted on.\\n\" +\n \"Every supersede, `memhtml correct` and `--consolidate last-wins` alike, also stamps a VALIDITY \" +\n \"WINDOW, in the same one commit. The superseded memory gains `memhtml-valid-until` set to the \" +\n \"moment the new fact became true (the winner's own `memhtml-valid-from`, else its first \" +\n \"`<time datetime>`, else the operation's instant), and the winner gains `memhtml-valid-from` at \" +\n \"that same moment, so one window closes exactly where the next opens. Min-wins: a memory \" +\n \"already stating an EARLIER `memhtml-valid-until` keeps it, because a fact cannot outlive its \" +\n \"earliest stated bound. That is what `--as-of` on `memhtml search` reads: pass an ISO instant and \" +\n \"the result is what was believed valid AT THAT MOMENT. Since-superseded memories return, each \" +\n \"marked `superseded_by` naming what replaced it, and facts not yet valid then are absent. \" +\n \"History is read from the files, not replayed from git, so it survives a full index rebuild.\"\n },\n {\n topic: \"authoring\",\n body:\n \"Every write authors the article in exactly one of two ways, and supplying both or neither is \" +\n \"refused. Either you write prose and the template owns the markup (`--claim` is the one \" +\n \"load-bearing sentence and becomes the `<mark>` claim span and `files.gist`, and each `--body` \" +\n \"is one paragraph after it) or you supply `--article-html` and own the markup yourself. \" +\n \"On a `memhtml apply` line the prose form is the `body` field, whose first sentence becomes the claim, \" +\n \"and the markup form is `article_html`. \" +\n \"When you supply markup you own two constraints. It must contain EXACTLY ONE `<mark>`, and that \" +\n \"`<mark>` must sit in the article's first `<p>` or `<li>` and not inside an `<aside>` or \" +\n \"`<details>`. The claim leads the article and is never a caveat or behind a fold. And the first \" +\n \"`<time datetime>` in your markup becomes the memory's event time, which is what recency ranks \" +\n \"on, so a memory about something that happened last year should say so rather than being ranked \" +\n \"as today's news. \" +\n \"Markup is checked before anything is written: the store renders your article, runs the format \" +\n \"check, and refuses with the list of violations before it creates a file, stages it, or commits. \" +\n \"A refused write leaves the tree byte-identical, so a failed attempt costs nothing and you can fix \" +\n \"the markup and retry. \" +\n \"Code goes in the prose path as a fenced block: a body paragraph that is entirely a ``` fence \" +\n \"becomes <figure><pre><code>, whitespace preserved verbatim, and the fence's info string \" +\n \"(```ts) is stamped as data-lang and promoted to a `lang:ts` entity, so `memhtml list --entity \" +\n \"lang:ts` finds every memory carrying TypeScript. A blank line inside a fence does NOT split \" +\n 'paragraphs. On the markup path write the same <figure><pre><code data-lang=\"ts\"> yourself; ' +\n \"never `class` (forbidden) and never `lang=` (that attribute names human languages).\"\n },\n {\n topic: \"code-mode\",\n body:\n \"Answering a question that takes MORE THAN ONE HOP through the corpus? Write it as a script and \" +\n \"run `memhtml exec` once, instead of spending a tool call per hop. Supersedence ancestry, live \" +\n \"contradiction pairs, orphan census, entity co-occurrence, 'which of these 40 paths has no \" +\n \"backlink': each of those is one traversal in code and N round trips through `memhtml read` and \" +\n \"`memhtml neighbors`. Measured on a 305-file corpus: a full census in 598ms, and 410 edges resolved \" +\n \"into 201 chains, longest 8 hops, in one execution at 430ms. \" +\n \"The script runs under QuickJS in a sandbox with the corpus mounted READ-ONLY at `/mnt/memhtml`, and \" +\n \"a helper is already seeded for you at `/workspace/lib/corpus.mjs`. Import it: \" +\n '`import { corpus, backlinks, chain, edges } from \"/workspace/lib/corpus.mjs\"`. `corpus()` ' +\n \"returns a Map keyed by root-absolute path (the SAME string an edge's href holds, so \" +\n \"`memories.get(link.href)` resolves with no path juggling) and each value carries `claim`, \" +\n \"`memoryType`, `status`, `tags`, `entities`, `links`, `facets`, `citations`, `eventAt`, and a \" +\n \"`document` escape hatch for any selector the fields do not cover. \" +\n \"Print your answer as JSON on stdout with `console.log`; it comes back verbatim in `data.stdout`, \" +\n \"so keep it small and structured rather than dumping the corpus. \" +\n \"THREE THINGS IT CANNOT DO, by design. It cannot write: the corpus is read-only and a write \" +\n \"answers EROFS, so every write still goes through `memhtml write` / `memhtml apply`, which own commits, \" +\n \"dedup, and conflict detection. It cannot rank: no cosine, no RRF, no salience, and no index \" +\n \"database. For ranked retrieval shell out to `memhtml search --json` and parse its envelope, which \" +\n \"the one-envelope-per-command contract already makes a code-mode API. And it cannot reach the \" +\n \"network: there is no curl and the guest's `fetch` refuses on call. \" +\n \"The intended opening move is ranked retrieval FIRST, code-mode second: `memhtml search` or \" +\n \"`memhtml recall` to get the handful of paths the ranking stack says matter, then `memhtml exec` to walk, \" +\n \"join, count, and filter from there. Starting in code-mode means starting with a full-corpus scan \" +\n \"and no relevance signal. \" +\n \"A non-zero `exitCode` in the response is YOUR script failing, not the command failing. Read \" +\n \"`data.stderr` for the diagnostic and the exit code is still 0. A script that runs past \" +\n \"`--timeout-ms` (default 30000) comes back `exitCode: 124` with `timedOut: true`. \" +\n \"The tree you get is a pinned commit, HEAD by default, named in `data.sha`, so an answer is \" +\n \"reproducible with `--sha`, and an uncommitted edit is NOT visible to the script.\"\n }\n]\n\nexport const GUIDE_TOPICS = GUIDE.map((block) => block.topic)\n\n/**\n * Derived from `COMMANDS` and `GLOBAL_FLAGS` by walking them, so adding a flag\n * updates the manifest automatically. A hand-written manifest drifts the first\n * time someone adds a flag and forgets to edit it.\n */\nexport const buildManifest = () => ({\n name: \"memhtml\",\n version: \"0.2.5\", // x-release-please-version\n summary: \"Read, write, and curate the git-backed memory repo.\",\n apiVersion: \"1\",\n /**\n * The prose an agent needs before the command table means anything, so it is listed before it.\n * A manifest that opened with 33 command specifications makes an agent infer the workflow from a\n * surface, while `guide` states it.\n */\n guide: GUIDE,\n globalFlags: GLOBAL_FLAGS,\n errorCodes: ERROR_CODES,\n config: CONFIG_VARS,\n responseTypes: [...new Set(COMMANDS.flatMap((command) => command.responseTypes))],\n commands: COMMANDS.map((command) => ({\n name: command.name,\n summary: command.summary,\n args: command.args,\n flags: command.flags,\n responseTypes: command.responseTypes,\n supportsJson: true,\n supportsDense: true\n }))\n})\n","import { readFile, writeFile } from \"node:fs/promises\"\nimport { resolve } from \"node:path\"\n\nimport { InvalidMemory, StorageFailure } from \"@memhtml/contracts/errors\"\nimport { Effect } from \"effect\"\n\nimport { COMMANDS, GLOBAL_FLAGS, GUIDE } from \"./commands.js\"\nimport { CONFIG_VARS } from \"./config.js\"\nimport { API_VERSION, ERROR_CODES, EXIT_OK, EXIT_RUNTIME, EXIT_USAGE } from \"./envelope.js\"\n\n/**\n * `AGENTS.md`, generated from the same `COMMANDS` array that drives parsing.\n *\n * Generated rather than written, so the doc cannot describe a flag the binary does not accept. A test\n * checks the committed file against a fresh render, and `memhtml agents-doc --check` runs the same\n * comparison as a command, so the drift is catchable in CI and fixable in one call.\n *\n * The rendering is deterministic to the byte: no timestamp, no version of anything but the CLI\n * itself, no iteration over an unordered structure. A generator whose output moved on every run\n * would make the drift check useless.\n */\n\n/** Where the doc lives by default: the repo root, next to `package.json`. */\nexport const AGENTS_DOC_PATH = \"AGENTS.md\"\n\nconst escapeCell = (text: string): string => text.replaceAll(\"|\", \"\\\\|\")\n\nconst flagCell = (flags: ReadonlyArray<{ readonly name: string; readonly required?: boolean }>) =>\n flags.length === 0\n ? \"—\"\n : flags\n .map((flag) => (flag.required === true ? `\\`--${flag.name}\\`*` : `\\`--${flag.name}\\``))\n .join(\" \")\n\nconst argCell = (args: ReadonlyArray<{ readonly name: string; readonly required: boolean }>) =>\n args.length === 0\n ? \"—\"\n : args.map((arg) => (arg.required ? `<${arg.name}>` : `[${arg.name}]`)).join(\" \")\n\n/**\n * The guide blocks as Markdown, each under its own topic heading.\n *\n * The topic is the heading and it is code-quoted, so the key an agent reads from\n * `memhtml manifest`'s `guide[].topic` is greppable in this file. The two projections of one array\n * must name their blocks identically, or the reader cannot cross-reference them.\n *\n * A body line beginning with `{` becomes a fenced JSON block. The `when-to-batch` block carries an\n * example op line an agent copies, and that example is only useful if it survives the trip through\n * Markdown unwrapped and unescaped. The rule is derived from the content's own shape rather than\n * from a per-block flag, so a second example added to a second block needs no edit here.\n */\nconst guideLines = (): ReadonlyArray<string> => {\n const lines: Array<string> = [\"## Guide\", \"\"]\n for (const block of GUIDE) {\n lines.push(`### \\`${block.topic}\\``)\n lines.push(\"\")\n for (const paragraph of block.body.split(\"\\n\")) {\n if (paragraph.startsWith(\"{\")) {\n lines.push(\"```json\")\n lines.push(paragraph)\n lines.push(\"```\")\n } else {\n lines.push(paragraph)\n }\n lines.push(\"\")\n }\n }\n return lines\n}\n\n/** The whole document, as bytes. */\nexport const renderAgentsDoc = (): string => {\n const lines: Array<string> = []\n\n lines.push(\"<!-- Generated by `memhtml agents-doc`. Edit `apps/cli/src/commands.ts` instead. -->\")\n lines.push(\"\")\n lines.push(\"# `memhtml` — agent instructions\")\n lines.push(\"\")\n lines.push(\n \"`memhtml` is the CLI over a git-backed memory repo. Every command writes exactly ONE JSON envelope\"\n )\n lines.push(\"to stdout and nothing else; logs go to stderr.\")\n lines.push(\"\")\n lines.push(\"## The envelope\")\n lines.push(\"\")\n lines.push(\"```json\")\n lines.push(`{ \"apiVersion\": \"${API_VERSION}\", \"type\": \"<response type>\", \"data\": { } }`)\n lines.push(\"```\")\n lines.push(\"\")\n lines.push(\"A failure is a different shape, and `code` is what you branch on:\")\n lines.push(\"\")\n lines.push(\"```json\")\n lines.push(\n `{ \"apiVersion\": \"${API_VERSION}\", \"error\": \"<prose>\", \"code\": \"<ERROR_CODE>\", \"suggestions\": [\"<command>\"] }`\n )\n lines.push(\"```\")\n lines.push(\"\")\n lines.push(\n \"Never branch on the `error` string — it changes freely as wording improves. `code` and `type`\"\n )\n lines.push(\"are append-only: a shipped value never changes meaning and is never removed.\")\n lines.push(\"\")\n lines.push(\n `Exit codes: **${EXIT_OK}** success, **${EXIT_USAGE}** usage error (unknown command, bad flag,`\n )\n lines.push(`missing argument), **${EXIT_RUNTIME}** runtime failure.`)\n lines.push(\"\")\n lines.push(\"## Start here\")\n lines.push(\"\")\n lines.push(\n \"`memhtml manifest` is the first call to make. It answers with every command, argument, flag,\"\n )\n lines.push(\n \"response type, and error code this binary accepts — and it answers on a machine with no repo,\"\n )\n lines.push(\"no database, and no credentials, so it is also the liveness check.\")\n lines.push(\"\")\n /**\n * The guide goes before the command table, because it is what makes the table mean something. The\n * three write doors, when to batch, and the authoring XOR are decisions an agent makes before it\n * picks a command. Rendered from the same `GUIDE` array `memhtml manifest` returns, so an agent that\n * read the doc and an agent that called the binary got the same words.\n */\n lines.push(...guideLines())\n lines.push(\"## Global flags\")\n lines.push(\"\")\n lines.push(\"| Flag | Type | Default | Meaning |\")\n lines.push(\"|---|---|---|---|\")\n for (const flag of GLOBAL_FLAGS) {\n lines.push(\n `| \\`--${flag.name}\\` | ${flag.type} | ${flag.default === \"\" ? \"—\" : String(flag.default)} | ${escapeCell(flag.description)} |`\n )\n }\n lines.push(\"\")\n lines.push(\"## Commands\")\n lines.push(\"\")\n lines.push(\"`<required>` `[optional]`; a flag marked `*` is required.\")\n lines.push(\"\")\n lines.push(\"| Command | Arguments | Flags | Response type |\")\n lines.push(\"|---|---|---|---|\")\n for (const command of COMMANDS) {\n lines.push(\n `| \\`memhtml ${command.name}\\` | ${argCell(command.args)} | ${flagCell(command.flags)} | ${command.responseTypes.map((type) => `\\`${type}\\``).join(\", \")} |`\n )\n }\n lines.push(\"\")\n\n for (const command of COMMANDS) {\n lines.push(`### \\`memhtml ${command.name}\\``)\n lines.push(\"\")\n lines.push(command.summary)\n lines.push(\"\")\n if (command.args.length > 0) {\n for (const arg of command.args) {\n lines.push(\n `- \\`${arg.required ? `<${arg.name}>` : `[${arg.name}]`}\\` — ${escapeCell(arg.description)}`\n )\n }\n lines.push(\"\")\n }\n if (command.flags.length > 0) {\n for (const flag of command.flags) {\n const suffix = [\n flag.required === true ? \"**required**\" : undefined,\n flag.repeatable === true ? \"repeatable\" : undefined,\n flag.default === undefined ? undefined : `default \\`${String(flag.default)}\\``,\n flag.values === undefined\n ? undefined\n : `one of: ${flag.values.map((value) => `\\`${value}\\``).join(\", \")}`\n ]\n .filter((part) => part !== undefined)\n .join(\"; \")\n lines.push(\n `- \\`--${flag.name}\\` (${flag.type}) — ${escapeCell(flag.description)}${suffix === \"\" ? \"\" : ` _(${suffix})_`}`\n )\n }\n lines.push(\"\")\n }\n }\n\n lines.push(\"## Error codes\")\n lines.push(\"\")\n for (const code of ERROR_CODES) lines.push(`- \\`${code}\\``)\n lines.push(\"\")\n lines.push(\"## Configuration\")\n lines.push(\"\")\n lines.push(\"| Variable | Default | Meaning |\")\n lines.push(\"|---|---|---|\")\n for (const variable of CONFIG_VARS) {\n lines.push(\n `| \\`${variable.name}\\` | ${variable.fallback === null ? \"—\" : `\\`${variable.fallback}\\``} | ${escapeCell(variable.description)} |`\n )\n }\n lines.push(\"\")\n\n return `${lines.join(\"\\n\")}\\n`\n}\n\n/** What a generate-or-check pass produced. */\nexport interface AgentsDocResult {\n readonly path: string\n readonly bytes: number\n /** True when the file on disk already matched. `--check` fails when this is false. */\n readonly inSync: boolean\n /** True when this call wrote the file. False under `--check`, which never writes. */\n readonly written: boolean\n}\n\n/**\n * Write the doc, or compare it and fail on drift.\n *\n * `--check` is the CI form and it writes nothing. A check that fixed the drift it found would make\n * a green pipeline out of an uncommitted change.\n */\nexport const runAgentsDoc = (options: {\n readonly check: boolean\n readonly out?: string | undefined\n}): Effect.Effect<AgentsDocResult, InvalidMemory | StorageFailure> =>\n Effect.gen(function* () {\n const path = resolve(options.out ?? AGENTS_DOC_PATH)\n const rendered = renderAgentsDoc()\n\n const existing = yield* Effect.tryPromise({\n try: () => readFile(path, \"utf8\"),\n catch: () => null\n }).pipe(Effect.orElseSucceed(() => null))\n\n const inSync = existing === rendered\n\n if (options.check) {\n if (!inSync) {\n return yield* Effect.fail(\n InvalidMemory.make({\n reason:\n existing === null\n ? `${path} is missing; run \\`memhtml agents-doc\\``\n : `${path} is out of date; run \\`memhtml agents-doc\\``\n })\n )\n }\n return { path, bytes: rendered.length, inSync, written: false }\n }\n\n if (inSync) return { path, bytes: rendered.length, inSync, written: false }\n\n yield* Effect.tryPromise({\n try: () => writeFile(path, rendered, \"utf8\"),\n catch: () => StorageFailure.make({ operation: `agents-doc.write:${path}` })\n })\n return { path, bytes: rendered.length, inSync: false, written: true }\n })\n","/**\n * Prose → claim derivation: the single implementation both write doors use.\n *\n * The tools take `{title, body}` because that is what a model produces, and the format needs a\n * `<mark>` claim plus one `<p>` per paragraph. Turning the first into the second is a text heuristic,\n * and it lives here for two reasons. It was duplicated once, as `claimOf`/`restOf` in `apps/mcp` and\n * `claimFromProse`/`proseTail` in `apps/cli`, the same regex in two packages. A sentence-splitting\n * rule that drifts between the doors also makes `memhtml apply` and `memory_write_batch` derive different\n * claims from the same body, so the gist of a memory would depend on which door wrote it.\n *\n * It does not live in `@memhtml/html`, which owns markup and the format's own rules. \"Where does a\n * sentence end\" is a guess about natural-language prose, and the format states no such constraint. It\n * is not in `operations.ts` either, because that module holds the use cases both doors call, and this\n * is a text helper they apply before calling one.\n *\n * The derivation is defense in depth now; it was once the only guard. `@memhtml/html` constraint 1 now\n * rejects an empty `<mark>` outright, so a door that skipped this would be stopped by the store's\n * render gate instead of landing a file with an empty `files.gist`. What is left here is the\n * authoring convenience the doors exist to provide: a JSONL line and an MCP call carry no `claim`\n * field, so the door derives one instead of asking an author to restate the body's first sentence.\n */\n\nimport { closesFence, fenceOpeningOf } from \"@memhtml/html\"\n\n/**\n * Split prose into paragraphs on blank lines, dropping the empties. Inside a fenced code block a\n * blank line is content, so the split skips it there. Without that carve-out, a snippet containing a\n * blank line splits into two paragraphs, neither of which is a complete fence, and both land as\n * escaped backtick text instead of the `<figure><pre><code>` an intact fence renders as.\n *\n * The fence grammar comes from `@memhtml/html` (`fenceOpeningOf`/`closesFence`) rather than a second\n * copy here. The splitter deciding \"this is one block\" and the template deciding \"this is a fence\"\n * must be the same judgment, or the doors drift the way the claim derivation once did.\n */\nconst paragraphsOf = (prose: string): ReadonlyArray<string> => {\n const parts: Array<Array<string>> = [[]]\n let opening: string | undefined\n for (const line of prose.split(\"\\n\")) {\n const current = parts.at(-1) as Array<string>\n if (opening === undefined && line.trim() === \"\") {\n if (current.length > 0) parts.push([])\n continue\n }\n current.push(line)\n if (opening === undefined) {\n opening = fenceOpeningOf(line)\n } else if (closesFence(line, opening)) {\n opening = undefined\n }\n }\n return parts.map((lines) => lines.join(\"\\n\").trim()).filter((part) => part !== \"\")\n}\n\n/**\n * The claim: the first sentence of the prose.\n *\n * The first sentence is where a model puts the assertion. Taking the title instead would make every\n * gist a restatement of the filename, which is the one thing a Tier-1 disclosure line must not be.\n * Prose with no sentence terminator is its own claim in full. A fragment is still an assertion, and\n * rejecting it would reject the shortest legitimate memory there is.\n */\nexport const claimFromProse = (prose: string): string => {\n const trimmed = prose.trim()\n const match = /^(.*?[.!?])(\\s|$)/s.exec(trimmed)\n return (match?.[1] ?? trimmed).trim()\n}\n\n/**\n * The prose after the claim, as paragraphs. Empty when the claim was the whole body.\n *\n * The first element becomes the claim paragraph's own tail rather than a second `<p>`, which is\n * `articleHtmlFor`'s contract in `@memhtml/html`'s template. A one-paragraph body therefore yields\n * exactly one `<p>` with the `<mark>` inside it, which is what constraint 1 requires.\n */\nexport const proseTail = (prose: string): ReadonlyArray<string> => {\n const remainder = prose.trim().slice(claimFromProse(prose).length).trim()\n return remainder === \"\" ? [] : paragraphsOf(remainder)\n}\n","import { readFile } from \"node:fs/promises\"\n\nimport { type ErrorCode, type Failure, fail } from \"./envelope.js\"\nimport type { BatchOpReport, BatchWriteResult, WriteParams } from \"./operations.js\"\nimport { claimFromProse, proseTail } from \"./prose.js\"\n\n/**\n * `memhtml apply`'s own layer: JSONL text in, decoded ops or a usage failure out.\n *\n * Separated from `run.ts` because everything here is a decision about one untrusted text format, and\n * because AC-6-4's contract is that the whole file is judged before any op executes. That makes\n * this a pure function from text to either an op list or a refusal, testable without a repo.\n *\n * The refusals are `Failure` values rather than thrown errors for the reason `validate` returns one:\n * the exit code is the contract. A usage error is exit 2 and a runtime error is exit 1, and a\n * malformed line is a usage error, because the caller wrote a bad file and the corpus is fine.\n */\n\n/**\n * The op vocabulary, v1.\n *\n * Writes only, per spec D4. `op` is carried on the wire anyway so v2 can add `correct`/`link`/\n * `archive` without a format break. An unknown value is refused with this list attached rather than\n * ignored, because a file of `{\"op\":\"wrote\",…}` lines that applied nothing and exited 0 is the silent\n * failure the whole pre-validation pass exists to prevent.\n */\nexport const APPLY_OPS: ReadonlyArray<string> = [\"write\"]\n\n/**\n * Every field a line may carry, mapped to the `WriteParams` field it becomes.\n *\n * A table rather than a hand-written decode, so the snake_case → camelCase rename is stated once and\n * the unknown-field check below is derived from it. The MCP tool's parameters use exactly these\n * snake_case names (`apps/mcp/src/tools.ts`), so an agent that learned the field names from one door\n * can write a JSONL file for the other without translating.\n */\nconst SCALAR_FIELDS = {\n title: \"title\",\n type: \"memoryType\",\n body: \"body\",\n article_html: \"articleHtml\",\n path: \"path\",\n workspace: \"workspace\",\n importance: \"importance\",\n confidence: \"confidence\",\n session_id: \"sessionId\",\n prompt_id: \"promptId\",\n turn_uuid: \"turnUuid\",\n status: \"taskStatus\",\n due: \"dueAt\"\n} as const\n\n/** Fields that accept a string or an array of strings, and always become an array. */\nconst LIST_FIELDS = { tag: \"tags\", tags: \"tags\", entity: \"entities\", entities: \"entities\" } as const\n\n/** `op` is the discriminator rather than a `WriteParams` field, so it is legal and never mapped. */\nconst KNOWN_FIELDS: ReadonlySet<string> = new Set([\n \"op\",\n ...Object.keys(SCALAR_FIELDS),\n ...Object.keys(LIST_FIELDS)\n])\n\n/** A usage failure naming the offending line, 1-based as a text editor counts. */\nconst lineError = (\n code: ErrorCode,\n line: number,\n reason: string,\n suggestions: ReadonlyArray<string> = []\n): Failure => fail(code, `${APPLY_DOC}: line ${line}: ${reason}`, suggestions)\n\n/** The prefix every apply refusal carries, so a caller can tell a file error from a corpus error. */\nconst APPLY_DOC = \"memhtml apply\"\n\n/** One line's parsed JSON as a record, or the refusal. */\nconst objectAt = (text: string, line: number): Record<string, unknown> | Failure => {\n let value: unknown\n try {\n value = JSON.parse(text)\n } catch (error) {\n return lineError(\n \"ERR_INVALID_FLAG\",\n line,\n `not valid JSON (${error instanceof Error ? error.message : String(error)}). Every line is one complete JSON object; a pretty-printed object spanning several lines is not JSONL`,\n [\n 'memhtml apply --file ops.jsonl, one object per line: {\"op\":\"write\",\"title\":\"…\",\"type\":\"semantic\",\"body\":\"…\"}'\n ]\n )\n }\n if (typeof value !== \"object\" || value === null || Array.isArray(value)) {\n return lineError(\n \"ERR_INVALID_FLAG\",\n line,\n `parsed as ${Array.isArray(value) ? \"an array\" : typeof value}, not a JSON object`\n )\n }\n return value as Record<string, unknown>\n}\n\nconst isFailure = (value: unknown): value is Failure =>\n typeof value === \"object\" && value !== null && \"code\" in value && \"error\" in value\n\n/** A field that must be a non-empty string, or the refusal naming it. */\nconst requiredString = (\n record: Record<string, unknown>,\n field: string,\n line: number\n): string | Failure => {\n const value = record[field]\n if (value === undefined) {\n return lineError(\"ERR_MISSING_ARGUMENT\", line, `missing required field \\`${field}\\``)\n }\n if (typeof value !== \"string\" || value.trim() === \"\") {\n return lineError(\n \"ERR_INVALID_FLAG\",\n line,\n `\\`${field}\\` must be a non-empty string, got ${value === null ? \"null\" : typeof value}`\n )\n }\n return value\n}\n\n/** A list field as an array of strings: a bare string is a one-element list, as `--tag` is. */\nconst strings = (value: unknown, field: string, line: number): Array<string> | Failure => {\n if (typeof value === \"string\") return value === \"\" ? [] : [value]\n if (!Array.isArray(value)) {\n return lineError(\n \"ERR_INVALID_FLAG\",\n line,\n `\\`${field}\\` must be a string or an array of strings, got ${typeof value}`\n )\n }\n const out: Array<string> = []\n for (const entry of value) {\n if (typeof entry !== \"string\") {\n return lineError(\n \"ERR_INVALID_FLAG\",\n line,\n `\\`${field}\\` holds a ${typeof entry} where every element must be a string`\n )\n }\n if (entry !== \"\") out.push(entry)\n }\n return out\n}\n\n/** A numeric field, accepting the JSON number or a numeric string. */\nconst numeric = (value: unknown, field: string, line: number): number | Failure => {\n const parsed = typeof value === \"number\" ? value : Number(value)\n if (typeof value !== \"number\" && typeof value !== \"string\") {\n return lineError(\"ERR_INVALID_FLAG\", line, `\\`${field}\\` must be a number, got ${typeof value}`)\n }\n if (!Number.isFinite(parsed)) {\n return lineError(\n \"ERR_INVALID_FLAG\",\n line,\n `\\`${field}\\` is not a finite number: ${String(value)}`\n )\n }\n return parsed\n}\n\n/**\n * One line as a `WriteParams`, or the refusal naming the line.\n *\n * The shape rules AC-6-4 puts at this door and nowhere else: the line parses, it declares an op in\n * the vocabulary, and it carries `title` and `type` as non-empty strings. Everything past that is\n * the operations layer's decode (is `type` in the vocabulary) or the store's render gate (is the\n * markup valid). Those are checked per op and reported per op, and they are not duplicated here,\n * because a second copy of the type vocabulary is a second thing to update when it moves.\n */\nconst opAt = (record: Record<string, unknown>, line: number): WriteParams | Failure => {\n for (const field of Object.keys(record)) {\n if (!KNOWN_FIELDS.has(field)) {\n return lineError(\n \"ERR_INVALID_FLAG\",\n line,\n `unknown field \\`${field}\\`. Fields: ${[...KNOWN_FIELDS].sort().join(\", \")}`\n )\n }\n }\n\n const op = record.op\n if (op === undefined) {\n return lineError(\n \"ERR_MISSING_ARGUMENT\",\n line,\n `missing required field \\`op\\`. One of: ${APPLY_OPS.join(\", \")}`\n )\n }\n if (typeof op !== \"string\" || !APPLY_OPS.includes(op)) {\n return lineError(\n \"ERR_INVALID_FLAG\",\n line,\n `\\`op\\` must be one of: ${APPLY_OPS.join(\", \")}, got ${JSON.stringify(op)}`\n )\n }\n\n const title = requiredString(record, \"title\", line)\n if (isFailure(title)) return title\n const memoryType = requiredString(record, \"type\", line)\n if (isFailure(memoryType)) return memoryType\n\n const params: Record<string, unknown> = { title, memoryType, claim: \"\" }\n\n for (const [field, target] of Object.entries(SCALAR_FIELDS)) {\n const value = record[field]\n if (value === undefined || value === null) continue\n if (field === \"title\" || field === \"type\") continue\n if (target === \"importance\" || target === \"confidence\") {\n const parsed = numeric(value, field, line)\n if (isFailure(parsed)) return parsed\n params[target] = parsed\n continue\n }\n if (typeof value !== \"string\") {\n return lineError(\n \"ERR_INVALID_FLAG\",\n line,\n `\\`${field}\\` must be a string, got ${typeof value}`\n )\n }\n params[target] = value\n }\n\n for (const [field, target] of Object.entries(LIST_FIELDS)) {\n const value = record[field]\n if (value === undefined || value === null) continue\n const parsed = strings(value, field, line)\n if (isFailure(parsed)) return parsed\n params[target] = [...((params[target] as Array<string> | undefined) ?? []), ...parsed]\n }\n\n /**\n * `body` prose becomes claim + tail; `article_html` is used verbatim and leaves `claim` empty.\n *\n * The XOR itself is not enforced here. The store's render gate owns it per op, so a batch with one\n * bad op reports that op and not the whole file. This branch owns the claim instead: the JSONL wire\n * has no `claim` field, so a prose line's claim is derived rather than restated by its author (see\n * {@link claimFromProse}, the one copy both doors share).\n *\n * Skipping this no longer lands a bad file. `@memhtml/html` constraint 1 rejects an empty `<mark>`, so\n * the render gate would stop the op instead of committing a file with an empty `files.gist`. The\n * derivation is what makes a prose line valid in the first place. It is no longer the only thing\n * standing between a missing claim and a silent write.\n */\n const prose = typeof params.body === \"string\" ? (params.body as string) : undefined\n if (prose !== undefined && prose.trim() !== \"\") {\n params.claim = claimFromProse(prose)\n params.body = proseTail(prose)\n } else if (prose !== undefined) {\n delete params.body\n }\n\n return params as unknown as WriteParams\n}\n\n/** What a whole-file decode produced: the ops, or the first line that refused. */\nexport type ApplyDecode =\n | { readonly ok: true; readonly ops: ReadonlyArray<WriteParams> }\n | { readonly ok: false; readonly failure: Failure }\n\n/**\n * Decode a whole JSONL document, refusing on the first bad line.\n *\n * Every line is judged before any op runs (AC-6-4), and that ordering is the contract rather than an\n * implementation detail. An apply that executed lines 1-6 and then refused line 7 would leave a\n * commit behind for a call that reported failure, and the caller's only recovery would be to work out\n * which prefix landed. Refusing first costs nothing, since no service has been touched yet.\n *\n * Blank lines are skipped rather than refused, because a file written by `printf '%s\\n'` or a heredoc\n * ends in one. The line numbers still count them, so an error naming line 7 means the seventh\n * line of the file the caller can open in an editor.\n */\nexport const decodeApply = (text: string): ApplyDecode => {\n const ops: Array<WriteParams> = []\n const lines = text.split(\"\\n\")\n\n for (const [at, raw] of lines.entries()) {\n const line = at + 1\n if (raw.trim() === \"\") continue\n const record = objectAt(raw, line)\n if (isFailure(record)) return { ok: false, failure: record }\n const op = opAt(record, line)\n if (isFailure(op)) return { ok: false, failure: op }\n ops.push(op)\n }\n\n if (ops.length === 0) {\n return {\n ok: false,\n failure: fail(\n \"ERR_MISSING_ARGUMENT\",\n `${APPLY_DOC}: no ops. The input held no non-blank lines, so there is nothing to write`,\n [\n \"memhtml apply --file ops.jsonl\",\n 'printf \\'%s\\\\n\\' \\'{\"op\":\"write\",\"title\":\"A fact\",\"type\":\"semantic\",\"body\":\"The thing that happened.\"}\\' | memhtml apply -'\n ]\n )\n }\n }\n\n return { ok: true, ops }\n}\n\n/**\n * Read the JSONL text for one invocation: `--file <path>`, or stdin.\n *\n * **The stdin seam.** `run()` takes this reader as an injectable parameter and defaults to\n * {@link readStdin}, so `bin.ts` needs no edit and a test supplies the text directly. Reading stdin\n * in `bin.ts` instead would make the entry point parse argv to discover whether\n * the command it is about to dispatch even wants stdin, and would put an I/O decision in the one file\n * whose whole job is \"call run, write the envelope, exit\".\n */\nexport const applyText = async (\n file: string | undefined,\n stdin: () => Promise<string>\n): Promise<string | Failure> => {\n if (file !== undefined && file.trim() !== \"\") {\n try {\n return await readFile(file, \"utf8\")\n } catch (error) {\n return fail(\n \"ERR_PATH_NOT_FOUND\",\n `${APPLY_DOC}: cannot read --file ${file}: ${error instanceof Error ? error.message : String(error)}`,\n [`ls ${file}`, \"memhtml apply - < ops.jsonl\"]\n )\n }\n }\n return await stdin()\n}\n\n/**\n * `process.stdin` as text, and nothing when a human is at a terminal.\n *\n * The TTY check is what makes a bare `memhtml apply` with no `--file` and no pipe answer with the\n * empty-input usage error instead of hanging forever waiting on a keyboard. An agent invoking this\n * without a pipe gets an envelope; a hang would get a timeout and no diagnosis.\n */\nexport const readStdin = async (): Promise<string> => {\n if (process.stdin.isTTY === true) return \"\"\n const chunks: Array<Buffer> = []\n for await (const chunk of process.stdin) {\n chunks.push(typeof chunk === \"string\" ? Buffer.from(chunk) : (chunk as Buffer))\n }\n return Buffer.concat(chunks).toString(\"utf8\")\n}\n\n/**\n * The `batch.applied` payload: the operation's result, renamed to the wire's snake_case.\n *\n * snake_case here and camelCase in `memory.written` is a real inconsistency, and it comes from the\n * spec (D6 names `commit_sha`). It was taken on purpose, because it makes this payload byte-comparable\n * with `memory_write_batch`'s over MCP. An agent that has parsed one has parsed the other, and a batch\n * result is the payload most likely to be handled by shared code across the two doors.\n *\n * Absent fields are `null` rather than missing. `deduped` and `skipped` are always booleans. An agent\n * branching on `deduped === true` should not have to also handle the key being absent, and `--dense`\n * strips the nulls for the context-window case anyway.\n */\nconst opPayload = (report: BatchOpReport) => ({\n index: report.index,\n ok: report.ok,\n path: report.path ?? null,\n deduped: report.deduped === true,\n existing_path: report.existingPath ?? null,\n code: report.code ?? null,\n error: report.error ?? null,\n skipped: report.skipped === true,\n /**\n * What this op's claim contradicts, when `--detect-conflicts` was passed and something matched.\n *\n * The inner field names are snake_case (`batch_index`) for the same reason the outer ones are: this\n * payload is byte-comparable with `memory_write_batch`'s, so shared code across the two doors reads\n * one shape. Null when the flag was off, when nothing matched, or when the claim has no frame\n * shape. An op carrying a conflict was still written, because the field is a report rather than a\n * refusal.\n */\n conflict:\n report.conflict === undefined\n ? null\n : {\n path: report.conflict.path,\n batch_index: report.conflict.batchIndex,\n claim: report.conflict.claim\n },\n /**\n * The two `--consolidate last-wins` outcomes, null everywhere else, including when the flag was\n * off. That is the same \"absent is null\" rule every field above follows, and the same shape\n * `memory_write_batch` publishes.\n */\n consolidated_into: report.consolidatedInto ?? null,\n superseded_path: report.supersededPath ?? null\n})\n\nexport const applyPayload = (result: BatchWriteResult) => ({\n results: result.results.map(opPayload),\n summary: result.summary,\n commit_sha: result.commitSha\n})\n","import { mkdir, writeFile } from \"node:fs/promises\"\nimport { dirname, join } from \"node:path\"\n\nimport { type EdgeRel, isEdgeRel } from \"@memhtml/contracts/edges\"\nimport { INBOX_DIR, normalizePath, TASKS_SUBDIR } from \"@memhtml/contracts/paths\"\nimport { checkMemory } from \"@memhtml/html\"\nimport { DatabaseService, type DatabaseShape, STATE_SCHEMA } from \"@memhtml/index\"\nimport { EMBED_WATERMARK } from \"@memhtml/llm\"\nimport {\n allPaths,\n applyHeadEdits,\n archivedFormOf,\n danglingEdges,\n hrefFor,\n link,\n meta,\n unlink\n} from \"@memhtml/sleep\"\nimport { attemptIo, commitSubject, readFileOrNull } from \"@memhtml/store\"\nimport { Effect } from \"effect\"\n\nimport { Git, Store } from \"./api-layer.js\"\n\n/**\n * `memhtml doctor`: the corpus's own health check, and `--fix` for the two findings a repair can settle\n * without a judgement call.\n *\n * Eight checks, and each one is a claim the design makes about the corpus rather than a lint:\n *\n * 1. **Dangling `<link>` hrefs**: an authored edge pointing at a path the tree does not hold. Design\n * §2.3 has no foreign key on `edges` deliberately (a `<link>` may name a file the indexer has not\n * reached), so a LEFT JOIN is the only thing that finds these.\n * 2. **Orphan state rows**: a `state.access` row whose path left the tree. There are no\n * cross-database foreign keys, so the store mirrors a move explicitly and an interrupted mirror\n * leaves a row describing nothing.\n * 3. **Inbox depth**: design §2.1 rule 6 routes an unplaceable memory to `areas/inbox/` and says\n * doctor reports the depth as a health signal. A deep inbox is a placement rule that stopped\n * matching what agents write, which nothing else surfaces.\n * 4. **Vocabulary warnings**: format constraint 6. An element outside the closed vocabulary still\n * indexes, so the only way it ever becomes visible is here.\n * 5. **Index staleness**: the index is a projection of a commit, so \"fresh\" means the commit it\n * describes is the commit we are on. Plus the vector-space watermark, because a stored space that\n * differs from the configured one makes every cosine in the index incomparable.\n * 6. **Overdue tasks**: a task is default-excluded from search and skipped by every sleep phase, so\n * nothing else in the system will ever mention that a deadline passed. Doctor is the only surface\n * that reads `due_at`.\n * 7. **Stale task blockers**: a `blocks` edge whose blocker is archived or absent. This is the one\n * task-graph state no single file can reveal, since each file individually is valid and the pair\n * is a task waiting on something that will never move.\n * 8. **Task inbox depth**: a task in `areas/inbox/tasks/` is work with no project, and a task inbox\n * is meant to be drained rather than accumulated.\n *\n * **`--fix` repairs exactly two of the eight, and the repair logic is imported from the sleep\n * integrity phase rather than re-ported.** `archivedFormOf` decides whether a dangling target moved\n * to the archive or is genuinely gone, and `applyHeadEdits`/`link`/`unlink`/`meta` are the byte-splice\n * editors that change one head line without touching the article. A parse→serialize round trip drops\n * a `<pre>` newline per write, so a \"repair\" through the serializer would move the content hash of\n * every file it touched. A second implementation of either would be the consumer-side reimplementation\n * of producer semantics the fleet has paid for repeatedly.\n *\n * The other six report and do not repair. An inbox memory or task needs a human or an agent to decide\n * where it belongs, a vocabulary warning needs the author's intent, and a stale index needs\n * `memhtml index update`, which doctor names in its own suggestions rather than running behind the\n * operator's back. An overdue task needs the work done or the deadline moved, and a stale blocker\n * needs someone to decide whether the blocked task is actually ready.\n */\n\n/** How deep the inbox may get before doctor calls it a finding. */\nexport const INBOX_WARN_DEPTH = 20\n\n/**\n * How many unplaced tasks may sit in `areas/inbox/tasks/` before doctor calls it a finding.\n *\n * Lower than {@link INBOX_WARN_DEPTH} because the two crowds mean different things. An unplaced\n * memory is a placement rule that stopped matching. An unplaced task is work with no project, which\n * is the state a to-do list rots in, and a task inbox is meant to be drained rather than accumulated.\n */\nexport const INBOX_TASK_WARN_DEPTH = 10\n\n/** One dangling href, and what a repair would do about it. */\nexport interface DanglingFinding {\n readonly srcPath: string\n readonly rel: string\n readonly dstPath: string\n /** The archive path the target moved to, or `null` when the target is genuinely gone. */\n readonly rewriteTo: string | null\n}\n\n/** One file carrying vocabulary warnings. */\nexport interface WarningFinding {\n readonly path: string\n readonly warnings: ReadonlyArray<string>\n}\n\n/** One open task past its deadline. */\nexport interface OverdueTaskFinding {\n readonly path: string\n readonly taskStatus: string | null\n /** The `memhtml-due` value, verbatim. An ISO date or datetime. */\n readonly dueAt: string\n}\n\n/** One open task whose blocker can never close it. */\nexport interface StaleBlockerFinding {\n readonly path: string\n readonly blockerPath: string\n /** `archived`: the blocker is finished or evicted. `missing`: no file at that path at all. */\n readonly blockerState: \"archived\" | \"missing\"\n}\n\n/** What a doctor pass found. Every list is present and possibly empty, so a parser never branches. */\nexport interface DoctorReport {\n readonly root: string\n /** True when every check is clean. */\n readonly healthy: boolean\n readonly dangling: ReadonlyArray<DanglingFinding>\n /** `state.access` rows whose path is absent from `files`. */\n readonly orphanAccessRows: ReadonlyArray<string>\n readonly inboxDepth: number\n /** True when the inbox is past {@link INBOX_WARN_DEPTH}. */\n readonly inboxCrowded: boolean\n /** Open tasks in `areas/inbox/tasks/`: work with no project. */\n readonly inboxTaskDepth: number\n /** True when the task inbox is past {@link INBOX_TASK_WARN_DEPTH}. */\n readonly inboxTasksCrowded: boolean\n /** Open tasks whose `memhtml-due` has passed, earliest first. */\n readonly overdueTasks: ReadonlyArray<OverdueTaskFinding>\n /** Open tasks blocked by a task that is archived or absent from the tree. */\n readonly staleBlockers: ReadonlyArray<StaleBlockerFinding>\n readonly warnings: ReadonlyArray<WarningFinding>\n /** Files the index holds that failed to parse when doctor re-read them. */\n readonly unparseable: ReadonlyArray<string>\n readonly indexFresh: boolean\n readonly indexHeadSha: string | null\n readonly headSha: string | null\n /** True when the stored vector space IS the configured one. */\n readonly embedModelMatches: boolean\n readonly storedEmbedModel: string | null\n readonly configuredEmbedModel: string\n readonly dirty: ReadonlyArray<string>\n /** Present under `--fix`: what the repair actually did. */\n readonly repaired?: RepairReport | undefined\n}\n\n/** What `--fix` changed. */\nexport interface RepairReport {\n /** Dangling hrefs rewritten to the target's archive path. */\n readonly rewritten: number\n /** Dangling hrefs dropped because the target has no file anywhere. */\n readonly dropped: number\n /** Orphan `state.access` rows deleted. */\n readonly prunedAccessRows: number\n /** The commit the href repairs landed in, or `null` when nothing was rewritten. */\n readonly commitSha: string | null\n}\n\n/** Every `state.access` path the index has no `files` row for. */\nconst orphanAccess = (db: DatabaseShape): Effect.Effect<ReadonlyArray<string>, never, never> =>\n db.hasState\n ? db\n .all<{ path: string }>(\n `SELECT a.path AS path FROM ${STATE_SCHEMA}.access a\n LEFT JOIN files f ON f.path = a.path\n WHERE f.path IS NULL ORDER BY a.path ASC`\n )\n .pipe(\n Effect.map((rows) => rows.map((row) => row.path)),\n Effect.orElseSucceed(() => [])\n )\n : Effect.succeed([])\n\n/** How many ACTIVE memories sit in the inbox. An archived one is no longer awaiting placement. */\nconst inboxDepth = (db: DatabaseShape): Effect.Effect<number, never, never> =>\n db\n .get<{ n: number }>(\n \"SELECT count(*) AS n FROM files WHERE archived = 0 AND path LIKE ? || '/%'\",\n [INBOX_DIR]\n )\n .pipe(\n Effect.map((row) => row?.n ?? 0),\n Effect.orElseSucceed(() => 0)\n )\n\n/**\n * How many ACTIVE tasks sit in the task inbox.\n *\n * `memory_type = 'task'` as well as the path prefix, because `areas/inbox/tasks/` is a directory and\n * a directory is not a type: a hand-authored memory filed there would inflate the task count and make\n * the finding say something it does not mean.\n */\nconst inboxTaskDepth = (db: DatabaseShape): Effect.Effect<number, never, never> =>\n db\n .get<{ n: number }>(\n `SELECT count(*) AS n FROM files\n WHERE archived = 0 AND memory_type = 'task' AND path LIKE ? || '/%'`,\n [`${INBOX_DIR}/${TASKS_SUBDIR}`]\n )\n .pipe(\n Effect.map((row) => row?.n ?? 0),\n Effect.orElseSucceed(() => 0)\n )\n\n/**\n * Open tasks past their deadline.\n *\n * `substr(due_at, 1, 10)` states that the comparison is one of calendar days. The bound is always a\n * bare `YYYY-MM-DD` (today, from the clock), and enumerated against that bound the truncation changes\n * no answer, because a time-bearing due date on the bound's own day sorts after it either way. It\n * stays as the statement of intent. `listTasks`' `--due-before` takes a caller-supplied bound that may\n * carry a time, where the truncation does change answers, and one form across both queries keeps\n * \"overdue\" meaning the same thing in the two places an operator reads it.\n *\n * **`archived = 0` and `task_status <> 'done'` both change the result** (mutation-verified\n * 2026-08-02). A finished task's deadline is history, and reporting it would make the finding grow\n * forever and never reach zero.\n */\nconst overdueTasks = (\n db: DatabaseShape,\n today: string\n): Effect.Effect<ReadonlyArray<OverdueTaskFinding>, never, never> =>\n db\n .all<{ path: string; task_status: string | null; due_at: string }>(\n `SELECT path, task_status, due_at FROM files\n WHERE memory_type = 'task' AND archived = 0 AND due_at IS NOT NULL\n AND substr(due_at, 1, 10) < ? AND task_status <> 'done'\n ORDER BY due_at ASC, path ASC`,\n [today]\n )\n .pipe(\n Effect.map((rows) =>\n rows.map((row) => ({ path: row.path, taskStatus: row.task_status, dueAt: row.due_at }))\n ),\n Effect.orElseSucceed(() => [])\n )\n\n/**\n * Open tasks whose blocker can never close them.\n *\n * A `blocks` edge points blocker → blocked, so the blocked task is the edge's `dst_path`. A LEFT JOIN\n * rather than an inner one, because the two failure modes differ. An archived blocker is finished work\n * whose edge nobody cleared, and a missing one is an edge whose source has no `files` row. Either way\n * the blocked task waits on something that will never move. This is the one task-graph state no single\n * file can reveal, since each file is individually valid and only the pair is wrong.\n *\n * **The `archived` arm is the reachable one, and `missing` is defense in depth.** Probed and\n * mutation-confirmed 2026-08-02: deleting a blocker's file makes `indexer.update` clear\n * `edges WHERE src_path = ?` in the same batch, so an edge cannot outlive its source file and the\n * `missing` branch has nothing to find. Removing that `DELETE` turns the branch on, and it stays for\n * that reason. `edges` carries no foreign key deliberately, so a future writer of edge rows would not\n * inherit the indexer's discipline.\n *\n * **`edge_class = 'task'` is redundant with `rel = 'blocks'` today.** The migration's per-class CHECKs\n * refuse `blocks` under every other class, so a mutation dropping it leaves the suite green. It is kept\n * because every memory-graph query filters on the class column, and a reader who saw this one trust\n * the rel alone would learn the wrong rule about where the firewall lives.\n *\n * Report-only. Clearing the edge is an authoring decision, since the blocked task may be genuinely\n * ready or the blocker may have been archived prematurely. `--fix` guessing between those would rewrite\n * a plan.\n */\nconst staleBlockers = (\n db: DatabaseShape\n): Effect.Effect<ReadonlyArray<StaleBlockerFinding>, never, never> =>\n db\n .all<{ path: string; blocker_path: string; blocker_state: string }>(\n `SELECT t.path AS path, e.src_path AS blocker_path,\n CASE WHEN b.path IS NULL THEN 'missing' ELSE 'archived' END AS blocker_state\n FROM files t\n JOIN edges e ON e.dst_path = t.path AND e.edge_class = 'task' AND e.rel = 'blocks'\n LEFT JOIN files b ON b.path = e.src_path\n WHERE t.memory_type = 'task' AND t.archived = 0 AND t.task_status <> 'done'\n AND (b.path IS NULL OR b.archived = 1)\n ORDER BY t.path ASC, e.src_path ASC`\n )\n .pipe(\n Effect.map((rows) =>\n rows.map((row) => ({\n path: row.path,\n blockerPath: row.blocker_path,\n blockerState:\n row.blocker_state === \"missing\" ? (\"missing\" as const) : (\"archived\" as const)\n }))\n ),\n Effect.orElseSucceed(() => [])\n )\n\n/**\n * Re-read every active file and collect its format warnings.\n *\n * Re-read rather than taken from the index, because a warning is not a stored column. The indexer\n * counts a parse failure and projects what it can, and constraint 6 is deliberately non-fatal. Doctor\n * is the one caller that wants the list, so it is the one caller that pays for the read.\n */\nconst collectWarnings = (\n root: string,\n paths: ReadonlyArray<string>\n): Effect.Effect<\n { readonly warnings: ReadonlyArray<WarningFinding>; readonly unparseable: ReadonlyArray<string> },\n never,\n never\n> =>\n Effect.gen(function* () {\n const warnings: Array<WarningFinding> = []\n const unparseable: Array<string> = []\n for (const path of paths) {\n const html = yield* readFileOrNull(join(root, path)).pipe(Effect.orElseSucceed(() => null))\n if (html === null) {\n unparseable.push(path)\n continue\n }\n const checked = checkMemory(html)\n if (checked.violations.length > 0) unparseable.push(path)\n if (checked.warnings.length > 0) warnings.push({ path, warnings: checked.warnings })\n }\n return { warnings, unparseable }\n })\n\n/** The year a run's repairs partition archive lookups under: the current calendar year. */\nconst currentYear = Effect.clockWith((clock) =>\n Effect.map(clock.currentTimeMillis, (millis) => new Date(millis).getUTCFullYear())\n)\n\n/** Today as `YYYY-MM-DD`, through the Effect clock so a test can pin what \"overdue\" means. */\nconst todayDate = Effect.clockWith((clock) =>\n Effect.map(clock.currentTimeMillis, (millis) => new Date(millis).toISOString().slice(0, 10))\n)\n\n/** An ISO-8601 UTC second, for the `memhtml-updated` stamp a repair writes. */\nconst nowSecond = Effect.clockWith((clock) =>\n Effect.map(clock.currentTimeMillis, (millis) => `${new Date(millis).toISOString().slice(0, 19)}Z`)\n)\n\n/**\n * Repair the dangling hrefs and prune the orphan access rows.\n *\n * The href repair mirrors the integrity phase exactly, using its own `archivedFormOf` and its own\n * head editors. A dangling target that moved under `archive/<YYYY>/` gets its href rewritten, so the\n * edge still says something true. A target with no file anywhere gets the link dropped with a\n * warning, because the edge asserts a relationship to nothing and leaving it would produce the same\n * finding on every rebuild forever.\n *\n * Remove-then-add on the same file in one pass, so a repair replaces one line rather than dropping a\n * line and appending another elsewhere in the head. A re-run is then a no-op: once the href points at\n * the archive path the removal matches nothing and the addition is already present.\n */\nconst repair = (\n root: string,\n findings: ReadonlyArray<DanglingFinding>,\n orphans: ReadonlyArray<string>\n) =>\n Effect.gen(function* () {\n const git = yield* Git\n const db = yield* DatabaseService\n const at = yield* nowSecond\n\n let rewritten = 0\n let dropped = 0\n const touched: Array<string> = []\n\n for (const finding of findings) {\n if (!isEdgeRel(finding.rel)) continue\n const rel = finding.rel as EdgeRel\n const absolute = join(root, finding.srcPath)\n const html = yield* readFileOrNull(absolute).pipe(Effect.orElseSucceed(() => null))\n if (html === null) continue\n\n const edits =\n finding.rewriteTo === null\n ? [unlink(rel, hrefFor(finding.dstPath)), meta(\"memhtml-updated\", at)]\n : [\n unlink(rel, hrefFor(finding.dstPath)),\n link(rel, hrefFor(finding.rewriteTo)),\n meta(\"memhtml-updated\", at)\n ]\n const edited = applyHeadEdits(html, edits)\n if (edited === html) continue\n\n if (finding.rewriteTo === null) {\n yield* Effect.logWarning(\n `doctor dropped a dangling ${rel} from ${finding.srcPath}: target has no file`\n )\n }\n yield* attemptIo(`doctor.write:${finding.srcPath}`, async () => {\n await mkdir(dirname(absolute), { recursive: true })\n await writeFile(absolute, edited, \"utf8\")\n }).pipe(Effect.orElseSucceed(() => undefined))\n touched.push(finding.srcPath)\n if (finding.rewriteTo === null) dropped += 1\n else rewritten += 1\n }\n\n let prunedAccessRows = 0\n if (orphans.length > 0 && db.hasState) {\n /**\n * One statement per path rather than an `IN` list, because the list is unbounded. A driver\n * parameter limit reached mid-prune would fail the whole batch and leave every row in place.\n */\n for (const path of orphans) {\n const done = yield* db\n .run(`DELETE FROM ${STATE_SCHEMA}.access WHERE path = ?`, [path])\n .pipe(\n Effect.as(true),\n Effect.orElseSucceed(() => false)\n )\n if (done) prunedAccessRows += 1\n }\n }\n\n let commitSha: string | null = null\n if (touched.length > 0) {\n yield* git.add(touched)\n const commit = yield* git.commit(\n commitSubject(\"link\", `repair ${rewritten + dropped} dangling links`)\n )\n commitSha = commit.sha\n }\n\n return { rewritten, dropped, prunedAccessRows, commitSha } satisfies RepairReport\n })\n\n/**\n * Run the health check, optionally repairing.\n *\n * The findings are gathered before any repair and the report carries the pre-repair lists alongside\n * `repaired`, which is what makes a `--fix` run auditable. An operator reads what was wrong and what\n * was done about it in one envelope, rather than a clean report that says nothing happened.\n */\nexport const doctor = (options: { readonly fix: boolean }) =>\n Effect.gen(function* () {\n const git = yield* Git\n const store = yield* Store\n const db = yield* DatabaseService\n\n const headSha = yield* git.revParseHead().pipe(Effect.orElseSucceed(() => null))\n const dirty = yield* store.dirtyPaths().pipe(Effect.orElseSucceed(() => []))\n\n const state = yield* db\n .get<{ head_sha: string | null; embed_model: string }>(\n \"SELECT head_sha, embed_model FROM index_state WHERE id = 1\"\n )\n .pipe(Effect.orElseSucceed(() => undefined))\n\n const known = new Set(\n (yield* allPaths(db).pipe(Effect.orElseSucceed(() => []))).map((row) => row.path)\n )\n const year = yield* currentYear\n const edges = yield* danglingEdges(db).pipe(Effect.orElseSucceed(() => []))\n const dangling: ReadonlyArray<DanglingFinding> = edges.map((edge) => {\n const dstPath = normalizePath(edge.dst_path)\n return {\n srcPath: edge.src_path,\n rel: edge.rel,\n dstPath,\n rewriteTo: archivedFormOf(dstPath, known, year) ?? null\n }\n })\n\n const orphanAccessRows = yield* orphanAccess(db)\n const depth = yield* inboxDepth(db)\n const taskDepth = yield* inboxTaskDepth(db)\n const overdue = yield* overdueTasks(db, yield* todayDate)\n const stale = yield* staleBlockers(db)\n\n const active = yield* db\n .all<{ path: string }>(\"SELECT path FROM files WHERE archived = 0 ORDER BY path ASC\")\n .pipe(Effect.orElseSucceed(() => []))\n const { warnings, unparseable } = yield* collectWarnings(\n git.root,\n active.map((row) => row.path)\n )\n\n const repaired = options.fix ? yield* repair(git.root, dangling, orphanAccessRows) : undefined\n\n const indexFresh = state?.head_sha !== null && state?.head_sha === headSha\n const embedModelMatches = state?.embed_model === EMBED_WATERMARK\n\n return {\n root: git.root,\n /**\n * `healthy` is computed from the findings and not from the repair. A `--fix` run that repaired\n * everything still reports the corpus as it was found. A command that flipped itself green by\n * fixing what it found would make \"doctor is clean\" unfalsifiable.\n */\n healthy:\n dangling.length === 0 &&\n orphanAccessRows.length === 0 &&\n depth <= INBOX_WARN_DEPTH &&\n /**\n * The task inbox counts toward `healthy` for the same reason the memory inbox does: an\n * unplaced item is a routing signal. `overdueTasks` and `staleBlockers` are excluded, because\n * those two are facts about the work rather than defects in the corpus. A repo whose owner is\n * late on a to-do is structurally sound, and folding them in would make `healthy: false` the\n * normal state and stop anyone reading the flag at all. Every other finding here is a defect\n * in the corpus; those two describe work that has fallen behind.\n */\n taskDepth <= INBOX_TASK_WARN_DEPTH &&\n warnings.length === 0 &&\n unparseable.length === 0 &&\n indexFresh &&\n embedModelMatches,\n dangling,\n orphanAccessRows,\n inboxDepth: depth,\n inboxCrowded: depth > INBOX_WARN_DEPTH,\n inboxTaskDepth: taskDepth,\n inboxTasksCrowded: taskDepth > INBOX_TASK_WARN_DEPTH,\n overdueTasks: overdue,\n staleBlockers: stale,\n warnings,\n unparseable,\n indexFresh,\n indexHeadSha: state?.head_sha ?? null,\n headSha,\n embedModelMatches,\n storedEmbedModel: state?.embed_model ?? null,\n configuredEmbedModel: EMBED_WATERMARK,\n dirty,\n ...(repaired === undefined ? {} : { repaired })\n } satisfies DoctorReport\n })\n","import { readFile } from \"node:fs/promises\"\nimport { createRequire } from \"node:module\"\nimport { dirname, resolve } from \"node:path\"\nimport { fileURLToPath } from \"node:url\"\n\nimport { InvalidMemory, StorageFailure } from \"@memhtml/contracts/errors\"\nimport { type GitFailure, makeGit } from \"@memhtml/store\"\nimport { Effect, type Scope } from \"effect\"\n\nimport { type Failure, fail } from \"./envelope.js\"\n\n/**\n * `memhtml exec`, the code-mode runtime: an agent-supplied script, a read-only corpus, one envelope.\n *\n * ROADMAP item 7 is the requirement. A multi-hop traversal written as code answers in one execution\n * what the tool path answers in one round trip per hop, and the closed vocabulary is what makes the\n * tree queryable without a new surface per question. Measured in the 2026-08 spike and\n * re-probed here on 2026-08-09: a 305-file\n * census in 598ms, and an edge walk resolving 410/410 edges into 201 chains, the longest 8 hops, in one\n * execution at 430ms.\n *\n * **Structural and lexical planes only. No index handle.** That is the division item 7 itself draws.\n * `memhtml search` finds entry points, code traverses from there, and a script needing ranked retrieval\n * shells out to `memhtml search` and consumes its envelope. Nothing here opens `index.db`, so CODE-2's\n * index half is satisfied by there being no handle to guard rather than by a guard. If one is ever\n * added, `scripts/probe-sqlite-concurrency.mjs` measures what a second process can do to a live store.\n *\n * **Read-only by contract.** Every write still goes through `memhtml apply` / `memory_write*`, so the\n * one-commit-per-op, dedup, and conflict machinery cannot be bypassed. The mount enforces it, since\n * `readOnly: true` on the `OverlayFs` answers `EROFS`, and this module offers no write path at all.\n */\n\n/** Where the corpus appears in the guest. Matches `ROOT` in `apps/cli/guest/corpus.mjs`. */\nexport const CORPUS_MOUNT = \"/mnt/memhtml\"\n\n/** Where the seeded modules live. `/workspace` is writable; the corpus mount is not. */\nconst GUEST_LIB = \"/workspace/lib\"\nconst GUEST_SCRIPT = \"/workspace/script.mjs\"\n\n/**\n * The default wall-clock bound on the script, in milliseconds.\n *\n * 30s, which is `maxJsTimeoutMs`'s own default in just-bash 3.2.0 (`dist/limits.d.ts:83`). It is named\n * here rather than inherited so the value appears in `memhtml manifest` and in `AGENTS.md`, where an\n * agent budgeting a call can read it. The measured work is far below it: the whole 305-file corpus\n * parses in 640ms, so 30s is roughly 45x the cost of a full-corpus pass.\n */\nexport const DEFAULT_TIMEOUT_MS = 30_000\n\n/**\n * The bound is capped, and the cap is what makes a runaway script terminate.\n *\n * `maxJsTimeoutMs` is the only thing standing between a runaway guest loop and a `memhtml exec` that\n * never returns. The guest is a QuickJS worker with no host-side reaper of its own, and an unbounded\n * script would hold the CLI process open indefinitely. Probed 2026-08-09 with `maxJsTimeoutMs: 700`\n * against `for(;;){n++}`: exit 124 at 724ms, \"js-exec: Execution timeout: exceeded 700ms limit\".\n */\nexport const MAX_TIMEOUT_MS = 600_000\n\n/**\n * How much looser the shell's bound is than the script's, so the script's bound fires first.\n *\n * This is not extra budget for the script, since `maxJsTimeoutMs` still cuts it off at the requested\n * value. It is the margin that decides which of the two bounds reports, and therefore whether `stderr`\n * carries the message naming the limit. See {@link runExec} for the measured table.\n */\nconst SHELL_TIMEOUT_GRACE_MS = 2_000\n\n/**\n * The `atob` shim, installed through just-bash's `javascript.bootstrap` before any guest module loads.\n *\n * QuickJS ships no base64 builtins and `node-html-parser` decodes a base64 entity table at load time,\n * so without this the parser throws \"'atob' is not defined\" at import and every script fails before\n * its first selector. Probed all three placements 2026-08-09: `bootstrap` works, prepending the shim\n * to the parser's own bytes works, and omitting it fails at `decodeBase64`. `bootstrap` is chosen\n * because it leaves the vendored parser byte-identical to the published artifact. A shim spliced into\n * the bundle would make the seeded file something no `pnpm` install reproduces.\n *\n * Base64 only, no `btoa`. The parser decodes and never encodes, and a shim for a capability nothing\n * uses is a capability added to the guest for free.\n */\nconst ATOB_BOOTSTRAP = `globalThis.atob = globalThis.atob || function (encoded) {\n const alphabet = \"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/\"\n let decoded = \"\", bits = 0, accumulator = 0\n for (const character of String(encoded).replace(/=+$/, \"\")) {\n const value = alphabet.indexOf(character)\n if (value < 0) continue\n accumulator = (accumulator << 6) | value\n bits += 6\n if (bits >= 8) { bits -= 8; decoded += String.fromCharCode((accumulator >> bits) & 0xff) }\n }\n return decoded\n}\n`\n\n/**\n * Where the guest-side helper's source lives on the host.\n *\n * `apps/cli/guest/corpus.mjs`, read as bytes at run time and never compiled. It sits outside `src/`\n * so `tsc` does not see it. It is guest source, its imports resolve against guest paths\n * (`/workspace/lib/nhp.mjs`), and a `.ts` file under `src/` would be typechecked against the host's\n * module graph and fail on an import that only exists inside the sandbox.\n *\n * Resolved from `import.meta.url` rather than from `process.cwd()`, so `memhtml exec` works from any\n * directory. `dist/exec.js` sits one level under the package root, which is where `guest/` is.\n */\nconst guestHelperPath = (): string =>\n resolve(dirname(fileURLToPath(import.meta.url)), \"..\", \"guest\", \"corpus.mjs\")\n\n/**\n * The HTML parser's bytes, as published.\n *\n * ## No bundling step, because the published artifact already is one\n *\n * `node-html-parser@9.0.1`'s `dist/index.mjs` is emitted by `tsdown` with its two dependencies\n * (`css-select`, `entities`) inlined: **zero `import` statements, zero `require(` calls, zero `node:`\n * references, 206655 bytes**, verified against the installed file rather than inferred from the\n * package's `sideEffects` field. The file `pnpm` installs is already loadable in the guest verbatim,\n * and there is nothing to regenerate. The reproduction path is `pnpm install`, pinned by\n * `pnpm-lock.yaml`, and a reader can re-verify self-containment with one grep. A checked-in bundle\n * would be a second copy of a published artifact that nobody could tell had drifted.\n *\n * ## Why this parser\n *\n * **cheerio and linkedom cannot load in QuickJS**, measured: `Object.getOwnPropertyDescriptor(\n * Function.prototype, \"toString\").writable === false` there, so `Object.assign(fn, source)` throws\n * whenever `source` carries a `toString`, which is what cheerio does when it attaches its\n * static API to `load`. linkedom fails identically through `cssom`. That is a property of the runtime,\n * so `docs/code-mode.md`'s cheerio examples do not carry over even though every selector does.\n *\n * `createRequire` against this module rather than a static import. The parser is never loaded on the\n * host at all, only read as text, and a static `import` would put a 200 KB module on the graph of\n * every `memhtml` command to obtain a path.\n */\nconst parserSourcePath = (): string =>\n createRequire(import.meta.url)\n .resolve(\"node-html-parser\")\n .replace(/index\\.cjs$/, \"index.mjs\")\n\n/**\n * Did the runtime cut this script off, or did the script exit 124 on its own?\n *\n * Exported, and a pure function of the two observable values, because it is the one piece of\n * classification here that cannot be exercised end-to-end. `runExec` deliberately sets the shell's\n * bound looser than the script's ({@link SHELL_TIMEOUT_GRACE_MS}), so the JS bound always wins and only\n * one of the two wordings ever reaches a live report. That makes the other branch unfalsifiable\n * through the command and therefore a claim rather than a guard. As a function it is testable against\n * both strings just-bash actually produces.\n *\n * Both wordings, measured 2026-08-09 on `for(;;)` at a 400ms bound:\n *\n * - `maxJsTimeoutMs` fires: `js-exec: Execution timeout: exceeded 400ms limit`\n * - `maxExecutionTimeMs` fires: `bash: js-exec exceeded its execution deadline`, with no \"timeout\" in it\n *\n * A pattern matching only `/timeout/` therefore reports `timedOut: false` on a script that was cut off,\n * which is what the first version of this did. `aborted` covers `bash: execution aborted`, which is what\n * an `AbortSignal` produces (probed). This module takes no such path today, and classifying it correctly\n * now is cheap if it ever does.\n *\n * The exit code is required as well as the wording. 124 alone is reachable from a script that exits 124\n * itself, and a caller branching on `timedOut` needs it to mean the bound fired.\n */\nexport const cutOffByTheRuntime = (exitCode: number, stderr: string): boolean =>\n exitCode === 124 && /timeout|deadline|aborted/i.test(stderr)\n\n/**\n * The two phrases just-bash's sandbox bridge speaks when it fails to answer a guest's filesystem call.\n *\n * ## Why this classification exists\n *\n * A guest `fs` call is a synchronous round trip over a `SharedArrayBuffer`: the QuickJS thread parks in\n * `Atomics.wait` while the host thread services the operation and writes a status back. When that\n * handshake does not complete, `SyncBackend.execSync` throws a message of its OWN making rather than the\n * host's — verbatim from `just-bash@3.2.0`'s bundle, byte-identical in 3.3.0:\n *\n * - `Error code: <n>` — the wait returned with a status that is not `SUCCESS` and no error was recorded.\n * - `Operation timed out` — the wait expired without the host answering at all.\n *\n * Neither is a fact about the corpus or the script. Both reach `stderr` as a thrown guest error, which\n * without this check is reported as the SCRIPT's non-zero exit — telling an agent its selector is wrong\n * when the sandbox merely failed to hand back a `stat`. Observed once on a 4-vCPU CI runner (2026-08-14,\n * `memhtml/memhtml` run 31830358200) on a walk of ~900 entries: `at isDirectory\n * (/workspace/lib/corpus.mjs:45:28): Error code: 0`, on a commit whose tree was byte-identical to one\n * that had passed minutes earlier. The bridge kept working afterwards — the guest's own `stderr` write\n * and exit both landed — so the fault is one operation, not a torn-down sandbox, which is what makes\n * re-running the script the right answer.\n *\n * A cut-off script is deliberately NOT a fault here: {@link cutOffByTheRuntime}'s wordings arrive with\n * exit 124 and name a limit, and treating them as a bridge fault would re-run a runaway script until it\n * had burned every attempt's full bound.\n *\n * Returns the phrase it matched, so a caller logs the evidence rather than a boolean.\n */\nexport const bridgeFault = (exitCode: number, stderr: string): string | null => {\n if (exitCode === 0) return null\n const matched = /(?:^|:\\s)(Error code: \\d+|Operation timed out)\\s*$/m.exec(stderr)\n return matched?.[1] ?? null\n}\n\n/**\n * How many times one script is run before a bridge fault is called the runtime's failure.\n *\n * Three, and the retry is sound rather than hopeful: the corpus is mounted read-only, the sandbox has no\n * network client, and every attempt reads the same pinned tree, so a script cannot have committed a\n * partial effect that a second run would double. Nothing about the guest survives an attempt either —\n * each one builds a fresh `Bash`, and therefore a fresh shared buffer and bridge.\n */\nexport const BRIDGE_ATTEMPTS = 3\n\n/**\n * Run one attempt at a time until a report is the script's own answer, or fail as the runtime.\n *\n * Exported and parameterized by `attempt` because that is the only shape this loop can be tested in: a\n * bridge fault is a rare race — 72 executions under 3x CPU oversubscription did not produce one\n * (measured 2026-08-14) — so a test driving the real sandbox could not distinguish a working retry from\n * a fault that never fired. The injected attempt makes the loop's three claims falsifiable: a faulting\n * attempt is re-run, a script's own failure is NOT, and exhaustion is a typed failure.\n *\n * Exhaustion becomes a `StorageFailure`, so it leaves through the error channel as exit 1 and\n * `ERR_STORAGE` rather than as an `exec.report` carrying the guest's confusing diagnostic. That is the\n * split this module already draws: a script's failure is a successful envelope, the runtime's own is not.\n */\nexport const withBridgeRetry = <E>(\n attempt: (attemptIndex: number) => Effect.Effect<ExecReport, E>,\n attempts: number = BRIDGE_ATTEMPTS\n): Effect.Effect<ExecReport, E | StorageFailure> =>\n Effect.gen(function* () {\n let fault = \"no attempt ran\"\n for (let attemptIndex = 1; attemptIndex <= attempts; attemptIndex++) {\n const report = yield* attempt(attemptIndex)\n const faulted = bridgeFault(report.exitCode, report.stderr)\n if (faulted === null) return report\n fault = faulted\n yield* Effect.logWarning(\n `exec.bridge: the sandbox did not answer a guest call (\"${faulted}\") on attempt ${attemptIndex} of ${attempts}; re-running the same script against the same tree`\n )\n }\n return yield* Effect.fail(\n StorageFailure.make({\n operation: `exec.bridge: the sandbox failed to answer a guest filesystem call ${attempts} times (\"${fault}\"), so no report is the script's own answer`\n })\n )\n })\n\n/** What a script produced. `stdout` is the script's own bytes, uninterpreted. */\nexport interface ExecReport {\n /** The guest path the corpus was mounted at, so a script's paths are explainable from the report. */\n readonly corpusMount: string\n /** The commit the mounted tree holds, or `null` when a directory was mounted directly. */\n readonly sha: string | null\n /** The script's exit code. Non-zero is reported rather than raised. See {@link runExec}. */\n readonly exitCode: number\n readonly stdout: string\n readonly stderr: string\n /** Wall-clock milliseconds for the guest execution alone, excluding mount and seeding. */\n readonly durationMs: number\n /** The bound that was in force. Present so a timeout is self-explaining from the envelope. */\n readonly timeoutMs: number\n /** True when the guest hit {@link timeoutMs}. just-bash reports exit 124 and says so on stderr. */\n readonly timedOut: boolean\n}\n\n/** Everything `memhtml exec` needs. `script` is source, already read; this module opens no script file. */\nexport interface ExecInput {\n /** The script's source, as the guest will see it. */\n readonly script: string\n /** An existing host directory holding the corpus. Mounted read-only at {@link CORPUS_MOUNT}. */\n readonly corpusPath: string\n /** Recorded into the report; `null` when the caller mounted a plain directory. */\n readonly sha?: string | null\n readonly timeoutMs?: number | undefined\n}\n\n/**\n * Run one script against a read-only corpus, and report what it printed.\n *\n * ## A non-zero exit is reported rather than raised\n *\n * A script that throws, or that exits 1 deliberately, comes back as a successful envelope carrying\n * `exitCode` and `stderr`. Mapping a guest exit onto the CLI's own exit 1 instead would\n * make `memhtml exec` unable to distinguish \"your script failed\" from \"the runtime could not run it\", and\n * an agent debugging a selector would get an error envelope with the script's real diagnostic buried\n * in an `error` string. The runtime's own failures (an absent corpus, an unreadable helper) do travel\n * the error channel and become exit 1.\n *\n * A sandbox that fails to answer a guest filesystem call is the RUNTIME failing, even though the guest\n * surfaces it as a thrown script error. {@link bridgeFault} names the two phrases that say so, and the\n * script is re-run against the same tree up to {@link BRIDGE_ATTEMPTS} times; only exhaustion becomes a\n * failure, and it becomes the runtime's. `durationMs` is therefore the attempt that answered.\n *\n * ## The sandbox has no network client, and that is this function's choice\n *\n * `new Bash()` is constructed with no `network` and no `fetch` option, so just-bash never registers its\n * network commands at all. Per `Bash.d.ts:80`: \"Network commands (curl, wget) are registered when either\n * `fetch` or `network` is provided.\" Probed 2026-08-09 (`scripts/probe-sandbox-egress.mjs`): `curl` is\n * exit 127 \"command not found\", and the guest's `fetch` refuses on call with \"Network access not\n * configured.\" `fetch` is a function there, so a `typeof` check on the global proves nothing. Eve\n * passes `dangerouslyAllowFullInternetAccess`, so the consolidator's sandbox does reach the network.\n * Whoever calls `new Bash()` decides egress, so it is decided here, for this runtime, by omission.\n *\n * ## Two opt-ins, one taken\n *\n * `javascript` is on because `js-exec` is the feature. `python` is off, and so is `network`. Both\n * are off by default in just-bash. That default is preserved as an explicit decision\n * rather than inherited silently, because a future edit adding `python: true` for one recipe would\n * hand every script a second language runtime.\n */\nexport const runExec = (\n input: ExecInput\n): Effect.Effect<ExecReport, InvalidMemory | StorageFailure> =>\n Effect.gen(function* () {\n const timeoutMs = input.timeoutMs ?? DEFAULT_TIMEOUT_MS\n\n /**\n * `just-bash` and the mount helper arrive by dynamic import, and the reason is measured.\n *\n * `just-bash`'s bundle is ~6 MB across 20 chunks and costs ~160ms to load. `@memhtml/consolidator`'s\n * barrel re-exports `mount.js`, which imports it statically, and `apps/cli/src/api-layer.ts`\n * imports that barrel, so today `just-bash` is already on the graph of every `memhtml read`\n * (20 chunks loaded, traced with `module.registerHooks`). Importing it here as well would add a\n * second static edge that survives any future fix to that one. This form keeps the exec path's own\n * cost on the exec path, which is the standing rule for the eve closure (`api-layer.ts`, where\n * `eve/client` is dynamic for the same reason).\n */\n const { Bash } = yield* Effect.tryPromise({\n try: () => import(\"just-bash\"),\n catch: (cause) => StorageFailure.make({ operation: `exec.sandbox-load: ${String(cause)}` })\n })\n const { mountReadOnlyRoots } = yield* Effect.tryPromise({\n try: () => import(\"@memhtml/consolidator\"),\n catch: (cause) => StorageFailure.make({ operation: `exec.mount-load: ${String(cause)}` })\n })\n\n const helperSource = yield* Effect.tryPromise({\n try: () => readFile(guestHelperPath(), \"utf8\"),\n catch: (cause) => StorageFailure.make({ operation: `exec.guest-helper: ${String(cause)}` })\n })\n const parserSource = yield* Effect.tryPromise({\n try: () => readFile(parserSourcePath(), \"utf8\"),\n catch: (cause) => StorageFailure.make({ operation: `exec.guest-parser: ${String(cause)}` })\n })\n\n /**\n * One attempt: a fresh mount, a fresh sandbox, one execution.\n *\n * Everything the guest touches is built here rather than above, so a retry\n * ({@link withBridgeRetry}) starts from a new shared buffer and a new bridge instead of re-running\n * against the one that just failed to answer. Only the two sources read off the host — the parser\n * and the helper — are hoisted, because they are the same bytes on every attempt.\n */\n const attempt = (): Effect.Effect<ExecReport, InvalidMemory | StorageFailure> =>\n Effect.gen(function* () {\n /**\n * The one composition, from `apps/consolidator/src/mount.ts`.\n *\n * Not re-derived here. That module encodes the `mountPoint: \"/\"` requirement on the nested\n * `OverlayFs`, which a file count cannot catch, because all three spellings expose the same\n * number of files at three different prefixes. It also validates roots eagerly, so a bad\n * `corpusPath` is refused before a sandbox exists.\n */\n const { filesystem } = yield* Effect.try({\n try: () =>\n mountReadOnlyRoots({\n roots: [{ mountPath: CORPUS_MOUNT, hostPath: input.corpusPath }]\n }),\n catch: (cause) =>\n InvalidMemory.make({ reason: `exec cannot mount the corpus: ${String(cause)}` })\n })\n\n /**\n * Two bounds, and the shell's is deliberately the looser one.\n *\n * `maxJsTimeoutMs` bounds the `js-exec` call and `maxExecutionTimeMs` bounds the whole shell\n * invocation, so both are needed. A script cannot outlive its budget by spending the time\n * outside the JS worker. Which one fires first changes the diagnostic, probed 2026-08-09 on a\n * `for(;;)` loop at a 400ms bound:\n *\n * | limits | exit | stderr |\n * | --- | --- | --- |\n * | `maxJsTimeoutMs` alone | 124 | `js-exec: Execution timeout: exceeded 400ms limit` |\n * | both equal | 124 | `bash: js-exec exceeded its execution deadline` |\n * | shell bound looser | 124 | `js-exec: execution timeout exceeded` + the limit-naming line |\n *\n * Setting them equal is a race whose winner decides whether the operator is told the number\n * they set. The shell's bound gets a small margin so the JS bound wins and its message, the one\n * naming the limit, is what reaches `stderr`. The margin is a grace period rather than extra\n * budget. The script is already cut off at `timeoutMs`, and the shell's bound exists only to\n * catch the case where `js-exec` itself fails to stop.\n */\n const bash = new Bash({\n fs: filesystem,\n javascript: { bootstrap: ATOB_BOOTSTRAP },\n executionLimits: {\n maxJsTimeoutMs: timeoutMs,\n maxExecutionTimeMs: timeoutMs + SHELL_TIMEOUT_GRACE_MS\n }\n })\n\n yield* Effect.tryPromise({\n try: async () => {\n await filesystem.mkdir(GUEST_LIB, { recursive: true })\n await filesystem.writeFile(`${GUEST_LIB}/nhp.mjs`, parserSource)\n await filesystem.writeFile(`${GUEST_LIB}/corpus.mjs`, helperSource)\n // Written through the filesystem rather than passed as `bash -c` text. A script arriving as\n // a shell argument would be subject to the shell's own quoting, and an agent's traversal is\n // full of `$`, backticks, and quotes that a heredoc mangles differently than a file does.\n await filesystem.writeFile(GUEST_SCRIPT, input.script)\n },\n catch: (cause) => StorageFailure.make({ operation: `exec.seed: ${String(cause)}` })\n })\n\n const started = Date.now()\n const result = yield* Effect.tryPromise({\n try: () => bash.exec(`js-exec ${GUEST_SCRIPT}`),\n // A thrown failure from `bash.exec` is the runtime's rather than the script's. just-bash\n // reports a script's own non-zero exit through `exitCode`, and throws only when it could not\n // run at all.\n catch: (cause) => StorageFailure.make({ operation: `exec.run: ${String(cause)}` })\n })\n const durationMs = Date.now() - started\n\n const stderr = String(result.stderr ?? \"\")\n return {\n corpusMount: CORPUS_MOUNT,\n sha: input.sha ?? null,\n exitCode: result.exitCode,\n stdout: String(result.stdout ?? \"\"),\n stderr,\n durationMs,\n timeoutMs,\n timedOut: cutOffByTheRuntime(result.exitCode, stderr)\n }\n })\n\n return yield* withBridgeRetry(attempt)\n })\n\n/**\n * `--file`'s bytes, or the usage failure for an unreadable path.\n *\n * A `Failure` return rather than a raised error, for the reason `applyText` has one. An unreadable\n * input path is a usage error the caller fixes by changing the call, so it must reach exit 2, and only\n * `validate`'s return path and this pre-dispatch read produce that code.\n */\nexport const readScript = async (file: string): Promise<string | Failure> => {\n try {\n return await readFile(file, \"utf8\")\n } catch (cause) {\n return fail(\n \"ERR_PATH_NOT_FOUND\",\n `exec cannot read --file ${file}: ${cause instanceof Error ? cause.message : String(cause)}`,\n [`ls ${file}`, \"cat script.mjs | memhtml exec\"]\n )\n }\n}\n\n/**\n * The whole command: pin a commit, mount it, run the script, release the worktree.\n *\n * ## Why a pinned worktree and not `$MEMHTML_ROOT` itself\n *\n * A live `$MEMHTML_ROOT` contains `.memhtml/index.db`, and the guest ships `sqlite3`. Probed 2026-08-09\n * against a read-only `OverlayFs` over a directory holding a real database: `sqlite3\n * /mnt/memhtml/.memhtml/index.db 'select count(*) …'` returned the row, exit 0. Read-only is therefore no\n * barrier to a reader, and mounting the live root would hand every script the ranked planes this command\n * is scoped to exclude, through a door no `memhtml exec` flag opens.\n *\n * `git worktree add --detach` is what closes it. Both databases are gitignored\n * (`packages/store/src/layout.ts`, `GITIGNORE`), and a gitignored file is absent from a checkout of a\n * commit. This is verified rather than argued: the worktree probe in\n * `apps/cli/tests/exec.test.ts` asserts `.memhtml` is not present and that the guest's own `sqlite3` finds\n * nothing to open. Containment is therefore a property of what is mounted, with the read-only flag as a\n * second layer, rather than resting on a flag that a reader can read straight through.\n *\n * The pin also makes an answer reproducible. `sha` rides back in the report, so the same\n * traversal over the same tree is one `--sha` away, and an uncommitted edit is invisible. That is\n * the right behavior for a command whose whole output is a claim about a corpus state.\n *\n * Cost measured: `git worktree add --detach` on the 305-file fixture is 31ms (three runs: 31/30/31),\n * against a 640ms full-corpus parse. The pin is ~5% of the work it makes correct.\n */\nexport const execCommand = (input: {\n readonly script: string\n readonly memhtmlRoot: string\n readonly sha?: string | undefined\n readonly timeoutMs?: number | undefined\n}): Effect.Effect<ExecReport, InvalidMemory | StorageFailure | GitFailure, Scope.Scope> =>\n Effect.gen(function* () {\n const git = makeGit(input.memhtmlRoot)\n\n const requested = input.sha\n const sha =\n requested !== undefined && requested.trim() !== \"\"\n ? requested.trim()\n : yield* git.revParseHead()\n if (sha === null) {\n return yield* Effect.fail(\n InvalidMemory.make({\n reason: `${input.memhtmlRoot} has no commit to mount: exec reads a committed tree, so an unborn HEAD has nothing to traverse`\n })\n )\n }\n\n /**\n * `pinCorpusSnapshot` from the shared mount module, released through `Effect.acquireRelease`.\n *\n * A worktree is an entry in the repo's own `.git/worktrees`, so a leaked one is durable state left\n * in the operator's repository rather than a temp directory the OS reclaims. The release runs on\n * the script's failure, on a timeout, and on an interrupt, which a `finally` around the happy path\n * would not cover.\n */\n const { pinCorpusSnapshot } = yield* Effect.tryPromise({\n try: () => import(\"@memhtml/consolidator\"),\n catch: (cause) => StorageFailure.make({ operation: `exec.mount-load: ${String(cause)}` })\n })\n\n const snapshot = yield* Effect.acquireRelease(\n Effect.tryPromise({\n try: () => pinCorpusSnapshot({ repoRoot: input.memhtmlRoot, sha }),\n catch: (cause) =>\n InvalidMemory.make({\n reason: `exec cannot materialize ${sha}: ${String(cause)}`\n })\n }),\n (pinned) => Effect.promise(() => pinned.release())\n )\n\n return yield* runExec({\n script: input.script,\n corpusPath: snapshot.hostPath,\n sha,\n timeoutMs: input.timeoutMs\n })\n })\n","import { mkdir, writeFile } from \"node:fs/promises\"\nimport { dirname, join } from \"node:path\"\nimport { DatabaseService } from \"@memhtml/index\"\nimport { type GeneratedFile, generateArtifacts, publishRows } from \"@memhtml/sleep\"\nimport { attemptIo, commitSubject, readFileOrNull } from \"@memhtml/store\"\nimport { Effect } from \"effect\"\n\nimport { Git } from \"./api-layer.js\"\n\n/**\n * `memhtml publish`: regenerate the per-directory `index.html` listings and the root `sitemap.xml`, and\n * commit whatever changed.\n *\n * **The generator is imported from `@memhtml/sleep` and never re-derived.** `generateArtifacts` lives\n * there because a listing needs `files.title`/`gist`/`updated_at`, all of them index projections, and\n * `@memhtml/store` is SQL-free by design. Two generators would produce two byte sequences for one tree,\n * and these files are the design's one merge-conflict source. `.gitattributes` marks them\n * `merge=ours` and a conflict is resolved by regenerating, which only works if regeneration is\n * unambiguous. The sleep integrity phase and this command therefore call the same function, and the\n * only difference between them is which commit the result lands in.\n *\n * The output is deterministic to the byte: the rows arrive path-ordered from SQL, every string is\n * escaped, and no timestamp of generation appears anywhere. Two runs over an unchanged corpus write\n * nothing and commit nothing, which also makes the command safe to run after every merge.\n */\n\n/** What a publish did. `written: 0` means the artifacts already matched the corpus. */\nexport interface PublishReport {\n readonly root: string\n /** Artifacts the generator produced: one listing per directory plus the sitemap. */\n readonly artifacts: number\n /** Artifacts whose bytes differed from what was on disk, and were therefore rewritten. */\n readonly written: number\n readonly paths: ReadonlyArray<string>\n /** The commit, or `null` when nothing changed. */\n readonly commitSha: string | null\n}\n\n/** Write one artifact if its bytes differ. Returns true when the file was rewritten. */\nconst writeIfChanged = (root: string, artifact: GeneratedFile) =>\n Effect.gen(function* () {\n const absolute = join(root, artifact.path)\n const existing = yield* readFileOrNull(absolute)\n if (existing === artifact.html) return false\n yield* attemptIo(`publish.write:${artifact.path}`, async () => {\n await mkdir(dirname(absolute), { recursive: true })\n await writeFile(absolute, artifact.html, \"utf8\")\n })\n return true\n })\n\n/**\n * Regenerate and commit.\n *\n * The whole artifact set is staged rather than only the rewritten files, because a listing that was\n * hand-edited and then regenerated to its correct bytes is a change git already knows about. `commit`\n * no-ops on an index matching HEAD, so staging everything costs nothing when nothing moved.\n */\nexport const publish = () =>\n Effect.gen(function* () {\n const git = yield* Git\n const db = yield* DatabaseService\n const rows = yield* publishRows(db)\n const artifacts = generateArtifacts(rows)\n\n const written: Array<string> = []\n for (const artifact of artifacts) {\n if (yield* writeIfChanged(git.root, artifact)) written.push(artifact.path)\n }\n\n yield* git.add(artifacts.map((artifact) => artifact.path))\n const commit = yield* git.commit(\n commitSubject(\"publish\", `regenerate ${artifacts.length} generated artifacts`)\n )\n\n return {\n root: git.root,\n artifacts: artifacts.length,\n written: written.length,\n paths: written,\n commitSha: commit.sha\n } satisfies PublishReport\n })\n","import { mkdir, writeFile } from \"node:fs/promises\"\nimport { dirname, join } from \"node:path\"\n\nimport { DatabaseService, STATE_SCHEMA } from \"@memhtml/index\"\nimport { accessRows, parseSidecar, renderSidecar } from \"@memhtml/sleep\"\nimport { attemptIo, commitSubject, readFileOrNull, STATE_SIDECAR_PATH } from \"@memhtml/store\"\nimport { Effect } from \"effect\"\n\nimport { Git } from \"./api-layer.js\"\n\n/**\n * `memhtml state export|import`: the state plane's only durability story.\n *\n * `state.db` is gitignored and cannot be rebuilt from git. Access counts, reinforcement counts, and\n * the outcome EWMA are the one set of facts the tree cannot reproduce. `.memhtml/state/access.jsonl` is\n * the committed sidecar that survives, so a fresh clone plus `memhtml state import` plus\n * `memhtml index rebuild` reproduces the whole system rather than a system with amnesia.\n *\n * Both halves reuse `@memhtml/sleep`'s own functions, `renderSidecar` for the export and `parseSidecar`\n * for the import, because the sleep cycle's state-export phase writes this file every night and two\n * writers producing two byte sequences for one plane would churn the file on alternating nights. The\n * only difference between this command and that phase is which commit the result lands in.\n */\n\n/** What an export wrote. `written: false` means the sidecar already matched the plane. */\nexport interface StateExportReport {\n readonly path: string\n readonly rows: number\n readonly bytes: number\n readonly written: boolean\n readonly commitSha: string | null\n}\n\n/** What an import restored. */\nexport interface StateImportReport {\n readonly path: string\n /** Rows the sidecar held. */\n readonly rows: number\n /** Rows actually written into `state.access`. */\n readonly restored: number\n /** Sidecar lines that did not parse. Counted and not fatal: a partial file restores what it holds. */\n readonly skipped: number\n readonly hasState: boolean\n}\n\n/**\n * Write the sidecar and commit it.\n *\n * The output is byte-stable, so an unchanged plane commits nothing. Rows arrive path-ordered from SQL\n * and floats are rounded to the domain's four-decimal grid, so an unchanged plane produces an\n * identical file and `git commit` no-ops on an index matching HEAD. Without that, the widest-churn\n * table in the system would produce a commit every time an operator ran this.\n */\nexport const stateExport = () =>\n Effect.gen(function* () {\n const git = yield* Git\n const db = yield* DatabaseService\n const rows = yield* accessRows(db)\n const contents = renderSidecar(rows)\n const absolute = join(git.root, STATE_SIDECAR_PATH)\n\n const existing = yield* readFileOrNull(absolute).pipe(Effect.orElseSucceed(() => null))\n if (existing === contents) {\n return {\n path: STATE_SIDECAR_PATH,\n rows: rows.length,\n bytes: contents.length,\n written: false,\n commitSha: null\n } satisfies StateExportReport\n }\n\n yield* attemptIo(`state.write:${STATE_SIDECAR_PATH}`, async () => {\n await mkdir(dirname(absolute), { recursive: true })\n await writeFile(absolute, contents, \"utf8\")\n })\n yield* git.add([STATE_SIDECAR_PATH])\n const commit = yield* git.commit(\n commitSubject(\"state\", `export ${rows.length} access rows to the committed sidecar`)\n )\n\n return {\n path: STATE_SIDECAR_PATH,\n rows: rows.length,\n bytes: contents.length,\n written: true,\n commitSha: commit.sha\n } satisfies StateExportReport\n })\n\n/**\n * Replay the sidecar into `state.access`.\n *\n * An upsert per row rather than a truncate-and-load, because an import onto a live plane must not\n * discard counters the sidecar predates. The sidecar is refreshed once per night, and a retrieval an\n * hour later is real state. The upsert takes the maximum of the two counts for the reason design §9's\n * multi-machine note gives: these columns are monotone, so max-of is the merge that cannot lose a\n * bump, while last-writer-wins can.\n *\n * `parseSidecar` is defensive per line, so a file truncated by an interrupted write restores every row\n * it does hold. Rejecting the whole file would turn a partial loss into a total one.\n */\nexport const stateImport = () =>\n Effect.gen(function* () {\n const git = yield* Git\n const db = yield* DatabaseService\n const absolute = join(git.root, STATE_SIDECAR_PATH)\n const contents = yield* readFileOrNull(absolute).pipe(Effect.orElseSucceed(() => null))\n\n if (contents === null) {\n return {\n path: STATE_SIDECAR_PATH,\n rows: 0,\n restored: 0,\n skipped: 0,\n hasState: db.hasState\n } satisfies StateImportReport\n }\n\n const { entries, skipped } = parseSidecar(contents)\n if (!db.hasState || entries.length === 0) {\n return {\n path: STATE_SIDECAR_PATH,\n rows: entries.length,\n restored: 0,\n skipped,\n hasState: db.hasState\n } satisfies StateImportReport\n }\n\n yield* db.writeAll(\n entries.map((entry) => ({\n sql: `INSERT INTO ${STATE_SCHEMA}.access\n (path, access_count, reinforcement_count, outcome_score,\n last_accessed_at, last_reinforced_at, updated_at)\n VALUES (?, ?, ?, ?, ?, ?, ?)\n ON CONFLICT(path) DO UPDATE SET\n access_count = max(access_count, excluded.access_count),\n reinforcement_count = max(reinforcement_count, excluded.reinforcement_count),\n outcome_score = excluded.outcome_score,\n last_accessed_at = max(coalesce(last_accessed_at, ''), coalesce(excluded.last_accessed_at, '')),\n last_reinforced_at = max(coalesce(last_reinforced_at, ''), coalesce(excluded.last_reinforced_at, '')),\n updated_at = excluded.updated_at`,\n params: [\n entry.path,\n entry.accessCount,\n entry.reinforcementCount,\n entry.outcomeScore,\n entry.lastAccessedAt,\n entry.lastReinforcedAt,\n entry.updatedAt\n ]\n }))\n )\n\n return {\n path: STATE_SIDECAR_PATH,\n rows: entries.length,\n restored: entries.length,\n skipped,\n hasState: true\n } satisfies StateImportReport\n })\n","import { InvalidMemory } from \"@memhtml/contracts/errors\"\nimport { DatabaseService, type DatabaseShape, readIndexState } from \"@memhtml/index\"\nimport { EMBED_WATERMARK } from \"@memhtml/llm\"\nimport { isSleepPhase, type RunReport, SLEEP_PHASES, type SleepPhase } from \"@memhtml/sleep\"\nimport { Effect } from \"effect\"\n\n/**\n * Response shaping: the few places a payload is not simply the use case's own return value.\n *\n * Kept out of the dispatcher so an arm stays one call. Each function here exists because a wire\n * shape and an internal shape differ. One is a report that must not carry an unbounded field. The\n * other is a flag list that must be validated against a closed vocabulary before it reaches a runner.\n */\n\n/**\n * The index's own report of itself: the watermark, the vector space, and the row counts.\n *\n * `memhtml index status` reads this rather than running an indexer method, because \"what does the index\n * currently contain\" must be answerable without the git subprocess an `update` would spawn. An\n * operator asking about a stale index is frequently asking because something is wrong with the repo.\n */\nexport const indexReport = () =>\n Effect.gen(function* () {\n const db = yield* DatabaseService\n const state = yield* readIndexState(db).pipe(Effect.orElseSucceed(() => undefined))\n\n return {\n mode: \"status\",\n headSha: state?.head_sha ?? null,\n embedModel: state?.embed_model ?? null,\n embedDim: state?.embed_dim ?? null,\n /**\n * True when the stored vector space IS the configured one. On a mismatch the indexer stops\n * instead of writing, so reporting the two values separately lets an operator see which side\n * to change.\n */\n embedModelMatches: state?.embed_model === EMBED_WATERMARK,\n configuredEmbedModel: EMBED_WATERMARK,\n rebuiltAt: state?.rebuilt_at ?? null,\n updatedAt: state?.updated_at ?? null,\n files: yield* count(db, \"SELECT count(*) AS n FROM files\"),\n activeFiles: yield* count(db, \"SELECT count(*) AS n FROM files WHERE archived = 0\"),\n chunks: yield* count(db, \"SELECT count(*) AS n FROM chunks\"),\n embeddings: yield* count(db, \"SELECT count(*) AS n FROM embeddings\"),\n edges: yield* count(db, \"SELECT count(*) AS n FROM edges\"),\n derivedEdges: yield* count(db, \"SELECT count(*) AS n FROM edges WHERE derived = 1\"),\n tags: yield* count(db, \"SELECT count(DISTINCT tag) AS n FROM file_tags\"),\n entities: yield* count(\n db,\n \"SELECT count(DISTINCT entity_type || ':' || entity_name) AS n FROM file_entities\"\n ),\n traces: yield* count(db, \"SELECT count(*) AS n FROM traces\"),\n hasState: db.hasState\n }\n })\n\nconst count = (db: DatabaseShape, sql: string) =>\n db.get<{ n: number }>(sql).pipe(\n Effect.map((row) => row?.n ?? 0),\n Effect.orElseSucceed(() => 0)\n )\n\n/**\n * A `--phases` value as a validated phase list, or `undefined` for \"all fifteen\".\n *\n * An unknown phase is rejected instead of dropped silently. A run asked for `--phases dedup,compress`\n * with a typo in the first name would otherwise execute only the second. `dedup-merge` is a hard\n * prerequisite of `compress`, so the typo would produce a compress pass over a corpus that still\n * holds its duplicates.\n */\nexport const sleepPhases = (\n raw: string | undefined\n): Effect.Effect<ReadonlyArray<SleepPhase> | undefined, InvalidMemory> => {\n if (raw === undefined || raw.trim() === \"\") return Effect.succeed(undefined)\n const names = raw\n .split(\",\")\n .map((name) => name.trim())\n .filter((name) => name !== \"\")\n\n const unknown = names.filter((name) => !isSleepPhase(name))\n if (unknown.length > 0) {\n return Effect.fail(\n InvalidMemory.make({\n reason: `unknown sleep phase: ${unknown.join(\", \")}. One of: ${SLEEP_PHASES.join(\", \")}`\n })\n )\n }\n\n // Canonical order, not the caller's. The order encodes real dependencies: decay runs before triage\n // so triage scores the decayed value. Honoring a caller's ordering would let a `--phases` value\n // silently invert them.\n return Effect.succeed(SLEEP_PHASES.filter((phase) => names.includes(phase)))\n}\n\n/**\n * A run report on the wire.\n *\n * Identical to the internal shape except for `llmCalls`, which is summed per phase and totalled. A\n * caller auditing Bedrock spend reads the total, and one debugging a phase reads the per-phase\n * number. Deriving either from the other at the call site is how two consumers end up disagreeing\n * about what a number counts.\n */\nexport const sleepRunReport = (report: RunReport) => ({\n runId: report.runId,\n branch: report.branch,\n baseSha: report.baseSha,\n headSha: report.headSha,\n dryRun: report.dryRun,\n llmCalls: report.llmCalls,\n phases: report.phases,\n /** Phases that ended `failed`. Present so a caller does not have to filter to know. */\n failedPhases: report.phases.flatMap((phase) => (phase.status === \"failed\" ? [phase.phase] : [])),\n commits: report.phases.flatMap((phase) => (phase.commitSha === null ? [] : [phase.commitSha]))\n})\n","import { discriminationGate, type EvalMode, runDiscrimination } from \"@memhtml/eval\"\nimport { initRepo } from \"@memhtml/store\"\nimport { Effect, type Layer, Logger } from \"effect\"\nimport { runAgentsDoc } from \"./agents-doc.js\"\nimport { Git, Indexer, layerApp, Sleep } from \"./api-layer.js\"\nimport { applyPayload, applyText, decodeApply, readStdin } from \"./apply.js\"\nimport { buildManifest, COMMAND_NAMES, COMMANDS, GLOBAL_FLAGS } from \"./commands.js\"\nimport { MemhtmlRoot } from \"./config.js\"\nimport { doctor } from \"./doctor.js\"\nimport {\n API_VERSION,\n EXIT_OK,\n EXIT_RUNTIME,\n EXIT_USAGE,\n type Failure,\n fail,\n nearest,\n render,\n type Success,\n succeed\n} from \"./envelope.js\"\nimport { failureFor } from \"./errors.js\"\nimport { DEFAULT_TIMEOUT_MS, execCommand, MAX_TIMEOUT_MS, readScript } from \"./exec.js\"\nimport * as ops from \"./operations.js\"\nimport { publish } from \"./publish.js\"\nimport { serveMcp } from \"./serve.js\"\nimport { stateExport, stateImport } from \"./state.js\"\nimport { indexReport, sleepPhases, sleepRunReport } from \"./views.js\"\n\nexport interface Parsed {\n readonly command: string\n readonly positional: ReadonlyArray<string>\n readonly flags: ReadonlyMap<string, ReadonlyArray<string | boolean>>\n}\n\nconst KNOWN_FLAGS = new Set([\n ...GLOBAL_FLAGS.map((flag) => flag.name),\n ...COMMANDS.flatMap((command) => command.flags.map((flag) => flag.name))\n])\n\n/**\n * The two-word command names, longest first.\n *\n * A subcommand is matched greedily so `index status` beats `index`, and the leftover tokens become\n * positionals. Matching the shorter name first would make `memhtml index status` a call to a\n * hypothetical `index` command with `status` as an argument, which is a wrong answer rather than an\n * error.\n */\nconst COMPOUND_NAMES = COMMAND_NAMES.filter((name) => name.includes(\" \")).sort(\n (left, right) => right.length - left.length\n)\n\n/**\n * `--flag value`, `--flag=value`, `--no-flag`, and bare `--flag`.\n *\n * Every flag's value is an array, because several flags are repeatable (`--tag`, `--entity`,\n * `--body`) and a map of scalars would silently keep only the last occurrence, so a write with three\n * entities would store one. Non-repeatable flags read `.at(-1)`, so a duplicate is last-wins rather\n * than an error, which is what a shell user retyping a flag expects.\n */\nexport const parseArgv = (argv: ReadonlyArray<string>): Parsed => {\n const positional: Array<string> = []\n const flags = new Map<string, Array<string | boolean>>()\n\n const push = (name: string, value: string | boolean): void => {\n const existing = flags.get(name)\n if (existing === undefined) flags.set(name, [value])\n else existing.push(value)\n }\n\n let index = 0\n while (index < argv.length) {\n const token = argv[index] as string\n if (token.startsWith(\"--\")) {\n const body = token.slice(2)\n const eq = body.indexOf(\"=\")\n if (eq !== -1) {\n push(body.slice(0, eq), body.slice(eq + 1))\n index += 1\n continue\n }\n // `--no-embed` is how a boolean defaulting to true is turned off. Without it, a flag whose\n // default is `true` would be unsettable from a shell.\n if (body.startsWith(\"no-\") && KNOWN_FLAGS.has(body.slice(3))) {\n push(body.slice(3), false)\n index += 1\n continue\n }\n const next = argv[index + 1]\n if (next !== undefined && !next.startsWith(\"--\")) {\n push(body, next)\n index += 2\n continue\n }\n push(body, true)\n index += 1\n continue\n }\n positional.push(token)\n index += 1\n }\n\n const joined = positional.join(\" \")\n const compound = COMPOUND_NAMES.find((name) => joined === name || joined.startsWith(`${name} `))\n if (compound !== undefined) {\n const consumed = compound.split(\" \").length\n return { command: compound, positional: positional.slice(consumed), flags }\n }\n\n return { command: positional[0] ?? \"\", positional: positional.slice(1), flags }\n}\n\n/** A flag's last value as a string, or `undefined` when it was not given. */\nconst str = (parsed: Parsed, name: string): string | undefined => {\n const value = parsed.flags.get(name)?.at(-1)\n return value === undefined || typeof value === \"boolean\" ? undefined : value\n}\n\n/** Every value a repeatable flag was given, in order. Empty when absent. */\nconst list = (parsed: Parsed, name: string): ReadonlyArray<string> =>\n (parsed.flags.get(name) ?? []).flatMap((value) =>\n typeof value === \"string\" && value !== \"\" ? [value] : []\n )\n\n/** A flag as a boolean: bare `--flag` is true, `--no-flag` is false, `--flag=false` is false. */\nconst bool = (parsed: Parsed, name: string, fallback: boolean): boolean => {\n const value = parsed.flags.get(name)?.at(-1)\n if (value === undefined) return fallback\n if (typeof value === \"boolean\") return value\n return value !== \"false\" && value !== \"0\" && value !== \"no\"\n}\n\n/** A flag as an integer, or `undefined` when absent or unparseable. */\nconst int = (parsed: Parsed, name: string): number | undefined => {\n const raw = str(parsed, name)\n if (raw === undefined) return undefined\n const value = Number.parseInt(raw, 10)\n return Number.isFinite(value) ? value : undefined\n}\n\n/** A flag as a finite number in a range, or `undefined`. */\nconst num = (parsed: Parsed, name: string): number | undefined => {\n const raw = str(parsed, name)\n if (raw === undefined) return undefined\n const value = Number.parseFloat(raw)\n return Number.isFinite(value) ? value : undefined\n}\n\n/** The scope every retrieval command shares, so `search` and `recall` cannot diverge. */\nconst scopeOf = (parsed: Parsed) => ({\n memoryTypes: list(parsed, \"type\") as ReadonlyArray<never>,\n workspace: str(parsed, \"workspace\"),\n tags: list(parsed, \"tag\"),\n entity: str(parsed, \"entity\"),\n includeArchived: bool(parsed, \"include-archived\", false),\n asOf: str(parsed, \"as-of\")\n})\n\n/** Session provenance, from the three flags every write-path command accepts. */\nconst provenanceOf = (parsed: Parsed) => ({\n sessionId: str(parsed, \"session-id\"),\n promptId: str(parsed, \"prompt-id\"),\n turnUuid: str(parsed, \"turn-uuid\")\n})\n\nexport interface RunResult {\n readonly stdout: string\n readonly exitCode: number\n}\n\n/** What a handler returns: a response type and its payload. The envelope is added once, below. */\ntype Handled = readonly [Success<unknown>[\"type\"], unknown]\n\n/**\n * Dispatch one parsed invocation against the provided services.\n *\n * Every arm is decode → call → name the response type. No arm builds an envelope, catches an error,\n * or writes to a stream. Those happen once in {@link run}, which keeps thirty-one commands\n * from having thirty-one slightly different failure shapes.\n *\n * `applyOps` is the one piece of state an arm cannot derive from `parsed`. Reading a file or draining\n * stdin is async I/O whose failures are usage errors (exit 2), and `run` has already done it and\n * refused before reaching here. It is passed in rather than read here, so the `apply` arm stays what\n * every other arm is: one call to a shared use case.\n */\nconst dispatch = (\n parsed: Parsed,\n applyOps: ReadonlyArray<ops.WriteParams> = []\n): Effect.Effect<Handled, unknown, DispatchServices> => {\n switch (parsed.command) {\n case \"manifest\":\n return Effect.succeed([\"cli.manifest\", buildManifest()])\n\n case \"init\":\n return Effect.gen(function* () {\n const git = yield* Git\n const result = yield* initRepo(git)\n return [\"repo.init\", result] as const\n })\n\n case \"write\":\n return Effect.gen(function* () {\n const result = yield* ops.writeMemory({\n title: str(parsed, \"title\") ?? \"\",\n // `claim` is \"\" exactly when `--article-html` supplied the article instead, which\n // `validate` has already proven is the only way to get here without a claim. The\n // template ignores `claim` entirely on that branch (`@memhtml/html` template.ts:88-91).\n claim: str(parsed, \"claim\") ?? \"\",\n body: list(parsed, \"body\"),\n articleHtml: str(parsed, \"article-html\"),\n memoryType: str(parsed, \"type\") ?? \"\",\n path: str(parsed, \"path\"),\n workspace: str(parsed, \"workspace\"),\n tags: list(parsed, \"tag\"),\n entities: list(parsed, \"entity\"),\n importance: int(parsed, \"importance\"),\n confidence: num(parsed, \"confidence\"),\n ...provenanceOf(parsed)\n })\n return [\"memory.written\", result] as const\n })\n\n /**\n * The batch door. One call to the shared `batchWrite`, and the per-op `code`/`error` it returns\n * are not re-mapped here. The operation already ran them through the same `codeFor`/`messageFor`\n * every envelope error takes, so this door and `memory_write_batch` cannot report\n * different codes for one refused op.\n */\n case \"apply\":\n return Effect.gen(function* () {\n const result = yield* ops.batchWrite({\n ops: applyOps,\n continueOnError: bool(parsed, \"continue-on-error\", false),\n detectConflicts: bool(parsed, \"detect-conflicts\", false),\n // `validate` has already refused any value outside the flag's closed vocabulary, so the\n // narrowing here cannot silently drop a caller's ask.\n ...(str(parsed, \"consolidate\") === \"last-wins\"\n ? { consolidate: \"last-wins\" as const }\n : {}),\n ...provenanceOf(parsed)\n })\n return [\"batch.applied\", applyPayload(result)] as const\n })\n\n case \"read\":\n return Effect.gen(function* () {\n const result = yield* ops.readMemory(parsed.positional[0] ?? \"\", provenanceOf(parsed))\n return [\n \"memory.detail\",\n {\n path: result.path,\n title: result.doc.title,\n metas: result.doc.metas,\n entities: result.doc.entities,\n tags: result.doc.tags,\n links: result.doc.links,\n gist: result.doc.article.gist,\n body: result.doc.article.bodyText,\n html: result.doc.article.html,\n archived: result.doc.metas.status === \"archived\",\n warnings: result.doc.warnings\n }\n ] as const\n })\n\n case \"search\":\n return Effect.gen(function* () {\n const result = yield* ops.searchMemories({\n query: parsed.positional[0] ?? \"\",\n limit: int(parsed, \"limit\"),\n ...scopeOf(parsed)\n })\n return [\"memory.hits\", result] as const\n })\n\n case \"recall\":\n return Effect.gen(function* () {\n const pack = yield* ops.recallMemories({\n query: parsed.positional[0] ?? \"\",\n budgetChars: int(parsed, \"budget\"),\n ...scopeOf(parsed)\n })\n return [\"recall.pack\", pack] as const\n })\n\n case \"correct\":\n return Effect.gen(function* () {\n const result = yield* ops.correctMemory({\n targetPath: parsed.positional[0] ?? \"\",\n title: str(parsed, \"title\") ?? \"\",\n claim: str(parsed, \"claim\") ?? \"\",\n body: list(parsed, \"body\"),\n articleHtml: str(parsed, \"article-html\"),\n memoryType: str(parsed, \"type\"),\n reason: str(parsed, \"reason\"),\n ...provenanceOf(parsed)\n })\n return [\"memory.corrected\", result] as const\n })\n\n case \"link\":\n return Effect.gen(function* () {\n const result = yield* ops.linkMemories(\n parsed.positional[0] ?? \"\",\n parsed.positional[1] ?? \"\",\n parsed.positional[2] ?? \"\"\n )\n return [\"memory.linked\", result] as const\n })\n\n case \"neighbors\":\n return Effect.gen(function* () {\n const result = yield* ops.neighborsOf({\n path: parsed.positional[0] ?? \"\",\n depth: int(parsed, \"depth\"),\n rels: list(parsed, \"rel\")\n })\n return [\"memory.neighbors\", result] as const\n })\n\n case \"archive\":\n return Effect.gen(function* () {\n const result = yield* ops.archiveMemory(\n parsed.positional[0] ?? \"\",\n str(parsed, \"reason\") ?? \"\"\n )\n return [\"memory.archived\", result] as const\n })\n\n case \"reinforce\":\n return Effect.gen(function* () {\n // Every positional is a path: `memhtml reinforce a.html b.html --signal positive` is the shape\n // an agent reaching for the MCP tool's `paths` array writes on a command line.\n const result = yield* ops.reinforceMemories(\n parsed.positional,\n str(parsed, \"signal\") ?? \"neutral\"\n )\n return [\"memory.reinforced\", result] as const\n })\n\n case \"list\":\n return Effect.gen(function* () {\n const result = yield* ops.listMemories({\n memoryType: str(parsed, \"type\"),\n workspace: str(parsed, \"workspace\"),\n tag: str(parsed, \"tag\"),\n entity: str(parsed, \"entity\"),\n para: str(parsed, \"para\"),\n limit: int(parsed, \"limit\"),\n cursor: str(parsed, \"cursor\"),\n includeArchived: bool(parsed, \"include-archived\", false)\n })\n return [\"memory.list\", result] as const\n })\n\n case \"task add\":\n return Effect.gen(function* () {\n const title = str(parsed, \"title\") ?? \"\"\n const result = yield* ops.writeMemory({\n title,\n // The claim defaults to the title, because a task's statement and its name are usually the\n // same sentence, and a required second phrasing would be restated verbatim every time.\n claim: str(parsed, \"claim\") ?? title,\n body: list(parsed, \"body\"),\n memoryType: \"task\",\n workspace: str(parsed, \"workspace\"),\n tags: list(parsed, \"tag\"),\n entities: list(parsed, \"entity\"),\n taskStatus: str(parsed, \"status\"),\n dueAt: str(parsed, \"due\"),\n ...provenanceOf(parsed)\n })\n return [\n \"task.written\",\n {\n path: result.path,\n created: result.created,\n deduped: result.deduped,\n // Two open tasks with identical bodies are two real work items, so the dedup carve-out\n // means this is normally false. It is reported anyway, because a caller cannot tell a\n // fresh file from a returned one without it.\n existingPath: result.existingPath ?? null,\n taskStatus: str(parsed, \"status\") ?? \"todo\",\n dueAt: str(parsed, \"due\") ?? null,\n commitSha: result.commitSha\n }\n ] as const\n })\n\n case \"task status\":\n return Effect.gen(function* () {\n const result = yield* ops.setTaskStatus({\n path: parsed.positional[0] ?? \"\",\n status: parsed.positional[1] ?? \"\",\n reason: str(parsed, \"reason\")\n })\n return [\"task.updated\", { ...result, archivePath: result.archivePath ?? null }] as const\n })\n\n case \"task list\":\n return Effect.gen(function* () {\n const result = yield* ops.listTasks({\n status: str(parsed, \"status\"),\n workspace: str(parsed, \"workspace\"),\n dueBefore: str(parsed, \"due-before\"),\n limit: int(parsed, \"limit\"),\n cursor: str(parsed, \"cursor\"),\n includeArchived: bool(parsed, \"include-archived\", false)\n })\n return [\"task.list\", result] as const\n })\n\n case \"index rebuild\":\n return Effect.gen(function* () {\n const indexer = yield* Indexer\n const report = yield* indexer.rebuild({ embed: bool(parsed, \"embed\", true) })\n return [\"index.report\", { mode: \"rebuild\", ...report }] as const\n })\n\n case \"index update\":\n return Effect.gen(function* () {\n const indexer = yield* Indexer\n const report = yield* indexer.update({ embed: bool(parsed, \"embed\", true) })\n return [\"index.report\", { mode: \"update\", ...report }] as const\n })\n\n case \"index status\":\n return Effect.gen(function* () {\n const report = yield* indexReport()\n return [\"index.report\", report] as const\n })\n\n case \"trace index\":\n return Effect.gen(function* () {\n const report = yield* ops.indexTraces()\n return [\"trace.report\", report] as const\n })\n\n case \"trace search\":\n return Effect.gen(function* () {\n const result = yield* ops.searchTraces({\n query: parsed.positional[0] ?? \"\",\n cwd: str(parsed, \"cwd\"),\n since: str(parsed, \"since\"),\n limit: int(parsed, \"limit\")\n })\n return [\"trace.sessions\", result] as const\n })\n\n case \"trace links\":\n return Effect.gen(function* () {\n const result = yield* ops.traceLinks({\n sessionId: str(parsed, \"session-id\"),\n path: str(parsed, \"path\")\n })\n return [\"trace.links\", result] as const\n })\n\n case \"sleep run\":\n return Effect.gen(function* () {\n const sleep = yield* Sleep\n const phases = yield* sleepPhases(str(parsed, \"phases\"))\n const report = yield* sleep.run({\n date: str(parsed, \"date\") ?? (yield* today),\n ...(phases === undefined ? {} : { phases }),\n dryRun: bool(parsed, \"dry-run\", false)\n })\n return [\"sleep.report\", sleepRunReport(report)] as const\n })\n\n case \"sleep resume\":\n return Effect.gen(function* () {\n const sleep = yield* Sleep\n const report = yield* sleep.resume(parsed.positional[0] ?? \"\")\n return [\"sleep.report\", sleepRunReport(report)] as const\n })\n\n case \"sleep review\":\n return Effect.gen(function* () {\n const sleep = yield* Sleep\n const report = yield* sleep.review(parsed.positional[0])\n const withDiff = bool(parsed, \"diff\", false)\n if (!withDiff) return [\"sleep.review\", report] as const\n // The raw diff is fetched here rather than inside `review`, because it is the one field whose\n // size is unbounded, and a review that always carried it would make the default response\n // unusable in a context window.\n const git = yield* Git\n const diff = yield* git\n .run([\"diff\", `${report.baseSha}..${report.headSha}`])\n .pipe(Effect.orElseSucceed(() => \"\"))\n return [\"sleep.review\", { ...report, diff }] as const\n })\n\n case \"sleep merge\":\n return Effect.gen(function* () {\n const sleep = yield* Sleep\n const skipGate = bool(parsed, \"skip-gate\", false)\n if (skipGate) {\n yield* Effect.logWarning(\n \"sleep merge --skip-gate: merging without re-running discrimination\"\n )\n }\n /**\n * **The discrimination gate, composed here.** A sleep run that degrades retrieval quality\n * cannot land. `@memhtml/sleep` takes the gate as a parameter and supplies none, so a package\n * that cannot import the eval also cannot silently default it. The composition is visible in\n * this wiring or it does not exist.\n *\n * `discriminationGate` fails on an inversion, `merge` wraps it in `Effect.result`, and the\n * failure becomes `refusal: \"gate-failed\"` with `main` never moving.\n *\n * `fake` mode, always. The gate measures the ranking stack against its own generated fixture\n * corpus, so a live-Bedrock run would make a nightly merge conditional on a network call and\n * on credentials being present at 3am. The deterministic embedder's cosine relations are\n * a pure function of the text, which is the property a regression gate needs. A\n * cron whose merge silently skipped its gate because a token expired is the failure this\n * arrangement prevents.\n */\n const report = yield* sleep.merge(\n parsed.positional[0] ?? \"\",\n skipGate ? {} : { preMergeGate: discriminationGate().pipe(Effect.asVoid) }\n )\n return [\"sleep.merge\", report] as const\n })\n\n case \"publish\":\n return Effect.gen(function* () {\n const report = yield* publish()\n return [\"publish.report\", report] as const\n })\n\n case \"doctor\":\n return Effect.gen(function* () {\n const report = yield* doctor({ fix: bool(parsed, \"fix\", false) })\n return [\"doctor.report\", report] as const\n })\n\n case \"state export\":\n return Effect.gen(function* () {\n const report = yield* stateExport()\n return [\"state.export\", report] as const\n })\n\n case \"state import\":\n return Effect.gen(function* () {\n const report = yield* stateImport()\n return [\"state.import\", report] as const\n })\n\n case \"sleep status\":\n return Effect.gen(function* () {\n const sleep = yield* Sleep\n const report = yield* sleep.review()\n return [\n \"sleep.report\",\n {\n runId: report.runId,\n branch: report.branch,\n baseSha: report.baseSha,\n headSha: report.headSha,\n phases: report.phases,\n commits: report.commits.length\n }\n ] as const\n })\n\n case \"status\":\n return Effect.gen(function* () {\n const report = yield* ops.statusReport()\n return [\"status.health\", report] as const\n })\n\n default:\n // Unreachable while every COMMANDS entry has a case. A new spec with no handler surfaces\n // here as a usage error rather than an empty stdout.\n return Effect.fail({ _tag: \"UnhandledCommand\", command: parsed.command })\n }\n}\n\n/** Today as `YYYY-MM-DD`, through the Effect clock so a test can pin the run date. */\nconst today = Effect.clockWith((clock) =>\n Effect.map(clock.currentTimeMillis, (millis) => new Date(millis).toISOString().slice(0, 10))\n)\n\n/**\n * The services `dispatch` may reach for, derived from the app layer's own output.\n *\n * Derived rather than listed. A service added to `layerCore` becomes available to a handler with no\n * edit here, and a service removed from the layer becomes a compile error at\n * the handler that reads it, rather than a runtime \"service not found\" at the one moment an operator\n * is running the command.\n */\ntype DispatchServices = Layer.Success<ReturnType<typeof layerApp>>\n\n/**\n * An unknown command, with candidates measured against the whole typed invocation.\n *\n * `parseArgv` only matches a compound name exactly, so a typo in either word of `memhtml index rebuild`\n * leaves `command` holding the first token alone and every remaining token in `positional`.\n * Measuring `\"index\"` against the flat name list scores `init` at 2 and `index rebuild` at 8, so the\n * suggestion an operator needs loses to one they did not ask for. Re-joining the tokens makes\n * the distance a comparison of the two things: `\"index rebiuld\"` is 2 from `index rebuild` and 12\n * from `init`.\n *\n * Both are offered, the joined form first, because the typo could be in either half. A one-word\n * invocation joins to itself, so the single-command path is unchanged.\n */\nconst unknownCommand = (parsed: Parsed): Failure => {\n const typed = [parsed.command, ...parsed.positional].join(\" \").trim()\n const candidates = [\n ...nearest(typed, COMMAND_NAMES),\n ...nearest(parsed.command, COMMAND_NAMES)\n ].filter((name, at, all) => all.indexOf(name) === at)\n return fail(\n \"ERR_UNKNOWN_COMMAND\",\n `unknown command: ${typed === \"\" ? parsed.command : typed}`,\n candidates.slice(0, 3)\n )\n}\n\n/**\n * The commands where the article body comes from either a claim or pre-authored markup, never both.\n *\n * Listed here rather than expressed in `FlagSpec`, because `FlagSpec` has one `required: boolean` and\n * no notion of a conditional. Inventing a table field for a rule that holds on two commands\n * would put a second, weaker copy of this check into the manifest for every command that does not\n * need it. Both flag descriptions state the rule, so `memhtml manifest` still carries it.\n */\nconst EITHER_CLAIM_OR_ARTICLE: ReadonlySet<string> = new Set([\"write\", \"correct\"])\n\n/**\n * `memhtml exec` takes at most one script door, and a bound inside the cap.\n *\n * Here for the reason `claimOrArticle` is: `validate`'s return becomes exit 2 and a failure raised in\n * `dispatch` becomes exit 1, so \"you passed the wrong flags\" must be decided before any service is\n * built. `.erpaval/solutions/api-patterns/xor-params-and-mcp-error-masking.md` records the rule.\n *\n * At most one rather than exactly one, because zero doors is legal and means stdin, the same shape\n * `memhtml apply` has, where a bare invocation drains the pipe. A missing script is not a usage error\n * here. An empty one is, and that check sits beside the read in {@link run} because reading is async.\n *\n * `--timeout-ms` is checked for a positive integer within the cap. Zero and negatives are refused\n * rather than clamped, because just-bash treats a non-positive `maxJsTimeoutMs` as no bound at all, so\n * `--timeout-ms 0` would read as \"be quick\" and mean \"run forever\".\n */\nconst execFlags = (parsed: Parsed): Failure | undefined => {\n if (parsed.command !== \"exec\") return undefined\n\n const doors = [\n str(parsed, \"file\") === undefined ? undefined : \"--file\",\n str(parsed, \"script\") === undefined ? undefined : \"--script\"\n ].filter((door) => door !== undefined)\n if (doors.length > 1) {\n return fail(\n \"ERR_INVALID_FLAG\",\n \"exec takes at most one of --file or --script, not both: two scripts cannot both be the one that runs\",\n [\n \"memhtml exec --file traverse.mjs\",\n \"memhtml exec --script 'console.log(1)'\",\n \"cat s.mjs | memhtml exec\"\n ]\n )\n }\n // A `-` positional is the explicit stdin spelling, so it cannot sit beside a door either.\n if (doors.length === 1 && parsed.positional[0] === \"-\") {\n return fail(\n \"ERR_INVALID_FLAG\",\n `exec cannot read stdin and ${doors[0]} in the same call: \\`-\\` names stdin as the script source`,\n [\"cat s.mjs | memhtml exec\", `memhtml exec ${doors[0]} …`]\n )\n }\n\n const raw = str(parsed, \"timeout-ms\")\n if (raw !== undefined) {\n const timeout = int(parsed, \"timeout-ms\")\n if (timeout === undefined || timeout <= 0 || timeout > MAX_TIMEOUT_MS) {\n return fail(\n \"ERR_INVALID_FLAG\",\n `--timeout-ms must be a positive integer of at most ${MAX_TIMEOUT_MS}: a non-positive bound is no bound at all, which is the one thing a sandbox may not be`,\n [`memhtml exec --timeout-ms ${DEFAULT_TIMEOUT_MS}`]\n )\n }\n }\n\n return undefined\n}\n\n/**\n * Exactly one of `--claim` / `--article-html`.\n *\n * Checked here rather than in the dispatch arm, because the exit code is the contract. `validate`'s\n * return is emitted as exit 2 ({@link EXIT_USAGE}), while a failure raised inside `dispatch` travels\n * through `failureFor` and becomes exit 1. Supplying the wrong flags is a usage error, and a shell\n * caller branching on the code must not see it as a runtime one.\n *\n * Two codes for two conditions, each following the convention already in this function. An absent\n * required flag is `ERR_MISSING_ARGUMENT` (as below), and a flag present but unusable as given is\n * `ERR_INVALID_FLAG` (as above, and in the closed-vocabulary check). Neither is newly minted.\n */\nconst claimOrArticle = (parsed: Parsed): Failure | undefined => {\n if (!EITHER_CLAIM_OR_ARTICLE.has(parsed.command)) return undefined\n const hasClaim = str(parsed, \"claim\") !== undefined\n const hasArticle = str(parsed, \"article-html\") !== undefined\n if (hasClaim && hasArticle) {\n return fail(\n \"ERR_INVALID_FLAG\",\n `${parsed.command} takes exactly one of --claim or --article-html, not both: --article-html is the whole article, so a --claim beside it would be silently discarded`,\n [\n `memhtml ${parsed.command} --claim <sentence>`,\n `memhtml ${parsed.command} --article-html '<p>…</p>'`\n ]\n )\n }\n if (!hasClaim && !hasArticle) {\n return fail(\n \"ERR_MISSING_ARGUMENT\",\n `${parsed.command} requires exactly one of --claim or --article-html`,\n [\n `memhtml ${parsed.command} --claim <sentence>`,\n `memhtml ${parsed.command} --article-html '<p>…</p>'`\n ]\n )\n }\n return undefined\n}\n\n/**\n * Validate a parsed invocation against its spec. Usage errors only; nothing here touches a service.\n *\n * Returning the failure rather than throwing keeps the exit code decision in one place. A usage\n * error is exit 2 and a runtime error is exit 1, and a validator that emitted its own envelope would\n * have to know that too.\n */\nconst validate = (parsed: Parsed): Failure | undefined => {\n for (const name of parsed.flags.keys()) {\n if (!KNOWN_FLAGS.has(name)) {\n return fail(\"ERR_INVALID_FLAG\", `unknown flag: --${name}`, nearest(name, [...KNOWN_FLAGS]))\n }\n }\n\n const spec = COMMANDS.find((command) => command.name === parsed.command)\n if (spec === undefined) return unknownCommand(parsed)\n\n const missingArgs = spec.args.filter(\n (arg, position) => arg.required && parsed.positional[position] === undefined\n )\n if (missingArgs.length > 0) {\n return fail(\n \"ERR_MISSING_ARGUMENT\",\n `${spec.name} requires: ${missingArgs.map((arg) => arg.name).join(\", \")}`,\n [`memhtml ${spec.name} <${missingArgs[0]?.name}>`]\n )\n }\n\n const missingFlags = spec.flags.filter(\n (flag) => flag.required === true && parsed.flags.get(flag.name) === undefined\n )\n if (missingFlags.length > 0) {\n return fail(\n \"ERR_MISSING_ARGUMENT\",\n `${spec.name} requires: ${missingFlags.map((flag) => `--${flag.name}`).join(\", \")}`,\n missingFlags.map((flag) => `memhtml ${spec.name} --${flag.name} <value>`)\n )\n }\n\n // Presence rules together: the unconditionally-required flags above, then the two conditional\n // rules the table cannot express, then the value checks below.\n const eitherOr = claimOrArticle(parsed)\n if (eitherOr !== undefined) return eitherOr\n\n const exec = execFlags(parsed)\n if (exec !== undefined) return exec\n\n /**\n * A closed-vocabulary flag is checked here rather than at the service, so a typo answers with the\n * whole vocabulary and never touches the database. Every value of a repeatable flag is checked, not\n * only the last one, so a `--type` list with one bad entry is a usage error rather than a silently\n * narrowed search.\n */\n for (const flag of spec.flags) {\n if (flag.values === undefined) continue\n for (const value of parsed.flags.get(flag.name) ?? []) {\n if (typeof value !== \"string\") continue\n if (!flag.values.includes(value)) {\n return fail(\n \"ERR_INVALID_FLAG\",\n `--${flag.name} must be one of: ${flag.values.join(\", \")}`,\n nearest(value, flag.values)\n )\n }\n }\n }\n\n return undefined\n}\n\n/**\n * Returns the rendered envelope and an exit code rather than writing to the process, so tests\n * assert on the exact bytes an agent would parse.\n *\n * `layer` is injectable for that reason. A test supplies the real composition over a temp\n * repo and a deterministic embedder, and every assertion below then describes the shipped path.\n *\n * `stdin` is injectable for the same reason one step further out. `memhtml apply` reads a JSONL stream\n * from a pipe, and a test that had to spawn a process and write to its descriptor to exercise the\n * stdin path would be an integration test of the shell rather than of this function. The default\n * reads `process.stdin`, so `bin.ts` needs no knowledge of which commands want input.\n */\nexport const run = async (\n argv: ReadonlyArray<string>,\n layer?: Layer.Layer<DispatchServices>,\n stdin: () => Promise<string> = readStdin\n): Promise<RunResult> => {\n const parsed = parseArgv(argv)\n const dense = bool(parsed, \"dense\", false)\n\n const emit = (payload: Success<unknown> | Failure, exitCode: number): RunResult => ({\n stdout: render(payload, dense),\n exitCode\n })\n\n if (parsed.command === \"\" || parsed.command === \"help\") {\n return emit(succeed(\"cli.manifest\", buildManifest()), EXIT_OK)\n }\n\n const invalid = validate(parsed)\n if (invalid !== undefined) return emit(invalid, EXIT_USAGE)\n\n /**\n * The two self-describing commands answer without building the app layer.\n *\n * `manifest` matters most here. It is the first call an agent makes and it must answer on a\n * machine with no repo, no database, and no credentials. Building the layer first would make the\n * self-description conditional on the thing it describes being already working.\n *\n * `agents-doc` is here because building the layer has a side effect. `layerDatabase` opens\n * `$MEMHTML_ROOT/.memhtml/index.db`, creating the directory and running every migration. A doc generator\n * that scaffolded a memory repo as a side effect of rendering Markdown would create `~/memhtml`\n * on any machine that ran `memhtml agents-doc --check` in CI. It reads only the command table, so it\n * has no reason to touch the app graph at all.\n */\n if (parsed.command === \"manifest\") {\n return emit(succeed(\"cli.manifest\", buildManifest()), EXIT_OK)\n }\n\n if (parsed.command === \"agents-doc\") {\n return Effect.runPromise(\n runAgentsDoc({ check: bool(parsed, \"check\", false), out: str(parsed, \"out\") }).pipe(\n Effect.map((data) => emit(succeed(\"agents.doc\", data), EXIT_OK)),\n Effect.catch((error) => Effect.succeed(emit(failureFor(error), EXIT_RUNTIME))),\n Effect.provideService(Logger.LogToStderr, true)\n )\n )\n }\n\n /**\n * `serve mcp` must not build the app layer either, and here the reason is the database.\n *\n * The supervisor's only job is to spawn the server and wait. Building `layerApp` first would open\n * `$MEMHTML_ROOT/.memhtml/index.db` and run its migrations in the parent. That is a second writer\n * against the store the child exists to serve, held open for as long as the child lives, by a process\n * that never issues a query. The parent needs the resolved repo root, which is config rather than a\n * service.\n *\n * Nothing is emitted until the child exits, because stdout belongs to the child from the moment it\n * is spawned. The `serve.exit` envelope describes how the server ended, and it is written after\n * the descriptors are the parent's again.\n */\n if (parsed.command === \"serve mcp\") {\n return Effect.runPromise(\n Effect.gen(function* () {\n const override = str(parsed, \"repo\")\n const configured = yield* MemhtmlRoot\n const memhtmlRoot =\n override !== undefined && override.trim() !== \"\" ? override.trim() : configured\n return yield* serveMcp(memhtmlRoot)\n }).pipe(\n Effect.map((data) => emit(succeed(\"serve.exit\", data), EXIT_OK)),\n Effect.catch((error) => Effect.succeed(emit(failureFor(error), EXIT_RUNTIME))),\n Effect.catchCause((cause) =>\n Effect.succeed(\n emit(fail(\"ERR_UNKNOWN\", `unexpected failure: ${String(cause)}`, []), EXIT_RUNTIME)\n )\n ),\n Effect.provideService(Logger.LogToStderr, true)\n )\n )\n }\n\n /**\n * `eval discriminate` does not build the app layer either, for the reason the command above gives.\n * The gate measures the ranking stack against its own generated fixture corpus in a temp directory\n * with an in-memory database, and reads the operator's `index.db` not at all. Building `layerApp`\n * would open and migrate a store this command never queries, and an operator checking the gate is\n * typically doing it while `memhtml-mcp` serves that store.\n *\n * **Exit 1 on a failed gate**, with `ERR_DISCRIMINATION_FAILED`. A gate that exited 0 and\n * left the verdict inside the payload would be a gate every shell caller forgets to read. The\n * exit code is what stops a pipeline.\n */\n if (parsed.command === \"eval discriminate\") {\n const requested = (str(parsed, \"mode\") ?? \"fake\") as EvalMode\n return Effect.runPromise(\n runDiscrimination({\n mode: requested,\n ...(int(parsed, \"seed\") === undefined ? {} : { seed: int(parsed, \"seed\") }),\n ...(int(parsed, \"size\") === undefined ? {} : { size: int(parsed, \"size\") }),\n ...(int(parsed, \"probes\") === undefined ? {} : { probes: int(parsed, \"probes\") }),\n ...(num(parsed, \"mrr-floor\") === undefined ? {} : { mrrFloor: num(parsed, \"mrr-floor\") })\n }).pipe(\n Effect.map((outcome) =>\n outcome.passed\n ? emit(succeed(\"eval.discrimination\", outcome), EXIT_OK)\n : {\n stdout: render(succeed(\"eval.discrimination\", outcome), dense),\n exitCode: EXIT_RUNTIME\n }\n ),\n Effect.catchCause((cause) =>\n Effect.succeed(\n emit(fail(\"ERR_UNKNOWN\", `unexpected failure: ${String(cause)}`, []), EXIT_RUNTIME)\n )\n ),\n Effect.provideService(Logger.LogToStderr, true)\n )\n )\n }\n\n /**\n * `memhtml exec` does not build the app layer either, for the reason two commands over.\n *\n * The command reads a git tree and nothing else. It materializes a commit as a detached worktree and\n * mounts that directory read-only. It never queries `index.db`, so building `layerApp` would open and\n * migrate a database it does not use, on the path an agent reaches for while `memhtml serve mcp` is\n * serving the repo. Nothing here can be reached through `dispatch`, because `dispatch`'s service set\n * is the app layer's.\n *\n * **Non-zero `exitCode` in the payload is still exit 0 for the process**, and that split is the\n * contract. A failing script is a report with `stderr` an agent reads and fixes. The CLI's exit 1 is\n * reserved for the runtime failing to run the script at all (no repo, unreadable sha, absent helper).\n * Collapsing the two would make an agent unable to tell a bad selector from a broken install, and\n * would bury the script's own diagnostic inside an `error` string.\n *\n * The script is read here rather than in `runExec`, so a missing or empty script is exit 2 like every\n * other input error. `runExec` takes source, never a path.\n */\n if (parsed.command === \"exec\") {\n const inline = str(parsed, \"script\")\n const file = parsed.positional[0] === \"-\" ? undefined : str(parsed, \"file\")\n const script =\n inline !== undefined ? inline : file === undefined ? await stdin() : await readScript(file)\n if (typeof script !== \"string\") return emit(script, EXIT_USAGE)\n if (script.trim() === \"\") {\n return emit(\n fail(\n \"ERR_MISSING_ARGUMENT\",\n \"exec needs a script: a blank one would report an empty answer rather than an error\",\n [\n \"memhtml exec --script 'console.log(1)'\",\n \"memhtml exec --file traverse.mjs\",\n \"cat s.mjs | memhtml exec\"\n ]\n ),\n EXIT_USAGE\n )\n }\n\n const override = str(parsed, \"repo\")\n return Effect.runPromise(\n Effect.gen(function* () {\n const configured = yield* MemhtmlRoot\n const memhtmlRoot =\n override !== undefined && override.trim() !== \"\" ? override.trim() : configured\n return yield* execCommand({\n script,\n memhtmlRoot,\n sha: str(parsed, \"sha\"),\n timeoutMs: int(parsed, \"timeout-ms\")\n })\n }).pipe(\n Effect.map((report) => emit(succeed(\"exec.report\", report), EXIT_OK)),\n Effect.catch((error) => Effect.succeed(emit(failureFor(error), EXIT_RUNTIME))),\n Effect.catchCause((cause) =>\n Effect.succeed(\n emit(fail(\"ERR_UNKNOWN\", `unexpected failure: ${String(cause)}`, []), EXIT_RUNTIME)\n )\n ),\n Effect.provideService(Logger.LogToStderr, true),\n Effect.scoped\n )\n )\n }\n\n /**\n * `memhtml apply` checks the shape of its whole op stream before any service is built (AC-6-4).\n *\n * Here rather than in `validate` because reading a file is async and `validate` is a pure synchronous\n * function of the parsed argv. Here rather than in the dispatch arm because a refusal raised inside\n * `dispatch` travels through `failureFor` and becomes exit 1, while a malformed input file is a usage\n * error and must be exit 2. The caller wrote a bad file, and the corpus is fine.\n *\n * The ordering is the observable contract. Nothing is written for a file with a bad line, and at this\n * point nothing can have been, because the app layer has not been built, so no database is open and\n * no git command has run.\n */\n let applyOps: ReadonlyArray<ops.WriteParams> = []\n if (parsed.command === \"apply\") {\n // `memhtml apply -` is the explicit \"read stdin\" spelling, and the dash is not a path.\n const file = parsed.positional[0] === \"-\" ? undefined : str(parsed, \"file\")\n const text = await applyText(file, stdin)\n if (typeof text !== \"string\") return emit(text, EXIT_USAGE)\n const decoded = decodeApply(text)\n if (!decoded.ok) return emit(decoded.failure, EXIT_USAGE)\n applyOps = decoded.ops\n }\n\n const program = dispatch(parsed, applyOps).pipe(\n Effect.map(([type, data]) => emit(succeed(type, data), EXIT_OK)),\n Effect.catch((error) => Effect.succeed(emit(failureFor(error), EXIT_RUNTIME))),\n // A defect is still an answer. An unexpected throw anywhere below would otherwise reach the\n // process as an unhandled rejection and print a stack trace onto stdout. Stdout is a parse\n // target, so it carries the envelope and nothing else.\n Effect.catchCause((cause) =>\n Effect.succeed(\n emit(fail(\"ERR_UNKNOWN\", `unexpected failure: ${String(cause)}`, []), EXIT_RUNTIME)\n )\n ),\n Effect.provide(layer ?? layerApp(str(parsed, \"repo\"))),\n // Logs go to stderr, always. Effect's default logger writes to stdout, which would interleave\n // log lines with the envelope and break every parser.\n Effect.provideService(Logger.LogToStderr, true),\n Effect.scoped\n )\n\n return Effect.runPromise(program)\n}\n\n/** The envelope's api version, re-exported so a caller can assert on it without a second import. */\nexport { API_VERSION }\n","#!/usr/bin/env node\nimport { run } from \"./run.js\"\n\n// stdout carries only the envelope so it stays a clean parse target.\nconst result = await run(process.argv.slice(2))\nprocess.stdout.write(`${result.stdout}\\n`)\nprocess.exit(result.exitCode)\n"],"mappings":"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N,MAAM;EACN,aAAa;EACb,YAAY;CACd;CACA;EACE,MAAM;EACN,MAAM;EAIN,aACE;CACJ;CACA;EACE,MAAM;EACN,MAAM;EACN,aAAa;EACb,SAAS;CACX;CACA;EACE,MAAM;EACN,MAAM;EACN,aACE;CACJ;AACF;;;;;;;;;;;AAYA,MAAa,WAAuC;CAClD;EACE,MAAM;EACN,SAAS;EACT,MAAM,CAAC;EACP,OAAO,CAAC;EACR,eAAe,CAAC,cAAc;CAChC;CACA;EACE,MAAM;EACN,SAAS;EACT,MAAM,CAAC;EACP,OAAO,CAAC;EACR,eAAe,CAAC,WAAW;CAC7B;CACA;EACE,MAAM;EACN,SAAS;EACT,MAAM,CAAC;EACP,OAAO;GACL;IACE,MAAM;IACN,MAAM;IACN,aAAa;IACb,UAAU;GACZ;GACA;IACE,MAAM;IACN,MAAM;IACN,aACE;GACJ;GACA;IACE,MAAM;IACN,MAAM;IACN,aAAa;IACb,YAAY;GACd;GACA;IACE,MAAM;IACN,MAAM;IACN,aACE;GACJ;GACA;IACE,MAAM;IACN,MAAM;IACN,aAAa;IACb,QAAQ;IACR,UAAU;GACZ;GACA;IACE,MAAM;IACN,MAAM;IACN,aAAa;GACf;GACA;IAAE,MAAM;IAAa,MAAM;IAAU,aAAa;GAAyC;GAC3F;IACE,MAAM;IACN,MAAM;IACN,aAAa;GACf;GACA;IACE,MAAM;IACN,MAAM;IACN,aAAa;IACb,YAAY;GACd;GACA;IACE,MAAM;IACN,MAAM;IACN,aAAa;GACf;GACA;IAAE,MAAM;IAAc,MAAM;IAAU,aAAa;GAAwC;GAC3F;IACE,MAAM;IACN,MAAM;IACN,aAAa;GACf;GACA;IAAE,MAAM;IAAa,MAAM;IAAU,aAAa;GAAkC;GACpF;IAAE,MAAM;IAAa,MAAM;IAAU,aAAa;GAAgC;EACpF;EACA,eAAe,CAAC,gBAAgB;CAClC;CACA;EACE,MAAM;EACN,SACE;EACF,MAAM,CAAC;EACP,OAAO;GACL;IACE,MAAM;IACN,MAAM;IACN,aACE;GACJ;GACA;IACE,MAAM;IACN,MAAM;IACN,aACE;IACF,SAAS;GACX;GAC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"}