@theokit/sdk 4.58.0 → 4.60.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (66) hide show
  1. package/CHANGELOG.md +41 -0
  2. package/dist/{agent-MIYY7TXV.cjs → agent-26RMDG4U.cjs} +8 -7
  3. package/dist/{agent-MIYY7TXV.cjs.map → agent-26RMDG4U.cjs.map} +1 -1
  4. package/dist/{agent-6WM4QOWS.js → agent-6ABK2DPG.js} +7 -6
  5. package/dist/{agent-6WM4QOWS.js.map → agent-6ABK2DPG.js.map} +1 -1
  6. package/dist/{chunk-N47KLTKD.cjs → chunk-23GPJGRR.cjs} +45 -28
  7. package/dist/chunk-23GPJGRR.cjs.map +1 -0
  8. package/dist/{chunk-QIRDQZYL.cjs → chunk-3HDTP4ZO.cjs} +4 -4
  9. package/dist/{chunk-QIRDQZYL.cjs.map → chunk-3HDTP4ZO.cjs.map} +1 -1
  10. package/dist/{chunk-GNT35C5U.cjs → chunk-6SBW4QR2.cjs} +2 -2
  11. package/dist/{chunk-GNT35C5U.cjs.map → chunk-6SBW4QR2.cjs.map} +1 -1
  12. package/dist/{chunk-CF5OMCZG.js → chunk-76XTUTKY.js} +34 -17
  13. package/dist/chunk-76XTUTKY.js.map +1 -0
  14. package/dist/{chunk-WLZ7XRWH.js → chunk-7OXXYBHD.js} +7 -179
  15. package/dist/chunk-7OXXYBHD.js.map +1 -0
  16. package/dist/{chunk-5QOIQJ5J.js → chunk-E5MWNLRX.js} +3 -3
  17. package/dist/{chunk-5QOIQJ5J.js.map → chunk-E5MWNLRX.js.map} +1 -1
  18. package/dist/{chunk-XV4IZNV4.js → chunk-FUL2I7G5.js} +2 -2
  19. package/dist/{chunk-XV4IZNV4.js.map → chunk-FUL2I7G5.js.map} +1 -1
  20. package/dist/chunk-JVERBPRD.js +191 -0
  21. package/dist/chunk-JVERBPRD.js.map +1 -0
  22. package/dist/chunk-NY25NBZB.cjs +203 -0
  23. package/dist/chunk-NY25NBZB.cjs.map +1 -0
  24. package/dist/{chunk-27AXGJMV.cjs → chunk-Y2KJ7MYO.cjs} +14 -194
  25. package/dist/chunk-Y2KJ7MYO.cjs.map +1 -0
  26. package/dist/cron.cjs +7 -6
  27. package/dist/cron.js +6 -5
  28. package/dist/eval.cjs +6 -5
  29. package/dist/eval.cjs.map +1 -1
  30. package/dist/eval.js +5 -4
  31. package/dist/eval.js.map +1 -1
  32. package/dist/{index-manager-WYESAVTX.js → index-manager-KP2JAXKN.js} +4 -3
  33. package/dist/{index-manager-WYESAVTX.js.map → index-manager-KP2JAXKN.js.map} +1 -1
  34. package/dist/{index-manager-J2QIDI6I.cjs → index-manager-YUORPS4G.cjs} +5 -4
  35. package/dist/{index-manager-J2QIDI6I.cjs.map → index-manager-YUORPS4G.cjs.map} +1 -1
  36. package/dist/index.cjs +35 -34
  37. package/dist/index.cjs.map +1 -1
  38. package/dist/index.js +12 -11
  39. package/dist/index.js.map +1 -1
  40. package/dist/internal/memory/storage/chunk-markdown.d.cts +2 -0
  41. package/dist/internal/memory/storage/index.cjs +54 -0
  42. package/dist/internal/memory/storage/index.cjs.map +1 -0
  43. package/dist/internal/memory/storage/index.d.cts +18 -0
  44. package/dist/internal/memory/storage/index.d.ts +18 -0
  45. package/dist/internal/memory/storage/index.js +13 -0
  46. package/dist/internal/memory/storage/index.js.map +1 -0
  47. package/dist/internal/memory/storage/markdown-store.d.cts +77 -0
  48. package/dist/internal/memory/storage/markdown-store.d.ts +46 -5
  49. package/dist/internal/memory/storage/memory-file.d.cts +54 -0
  50. package/dist/internal/memory/storage/reader.d.cts +8 -0
  51. package/dist/internal/memory/storage/session-loader.d.cts +1 -0
  52. package/dist/internal/memory/storage/session-summary-writer.d.cts +2 -0
  53. package/dist/internal/memory/storage/transcript-store.d.cts +1 -0
  54. package/dist/internal/memory/storage/wiki-loader.d.cts +2 -0
  55. package/dist/internal/persistence/session-dir.d.cts +15 -0
  56. package/dist/internal/persistence/session-dir.d.ts +15 -0
  57. package/dist/internal/runtime/memory/memory-store.d.ts +2 -2
  58. package/dist/workflow.cjs +9 -9
  59. package/dist/workflow.js +1 -1
  60. package/docs/error-codes.md +1 -1
  61. package/docs/harness-capability-map.md +15 -1
  62. package/package.json +11 -1
  63. package/dist/chunk-27AXGJMV.cjs.map +0 -1
  64. package/dist/chunk-CF5OMCZG.js.map +0 -1
  65. package/dist/chunk-N47KLTKD.cjs.map +0 -1
  66. package/dist/chunk-WLZ7XRWH.js.map +0 -1
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/internal/memory/types.ts","../src/internal/memory/storage/memory-file.ts","../src/internal/memory/storage/markdown-store.ts"],"names":["resolvePath"],"mappings":"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","file":"chunk-JVERBPRD.js","sourcesContent":["/**\n * Public memory types (used by runtime + storage + migration + future index).\n *\n * Leaf module — only depends on `node:path` — so neither `runtime/memory-store.ts`\n * nor `internal/memory/markdown-store.ts` introduces a dependency cycle.\n *\n * @internal\n */\nimport { resolve as resolvePath } from \"node:path\";\n\nimport { safePathJoin, sanitizeIdentifier } from \"../security/path-guard.js\";\n\nexport interface MemoryConfig {\n enabled: boolean;\n namespace?: string;\n userId?: string;\n scope?: \"agent\" | \"user\" | \"team\";\n storePath?: string;\n}\n\n/**\n * What a fact IS, which is what decides whether it ages (#389).\n *\n * The four are the distinctions that matter for retention and recall: a preference stays true until\n * the user changes their mind, a project fact goes stale when the code moves, a reference either\n * resolves or 404s, and feedback records a correction that was given. Without them, recall ranks one\n * undifferentiated corpus and pruning has no basis to prefer a durable fact over a transient one.\n *\n * A kind is never INFERRED. A wrong kind is worse than none, because it makes retention and recall\n * confident about the wrong thing — so a fact whose author did not say stays untyped.\n */\nexport type MemoryKind = \"user\" | \"feedback\" | \"project\" | \"reference\";\n\n/** The four values {@link MemoryKind} admits, for runtime validation at the storage boundary. */\nexport const MEMORY_KINDS: readonly MemoryKind[] = [\"user\", \"feedback\", \"project\", \"reference\"];\n\nexport interface MemoryFact {\n text: string;\n /**\n * What this fact is (#389). Absent means untyped, which is what a hand-written bullet under\n * `## Facts` stays — those files are already on disk in consumers' repositories and the store's\n * own header invites editing them.\n */\n kind?: MemoryKind;\n /**\n * ISO 8601 instant this fact was last written, stamped BY THE SDK.\n *\n * Supplying it does nothing: a timestamp a caller can set is a timestamp that can lie about when\n * something was learned, and the whole point is to weigh a note from this morning against one\n * from four months ago. Absent on a fact written before this existed, or hand-added.\n */\n modified?: string;\n}\n\n// `redactSecrets` is now re-exported from the canonical security module\n// (ADR D68). Pre-T0.2 it was a 3-pattern local fn; consolidated to avoid\n// drift with the central 12-pattern list.\nexport { redactSecrets } from \"../security/index.js\";\n\n/**\n * Resolve the legacy JSON memory path used pre-ADR-D8 (kept for migration\n * helpers + tests). Centralized here so `migration.ts` and the legacy-aware\n * `runtime/memory-store.ts` don't duplicate the path logic (jscpd cleanup).\n */\nexport function legacyMemoryJsonPath(cwd: string, config: MemoryConfig): string {\n // ADRs D79-D81: storePath is programmatic (trusted); namespace/scope/userId\n // are user-shaped and pass sanitizeIdentifier. EC-7 (edge-case review):\n // realistic userIds (UUIDs, hash IDs, \"default\") pass; \"user@example.com\"\n // and similar need to be normalized by the caller before passing.\n if (config.storePath !== undefined) {\n return resolvePath(cwd, config.storePath);\n }\n const namespace = sanitizeIdentifier(config.namespace ?? \"default\");\n const scope = sanitizeIdentifier(config.scope ?? \"agent\", { maxLen: 16 });\n const userId = sanitizeIdentifier(config.userId ?? \"default\");\n return safePathJoin(cwd, \".theokit\", \"memory\", namespace, `${scope}-${userId}.json`);\n}\n\n/**\n * A semantically meaningful slice of a markdown memory file, produced by\n * `chunkMarkdown`. Each chunk carries stable line numbers + a content hash\n * used downstream by the embedding cache.\n *\n * Mirrors peer-project's `MemoryChunk` shape\n * (`reference/peer-project/packages/memory-host-sdk/src/host/engine-storage.ts`).\n *\n * @internal\n */\nexport interface MemoryChunk {\n /** 1-indexed starting line in the source file. */\n startLine: number;\n /** 1-indexed ending line (inclusive). */\n endLine: number;\n /** Slice of markdown source text. */\n text: string;\n /** sha256 of `text`; stable across runs for identical inputs. */\n hash: string;\n /** Optional nearest heading text (without the `#` markers). */\n heading?: string;\n}\n\n/**\n * Result of `reader.readFile`. Contains the bounded slice plus truncation\n * + provenance info.\n *\n * Mirrors peer-project's `MemoryReadResult` shape.\n *\n * @internal\n */\nexport interface MemoryReadResult {\n path: string;\n /** Requested starting line (1-indexed, defaults to 1). */\n from: number;\n /** Number of lines actually returned (may be less than `lines` near EOF). */\n linesReturned: number;\n /** Total lines in the file (after the read). */\n totalLines: number;\n /** True when fewer lines were returned than the requested `lines` AND EOF was hit. */\n truncated: boolean;\n /** Lines past the returned slice that remain in the file. */\n remainingLines: number;\n /** Slice text (joined with `\\n`). */\n text: string;\n}\n","/**\n * One memory as a file, in the shape the Claude Code CLI reads.\n *\n * `@theokit/sdk` already writes native Claude Code `.jsonl` sessions — the README's differentiator\n * is \"point `local.sessionDir` at `~/.claude` and the Claude Code CLI can `--continue` a session\n * your agent wrote\". Memory had no such convergence: a fact was a bullet under `## Facts` with its\n * kind in an HTML comment (#389), which that CLI reads as prose. Pointing a memory directory at\n * `~/.claude/projects/<project>/memory/` produced nothing it could open.\n *\n * The contract here was measured against a real store rather than inferred from documentation. Of\n * nine files, all nine carry `name`, `description` and `metadata.type`; six also carry\n * `node_type`, `originSessionId` and `modified`, which the runtime stamps on write. So the minimum\n * a reader must accept is the first three — refusing the rest would refuse memories the CLI itself\n * accepts.\n *\n * `originSessionId` is deliberately not written. It identifies the session that learned the fact,\n * and the append path has no session in scope; inventing one would be worse than omitting a field\n * the format already treats as optional.\n *\n * @internal\n */\n\nimport { parseSimpleYaml, splitFrontmatter } from \"../../runtime/context/context-yaml-lite.js\";\nimport { safeFilenameForId } from \"../../security/path-guard.js\";\nimport { MEMORY_KINDS, type MemoryKind } from \"../types.js\";\n\n/** The fields one memory file carries. */\nexport interface MemoryFileFields {\n /** Slug, and the file's basename. */\n readonly name: string;\n /** One-line summary — what the index shows and what recall ranks. */\n readonly description: string;\n /** `metadata.type`, absent when the file does not declare one this contract admits. */\n readonly kind?: MemoryKind;\n /** `metadata.modified`, an ISO 8601 instant stamped by whoever wrote the file. */\n readonly modified?: string;\n /** The markdown after the frontmatter. */\n readonly body: string;\n}\n\n/** The safe filename grammar a slug must satisfy before it is used as one. */\nconst SAFE_SLUG = /^[a-z0-9][a-z0-9_-]*$/;\n/** Long enough to stay readable, short enough to survive every filesystem's component limit. */\nconst MAX_SLUG_LENGTH = 64;\n\n/**\n * A readable, filesystem-safe slug for `text`.\n *\n * Readability is the goal — a directory of `h-3f2a…` files is a directory nobody browses — but it\n * is not the floor. The text comes from whatever a caller learned, so anything that fails the safe\n * grammar falls back to {@link safeFilenameForId}, which is total and always yields a valid\n * component.\n */\nexport function slugForFact(text: string): string {\n const slug = text\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, \"-\")\n .replace(/^-+|-+$/g, \"\")\n .slice(0, MAX_SLUG_LENGTH)\n .replace(/-+$/, \"\");\n return SAFE_SLUG.test(slug) ? slug : safeFilenameForId(text);\n}\n\n/** Render one memory file. `description` is quoted so a colon in the text cannot break the block. */\nexport function renderMemoryFile(fields: MemoryFileFields): string {\n const metadata = [\" node_type: memory\"];\n if (fields.kind !== undefined) metadata.push(` type: ${fields.kind}`);\n if (fields.modified !== undefined) metadata.push(` modified: ${fields.modified}`);\n return [\n \"---\",\n `name: ${fields.name}`,\n `description: ${JSON.stringify(fields.description)}`,\n \"metadata:\",\n ...metadata,\n \"---\",\n \"\",\n fields.body,\n \"\",\n ].join(\"\\n\");\n}\n\n/**\n * Read one memory file, or `undefined` when the content is not one.\n *\n * `undefined` rather than a throw, and rather than a best-effort object: the directory holds\n * hand-written notes and a `MEMORY.md` index alongside the memories, and turning any of those into\n * a fact would put text into recall that nobody recorded as one.\n */\nexport function parseMemoryFile(raw: string): MemoryFileFields | undefined {\n const { yaml, body } = splitFrontmatter(raw);\n if (yaml === undefined) return undefined;\n\n let fields: Record<string, unknown>;\n try {\n fields = parseSimpleYaml(yaml);\n } catch {\n return undefined; // malformed frontmatter is not a memory\n }\n\n const name = fields.name;\n const description = fields.description;\n if (typeof name !== \"string\" || typeof description !== \"string\") return undefined;\n\n const metadata = (fields.metadata ?? {}) as Record<string, unknown>;\n const rawKind = metadata.type;\n // An unknown `type` reads as untyped rather than as a fifth kind: the file is hand-editable and\n // recall must not act on a value this contract does not admit.\n const kind =\n typeof rawKind === \"string\" && MEMORY_KINDS.includes(rawKind as MemoryKind)\n ? (rawKind as MemoryKind)\n : undefined;\n const modified = typeof metadata.modified === \"string\" ? metadata.modified : undefined;\n\n return {\n name,\n description,\n ...(kind !== undefined ? { kind } : {}),\n ...(modified !== undefined ? { modified } : {}),\n body: body.trim(),\n };\n}\n","import { mkdir, readdir, readFile } from \"node:fs/promises\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\n\nimport { ConfigurationError } from \"../../../errors.js\";\nimport { replaceFileAtomic } from \"../../persistence/atomic-write.js\";\nimport { withCwdMutex } from \"../../persistence/cwd-mutex.js\";\nimport { encodeProjectDir } from \"../../persistence/session-transcript.js\";\nimport { MEMORY_KINDS, type MemoryConfig, type MemoryFact, redactSecrets } from \"../types.js\";\nimport { parseMemoryFile, renderMemoryFile, slugForFact } from \"./memory-file.js\";\n\n/**\n * Markdown-first memory storage (ADR D1 of memory-system-peer-project-parity).\n *\n * Layout, converged with the one the Claude Code CLI reads:\n * <memoryDir>/\n * ├── MEMORY.md # INDEX — one `- [text](slug.md)` line per memory\n * ├── <slug>.md # one memory, frontmatter carrying `metadata.type` + `modified`\n * └── notes/\n * └── <slug>.md # hand-written per-topic notes (read by the indexer, never written here)\n *\n * The SDK already emits native Claude Code `.jsonl` sessions, so a consumer can point\n * `local.sessionDir` at `~/.claude` and `--continue` a session its agent wrote. Memory did not hold\n * that line: a fact was a bullet under `## Facts` with its kind in an HTML comment (#389), which\n * that CLI reads as prose. Pointing a memory directory at `~/.claude/projects/<project>/memory/`\n * produced nothing it could open.\n *\n * `## Facts` bullets are still READ. They are already on disk in consumers' repositories, and a\n * format change that stopped reading them would delete what someone recorded — worse than the\n * format it replaces.\n *\n * All writes go through `replaceFileAtomic` + a per-cwd mutex (EC-4 of the\n * edge-case review) so concurrent `appendFact` calls within the same process\n * serialize. Multi-process safety is NOT provided.\n *\n * @internal\n */\n\nconst MEMORY_MD_HEADER =\n \"# Memory\\n\\n> Auto-managed by @theokit/sdk. Edit freely — the SDK reads from here.\\n\";\nconst FACTS_HEADING = \"## Facts\";\n\n/**\n * The memory root for a workspace: `<cwd>/.theokit/memory`. Every other path here derives from it,\n * and `memory_get` refuses to read outside it. Pure path computation — nothing is created on disk.\n */\nexport function memoryDir(cwd: string): string {\n return join(cwd, \".theokit\", \"memory\");\n}\n\n/**\n * Where a NEW fact should be written.\n *\n * `.theokit/memory` by default, exactly as before. When the agent was given a `local.sessionDir`,\n * it becomes `<sessionDir>/projects/<encoded-cwd>/memory` — the same place the transcript for that\n * project goes, so a session and the memories recorded during it land beside each other.\n *\n * `local.sessionDir` is the switch because it is already the option this project documents for CLI\n * interop: point it at `~/.claude` and the CLI can `--continue` a session this agent wrote. Someone\n * who set it has said they share state with that CLI, and memory following is what the sentence\n * already implied. It needs no new option, and nothing moves for anyone who never set it.\n *\n * Safe because of the rule this pairs with — WRITE ONE, READ ALL. {@link readFactsFromMarkdown}\n * covers every location, so a consumer whose new facts move keeps every fact they already had. The\n * change relocates where the next one lands; it orphans nothing.\n */\nexport function memoryWriteDir(cwd: string, sessionDir: string | undefined): string {\n if (sessionDir === undefined || sessionDir.trim().length === 0) return memoryDir(cwd);\n return join(sessionDir, \"projects\", encodeProjectDir(cwd), \"memory\");\n}\n\n/**\n * Where the Claude Code CLI keeps THIS project's memories.\n *\n * `<claudeHome>/projects/<encoded-cwd>/memory` — the same `encodeProjectDir` scheme the transcripts\n * already use, which is why no new encoding is invented here. `CLAUDE_CONFIG_DIR` names the home\n * when set (the CLI's own variable); `~/.claude` otherwise.\n *\n * Read, never written. Writing here by default would relocate every existing consumer's memories,\n * and an additive change must not move what is already on disk — so this is the direction that\n * costs nothing: a memory the CLI wrote becomes visible, and a memory the SDK wrote stays where the\n * SDK put it.\n */\nexport function claudeProjectMemoryDir(cwd: string): string {\n const home = process.env.CLAUDE_CONFIG_DIR?.trim();\n const root = home !== undefined && home.length > 0 ? home : join(homedir(), \".claude\");\n return join(root, \"projects\", encodeProjectDir(cwd), \"memory\");\n}\n\n/**\n * Path to `MEMORY.md`, the index that points at the per-memory files — and, in stores written before\n * #389, the flat `## Facts` list itself. Pure path computation; the file may not exist.\n */\nexport function memoryMdPath(cwd: string): string {\n return join(memoryDir(cwd), \"MEMORY.md\");\n}\n\n/**\n * Path to `<memory root>/notes`, where per-topic notes and the consolidated notes a dreaming sweep\n * writes live. Pure path computation — the directory may not exist.\n */\nexport function notesDir(cwd: string): string {\n return join(memoryDir(cwd), \"notes\");\n}\n\n/**\n * Every memory in the store: the per-memory files, plus any legacy `## Facts` bullets still in\n * `MEMORY.md`. Returns `[]` when the directory does not exist.\n *\n * Reading both is not transitional politeness. Those bullets are already on disk in consumers'\n * repositories, and the store's own header invites editing them by hand — a converged writer that\n * stopped reading them would delete what someone recorded, which is worse than the format it fixes.\n */\nexport async function readFactsFromMarkdown(\n cwd: string,\n sessionDir?: string,\n): Promise<MemoryFact[]> {\n const facts: MemoryFact[] = [];\n // Both stores: this SDK's, then the one the Claude Code CLI keeps for the same project. The\n // format has been shared since #389; only the directory was not, so a memory the CLI recorded was\n // invisible to an agent working in the same repository.\n // READ ALL: the project store, the location a configured `sessionDir` writes to, and the one the\n // CLI uses by default. Deduplicated, because with `sessionDir` pointed at the CLI's own home the\n // last two are the same directory and a fact would otherwise be recalled twice.\n const roots = [\n ...new Set([memoryDir(cwd), memoryWriteDir(cwd, sessionDir), claudeProjectMemoryDir(cwd)]),\n ];\n for (const dir of roots) {\n let entries: string[];\n try {\n entries = await readdir(dir);\n } catch {\n continue;\n }\n for (const entry of entries.sort()) {\n const fact = await readMemoryFileIn(dir, entry);\n if (fact !== undefined) facts.push(fact);\n }\n }\n\n try {\n facts.push(...parseFactsSection(await readFile(memoryMdPath(cwd), \"utf8\")));\n } catch {\n // no index yet — the per-memory files above are the whole store\n }\n return facts;\n}\n\n/**\n * One directory entry as a fact, or `undefined` when it is not one.\n *\n * `MEMORY.md` is the index, not a memory; a non-markdown entry is not a memory; and a markdown file\n * without the frontmatter is a note somebody wrote by hand. Turning any of those into a fact would\n * put text into recall that nobody recorded as one.\n *\n * The DIRECTORY is a parameter rather than derived from `cwd`, because both stores — this SDK's and\n * the one the Claude Code CLI keeps for the same project — read entries the same way, and a second\n * copy of this function is a second place for those three rules to drift.\n */\nasync function readMemoryFileIn(dir: string, entry: string): Promise<MemoryFact | undefined> {\n if (!entry.endsWith(\".md\") || entry === \"MEMORY.md\") return undefined;\n let raw: string;\n try {\n raw = await readFile(join(dir, entry), \"utf8\");\n } catch {\n return undefined; // vanished between readdir and read\n }\n const parsed = parseMemoryFile(raw);\n if (parsed === undefined) return undefined;\n // The BODY is the memory; `description` is the one-line recall aid. This SDK writes both the same,\n // so nothing it wrote changes — but the Claude Code CLI writes a summary in `description` and the\n // substance below it, and reading only the summary silently dropped the fact itself.\n const body = parsed.body.trim();\n return {\n text: body.length > 0 ? body : parsed.description,\n ...(parsed.kind !== undefined ? { kind: parsed.kind } : {}),\n ...(parsed.modified !== undefined ? { modified: parsed.modified } : {}),\n };\n}\n\n/**\n * Write a fact as its own memory file and point the `MEMORY.md` index at it. Atomic + serialized.\n *\n * `modified` is stamped HERE and never read from `fact`: a timestamp a caller can set is a\n * timestamp that can lie about when something was learned, and weighing recency is the point.\n */\nexport function appendFactToMarkdown(\n cwd: string,\n fact: MemoryFact,\n targetDir: string = memoryDir(cwd),\n): Promise<void> {\n return withCwdMutex(targetDir, async () => {\n // Validate at the boundary (`error-handling.md` § 2): a kind outside the four would be written\n // to a file recall later trusts, so it is refused here rather than stored and believed.\n if (fact.kind !== undefined && !MEMORY_KINDS.includes(fact.kind)) {\n throw new ConfigurationError(\n `Unknown memory fact kind \"${fact.kind}\". Expected one of: ${MEMORY_KINDS.join(\", \")}.`,\n { code: \"invalid_memory_kind\" },\n );\n }\n const text = redactSecrets(fact.text);\n const name = slugForFact(text);\n await mkdir(targetDir, { recursive: true });\n await replaceFileAtomic(\n join(targetDir, `${name}.md`),\n renderMemoryFile({\n name,\n description: text,\n ...(fact.kind !== undefined ? { kind: fact.kind } : {}),\n modified: new Date().toISOString(),\n body: text,\n }),\n );\n // The index lives BESIDE the files it lists. A `MEMORY.md` in one directory pointing at\n // memories in another names files that are not there — and the CLI reads that index.\n await replaceFileAtomic(join(targetDir, \"MEMORY.md\"), await nextIndex(targetDir, text, name));\n });\n}\n\n/**\n * The `MEMORY.md` index with `name` present exactly once.\n *\n * Rewriting the same memory replaces its line rather than adding a second: the index is a map from\n * memory to file, and two lines for one file is a map that disagrees with itself.\n */\nasync function nextIndex(dir: string, text: string, name: string): Promise<string> {\n let existing = \"\";\n try {\n // The index in the directory being WRITTEN, not the project one — see the caller.\n existing = await readFile(join(dir, \"MEMORY.md\"), \"utf8\");\n } catch {\n existing = \"\";\n }\n const entry = `- [${text}](${name}.md)`;\n const kept = existing\n .split(\"\\n\")\n .filter((line) => !line.startsWith(`- [`) || !line.includes(`](${name}.md)`));\n const body = kept.join(\"\\n\").trimEnd();\n const head = body.length > 0 ? body : MEMORY_MD_HEADER.trimEnd();\n return `${head}\\n${entry}\\n`;\n}\n\n/** A `MEMORY.md` index entry: a link whose target is a sibling `.md` file. */\nconst INDEX_ENTRY = /^\\[[^\\]]*\\]\\([^)]+\\.md\\)$/;\n\n/**\n * Facts from a legacy `## Facts` section — the shape every released version wrote.\n *\n * Kept for reading only. The converged writer puts each memory in its own file, and this parser\n * exists so a store written by an earlier version keeps answering.\n *\n * There is no metadata to recover from a bullet: `kind` and `modified` are absent, which is exactly\n * right, since nothing recorded them. A brief encoding that carried them in a trailing HTML comment\n * (#389) never reached a published version — 4.55.0 was published at 17:23Z and that commit landed\n * at 20:06Z — so there is no store in the wild to migrate from it.\n */\nfunction parseFactsSection(raw: string): MemoryFact[] {\n const idx = raw.indexOf(FACTS_HEADING);\n if (idx === -1) return [];\n const tail = raw.slice(idx + FACTS_HEADING.length);\n // Stop at the next top-level or h2 heading.\n const nextHeading = tail.search(/\\n#{1,2}\\s/);\n const block = nextHeading === -1 ? tail : tail.slice(0, nextHeading);\n return (\n block\n .split(\"\\n\")\n .map((line) => line.trim())\n .filter((line) => line.startsWith(\"- \"))\n .map((line) => line.slice(2).trim())\n // An index entry is a POINTER to a memory, not a memory. Both are `- ` bullets, and when a\n // legacy `## Facts` heading is present the appended index lines land under it — counting them\n // here would report every converged memory twice, once from its file and once from its link.\n .filter((body) => !INDEX_ENTRY.test(body))\n .map((body) => ({ text: body }))\n );\n}\n\n/**\n * Every memory in the store, honouring the `enabled` gate on {@link MemoryConfig}: when memory is\n * disabled the call resolves to `[]` without touching disk. Configuration-aware entry point;\n * {@link readFactsFromMarkdown} is the same read without the gate.\n */\nexport async function readFacts(\n cwd: string,\n config: MemoryConfig,\n memoryHome?: string,\n): Promise<MemoryFact[]> {\n if (!config.enabled) return [];\n return readFactsFromMarkdown(cwd, memoryHome);\n}\n\n/**\n * Record a fact, honouring the `enabled` gate on {@link MemoryConfig}: when memory is disabled the\n * call resolves without touching disk. Configuration-aware entry point;\n * {@link appendFactToMarkdown} is the same write without the gate.\n *\n * `memoryHome` is the agent's `local.sessionDir` when it has one — see {@link memoryWriteDir} for\n * which store that sends the fact to.\n */\nexport async function appendFact(\n cwd: string,\n config: MemoryConfig,\n fact: MemoryFact,\n memoryHome?: string,\n): Promise<void> {\n if (!config.enabled) return;\n await appendFactToMarkdown(cwd, fact, memoryWriteDir(cwd, memoryHome));\n}\n"]}
@@ -0,0 +1,203 @@
1
+ 'use strict';
2
+
3
+ var chunkKRD3GQAA_cjs = require('./chunk-KRD3GQAA.cjs');
4
+ var chunkR3UPQFKK_cjs = require('./chunk-R3UPQFKK.cjs');
5
+ var chunkBUIK7GUA_cjs = require('./chunk-BUIK7GUA.cjs');
6
+ var chunkZF2LDKQQ_cjs = require('./chunk-ZF2LDKQQ.cjs');
7
+ var chunkI6TGFUCO_cjs = require('./chunk-I6TGFUCO.cjs');
8
+ var chunkK3FW2XZD_cjs = require('./chunk-K3FW2XZD.cjs');
9
+ var chunkJTB5Q42C_cjs = require('./chunk-JTB5Q42C.cjs');
10
+ var promises = require('fs/promises');
11
+ var os = require('os');
12
+ var path = require('path');
13
+
14
+ var MEMORY_KINDS = ["user", "feedback", "project", "reference"];
15
+ function legacyMemoryJsonPath(cwd, config) {
16
+ if (config.storePath !== void 0) {
17
+ return path.resolve(cwd, config.storePath);
18
+ }
19
+ const namespace = chunkR3UPQFKK_cjs.sanitizeIdentifier(config.namespace ?? "default");
20
+ const scope = chunkR3UPQFKK_cjs.sanitizeIdentifier(config.scope ?? "agent", { maxLen: 16 });
21
+ const userId = chunkR3UPQFKK_cjs.sanitizeIdentifier(config.userId ?? "default");
22
+ return chunkR3UPQFKK_cjs.safePathJoin(cwd, ".theokit", "memory", namespace, `${scope}-${userId}.json`);
23
+ }
24
+
25
+ // src/internal/memory/storage/memory-file.ts
26
+ var SAFE_SLUG = /^[a-z0-9][a-z0-9_-]*$/;
27
+ var MAX_SLUG_LENGTH = 64;
28
+ function slugForFact(text) {
29
+ const slug = text.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, MAX_SLUG_LENGTH).replace(/-+$/, "");
30
+ return SAFE_SLUG.test(slug) ? slug : chunkR3UPQFKK_cjs.safeFilenameForId(text);
31
+ }
32
+ function renderMemoryFile(fields) {
33
+ const metadata = [" node_type: memory"];
34
+ if (fields.kind !== void 0) metadata.push(` type: ${fields.kind}`);
35
+ if (fields.modified !== void 0) metadata.push(` modified: ${fields.modified}`);
36
+ return [
37
+ "---",
38
+ `name: ${fields.name}`,
39
+ `description: ${JSON.stringify(fields.description)}`,
40
+ "metadata:",
41
+ ...metadata,
42
+ "---",
43
+ "",
44
+ fields.body,
45
+ ""
46
+ ].join("\n");
47
+ }
48
+ function parseMemoryFile(raw) {
49
+ const { yaml, body } = chunkKRD3GQAA_cjs.splitFrontmatter(raw);
50
+ if (yaml === void 0) return void 0;
51
+ let fields;
52
+ try {
53
+ fields = chunkKRD3GQAA_cjs.parseSimpleYaml(yaml);
54
+ } catch {
55
+ return void 0;
56
+ }
57
+ const name = fields.name;
58
+ const description = fields.description;
59
+ if (typeof name !== "string" || typeof description !== "string") return void 0;
60
+ const metadata = fields.metadata ?? {};
61
+ const rawKind = metadata.type;
62
+ const kind = typeof rawKind === "string" && MEMORY_KINDS.includes(rawKind) ? rawKind : void 0;
63
+ const modified = typeof metadata.modified === "string" ? metadata.modified : void 0;
64
+ return {
65
+ name,
66
+ description,
67
+ ...kind !== void 0 ? { kind } : {},
68
+ ...modified !== void 0 ? { modified } : {},
69
+ body: body.trim()
70
+ };
71
+ }
72
+
73
+ // src/internal/memory/storage/markdown-store.ts
74
+ var MEMORY_MD_HEADER = "# Memory\n\n> Auto-managed by @theokit/sdk. Edit freely \u2014 the SDK reads from here.\n";
75
+ var FACTS_HEADING = "## Facts";
76
+ function memoryDir(cwd) {
77
+ return path.join(cwd, ".theokit", "memory");
78
+ }
79
+ function memoryWriteDir(cwd, sessionDir) {
80
+ if (sessionDir === void 0 || sessionDir.trim().length === 0) return memoryDir(cwd);
81
+ return path.join(sessionDir, "projects", chunkBUIK7GUA_cjs.encodeProjectDir(cwd), "memory");
82
+ }
83
+ function claudeProjectMemoryDir(cwd) {
84
+ const home = process.env.CLAUDE_CONFIG_DIR?.trim();
85
+ const root = home !== void 0 && home.length > 0 ? home : path.join(os.homedir(), ".claude");
86
+ return path.join(root, "projects", chunkBUIK7GUA_cjs.encodeProjectDir(cwd), "memory");
87
+ }
88
+ function memoryMdPath(cwd) {
89
+ return path.join(memoryDir(cwd), "MEMORY.md");
90
+ }
91
+ function notesDir(cwd) {
92
+ return path.join(memoryDir(cwd), "notes");
93
+ }
94
+ async function readFactsFromMarkdown(cwd, sessionDir) {
95
+ const facts = [];
96
+ const roots = [
97
+ .../* @__PURE__ */ new Set([memoryDir(cwd), memoryWriteDir(cwd, sessionDir), claudeProjectMemoryDir(cwd)])
98
+ ];
99
+ for (const dir of roots) {
100
+ let entries;
101
+ try {
102
+ entries = await promises.readdir(dir);
103
+ } catch {
104
+ continue;
105
+ }
106
+ for (const entry of entries.sort()) {
107
+ const fact = await readMemoryFileIn(dir, entry);
108
+ if (fact !== void 0) facts.push(fact);
109
+ }
110
+ }
111
+ try {
112
+ facts.push(...parseFactsSection(await promises.readFile(memoryMdPath(cwd), "utf8")));
113
+ } catch {
114
+ }
115
+ return facts;
116
+ }
117
+ async function readMemoryFileIn(dir, entry) {
118
+ if (!entry.endsWith(".md") || entry === "MEMORY.md") return void 0;
119
+ let raw;
120
+ try {
121
+ raw = await promises.readFile(path.join(dir, entry), "utf8");
122
+ } catch {
123
+ return void 0;
124
+ }
125
+ const parsed = parseMemoryFile(raw);
126
+ if (parsed === void 0) return void 0;
127
+ const body = parsed.body.trim();
128
+ return {
129
+ text: body.length > 0 ? body : parsed.description,
130
+ ...parsed.kind !== void 0 ? { kind: parsed.kind } : {},
131
+ ...parsed.modified !== void 0 ? { modified: parsed.modified } : {}
132
+ };
133
+ }
134
+ function appendFactToMarkdown(cwd, fact, targetDir = memoryDir(cwd)) {
135
+ return chunkZF2LDKQQ_cjs.withCwdMutex(targetDir, async () => {
136
+ if (fact.kind !== void 0 && !MEMORY_KINDS.includes(fact.kind)) {
137
+ throw new chunkK3FW2XZD_cjs.ConfigurationError(
138
+ `Unknown memory fact kind "${fact.kind}". Expected one of: ${MEMORY_KINDS.join(", ")}.`,
139
+ { code: "invalid_memory_kind" }
140
+ );
141
+ }
142
+ const text = chunkJTB5Q42C_cjs.redactSecrets(fact.text);
143
+ const name = slugForFact(text);
144
+ await promises.mkdir(targetDir, { recursive: true });
145
+ await chunkI6TGFUCO_cjs.replaceFileAtomic(
146
+ path.join(targetDir, `${name}.md`),
147
+ renderMemoryFile({
148
+ name,
149
+ description: text,
150
+ ...fact.kind !== void 0 ? { kind: fact.kind } : {},
151
+ modified: (/* @__PURE__ */ new Date()).toISOString(),
152
+ body: text
153
+ })
154
+ );
155
+ await chunkI6TGFUCO_cjs.replaceFileAtomic(path.join(targetDir, "MEMORY.md"), await nextIndex(targetDir, text, name));
156
+ });
157
+ }
158
+ async function nextIndex(dir, text, name) {
159
+ let existing = "";
160
+ try {
161
+ existing = await promises.readFile(path.join(dir, "MEMORY.md"), "utf8");
162
+ } catch {
163
+ existing = "";
164
+ }
165
+ const entry = `- [${text}](${name}.md)`;
166
+ const kept = existing.split("\n").filter((line) => !line.startsWith(`- [`) || !line.includes(`](${name}.md)`));
167
+ const body = kept.join("\n").trimEnd();
168
+ const head = body.length > 0 ? body : MEMORY_MD_HEADER.trimEnd();
169
+ return `${head}
170
+ ${entry}
171
+ `;
172
+ }
173
+ var INDEX_ENTRY = /^\[[^\]]*\]\([^)]+\.md\)$/;
174
+ function parseFactsSection(raw) {
175
+ const idx = raw.indexOf(FACTS_HEADING);
176
+ if (idx === -1) return [];
177
+ const tail = raw.slice(idx + FACTS_HEADING.length);
178
+ const nextHeading = tail.search(/\n#{1,2}\s/);
179
+ const block = nextHeading === -1 ? tail : tail.slice(0, nextHeading);
180
+ return block.split("\n").map((line) => line.trim()).filter((line) => line.startsWith("- ")).map((line) => line.slice(2).trim()).filter((body) => !INDEX_ENTRY.test(body)).map((body) => ({ text: body }));
181
+ }
182
+ async function readFacts(cwd, config, memoryHome) {
183
+ if (!config.enabled) return [];
184
+ return readFactsFromMarkdown(cwd, memoryHome);
185
+ }
186
+ async function appendFact(cwd, config, fact, memoryHome) {
187
+ if (!config.enabled) return;
188
+ await appendFactToMarkdown(cwd, fact, memoryWriteDir(cwd, memoryHome));
189
+ }
190
+
191
+ exports.MEMORY_KINDS = MEMORY_KINDS;
192
+ exports.appendFact = appendFact;
193
+ exports.appendFactToMarkdown = appendFactToMarkdown;
194
+ exports.claudeProjectMemoryDir = claudeProjectMemoryDir;
195
+ exports.legacyMemoryJsonPath = legacyMemoryJsonPath;
196
+ exports.memoryDir = memoryDir;
197
+ exports.memoryMdPath = memoryMdPath;
198
+ exports.memoryWriteDir = memoryWriteDir;
199
+ exports.notesDir = notesDir;
200
+ exports.readFacts = readFacts;
201
+ exports.readFactsFromMarkdown = readFactsFromMarkdown;
202
+ //# sourceMappingURL=chunk-NY25NBZB.cjs.map
203
+ //# sourceMappingURL=chunk-NY25NBZB.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/internal/memory/types.ts","../src/internal/memory/storage/memory-file.ts","../src/internal/memory/storage/markdown-store.ts"],"names":["resolvePath","sanitizeIdentifier","safePathJoin","safeFilenameForId","splitFrontmatter","parseSimpleYaml","join","encodeProjectDir","homedir","readdir","readFile","withCwdMutex","ConfigurationError","redactSecrets","mkdir","replaceFileAtomic"],"mappings":"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","file":"chunk-NY25NBZB.cjs","sourcesContent":["/**\n * Public memory types (used by runtime + storage + migration + future index).\n *\n * Leaf module — only depends on `node:path` — so neither `runtime/memory-store.ts`\n * nor `internal/memory/markdown-store.ts` introduces a dependency cycle.\n *\n * @internal\n */\nimport { resolve as resolvePath } from \"node:path\";\n\nimport { safePathJoin, sanitizeIdentifier } from \"../security/path-guard.js\";\n\nexport interface MemoryConfig {\n enabled: boolean;\n namespace?: string;\n userId?: string;\n scope?: \"agent\" | \"user\" | \"team\";\n storePath?: string;\n}\n\n/**\n * What a fact IS, which is what decides whether it ages (#389).\n *\n * The four are the distinctions that matter for retention and recall: a preference stays true until\n * the user changes their mind, a project fact goes stale when the code moves, a reference either\n * resolves or 404s, and feedback records a correction that was given. Without them, recall ranks one\n * undifferentiated corpus and pruning has no basis to prefer a durable fact over a transient one.\n *\n * A kind is never INFERRED. A wrong kind is worse than none, because it makes retention and recall\n * confident about the wrong thing — so a fact whose author did not say stays untyped.\n */\nexport type MemoryKind = \"user\" | \"feedback\" | \"project\" | \"reference\";\n\n/** The four values {@link MemoryKind} admits, for runtime validation at the storage boundary. */\nexport const MEMORY_KINDS: readonly MemoryKind[] = [\"user\", \"feedback\", \"project\", \"reference\"];\n\nexport interface MemoryFact {\n text: string;\n /**\n * What this fact is (#389). Absent means untyped, which is what a hand-written bullet under\n * `## Facts` stays — those files are already on disk in consumers' repositories and the store's\n * own header invites editing them.\n */\n kind?: MemoryKind;\n /**\n * ISO 8601 instant this fact was last written, stamped BY THE SDK.\n *\n * Supplying it does nothing: a timestamp a caller can set is a timestamp that can lie about when\n * something was learned, and the whole point is to weigh a note from this morning against one\n * from four months ago. Absent on a fact written before this existed, or hand-added.\n */\n modified?: string;\n}\n\n// `redactSecrets` is now re-exported from the canonical security module\n// (ADR D68). Pre-T0.2 it was a 3-pattern local fn; consolidated to avoid\n// drift with the central 12-pattern list.\nexport { redactSecrets } from \"../security/index.js\";\n\n/**\n * Resolve the legacy JSON memory path used pre-ADR-D8 (kept for migration\n * helpers + tests). Centralized here so `migration.ts` and the legacy-aware\n * `runtime/memory-store.ts` don't duplicate the path logic (jscpd cleanup).\n */\nexport function legacyMemoryJsonPath(cwd: string, config: MemoryConfig): string {\n // ADRs D79-D81: storePath is programmatic (trusted); namespace/scope/userId\n // are user-shaped and pass sanitizeIdentifier. EC-7 (edge-case review):\n // realistic userIds (UUIDs, hash IDs, \"default\") pass; \"user@example.com\"\n // and similar need to be normalized by the caller before passing.\n if (config.storePath !== undefined) {\n return resolvePath(cwd, config.storePath);\n }\n const namespace = sanitizeIdentifier(config.namespace ?? \"default\");\n const scope = sanitizeIdentifier(config.scope ?? \"agent\", { maxLen: 16 });\n const userId = sanitizeIdentifier(config.userId ?? \"default\");\n return safePathJoin(cwd, \".theokit\", \"memory\", namespace, `${scope}-${userId}.json`);\n}\n\n/**\n * A semantically meaningful slice of a markdown memory file, produced by\n * `chunkMarkdown`. Each chunk carries stable line numbers + a content hash\n * used downstream by the embedding cache.\n *\n * Mirrors peer-project's `MemoryChunk` shape\n * (`reference/peer-project/packages/memory-host-sdk/src/host/engine-storage.ts`).\n *\n * @internal\n */\nexport interface MemoryChunk {\n /** 1-indexed starting line in the source file. */\n startLine: number;\n /** 1-indexed ending line (inclusive). */\n endLine: number;\n /** Slice of markdown source text. */\n text: string;\n /** sha256 of `text`; stable across runs for identical inputs. */\n hash: string;\n /** Optional nearest heading text (without the `#` markers). */\n heading?: string;\n}\n\n/**\n * Result of `reader.readFile`. Contains the bounded slice plus truncation\n * + provenance info.\n *\n * Mirrors peer-project's `MemoryReadResult` shape.\n *\n * @internal\n */\nexport interface MemoryReadResult {\n path: string;\n /** Requested starting line (1-indexed, defaults to 1). */\n from: number;\n /** Number of lines actually returned (may be less than `lines` near EOF). */\n linesReturned: number;\n /** Total lines in the file (after the read). */\n totalLines: number;\n /** True when fewer lines were returned than the requested `lines` AND EOF was hit. */\n truncated: boolean;\n /** Lines past the returned slice that remain in the file. */\n remainingLines: number;\n /** Slice text (joined with `\\n`). */\n text: string;\n}\n","/**\n * One memory as a file, in the shape the Claude Code CLI reads.\n *\n * `@theokit/sdk` already writes native Claude Code `.jsonl` sessions — the README's differentiator\n * is \"point `local.sessionDir` at `~/.claude` and the Claude Code CLI can `--continue` a session\n * your agent wrote\". Memory had no such convergence: a fact was a bullet under `## Facts` with its\n * kind in an HTML comment (#389), which that CLI reads as prose. Pointing a memory directory at\n * `~/.claude/projects/<project>/memory/` produced nothing it could open.\n *\n * The contract here was measured against a real store rather than inferred from documentation. Of\n * nine files, all nine carry `name`, `description` and `metadata.type`; six also carry\n * `node_type`, `originSessionId` and `modified`, which the runtime stamps on write. So the minimum\n * a reader must accept is the first three — refusing the rest would refuse memories the CLI itself\n * accepts.\n *\n * `originSessionId` is deliberately not written. It identifies the session that learned the fact,\n * and the append path has no session in scope; inventing one would be worse than omitting a field\n * the format already treats as optional.\n *\n * @internal\n */\n\nimport { parseSimpleYaml, splitFrontmatter } from \"../../runtime/context/context-yaml-lite.js\";\nimport { safeFilenameForId } from \"../../security/path-guard.js\";\nimport { MEMORY_KINDS, type MemoryKind } from \"../types.js\";\n\n/** The fields one memory file carries. */\nexport interface MemoryFileFields {\n /** Slug, and the file's basename. */\n readonly name: string;\n /** One-line summary — what the index shows and what recall ranks. */\n readonly description: string;\n /** `metadata.type`, absent when the file does not declare one this contract admits. */\n readonly kind?: MemoryKind;\n /** `metadata.modified`, an ISO 8601 instant stamped by whoever wrote the file. */\n readonly modified?: string;\n /** The markdown after the frontmatter. */\n readonly body: string;\n}\n\n/** The safe filename grammar a slug must satisfy before it is used as one. */\nconst SAFE_SLUG = /^[a-z0-9][a-z0-9_-]*$/;\n/** Long enough to stay readable, short enough to survive every filesystem's component limit. */\nconst MAX_SLUG_LENGTH = 64;\n\n/**\n * A readable, filesystem-safe slug for `text`.\n *\n * Readability is the goal — a directory of `h-3f2a…` files is a directory nobody browses — but it\n * is not the floor. The text comes from whatever a caller learned, so anything that fails the safe\n * grammar falls back to {@link safeFilenameForId}, which is total and always yields a valid\n * component.\n */\nexport function slugForFact(text: string): string {\n const slug = text\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, \"-\")\n .replace(/^-+|-+$/g, \"\")\n .slice(0, MAX_SLUG_LENGTH)\n .replace(/-+$/, \"\");\n return SAFE_SLUG.test(slug) ? slug : safeFilenameForId(text);\n}\n\n/** Render one memory file. `description` is quoted so a colon in the text cannot break the block. */\nexport function renderMemoryFile(fields: MemoryFileFields): string {\n const metadata = [\" node_type: memory\"];\n if (fields.kind !== undefined) metadata.push(` type: ${fields.kind}`);\n if (fields.modified !== undefined) metadata.push(` modified: ${fields.modified}`);\n return [\n \"---\",\n `name: ${fields.name}`,\n `description: ${JSON.stringify(fields.description)}`,\n \"metadata:\",\n ...metadata,\n \"---\",\n \"\",\n fields.body,\n \"\",\n ].join(\"\\n\");\n}\n\n/**\n * Read one memory file, or `undefined` when the content is not one.\n *\n * `undefined` rather than a throw, and rather than a best-effort object: the directory holds\n * hand-written notes and a `MEMORY.md` index alongside the memories, and turning any of those into\n * a fact would put text into recall that nobody recorded as one.\n */\nexport function parseMemoryFile(raw: string): MemoryFileFields | undefined {\n const { yaml, body } = splitFrontmatter(raw);\n if (yaml === undefined) return undefined;\n\n let fields: Record<string, unknown>;\n try {\n fields = parseSimpleYaml(yaml);\n } catch {\n return undefined; // malformed frontmatter is not a memory\n }\n\n const name = fields.name;\n const description = fields.description;\n if (typeof name !== \"string\" || typeof description !== \"string\") return undefined;\n\n const metadata = (fields.metadata ?? {}) as Record<string, unknown>;\n const rawKind = metadata.type;\n // An unknown `type` reads as untyped rather than as a fifth kind: the file is hand-editable and\n // recall must not act on a value this contract does not admit.\n const kind =\n typeof rawKind === \"string\" && MEMORY_KINDS.includes(rawKind as MemoryKind)\n ? (rawKind as MemoryKind)\n : undefined;\n const modified = typeof metadata.modified === \"string\" ? metadata.modified : undefined;\n\n return {\n name,\n description,\n ...(kind !== undefined ? { kind } : {}),\n ...(modified !== undefined ? { modified } : {}),\n body: body.trim(),\n };\n}\n","import { mkdir, readdir, readFile } from \"node:fs/promises\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\n\nimport { ConfigurationError } from \"../../../errors.js\";\nimport { replaceFileAtomic } from \"../../persistence/atomic-write.js\";\nimport { withCwdMutex } from \"../../persistence/cwd-mutex.js\";\nimport { encodeProjectDir } from \"../../persistence/session-transcript.js\";\nimport { MEMORY_KINDS, type MemoryConfig, type MemoryFact, redactSecrets } from \"../types.js\";\nimport { parseMemoryFile, renderMemoryFile, slugForFact } from \"./memory-file.js\";\n\n/**\n * Markdown-first memory storage (ADR D1 of memory-system-peer-project-parity).\n *\n * Layout, converged with the one the Claude Code CLI reads:\n * <memoryDir>/\n * ├── MEMORY.md # INDEX — one `- [text](slug.md)` line per memory\n * ├── <slug>.md # one memory, frontmatter carrying `metadata.type` + `modified`\n * └── notes/\n * └── <slug>.md # hand-written per-topic notes (read by the indexer, never written here)\n *\n * The SDK already emits native Claude Code `.jsonl` sessions, so a consumer can point\n * `local.sessionDir` at `~/.claude` and `--continue` a session its agent wrote. Memory did not hold\n * that line: a fact was a bullet under `## Facts` with its kind in an HTML comment (#389), which\n * that CLI reads as prose. Pointing a memory directory at `~/.claude/projects/<project>/memory/`\n * produced nothing it could open.\n *\n * `## Facts` bullets are still READ. They are already on disk in consumers' repositories, and a\n * format change that stopped reading them would delete what someone recorded — worse than the\n * format it replaces.\n *\n * All writes go through `replaceFileAtomic` + a per-cwd mutex (EC-4 of the\n * edge-case review) so concurrent `appendFact` calls within the same process\n * serialize. Multi-process safety is NOT provided.\n *\n * @internal\n */\n\nconst MEMORY_MD_HEADER =\n \"# Memory\\n\\n> Auto-managed by @theokit/sdk. Edit freely — the SDK reads from here.\\n\";\nconst FACTS_HEADING = \"## Facts\";\n\n/**\n * The memory root for a workspace: `<cwd>/.theokit/memory`. Every other path here derives from it,\n * and `memory_get` refuses to read outside it. Pure path computation — nothing is created on disk.\n */\nexport function memoryDir(cwd: string): string {\n return join(cwd, \".theokit\", \"memory\");\n}\n\n/**\n * Where a NEW fact should be written.\n *\n * `.theokit/memory` by default, exactly as before. When the agent was given a `local.sessionDir`,\n * it becomes `<sessionDir>/projects/<encoded-cwd>/memory` — the same place the transcript for that\n * project goes, so a session and the memories recorded during it land beside each other.\n *\n * `local.sessionDir` is the switch because it is already the option this project documents for CLI\n * interop: point it at `~/.claude` and the CLI can `--continue` a session this agent wrote. Someone\n * who set it has said they share state with that CLI, and memory following is what the sentence\n * already implied. It needs no new option, and nothing moves for anyone who never set it.\n *\n * Safe because of the rule this pairs with — WRITE ONE, READ ALL. {@link readFactsFromMarkdown}\n * covers every location, so a consumer whose new facts move keeps every fact they already had. The\n * change relocates where the next one lands; it orphans nothing.\n */\nexport function memoryWriteDir(cwd: string, sessionDir: string | undefined): string {\n if (sessionDir === undefined || sessionDir.trim().length === 0) return memoryDir(cwd);\n return join(sessionDir, \"projects\", encodeProjectDir(cwd), \"memory\");\n}\n\n/**\n * Where the Claude Code CLI keeps THIS project's memories.\n *\n * `<claudeHome>/projects/<encoded-cwd>/memory` — the same `encodeProjectDir` scheme the transcripts\n * already use, which is why no new encoding is invented here. `CLAUDE_CONFIG_DIR` names the home\n * when set (the CLI's own variable); `~/.claude` otherwise.\n *\n * Read, never written. Writing here by default would relocate every existing consumer's memories,\n * and an additive change must not move what is already on disk — so this is the direction that\n * costs nothing: a memory the CLI wrote becomes visible, and a memory the SDK wrote stays where the\n * SDK put it.\n */\nexport function claudeProjectMemoryDir(cwd: string): string {\n const home = process.env.CLAUDE_CONFIG_DIR?.trim();\n const root = home !== undefined && home.length > 0 ? home : join(homedir(), \".claude\");\n return join(root, \"projects\", encodeProjectDir(cwd), \"memory\");\n}\n\n/**\n * Path to `MEMORY.md`, the index that points at the per-memory files — and, in stores written before\n * #389, the flat `## Facts` list itself. Pure path computation; the file may not exist.\n */\nexport function memoryMdPath(cwd: string): string {\n return join(memoryDir(cwd), \"MEMORY.md\");\n}\n\n/**\n * Path to `<memory root>/notes`, where per-topic notes and the consolidated notes a dreaming sweep\n * writes live. Pure path computation — the directory may not exist.\n */\nexport function notesDir(cwd: string): string {\n return join(memoryDir(cwd), \"notes\");\n}\n\n/**\n * Every memory in the store: the per-memory files, plus any legacy `## Facts` bullets still in\n * `MEMORY.md`. Returns `[]` when the directory does not exist.\n *\n * Reading both is not transitional politeness. Those bullets are already on disk in consumers'\n * repositories, and the store's own header invites editing them by hand — a converged writer that\n * stopped reading them would delete what someone recorded, which is worse than the format it fixes.\n */\nexport async function readFactsFromMarkdown(\n cwd: string,\n sessionDir?: string,\n): Promise<MemoryFact[]> {\n const facts: MemoryFact[] = [];\n // Both stores: this SDK's, then the one the Claude Code CLI keeps for the same project. The\n // format has been shared since #389; only the directory was not, so a memory the CLI recorded was\n // invisible to an agent working in the same repository.\n // READ ALL: the project store, the location a configured `sessionDir` writes to, and the one the\n // CLI uses by default. Deduplicated, because with `sessionDir` pointed at the CLI's own home the\n // last two are the same directory and a fact would otherwise be recalled twice.\n const roots = [\n ...new Set([memoryDir(cwd), memoryWriteDir(cwd, sessionDir), claudeProjectMemoryDir(cwd)]),\n ];\n for (const dir of roots) {\n let entries: string[];\n try {\n entries = await readdir(dir);\n } catch {\n continue;\n }\n for (const entry of entries.sort()) {\n const fact = await readMemoryFileIn(dir, entry);\n if (fact !== undefined) facts.push(fact);\n }\n }\n\n try {\n facts.push(...parseFactsSection(await readFile(memoryMdPath(cwd), \"utf8\")));\n } catch {\n // no index yet — the per-memory files above are the whole store\n }\n return facts;\n}\n\n/**\n * One directory entry as a fact, or `undefined` when it is not one.\n *\n * `MEMORY.md` is the index, not a memory; a non-markdown entry is not a memory; and a markdown file\n * without the frontmatter is a note somebody wrote by hand. Turning any of those into a fact would\n * put text into recall that nobody recorded as one.\n *\n * The DIRECTORY is a parameter rather than derived from `cwd`, because both stores — this SDK's and\n * the one the Claude Code CLI keeps for the same project — read entries the same way, and a second\n * copy of this function is a second place for those three rules to drift.\n */\nasync function readMemoryFileIn(dir: string, entry: string): Promise<MemoryFact | undefined> {\n if (!entry.endsWith(\".md\") || entry === \"MEMORY.md\") return undefined;\n let raw: string;\n try {\n raw = await readFile(join(dir, entry), \"utf8\");\n } catch {\n return undefined; // vanished between readdir and read\n }\n const parsed = parseMemoryFile(raw);\n if (parsed === undefined) return undefined;\n // The BODY is the memory; `description` is the one-line recall aid. This SDK writes both the same,\n // so nothing it wrote changes — but the Claude Code CLI writes a summary in `description` and the\n // substance below it, and reading only the summary silently dropped the fact itself.\n const body = parsed.body.trim();\n return {\n text: body.length > 0 ? body : parsed.description,\n ...(parsed.kind !== undefined ? { kind: parsed.kind } : {}),\n ...(parsed.modified !== undefined ? { modified: parsed.modified } : {}),\n };\n}\n\n/**\n * Write a fact as its own memory file and point the `MEMORY.md` index at it. Atomic + serialized.\n *\n * `modified` is stamped HERE and never read from `fact`: a timestamp a caller can set is a\n * timestamp that can lie about when something was learned, and weighing recency is the point.\n */\nexport function appendFactToMarkdown(\n cwd: string,\n fact: MemoryFact,\n targetDir: string = memoryDir(cwd),\n): Promise<void> {\n return withCwdMutex(targetDir, async () => {\n // Validate at the boundary (`error-handling.md` § 2): a kind outside the four would be written\n // to a file recall later trusts, so it is refused here rather than stored and believed.\n if (fact.kind !== undefined && !MEMORY_KINDS.includes(fact.kind)) {\n throw new ConfigurationError(\n `Unknown memory fact kind \"${fact.kind}\". Expected one of: ${MEMORY_KINDS.join(\", \")}.`,\n { code: \"invalid_memory_kind\" },\n );\n }\n const text = redactSecrets(fact.text);\n const name = slugForFact(text);\n await mkdir(targetDir, { recursive: true });\n await replaceFileAtomic(\n join(targetDir, `${name}.md`),\n renderMemoryFile({\n name,\n description: text,\n ...(fact.kind !== undefined ? { kind: fact.kind } : {}),\n modified: new Date().toISOString(),\n body: text,\n }),\n );\n // The index lives BESIDE the files it lists. A `MEMORY.md` in one directory pointing at\n // memories in another names files that are not there — and the CLI reads that index.\n await replaceFileAtomic(join(targetDir, \"MEMORY.md\"), await nextIndex(targetDir, text, name));\n });\n}\n\n/**\n * The `MEMORY.md` index with `name` present exactly once.\n *\n * Rewriting the same memory replaces its line rather than adding a second: the index is a map from\n * memory to file, and two lines for one file is a map that disagrees with itself.\n */\nasync function nextIndex(dir: string, text: string, name: string): Promise<string> {\n let existing = \"\";\n try {\n // The index in the directory being WRITTEN, not the project one — see the caller.\n existing = await readFile(join(dir, \"MEMORY.md\"), \"utf8\");\n } catch {\n existing = \"\";\n }\n const entry = `- [${text}](${name}.md)`;\n const kept = existing\n .split(\"\\n\")\n .filter((line) => !line.startsWith(`- [`) || !line.includes(`](${name}.md)`));\n const body = kept.join(\"\\n\").trimEnd();\n const head = body.length > 0 ? body : MEMORY_MD_HEADER.trimEnd();\n return `${head}\\n${entry}\\n`;\n}\n\n/** A `MEMORY.md` index entry: a link whose target is a sibling `.md` file. */\nconst INDEX_ENTRY = /^\\[[^\\]]*\\]\\([^)]+\\.md\\)$/;\n\n/**\n * Facts from a legacy `## Facts` section — the shape every released version wrote.\n *\n * Kept for reading only. The converged writer puts each memory in its own file, and this parser\n * exists so a store written by an earlier version keeps answering.\n *\n * There is no metadata to recover from a bullet: `kind` and `modified` are absent, which is exactly\n * right, since nothing recorded them. A brief encoding that carried them in a trailing HTML comment\n * (#389) never reached a published version — 4.55.0 was published at 17:23Z and that commit landed\n * at 20:06Z — so there is no store in the wild to migrate from it.\n */\nfunction parseFactsSection(raw: string): MemoryFact[] {\n const idx = raw.indexOf(FACTS_HEADING);\n if (idx === -1) return [];\n const tail = raw.slice(idx + FACTS_HEADING.length);\n // Stop at the next top-level or h2 heading.\n const nextHeading = tail.search(/\\n#{1,2}\\s/);\n const block = nextHeading === -1 ? tail : tail.slice(0, nextHeading);\n return (\n block\n .split(\"\\n\")\n .map((line) => line.trim())\n .filter((line) => line.startsWith(\"- \"))\n .map((line) => line.slice(2).trim())\n // An index entry is a POINTER to a memory, not a memory. Both are `- ` bullets, and when a\n // legacy `## Facts` heading is present the appended index lines land under it — counting them\n // here would report every converged memory twice, once from its file and once from its link.\n .filter((body) => !INDEX_ENTRY.test(body))\n .map((body) => ({ text: body }))\n );\n}\n\n/**\n * Every memory in the store, honouring the `enabled` gate on {@link MemoryConfig}: when memory is\n * disabled the call resolves to `[]` without touching disk. Configuration-aware entry point;\n * {@link readFactsFromMarkdown} is the same read without the gate.\n */\nexport async function readFacts(\n cwd: string,\n config: MemoryConfig,\n memoryHome?: string,\n): Promise<MemoryFact[]> {\n if (!config.enabled) return [];\n return readFactsFromMarkdown(cwd, memoryHome);\n}\n\n/**\n * Record a fact, honouring the `enabled` gate on {@link MemoryConfig}: when memory is disabled the\n * call resolves without touching disk. Configuration-aware entry point;\n * {@link appendFactToMarkdown} is the same write without the gate.\n *\n * `memoryHome` is the agent's `local.sessionDir` when it has one — see {@link memoryWriteDir} for\n * which store that sends the fact to.\n */\nexport async function appendFact(\n cwd: string,\n config: MemoryConfig,\n fact: MemoryFact,\n memoryHome?: string,\n): Promise<void> {\n if (!config.enabled) return;\n await appendFactToMarkdown(cwd, fact, memoryWriteDir(cwd, memoryHome));\n}\n"]}
@@ -1,11 +1,9 @@
1
1
  'use strict';
2
2
 
3
3
  var chunkGHX4P3V2_cjs = require('./chunk-GHX4P3V2.cjs');
4
- var chunkKRD3GQAA_cjs = require('./chunk-KRD3GQAA.cjs');
4
+ var chunkNY25NBZB_cjs = require('./chunk-NY25NBZB.cjs');
5
5
  var chunkR3UPQFKK_cjs = require('./chunk-R3UPQFKK.cjs');
6
- var chunkBUIK7GUA_cjs = require('./chunk-BUIK7GUA.cjs');
7
6
  var chunkSKXBJ2NU_cjs = require('./chunk-SKXBJ2NU.cjs');
8
- var chunkZF2LDKQQ_cjs = require('./chunk-ZF2LDKQQ.cjs');
9
7
  var chunkI6TGFUCO_cjs = require('./chunk-I6TGFUCO.cjs');
10
8
  var chunkK3FW2XZD_cjs = require('./chunk-K3FW2XZD.cjs');
11
9
  var chunkJTB5Q42C_cjs = require('./chunk-JTB5Q42C.cjs');
@@ -14,7 +12,6 @@ var promises = require('fs/promises');
14
12
  var path = require('path');
15
13
  var fs = require('fs');
16
14
  var module$1 = require('module');
17
- var os = require('os');
18
15
 
19
16
  var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null;
20
17
  // src/internal/memory/escape-like-pattern.ts
@@ -80,7 +77,7 @@ function defaultIndexPath(cwd) {
80
77
  }
81
78
  function requireLance() {
82
79
  try {
83
- const r = module$1.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('chunk-27AXGJMV.cjs', document.baseURI).href)));
80
+ const r = module$1.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('chunk-Y2KJ7MYO.cjs', document.baseURI).href)));
84
81
  return r("@lancedb/lancedb");
85
82
  } catch (cause) {
86
83
  throw new chunkK3FW2XZD_cjs.ConfigurationError(
@@ -303,178 +300,9 @@ async function openLanceIndex(opts) {
303
300
  });
304
301
  return new LanceMemoryAdapter(lance);
305
302
  }
306
- var MEMORY_KINDS = ["user", "feedback", "project", "reference"];
307
- function legacyMemoryJsonPath(cwd, config) {
308
- if (config.storePath !== void 0) {
309
- return path.resolve(cwd, config.storePath);
310
- }
311
- const namespace = chunkR3UPQFKK_cjs.sanitizeIdentifier(config.namespace ?? "default");
312
- const scope = chunkR3UPQFKK_cjs.sanitizeIdentifier(config.scope ?? "agent", { maxLen: 16 });
313
- const userId = chunkR3UPQFKK_cjs.sanitizeIdentifier(config.userId ?? "default");
314
- return chunkR3UPQFKK_cjs.safePathJoin(cwd, ".theokit", "memory", namespace, `${scope}-${userId}.json`);
315
- }
316
-
317
- // src/internal/memory/storage/memory-file.ts
318
- var SAFE_SLUG = /^[a-z0-9][a-z0-9_-]*$/;
319
- var MAX_SLUG_LENGTH = 64;
320
- function slugForFact(text) {
321
- const slug = text.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, MAX_SLUG_LENGTH).replace(/-+$/, "");
322
- return SAFE_SLUG.test(slug) ? slug : chunkR3UPQFKK_cjs.safeFilenameForId(text);
323
- }
324
- function renderMemoryFile(fields) {
325
- const metadata = [" node_type: memory"];
326
- if (fields.kind !== void 0) metadata.push(` type: ${fields.kind}`);
327
- if (fields.modified !== void 0) metadata.push(` modified: ${fields.modified}`);
328
- return [
329
- "---",
330
- `name: ${fields.name}`,
331
- `description: ${JSON.stringify(fields.description)}`,
332
- "metadata:",
333
- ...metadata,
334
- "---",
335
- "",
336
- fields.body,
337
- ""
338
- ].join("\n");
339
- }
340
- function parseMemoryFile(raw) {
341
- const { yaml, body } = chunkKRD3GQAA_cjs.splitFrontmatter(raw);
342
- if (yaml === void 0) return void 0;
343
- let fields;
344
- try {
345
- fields = chunkKRD3GQAA_cjs.parseSimpleYaml(yaml);
346
- } catch {
347
- return void 0;
348
- }
349
- const name = fields.name;
350
- const description = fields.description;
351
- if (typeof name !== "string" || typeof description !== "string") return void 0;
352
- const metadata = fields.metadata ?? {};
353
- const rawKind = metadata.type;
354
- const kind = typeof rawKind === "string" && MEMORY_KINDS.includes(rawKind) ? rawKind : void 0;
355
- const modified = typeof metadata.modified === "string" ? metadata.modified : void 0;
356
- return {
357
- name,
358
- description,
359
- ...kind !== void 0 ? { kind } : {},
360
- ...modified !== void 0 ? { modified } : {},
361
- body: body.trim()
362
- };
363
- }
364
-
365
- // src/internal/memory/storage/markdown-store.ts
366
- var MEMORY_MD_HEADER = "# Memory\n\n> Auto-managed by @theokit/sdk. Edit freely \u2014 the SDK reads from here.\n";
367
- var FACTS_HEADING = "## Facts";
368
- function memoryDir(cwd) {
369
- return path.join(cwd, ".theokit", "memory");
370
- }
371
- function claudeProjectMemoryDir(cwd) {
372
- const home = process.env.CLAUDE_CONFIG_DIR?.trim();
373
- const root = home !== void 0 && home.length > 0 ? home : path.join(os.homedir(), ".claude");
374
- return path.join(root, "projects", chunkBUIK7GUA_cjs.encodeProjectDir(cwd), "memory");
375
- }
376
- function memoryMdPath(cwd) {
377
- return path.join(memoryDir(cwd), "MEMORY.md");
378
- }
379
- function notesDir(cwd) {
380
- return path.join(memoryDir(cwd), "notes");
381
- }
382
- async function readFactsFromMarkdown(cwd) {
383
- const facts = [];
384
- for (const dir of [memoryDir(cwd), claudeProjectMemoryDir(cwd)]) {
385
- let entries;
386
- try {
387
- entries = await promises.readdir(dir);
388
- } catch {
389
- continue;
390
- }
391
- for (const entry of entries.sort()) {
392
- const fact = await readMemoryFileIn(dir, entry);
393
- if (fact !== void 0) facts.push(fact);
394
- }
395
- }
396
- try {
397
- facts.push(...parseFactsSection(await promises.readFile(memoryMdPath(cwd), "utf8")));
398
- } catch {
399
- }
400
- return facts;
401
- }
402
- async function readMemoryFileIn(dir, entry) {
403
- if (!entry.endsWith(".md") || entry === "MEMORY.md") return void 0;
404
- let raw;
405
- try {
406
- raw = await promises.readFile(path.join(dir, entry), "utf8");
407
- } catch {
408
- return void 0;
409
- }
410
- const parsed = parseMemoryFile(raw);
411
- if (parsed === void 0) return void 0;
412
- const body = parsed.body.trim();
413
- return {
414
- text: body.length > 0 ? body : parsed.description,
415
- ...parsed.kind !== void 0 ? { kind: parsed.kind } : {},
416
- ...parsed.modified !== void 0 ? { modified: parsed.modified } : {}
417
- };
418
- }
419
- function appendFactToMarkdown(cwd, fact) {
420
- return chunkZF2LDKQQ_cjs.withCwdMutex(memoryDir(cwd), async () => {
421
- if (fact.kind !== void 0 && !MEMORY_KINDS.includes(fact.kind)) {
422
- throw new chunkK3FW2XZD_cjs.ConfigurationError(
423
- `Unknown memory fact kind "${fact.kind}". Expected one of: ${MEMORY_KINDS.join(", ")}.`,
424
- { code: "invalid_memory_kind" }
425
- );
426
- }
427
- const text = chunkJTB5Q42C_cjs.redactSecrets(fact.text);
428
- const name = slugForFact(text);
429
- await promises.mkdir(memoryDir(cwd), { recursive: true });
430
- await chunkI6TGFUCO_cjs.replaceFileAtomic(
431
- path.join(memoryDir(cwd), `${name}.md`),
432
- renderMemoryFile({
433
- name,
434
- description: text,
435
- ...fact.kind !== void 0 ? { kind: fact.kind } : {},
436
- modified: (/* @__PURE__ */ new Date()).toISOString(),
437
- body: text
438
- })
439
- );
440
- await chunkI6TGFUCO_cjs.replaceFileAtomic(memoryMdPath(cwd), await nextIndex(cwd, text, name));
441
- });
442
- }
443
- async function nextIndex(cwd, text, name) {
444
- let existing = "";
445
- try {
446
- existing = await promises.readFile(memoryMdPath(cwd), "utf8");
447
- } catch {
448
- existing = "";
449
- }
450
- const entry = `- [${text}](${name}.md)`;
451
- const kept = existing.split("\n").filter((line) => !line.startsWith(`- [`) || !line.includes(`](${name}.md)`));
452
- const body = kept.join("\n").trimEnd();
453
- const head = body.length > 0 ? body : MEMORY_MD_HEADER.trimEnd();
454
- return `${head}
455
- ${entry}
456
- `;
457
- }
458
- var INDEX_ENTRY = /^\[[^\]]*\]\([^)]+\.md\)$/;
459
- function parseFactsSection(raw) {
460
- const idx = raw.indexOf(FACTS_HEADING);
461
- if (idx === -1) return [];
462
- const tail = raw.slice(idx + FACTS_HEADING.length);
463
- const nextHeading = tail.search(/\n#{1,2}\s/);
464
- const block = nextHeading === -1 ? tail : tail.slice(0, nextHeading);
465
- return block.split("\n").map((line) => line.trim()).filter((line) => line.startsWith("- ")).map((line) => line.slice(2).trim()).filter((body) => !INDEX_ENTRY.test(body)).map((body) => ({ text: body }));
466
- }
467
- async function readFacts(cwd, config) {
468
- if (!config.enabled) return [];
469
- return readFactsFromMarkdown(cwd);
470
- }
471
- async function appendFact(cwd, config, fact) {
472
- if (!config.enabled) return;
473
- await appendFactToMarkdown(cwd, fact);
474
- }
475
303
  var MAX_TURN_CHARS = 2e3;
476
304
  function sessionsDir(cwd) {
477
- return path.join(memoryDir(cwd), "sessions");
305
+ return path.join(chunkNY25NBZB_cjs.memoryDir(cwd), "sessions");
478
306
  }
479
307
  function sessionSummaryPath(cwd, runId) {
480
308
  return path.join(sessionsDir(cwd), `${chunkR3UPQFKK_cjs.safeFilenameForId(runId, { maxLen: 128 })}.md`);
@@ -518,7 +346,7 @@ async function discoverSessionFiles(cwd) {
518
346
  } catch {
519
347
  return [];
520
348
  }
521
- const root = memoryDir(cwd);
349
+ const root = chunkNY25NBZB_cjs.memoryDir(cwd);
522
350
  return entries.filter((entry) => entry.endsWith(".md")).map((entry) => {
523
351
  const absolutePath = path.join(sessionsDir(cwd), entry);
524
352
  return {
@@ -532,7 +360,7 @@ function relativeToRoot(root, absolutePath) {
532
360
  return absolutePath;
533
361
  }
534
362
  function wikiDir(cwd) {
535
- return path.join(memoryDir(cwd), "wiki");
363
+ return path.join(chunkNY25NBZB_cjs.memoryDir(cwd), "wiki");
536
364
  }
537
365
  async function discoverWikiFiles(cwd) {
538
366
  let entries;
@@ -541,7 +369,7 @@ async function discoverWikiFiles(cwd) {
541
369
  } catch {
542
370
  return [];
543
371
  }
544
- const root = memoryDir(cwd);
372
+ const root = chunkNY25NBZB_cjs.memoryDir(cwd);
545
373
  return entries.filter((entry) => entry.endsWith(".md")).map((entry) => ({
546
374
  absolutePath: path.join(wikiDir(cwd), entry),
547
375
  relPath: path.join("wiki", entry)
@@ -590,19 +418,19 @@ async function markdownFilesIn(dir, root, skip = []) {
590
418
  }));
591
419
  }
592
420
  async function collectMarkdownFiles(cwd) {
593
- const root = memoryDir(cwd);
421
+ const root = chunkNY25NBZB_cjs.memoryDir(cwd);
594
422
  const results = [];
595
423
  try {
596
- await promises.stat(memoryMdPath(cwd));
424
+ await promises.stat(chunkNY25NBZB_cjs.memoryMdPath(cwd));
597
425
  results.push({
598
- absolutePath: memoryMdPath(cwd),
599
- relPath: path.relative(root, memoryMdPath(cwd)),
426
+ absolutePath: chunkNY25NBZB_cjs.memoryMdPath(cwd),
427
+ relPath: path.relative(root, chunkNY25NBZB_cjs.memoryMdPath(cwd)),
600
428
  source: "memory"
601
429
  });
602
430
  } catch {
603
431
  }
604
- results.push(...await markdownFilesIn(memoryDir(cwd), root, ["MEMORY.md"]));
605
- results.push(...await markdownFilesIn(notesDir(cwd), root));
432
+ results.push(...await markdownFilesIn(chunkNY25NBZB_cjs.memoryDir(cwd), root, ["MEMORY.md"]));
433
+ results.push(...await markdownFilesIn(chunkNY25NBZB_cjs.notesDir(cwd), root));
606
434
  const wikiFiles = await discoverWikiFiles(cwd);
607
435
  for (const wiki of wikiFiles) {
608
436
  results.push({
@@ -1059,17 +887,9 @@ var IndexManager = class _IndexManager {
1059
887
 
1060
888
  exports.IndexManager = IndexManager;
1061
889
  exports.LanceIndex = LanceIndex;
1062
- exports.MEMORY_KINDS = MEMORY_KINDS;
1063
- exports.appendFact = appendFact;
1064
- exports.appendFactToMarkdown = appendFactToMarkdown;
1065
890
  exports.defaultIndexPath = defaultIndexPath;
1066
891
  exports.lanceStoragePath = lanceStoragePath;
1067
- exports.legacyMemoryJsonPath = legacyMemoryJsonPath;
1068
- exports.memoryDir = memoryDir;
1069
- exports.memoryMdPath = memoryMdPath;
1070
892
  exports.openMemoryDb = openMemoryDb;
1071
- exports.readFacts = readFacts;
1072
- exports.readFactsFromMarkdown = readFactsFromMarkdown;
1073
893
  exports.writeSessionSummary = writeSessionSummary;
1074
- //# sourceMappingURL=chunk-27AXGJMV.cjs.map
1075
- //# sourceMappingURL=chunk-27AXGJMV.cjs.map
894
+ //# sourceMappingURL=chunk-Y2KJ7MYO.cjs.map
895
+ //# sourceMappingURL=chunk-Y2KJ7MYO.cjs.map