@theokit/sdk 4.62.0 → 4.63.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +66 -0
- package/dist/{agent-NVBFTY5H.js → agent-536OOESZ.js} +8 -6
- package/dist/{agent-NVBFTY5H.js.map → agent-536OOESZ.js.map} +1 -1
- package/dist/{agent-VYPUO4UB.cjs → agent-5KYMG63I.cjs} +9 -7
- package/dist/{agent-VYPUO4UB.cjs.map → agent-5KYMG63I.cjs.map} +1 -1
- package/dist/{agent-DIu6FooJ.d.ts → agent-BFno7Sfn.d.ts} +36 -21
- package/dist/{agent-D3Xr_-6Z.d.cts → agent-X0DKA943.d.cts} +36 -21
- package/dist/chunk-A4RAL2ER.cjs +51 -0
- package/dist/chunk-A4RAL2ER.cjs.map +1 -0
- package/dist/chunk-A4VHSE56.cjs +21 -0
- package/dist/chunk-A4VHSE56.cjs.map +1 -0
- package/dist/{chunk-CQ2TQ32Y.js → chunk-AMFXSENK.js} +3 -48
- package/dist/chunk-AMFXSENK.js.map +1 -0
- package/dist/chunk-C7QPML3L.js +831 -0
- package/dist/chunk-C7QPML3L.js.map +1 -0
- package/dist/{chunk-CWHTMNNK.cjs → chunk-CASUEY42.cjs} +4 -4
- package/dist/{chunk-CWHTMNNK.cjs.map → chunk-CASUEY42.cjs.map} +1 -1
- package/dist/{chunk-SKOCYA55.js → chunk-CHKH5452.js} +37 -50
- package/dist/chunk-CHKH5452.js.map +1 -0
- package/dist/chunk-EHJEZAOO.cjs +864 -0
- package/dist/chunk-EHJEZAOO.cjs.map +1 -0
- package/dist/chunk-IRCJ7EHV.cjs +201 -0
- package/dist/chunk-IRCJ7EHV.cjs.map +1 -0
- package/dist/chunk-LW7G5DYW.js +19 -0
- package/dist/chunk-LW7G5DYW.js.map +1 -0
- package/dist/{chunk-IBYRA5PM.js → chunk-MG3SOM3M.js} +3 -3
- package/dist/{chunk-IBYRA5PM.js.map → chunk-MG3SOM3M.js.map} +1 -1
- package/dist/{chunk-AH6WD7JR.cjs → chunk-NLXOGBRJ.cjs} +45 -58
- package/dist/chunk-NLXOGBRJ.cjs.map +1 -0
- package/dist/{chunk-SKXBJ2NU.cjs → chunk-NXH4GPAQ.cjs} +2 -49
- package/dist/chunk-NXH4GPAQ.cjs.map +1 -0
- package/dist/chunk-R6TA2DRJ.js +194 -0
- package/dist/chunk-R6TA2DRJ.js.map +1 -0
- package/dist/{chunk-6OBIWHDR.cjs → chunk-UUP3MUZ6.cjs} +20 -361
- package/dist/chunk-UUP3MUZ6.cjs.map +1 -0
- package/dist/chunk-WE22OXQA.js +48 -0
- package/dist/chunk-WE22OXQA.js.map +1 -0
- package/dist/{chunk-QEKI3YKI.js → chunk-YTR3RBUZ.js} +13 -348
- package/dist/chunk-YTR3RBUZ.js.map +1 -0
- package/dist/{cron-BcWmzWzT.d.cts → cron-BuiRPrvt.d.cts} +1 -1
- package/dist/{cron-De6hzWCF.d.ts → cron-C2SIi31n.d.ts} +1 -1
- package/dist/cron.cjs +8 -6
- package/dist/cron.d.cts +2 -2
- package/dist/cron.d.ts +2 -2
- package/dist/cron.js +7 -5
- package/dist/eval.cjs +7 -5
- package/dist/eval.cjs.map +1 -1
- package/dist/eval.js +6 -4
- package/dist/eval.js.map +1 -1
- package/dist/{index-manager-RHPFVFSC.cjs → index-manager-6TEEIWM7.cjs} +7 -6
- package/dist/{index-manager-RHPFVFSC.cjs.map → index-manager-6TEEIWM7.cjs.map} +1 -1
- package/dist/{index-manager-AHAYJ33H.js → index-manager-ACEQG3IJ.js} +6 -5
- package/dist/{index-manager-AHAYJ33H.js.map → index-manager-ACEQG3IJ.js.map} +1 -1
- package/dist/index.cjs +35 -208
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +8 -3
- package/dist/index.d.ts +8 -3
- package/dist/index.js +22 -195
- package/dist/index.js.map +1 -1
- package/dist/internal/memory/active-memory.d.ts +8 -1
- package/dist/internal/memory/dreaming/diary.d.ts +39 -2
- package/dist/internal/memory/index-db.d.ts +44 -1
- package/dist/internal/memory/index-manager-contract.d.ts +10 -0
- package/dist/internal/memory/index-manager-helpers.d.ts +20 -1
- package/dist/internal/memory/index-manager.d.ts +1 -1
- package/dist/internal/memory/lance-index.d.ts +15 -1
- package/dist/internal/memory/migrate-sqlite-to-lance.d.ts +43 -0
- package/dist/internal/memory/storage/index.cjs +95 -12
- package/dist/internal/memory/storage/index.d.cts +11 -1
- package/dist/internal/memory/storage/index.d.ts +11 -1
- package/dist/internal/memory/storage/index.js +4 -1
- package/dist/internal/memory/storage/markdown-store.d.cts +13 -42
- package/dist/internal/memory/storage/markdown-store.d.ts +13 -42
- package/dist/internal/memory/storage/memory-root.d.cts +93 -0
- package/dist/internal/memory/storage/memory-root.d.ts +93 -0
- package/dist/internal/memory/storage/session-loader.d.cts +35 -1
- package/dist/internal/memory/storage/session-loader.d.ts +35 -1
- package/dist/internal/memory/storage/session-summary-writer.d.cts +50 -2
- package/dist/internal/memory/storage/session-summary-writer.d.ts +50 -2
- package/dist/internal/memory/storage/transcript-store.d.cts +38 -1
- package/dist/internal/memory/storage/transcript-store.d.ts +38 -1
- package/dist/internal/memory/storage/wiki-loader.d.cts +27 -2
- package/dist/internal/memory/storage/wiki-loader.d.ts +27 -2
- package/dist/internal/memory/tools.d.ts +8 -1
- package/dist/internal/memory/types.d.ts +5 -0
- package/dist/internal/persistence/index.cjs +12 -11
- package/dist/internal/persistence/index.cjs.map +1 -1
- package/dist/internal/persistence/index.js +2 -1
- package/dist/internal/persistence/index.js.map +1 -1
- package/dist/internal/persistence/session-dir.d.cts +0 -15
- package/dist/internal/persistence/session-dir.d.ts +0 -15
- package/dist/internal/runtime/memory/memory-store.d.ts +2 -2
- package/dist/persistence.cjs +9 -8
- package/dist/persistence.cjs.map +1 -1
- package/dist/persistence.js +2 -1
- package/dist/persistence.js.map +1 -1
- package/dist/subagents-loader.d.cts +1 -1
- package/dist/subagents-loader.d.ts +1 -1
- package/dist/types/agent.d.ts +11 -0
- package/dist/types/memory-provider.d.ts +8 -0
- package/docs/error-codes.md +10 -9
- package/docs/harness-capability-map.md +57 -17
- package/docs/memory-decisions.md +44 -7
- package/package.json +1 -1
- package/dist/chunk-2UCFUSPW.cjs +0 -468
- package/dist/chunk-2UCFUSPW.cjs.map +0 -1
- package/dist/chunk-6OBIWHDR.cjs.map +0 -1
- package/dist/chunk-AH6WD7JR.cjs.map +0 -1
- package/dist/chunk-CQ2TQ32Y.js.map +0 -1
- package/dist/chunk-QEKI3YKI.js.map +0 -1
- package/dist/chunk-SKOCYA55.js.map +0 -1
- package/dist/chunk-SKXBJ2NU.cjs.map +0 -1
- package/dist/chunk-WCLDJSMY.js +0 -456
- package/dist/chunk-WCLDJSMY.js.map +0 -1
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/internal/persistence/fts5-sanitize.ts","../src/internal/persistence/sqlite-wal.ts","../src/internal/persistence/sqlite-open.ts"],"names":["diag","mkdir","dirname","ConfigurationError","rename"],"mappings":"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","file":"chunk-SKXBJ2NU.cjs","sourcesContent":["/**\n * FTS5 query sanitization + CJK detection (ADR D64).\n *\n * Port of Hermes' 6-step sanitizer (`hermes_state.py:1797-1847`). Prevents\n * crashes on user inputs with hyphens, dots, underscores, and unmatched\n * specials. Auto-quotes identifier-shaped tokens so `error-code` finds\n * literal `error-code` instead of `error AND code`.\n *\n * CJK detection returns true for inputs containing characters in the main\n * CJK Unicode ranges (Chinese, Japanese, Korean). CJK trigram routing is\n * deferred to v1.4 — callers receiving `containsCjk === true` should\n * short-circuit to an empty result or LIKE fallback for v1.3.\n *\n * @internal\n */\n\n// Control-char sentinels for the phrase-preservation placeholder. U+0001\n// and U+0002 are essentially never present in real user queries, and\n// crucially do NOT form word boundaries / `\\w` characters, so Step 5's\n// auto-quote regex (`\\b\\w+[-._]\\w[\\w\\-._]*\\b`) cannot match them.\n// Choosing `__PHRASE_N__` instead would re-trigger Step 5 on the second\n// sanitize pass and break idempotence.\nconst PHRASE_OPEN = \"\u0001\";\nconst PHRASE_CLOSE = \"\u0002\";\n\n/**\n * Six-step FTS5 query sanitizer. Returns a query string safe for passing\n * to `WHERE <fts5_table> MATCH ?` as a parameter.\n *\n * Returns empty string when the input contains only specials (caller MUST\n * short-circuit to avoid runtime SQL error — EC-3).\n *\n */\nexport function sanitizeFts5Query(query: string): string {\n if (query.length === 0) return query;\n\n // Step 1: preserve \"quoted phrases\" via control-char placeholders.\n const phrases: string[] = [];\n let text = query.replace(/\"[^\"]+\"/g, (match) => {\n phrases.push(match);\n return `${PHRASE_OPEN}${phrases.length - 1}${PHRASE_CLOSE}`;\n });\n\n // Step 2: strip unmatched specials (brackets, braces, parens, double quotes, caret).\n text = text.replace(/[[\\]{}()\"^]/g, \" \");\n\n // Step 3: collapse repeated asterisks (FTS5 prefix operator is single `*`).\n text = text.replace(/\\*+/g, \"*\");\n\n // Step 4: strip dangling boolean operators (AND/OR/NOT) at start/end.\n text = text.replace(/^\\s*(AND|OR|NOT)\\s+/i, \"\");\n text = text.replace(/\\s+(AND|OR|NOT)\\s*$/i, \"\");\n\n // Step 5: auto-quote identifier-shaped tokens that contain `-`, `.`, or `_`.\n // FTS5 tokenizer would otherwise split them as boolean conjunctions.\n text = text.replace(/\\b\\w+[-._]\\w[\\w\\-._]*\\b/g, (match) => `\"${match}\"`);\n\n // Step 6: restore preserved phrases.\n for (let i = 0; i < phrases.length; i += 1) {\n text = text.replace(`${PHRASE_OPEN}${i}${PHRASE_CLOSE}`, phrases[i] ?? \"\");\n }\n\n return text.trim();\n}\n\n// CJK code-point ranges. Coverage matches Hermes' coarse detection for v1.3;\n// fine-grained trigram routing comes in v1.4.\nconst CJK_RANGES: ReadonlyArray<readonly [number, number]> = [\n [0x3000, 0x303f], // CJK Symbols and Punctuation\n [0x3040, 0x309f], // Hiragana\n [0x30a0, 0x30ff], // Katakana\n [0x3400, 0x4dbf], // CJK Unified Ideographs Extension A\n [0x4e00, 0x9fff], // CJK Unified Ideographs\n [0xac00, 0xd7af], // Hangul Syllables\n];\n\n/**\n * Report whether `text` holds at least one Chinese, Japanese or Korean character.\n *\n * Iterates by code point, so surrogate pairs are handled correctly, and returns on the first hit.\n * An empty string is `false`.\n *\n * Coverage is deliberately coarse: CJK Symbols and Punctuation, Hiragana, Katakana, Hangul\n * Syllables, and CJK Unified Ideographs including Extension A. Everything beyond that — the\n * higher ideograph extensions, Halfwidth and Fullwidth Forms, Hangul Jamo — reads as `false`, so\n * a `false` is not proof that the text is CJK-free.\n *\n * The reason to ask is FTS5: the default tokenizer splits on whitespace, which CJK text does not\n * use, so a matching query against it returns nothing rather than failing. A caller seeing `true`\n * should short-circuit to an empty result or a LIKE fallback instead of running the search and\n * reporting no matches.\n *\n * Semver-exempt: reachable via the `@theokit/sdk/internal/persistence` sub-path, which the package\n * declares in `exports` but does NOT cover with its semver contract.\n */\nexport function containsCjk(text: string): boolean {\n for (const char of text) {\n const cp = char.codePointAt(0);\n if (cp === undefined) continue;\n for (const [lo, hi] of CJK_RANGES) {\n if (cp >= lo && cp <= hi) return true;\n }\n }\n return false;\n}\n","/**\n * SQLite WAL mode helper with NFS/SMB/FUSE fallback to DELETE (ADR D63).\n *\n * WAL is faster (concurrent readers + one writer) but unsupported on some\n * network/FUSE filesystems. Try WAL; if the pragma returns something else\n * or throws, fall back to DELETE journal mode. Warn one time per label.\n *\n * This block is the MODULE header and must stay at offset 0. Sitting below the import it became a\n * leading comment of the first declaration instead, which is how its tag deleted `PragmaCapable`\n * from the emitted `.d.ts` while `applyWalWithFallback` — which names it — survived.\n */\n\nimport { diag } from \"../diagnostics.js\";\n\n/**\n * The narrow slice of a SQLite handle this module needs: anything with a `pragma()` method, which\n * `better-sqlite3` satisfies without being named here.\n *\n * Not exported, but it appears in the signature of `applyWalWithFallback`, so it is emitted into\n * the published declarations and a consumer can structurally satisfy it.\n */\ninterface PragmaCapable {\n pragma: (statement: string, options?: { simple?: boolean }) => unknown;\n}\n\n/**\n * What journal mode a connection ended up in after `applyWalWithFallback`.\n *\n * `mode` is the mode actually in effect, never the one that was requested. `fellBack` is `true`\n * only when WAL was attempted and refused — either the pragma threw or it reported a mode other\n * than `wal` — and the connection was put into DELETE instead.\n *\n * `fellBack: true` is normal on NFS, SMB and FUSE, where WAL needs shared memory the filesystem\n * does not provide. It is not an error and nothing further is required of the caller; the\n * consequence is slower concurrent access, since DELETE mode does not allow readers alongside a\n * writer. Treat it as a signal about the storage, not about the database.\n *\n * @public — re-exported from the semver-protected `@theokit/sdk/persistence` barrel, and (for\n * back-compat) from the semver-exempt `@theokit/sdk/internal/persistence` alias.\n */\nexport interface WalApplyResult {\n /** Final journal_mode actually in effect. */\n mode: \"wal\" | \"delete\";\n /** True if we wanted WAL but the filesystem refused. */\n fellBack: boolean;\n}\n\nconst warnedLabels = new Set<string>();\n\n/**\n * Apply WAL mode with DELETE fallback. Idempotent — safe to call multiple\n * times on the same connection.\n *\n * @param db any `pragma()`-capable SQLite handle (e.g., `better-sqlite3`)\n * @param label short identifier used in the warning (e.g., \"memory-index\")\n *\n */\nexport function applyWalWithFallback(db: PragmaCapable, label: string): WalApplyResult {\n try {\n const result = db.pragma(\"journal_mode = WAL\", { simple: true });\n if (typeof result === \"string\" && result.toLowerCase() === \"wal\") {\n return { mode: \"wal\", fellBack: false };\n }\n logFallback(label, `got \"${String(result)}\" instead of \"wal\"`);\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n logFallback(label, msg);\n }\n\n db.pragma(\"journal_mode = DELETE\");\n return { mode: \"delete\", fellBack: true };\n}\n\nfunction logFallback(label: string, reason: string): void {\n if (warnedLabels.has(label)) return;\n warnedLabels.add(label);\n diag(\n `[theokit-sdk] ${label}: WAL unavailable (${reason}); using DELETE journal mode. ` +\n \"This is normal on NFS/SMB/FUSE; expect slightly slower concurrent access.\\n\",\n );\n}\n\n/**\n * Test helper — clears the warn-once registry.\n *\n * @internal\n */\nexport function _resetWalWarnings(): void {\n warnedLabels.clear();\n}\n","/**\n * Resilient SQLite open (plan m0-foundation-expose-primitives, M0-5).\n *\n * Generalizes the driver-load + WAL-apply + corruption-recovery logic that was\n * duplicated (byte-identical) across `sdk/internal/memory/index-db.ts` and\n * `sdk-memory/internal/index/index-db.ts`. Schema-agnostic: the caller applies\n * its own PRAGMA/SCHEMA via the `onOpen` callback.\n *\n * Corruption recovery (EC-7): when opening fails with a \"malformed\" / \"not a\n * database\" / \"encrypted\" error and `recoverCorrupt` is not false, the file is\n * renamed aside to `<path>.corrupt-<ts>` (plus its WAL/SHM siblings) and a fresh\n * DB is opened. The corrupt file is renamed, NOT backed up — the timestamped\n * `.corrupt-*` file is kept for manual recovery.\n *\n * @internal — public via `@theokit/sdk/internal/persistence` (semver-exempt)\n */\n\nimport { mkdir, rename } from \"node:fs/promises\";\nimport { dirname } from \"node:path\";\n\nimport { ConfigurationError } from \"../../errors.js\";\nimport { diag } from \"../diagnostics.js\";\nimport { applyWalWithFallback } from \"./sqlite-wal.js\";\n\n/** Minimal SQLite handle surface every driver (`better-sqlite3`) exposes. */\nexport interface ResilientSqliteDb {\n /** SQLite `pragma()` access (used by `applyWalWithFallback`). */\n pragma(statement: string, options?: { simple?: boolean }): unknown;\n exec(sql: string): void;\n close(): void;\n}\n\n/**\n * Input to {@link openSqliteResilient}.\n *\n * The trap is `recoverCorrupt`, whose default is ON. When the driver reports a corrupt or encrypted\n * database, the file is renamed aside and a FRESH one is opened — so the call SUCCEEDS and hands\n * back an EMPTY database. The old bytes survive on disk under the renamed path, but a caller that\n * treats a resolved promise as \"my data is here\" is wrong exactly when it matters. Pass\n * `recoverCorrupt: false` to get the corruption error thrown instead.\n *\n * Semver-exempt: reachable via the '@theokit/sdk/internal/persistence' sub-path, which the package\n * declares in 'exports' but does NOT cover with its semver contract.\n *\n * @typeParam T - the concrete DB handle the driver returns; defaults to {@link ResilientSqliteDb}\n */\nexport interface OpenSqliteResilientOptions<T extends ResilientSqliteDb> {\n /** Absolute path to the SQLite file. Parent directories are created. */\n filePath: string;\n /**\n * Called after the driver is open and WAL is applied, before the handle is\n * returned. Apply PRAGMA/SCHEMA statements here. Errors propagate.\n */\n onOpen?: (db: T) => void | Promise<void>;\n /** Label used in the WAL-fallback warning and corruption-recovery log. Default \"sqlite\". */\n label?: string;\n /** When true (default) a corruption error renames the file aside and rebuilds. */\n recoverCorrupt?: boolean;\n}\n\n/**\n * Open a SQLite file with WAL (+ DELETE fallback) and corruption recovery.\n *\n * @typeParam T - the concrete DB handle type the driver returns (defaults to the\n * minimal {@link ResilientSqliteDb} surface)\n */\nexport async function openSqliteResilient<T extends ResilientSqliteDb = ResilientSqliteDb>(\n options: OpenSqliteResilientOptions<T>,\n): Promise<T> {\n await mkdir(dirname(options.filePath), { recursive: true });\n try {\n return await openConcrete(options);\n } catch (cause) {\n if (options.recoverCorrupt !== false && isCorruptionError(cause)) {\n await renameAside(options.filePath, options.label ?? \"sqlite\");\n return await openConcrete(options);\n }\n throw cause;\n }\n}\n\nasync function openConcrete<T extends ResilientSqliteDb>(\n options: OpenSqliteResilientOptions<T>,\n): Promise<T> {\n const db = await loadDriver<T>(options.filePath);\n // Apply WAL with NFS/SMB/FUSE fallback BEFORE schema so the journal mode is\n // set for the whole session.\n applyWalWithFallback(db, options.label ?? \"sqlite\");\n await options.onOpen?.(db);\n return db;\n}\n\n/** Injectable driver loaders (tests simulate a consumer env without better-sqlite3). */\ninterface DriverLoaders {\n betterSqlite3?: () => Promise<unknown>;\n nodeSqlite?: () => Promise<unknown>;\n}\nlet driverLoaderOverrides: DriverLoaders | undefined;\n\n/** Test-only. @internal */\nexport function _setDriverLoadersForTests(overrides: DriverLoaders | undefined): void {\n driverLoaderOverrides = overrides;\n}\n\n/**\n * Adapt `node:sqlite`'s `DatabaseSync` to the better-sqlite3 surface this module's callers use\n * (`prepare/get/all/run`, `exec`, `close`, `pragma`, `loadExtension`). The error message below has\n * ALWAYS promised this fallback (\"or run on Node 22.5+ for built-in node:sqlite\") — before the\n * flicker-bug fix the promise was fabricated: only better-sqlite3 was ever tried, so every consumer\n * without the optional native dep lost memory tools AND got a per-turn stderr WARN.\n */\nfunction adaptNodeSqlite(db: {\n prepare(sql: string): unknown;\n exec(sql: string): void;\n close(): void;\n loadExtension?: (path: string) => void;\n}): ResilientSqliteDb {\n const pragma = (statement: string, options?: { simple?: boolean }): unknown => {\n const stmt = db.prepare(`PRAGMA ${statement}`) as {\n get(): Record<string, unknown> | undefined;\n };\n const row = stmt.get();\n if (options?.simple === true) {\n return row === undefined ? undefined : Object.values(row)[0];\n }\n return row === undefined ? [] : [row];\n };\n return new Proxy(db as unknown as ResilientSqliteDb, {\n get(target, prop, receiver) {\n if (prop === \"pragma\") return pragma;\n if (prop === \"loadExtension\" && typeof db.loadExtension !== \"function\") {\n return () => {\n throw new Error(\n \"SQLite extension loading is unavailable on the node:sqlite fallback — install better-sqlite3 for sqlite-vec\",\n );\n };\n }\n const value = Reflect.get(target, prop, receiver) as unknown;\n return typeof value === \"function\"\n ? (value as (...a: unknown[]) => unknown).bind(target)\n : value;\n },\n });\n}\n\n// PRE-EXISTING debt, exposed when M75 fixed the Biome config that used to abort before\n// sweeping these files (a nested root under refactor/). It is not new code and was not touched\n// by M75; refactoring SDK internals without review would trade a visible problem for a diff\n// risky. Tracked in usetheodev/theokit-sdk#151.\n// biome-ignore lint/complexity/noExcessiveCognitiveComplexity: see the reason just above\nasync function loadDriver<T extends ResilientSqliteDb>(filePath: string): Promise<T> {\n let betterSqliteCause: unknown;\n try {\n const mod = (await (driverLoaderOverrides?.betterSqlite3?.() ?? import(\"better-sqlite3\"))) as {\n default?: unknown;\n };\n const Ctor = mod.default ?? mod;\n if (typeof Ctor !== \"function\") {\n throw new Error(`better-sqlite3 export is not a constructor (got ${typeof Ctor})`);\n }\n return new (Ctor as new (path: string) => unknown)(filePath) as T;\n } catch (cause) {\n betterSqliteCause = cause;\n }\n // Fallback: the Node 22.5+ built-in driver (the path the error message documents).\n // `process.getBuiltinModule` (Node 22.3+) instead of `import(\"node:sqlite\")` — bundlers that\n // predate the sqlite builtin rewrite the import specifier to a bare \"sqlite\" package (proven in\n // the published dist: \"Cannot find package 'sqlite'\"), while getBuiltinModule is opaque to them.\n try {\n const mod = (await (driverLoaderOverrides?.nodeSqlite?.() ??\n Promise.resolve(\n (process as { getBuiltinModule?: (id: string) => unknown }).getBuiltinModule?.(\n \"node:sqlite\",\n ) ??\n (() => {\n throw new Error(\"node:sqlite built-in unavailable (Node < 22.3)\");\n })(),\n ))) as {\n DatabaseSync: new (\n path: string,\n ) => {\n prepare(sql: string): unknown;\n exec(sql: string): void;\n close(): void;\n };\n };\n return adaptNodeSqlite(new mod.DatabaseSync(filePath)) as T;\n } catch (nodeSqliteCause) {\n const b =\n betterSqliteCause instanceof Error ? betterSqliteCause.message : String(betterSqliteCause);\n const n = nodeSqliteCause instanceof Error ? nodeSqliteCause.message : String(nodeSqliteCause);\n throw new ConfigurationError(\n `Failed to load SQLite driver. Install \\`better-sqlite3\\` or run on Node 22.5+ for built-in \\`node:sqlite\\`. better-sqlite3: ${b}; node:sqlite: ${n}`,\n { code: \"sqlite_driver_unavailable\", cause: nodeSqliteCause },\n );\n }\n}\n\n/** True when an open error indicates an unreadable / corrupt database file. */\nexport function isCorruptionError(cause: unknown): boolean {\n if (!(cause instanceof Error)) return false;\n const msg = cause.message.toLowerCase();\n return (\n msg.includes(\"malformed\") ||\n msg.includes(\"not a database\") ||\n msg.includes(\"encrypted\") ||\n msg.includes(\"disk image is malformed\")\n );\n}\n\nasync function renameAside(filePath: string, label: string): Promise<void> {\n const asidePath = `${filePath}.corrupt-${Date.now()}`;\n await rename(filePath, asidePath).catch(() => undefined);\n await rename(`${filePath}-wal`, `${asidePath}-wal`).catch(() => undefined);\n await rename(`${filePath}-shm`, `${asidePath}-shm`).catch(() => undefined);\n diag(\n `[theokit-sdk] ${label} database corrupt; renamed aside to ${asidePath} and rebuilt schema\\n`,\n );\n}\n"]}
|
package/dist/chunk-WCLDJSMY.js
DELETED
|
@@ -1,456 +0,0 @@
|
|
|
1
|
-
import { splitFrontmatter, parseSimpleYaml } from './chunk-KVNWIAO4.js';
|
|
2
|
-
import { sanitizeIdentifier, safePathJoin, safeFilenameForId } from './chunk-QARJGQSA.js';
|
|
3
|
-
import { encodeProjectDir } from './chunk-FKMUFNQE.js';
|
|
4
|
-
import { withCwdMutex } from './chunk-Q5EWJPRY.js';
|
|
5
|
-
import { replaceFileAtomic } from './chunk-VF7EWVDG.js';
|
|
6
|
-
import { ConfigurationError } from './chunk-IDCKSLYH.js';
|
|
7
|
-
import { redactSecrets } from './chunk-T7XEKOVW.js';
|
|
8
|
-
import { readdir, readFile, mkdir } from 'fs/promises';
|
|
9
|
-
import { homedir } from 'os';
|
|
10
|
-
import { resolve, join } from 'path';
|
|
11
|
-
|
|
12
|
-
var MEMORY_KINDS = ["user", "feedback", "project", "reference"];
|
|
13
|
-
function legacyMemoryJsonPath(cwd, config) {
|
|
14
|
-
if (config.storePath !== void 0) {
|
|
15
|
-
return resolve(cwd, config.storePath);
|
|
16
|
-
}
|
|
17
|
-
const namespace = sanitizeIdentifier(config.namespace ?? "default");
|
|
18
|
-
const scope = sanitizeIdentifier(config.scope ?? "agent", { maxLen: 16 });
|
|
19
|
-
const userId = sanitizeIdentifier(config.userId ?? "default");
|
|
20
|
-
return safePathJoin(cwd, ".theokit", "memory", namespace, `${scope}-${userId}.json`);
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
// src/internal/memory/storage/memory-file.ts
|
|
24
|
-
var SAFE_SLUG = /^[a-z0-9][a-z0-9_-]*$/;
|
|
25
|
-
var MAX_SLUG_LENGTH = 64;
|
|
26
|
-
var TARGET_SLUG_LENGTH = 32;
|
|
27
|
-
var TITLE_MAX_LENGTH = 40;
|
|
28
|
-
var TITLE_MAX_WORDS = 4;
|
|
29
|
-
var SLUG_STOPWORDS = /* @__PURE__ */ new Set([
|
|
30
|
-
"the",
|
|
31
|
-
"a",
|
|
32
|
-
"an",
|
|
33
|
-
"and",
|
|
34
|
-
"or",
|
|
35
|
-
"but",
|
|
36
|
-
"is",
|
|
37
|
-
"are",
|
|
38
|
-
"was",
|
|
39
|
-
"were",
|
|
40
|
-
"be",
|
|
41
|
-
"been",
|
|
42
|
-
"being",
|
|
43
|
-
"for",
|
|
44
|
-
"of",
|
|
45
|
-
"to",
|
|
46
|
-
"in",
|
|
47
|
-
"on",
|
|
48
|
-
"at",
|
|
49
|
-
"by",
|
|
50
|
-
"with",
|
|
51
|
-
"from",
|
|
52
|
-
"as",
|
|
53
|
-
"that",
|
|
54
|
-
"this",
|
|
55
|
-
"these",
|
|
56
|
-
"those",
|
|
57
|
-
"it",
|
|
58
|
-
"its",
|
|
59
|
-
"he",
|
|
60
|
-
"she",
|
|
61
|
-
"they",
|
|
62
|
-
"we",
|
|
63
|
-
"you",
|
|
64
|
-
"i",
|
|
65
|
-
"do",
|
|
66
|
-
"does",
|
|
67
|
-
"did",
|
|
68
|
-
"has",
|
|
69
|
-
"have",
|
|
70
|
-
"had",
|
|
71
|
-
"will",
|
|
72
|
-
"would",
|
|
73
|
-
"can",
|
|
74
|
-
"could",
|
|
75
|
-
"should",
|
|
76
|
-
"must",
|
|
77
|
-
"not",
|
|
78
|
-
"no",
|
|
79
|
-
"over",
|
|
80
|
-
"under",
|
|
81
|
-
"into",
|
|
82
|
-
"onto",
|
|
83
|
-
"than",
|
|
84
|
-
"then",
|
|
85
|
-
"when",
|
|
86
|
-
"where",
|
|
87
|
-
"which",
|
|
88
|
-
"who",
|
|
89
|
-
"why",
|
|
90
|
-
"how",
|
|
91
|
-
"all",
|
|
92
|
-
"any",
|
|
93
|
-
"each",
|
|
94
|
-
"more",
|
|
95
|
-
"most",
|
|
96
|
-
"other",
|
|
97
|
-
"some",
|
|
98
|
-
"such",
|
|
99
|
-
"only",
|
|
100
|
-
"own",
|
|
101
|
-
"same",
|
|
102
|
-
"so",
|
|
103
|
-
"too",
|
|
104
|
-
"very",
|
|
105
|
-
"just",
|
|
106
|
-
"also",
|
|
107
|
-
"about",
|
|
108
|
-
"after",
|
|
109
|
-
"before",
|
|
110
|
-
"between",
|
|
111
|
-
"during",
|
|
112
|
-
"up",
|
|
113
|
-
"down",
|
|
114
|
-
"out",
|
|
115
|
-
"off",
|
|
116
|
-
"again",
|
|
117
|
-
"once",
|
|
118
|
-
"here",
|
|
119
|
-
"there",
|
|
120
|
-
"if",
|
|
121
|
-
"because",
|
|
122
|
-
"while"
|
|
123
|
-
]);
|
|
124
|
-
function topicWords(text) {
|
|
125
|
-
return text.toLowerCase().normalize("NFD").replace(/[̀-ͯ]/g, "").split(/[^a-z0-9]+/).filter((w) => w.length >= 2 && !SLUG_STOPWORDS.has(w));
|
|
126
|
-
}
|
|
127
|
-
function slugForFact(text) {
|
|
128
|
-
const words = topicWords(text);
|
|
129
|
-
let slug = "";
|
|
130
|
-
for (const w of words) {
|
|
131
|
-
const next = slug.length === 0 ? w : `${slug}-${w}`;
|
|
132
|
-
if (next.length > TARGET_SLUG_LENGTH && slug.length > 0) break;
|
|
133
|
-
if (next.length > MAX_SLUG_LENGTH) break;
|
|
134
|
-
slug = next;
|
|
135
|
-
}
|
|
136
|
-
if (slug.length === 0) {
|
|
137
|
-
slug = text.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, MAX_SLUG_LENGTH).replace(/-+$/, "");
|
|
138
|
-
}
|
|
139
|
-
return SAFE_SLUG.test(slug) ? slug : safeFilenameForId(text);
|
|
140
|
-
}
|
|
141
|
-
function titleForFact(text) {
|
|
142
|
-
const words = topicWords(text);
|
|
143
|
-
if (words.length === 0) return text.trim().slice(0, TITLE_MAX_LENGTH);
|
|
144
|
-
let title = "";
|
|
145
|
-
let used = 0;
|
|
146
|
-
for (const w of words) {
|
|
147
|
-
if (used >= TITLE_MAX_WORDS) break;
|
|
148
|
-
const next = title.length === 0 ? w : `${title} ${w}`;
|
|
149
|
-
if (next.length > TITLE_MAX_LENGTH && title.length > 0) break;
|
|
150
|
-
title = next;
|
|
151
|
-
used += 1;
|
|
152
|
-
}
|
|
153
|
-
if (title.length === 0) title = words[0];
|
|
154
|
-
return title.charAt(0).toUpperCase() + title.slice(1);
|
|
155
|
-
}
|
|
156
|
-
function readMetadata(raw) {
|
|
157
|
-
const metadata = raw ?? {};
|
|
158
|
-
const rawKind = metadata.type;
|
|
159
|
-
const kind = typeof rawKind === "string" && MEMORY_KINDS.includes(rawKind) ? rawKind : void 0;
|
|
160
|
-
const modified = typeof metadata.modified === "string" ? metadata.modified : void 0;
|
|
161
|
-
const observations = readObservationCount(metadata.observations);
|
|
162
|
-
return {
|
|
163
|
-
...kind !== void 0 ? { kind } : {},
|
|
164
|
-
...modified !== void 0 ? { modified } : {},
|
|
165
|
-
...observations !== void 0 ? { observations } : {}
|
|
166
|
-
};
|
|
167
|
-
}
|
|
168
|
-
function readObservationCount(raw) {
|
|
169
|
-
if (typeof raw !== "number") return void 0;
|
|
170
|
-
if (!Number.isInteger(raw) || raw <= 0) return void 0;
|
|
171
|
-
return raw;
|
|
172
|
-
}
|
|
173
|
-
function renderMemoryFile(fields) {
|
|
174
|
-
const metadata = [" node_type: memory"];
|
|
175
|
-
if (fields.kind !== void 0) metadata.push(` type: ${fields.kind}`);
|
|
176
|
-
if (fields.modified !== void 0) metadata.push(` modified: ${fields.modified}`);
|
|
177
|
-
if (fields.observations !== void 0) {
|
|
178
|
-
metadata.push(` observations: ${fields.observations}`);
|
|
179
|
-
}
|
|
180
|
-
return [
|
|
181
|
-
"---",
|
|
182
|
-
`name: ${fields.name}`,
|
|
183
|
-
`description: ${JSON.stringify(fields.description)}`,
|
|
184
|
-
"metadata:",
|
|
185
|
-
...metadata,
|
|
186
|
-
"---",
|
|
187
|
-
"",
|
|
188
|
-
fields.body,
|
|
189
|
-
""
|
|
190
|
-
].join("\n");
|
|
191
|
-
}
|
|
192
|
-
function parseMemoryFile(raw) {
|
|
193
|
-
const { yaml, body } = splitFrontmatter(raw);
|
|
194
|
-
if (yaml === void 0) return void 0;
|
|
195
|
-
let fields;
|
|
196
|
-
try {
|
|
197
|
-
fields = parseSimpleYaml(yaml);
|
|
198
|
-
} catch {
|
|
199
|
-
return void 0;
|
|
200
|
-
}
|
|
201
|
-
const name = fields.name;
|
|
202
|
-
const description = fields.description;
|
|
203
|
-
if (typeof name !== "string" || typeof description !== "string") return void 0;
|
|
204
|
-
return {
|
|
205
|
-
name,
|
|
206
|
-
description,
|
|
207
|
-
...readMetadata(fields.metadata),
|
|
208
|
-
body: body.trim()
|
|
209
|
-
};
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
// src/internal/memory/storage/threat-scan.ts
|
|
213
|
-
var INVISIBLE_CLASS = "\\u200B-\\u200F\\u202A-\\u202E\\u2066-\\u2069\\uFEFF";
|
|
214
|
-
var THREAT_PATTERNS = [
|
|
215
|
-
{
|
|
216
|
-
id: "invisible_unicode",
|
|
217
|
-
// Text that renders as one thing to a reviewer and another to a parser is the whole
|
|
218
|
-
// technique.
|
|
219
|
-
test: new RegExp(`[${INVISIBLE_CLASS}]`, "u"),
|
|
220
|
-
why: "contains invisible or bidirectional control characters"
|
|
221
|
-
},
|
|
222
|
-
{
|
|
223
|
-
id: "instruction_override",
|
|
224
|
-
// The framing that tries to make recalled text outrank the system prompt. A memory entry
|
|
225
|
-
// states what was learned; it never addresses the model's instructions.
|
|
226
|
-
test: /\b(?:ignore|disregard|forget|override)\s+(?:all\s+|any\s+|the\s+|your\s+|previous\s+|prior\s+|earlier\s+|above\s+)*(?:instruction|prompt|rule|directive|guideline|system\s+prompt)/i,
|
|
227
|
-
why: "addresses the model's instructions instead of stating what was learned"
|
|
228
|
-
},
|
|
229
|
-
{
|
|
230
|
-
id: "role_reassignment",
|
|
231
|
-
test: /\b(?:you\s+are\s+now|from\s+now\s+on\s+you\s+(?:are|will|must)|new\s+system\s+prompt|act\s+as\s+(?:if\s+you\s+are\s+)?(?:an?\s+)?(?:unrestricted|jailbroken|developer\s+mode))/i,
|
|
232
|
-
why: "attempts to reassign the agent's role"
|
|
233
|
-
},
|
|
234
|
-
// A `pipe_to_shell` pattern (`curl … | sh`) was written here and REMOVED after measurement.
|
|
235
|
-
// It fired on 1 of 797 real memory files, and the hit was legitimate: a note documenting the
|
|
236
|
-
// product's own install command in a table. Fetch-and-execute in a hostile entry and in an
|
|
237
|
-
// install instruction are textually identical, so the pattern cannot be narrowed — only
|
|
238
|
-
// traded. Rejecting the write would mean the first person to save install docs to memory
|
|
239
|
-
// gets a hard failure, which buys nothing: an entry the agent READS is not an entry the
|
|
240
|
-
// agent RUNS, and execution is gated at the tool boundary, where it belongs. Left out on
|
|
241
|
-
// purpose, so nobody re-adds it without repeating the measurement.
|
|
242
|
-
{
|
|
243
|
-
id: "encoded_payload",
|
|
244
|
-
// A base64 run this long is not prose. Short tokens are left alone precisely so that hashes,
|
|
245
|
-
// commit SHAs and identifiers keep working.
|
|
246
|
-
test: /[A-Za-z0-9+/]{256,}={0,2}/,
|
|
247
|
-
why: "carries a long encoded payload rather than readable text"
|
|
248
|
-
}
|
|
249
|
-
];
|
|
250
|
-
var EXCERPT_RADIUS = 40;
|
|
251
|
-
var EXCERPT_SCRUB = new RegExp(`[\\u0000-\\u001F${INVISIBLE_CLASS}]`, "gu");
|
|
252
|
-
function scanForThreats(text) {
|
|
253
|
-
for (const pattern of THREAT_PATTERNS) {
|
|
254
|
-
const m = pattern.test.exec(text);
|
|
255
|
-
if (m === null) continue;
|
|
256
|
-
const at = m.index;
|
|
257
|
-
const start = Math.max(0, at - EXCERPT_RADIUS);
|
|
258
|
-
const end = Math.min(text.length, at + m[0].length + EXCERPT_RADIUS);
|
|
259
|
-
const window = text.slice(start, end).replace(EXCERPT_SCRUB, "\u2423");
|
|
260
|
-
return {
|
|
261
|
-
id: pattern.id,
|
|
262
|
-
why: pattern.why,
|
|
263
|
-
excerpt: `${start > 0 ? "\u2026" : ""}${window}${end < text.length ? "\u2026" : ""}`
|
|
264
|
-
};
|
|
265
|
-
}
|
|
266
|
-
return void 0;
|
|
267
|
-
}
|
|
268
|
-
THREAT_PATTERNS.map((p) => p.id);
|
|
269
|
-
|
|
270
|
-
// src/internal/memory/storage/markdown-store.ts
|
|
271
|
-
var MEMORY_MD_HEADER = "# Memory Index\n";
|
|
272
|
-
var FACTS_HEADING = "## Facts";
|
|
273
|
-
var MAX_NAME_VARIANTS = 50;
|
|
274
|
-
function memoryDir(cwd) {
|
|
275
|
-
return join(cwd, ".theokit", "memory");
|
|
276
|
-
}
|
|
277
|
-
function memoryWriteDir(cwd, sessionDir) {
|
|
278
|
-
if (sessionDir === void 0 || sessionDir.trim().length === 0) return memoryDir(cwd);
|
|
279
|
-
return join(sessionDir, "projects", encodeProjectDir(cwd), "memory");
|
|
280
|
-
}
|
|
281
|
-
function claudeProjectMemoryDir(cwd) {
|
|
282
|
-
const home = process.env.CLAUDE_CONFIG_DIR?.trim();
|
|
283
|
-
const root = home !== void 0 && home.length > 0 ? home : join(homedir(), ".claude");
|
|
284
|
-
return join(root, "projects", encodeProjectDir(cwd), "memory");
|
|
285
|
-
}
|
|
286
|
-
function memoryMdPath(cwd) {
|
|
287
|
-
return join(memoryDir(cwd), "MEMORY.md");
|
|
288
|
-
}
|
|
289
|
-
function notesDir(cwd) {
|
|
290
|
-
return join(memoryDir(cwd), "notes");
|
|
291
|
-
}
|
|
292
|
-
function byNaturalName(a, b) {
|
|
293
|
-
const split = (f) => {
|
|
294
|
-
const stem = f.replace(/\.md$/, "");
|
|
295
|
-
const m = /^(.*?)-(\d+)$/.exec(stem);
|
|
296
|
-
return m === null ? [stem, 0] : [m[1], Number(m[2])];
|
|
297
|
-
};
|
|
298
|
-
const [baseA, nA] = split(a);
|
|
299
|
-
const [baseB, nB] = split(b);
|
|
300
|
-
return baseA === baseB ? nA - nB : baseA.localeCompare(baseB);
|
|
301
|
-
}
|
|
302
|
-
async function readFactsFromMarkdown(cwd, sessionDir) {
|
|
303
|
-
const facts = [];
|
|
304
|
-
const roots = [
|
|
305
|
-
.../* @__PURE__ */ new Set([memoryDir(cwd), memoryWriteDir(cwd, sessionDir), claudeProjectMemoryDir(cwd)])
|
|
306
|
-
];
|
|
307
|
-
for (const dir of roots) {
|
|
308
|
-
let entries;
|
|
309
|
-
try {
|
|
310
|
-
entries = await readdir(dir);
|
|
311
|
-
} catch {
|
|
312
|
-
continue;
|
|
313
|
-
}
|
|
314
|
-
const inDir = [];
|
|
315
|
-
for (const entry of entries.sort(byNaturalName)) {
|
|
316
|
-
const fact = await readMemoryFileIn(dir, entry);
|
|
317
|
-
if (fact !== void 0) inDir.push(fact);
|
|
318
|
-
}
|
|
319
|
-
inDir.sort((a, b) => (a.modified ?? "").localeCompare(b.modified ?? ""));
|
|
320
|
-
facts.push(...inDir);
|
|
321
|
-
}
|
|
322
|
-
try {
|
|
323
|
-
facts.push(...parseFactsSection(await readFile(memoryMdPath(cwd), "utf8")));
|
|
324
|
-
} catch {
|
|
325
|
-
}
|
|
326
|
-
return facts;
|
|
327
|
-
}
|
|
328
|
-
async function readMemoryFileIn(dir, entry) {
|
|
329
|
-
if (!entry.endsWith(".md") || entry === "MEMORY.md") return void 0;
|
|
330
|
-
let raw;
|
|
331
|
-
try {
|
|
332
|
-
raw = await readFile(join(dir, entry), "utf8");
|
|
333
|
-
} catch {
|
|
334
|
-
return void 0;
|
|
335
|
-
}
|
|
336
|
-
const parsed = parseMemoryFile(raw);
|
|
337
|
-
if (parsed === void 0) return void 0;
|
|
338
|
-
const body = parsed.body.trim();
|
|
339
|
-
return {
|
|
340
|
-
text: body.length > 0 ? body : parsed.description,
|
|
341
|
-
...parsed.kind !== void 0 ? { kind: parsed.kind } : {},
|
|
342
|
-
...parsed.modified !== void 0 ? { modified: parsed.modified } : {},
|
|
343
|
-
...parsed.observations !== void 0 ? { observations: parsed.observations } : {}
|
|
344
|
-
};
|
|
345
|
-
}
|
|
346
|
-
function assertWritable(fact, text) {
|
|
347
|
-
if (fact.kind !== void 0 && !MEMORY_KINDS.includes(fact.kind)) {
|
|
348
|
-
throw new ConfigurationError(
|
|
349
|
-
`Unknown memory fact kind "${fact.kind}". Expected one of: ${MEMORY_KINDS.join(", ")}.`,
|
|
350
|
-
{ code: "invalid_memory_kind" }
|
|
351
|
-
);
|
|
352
|
-
}
|
|
353
|
-
const threat = scanForThreats(text);
|
|
354
|
-
if (threat !== void 0) {
|
|
355
|
-
throw new ConfigurationError(
|
|
356
|
-
`Refusing to write a memory entry that ${threat.why}: ${threat.excerpt}`,
|
|
357
|
-
{ code: "memory_threat_rejected" }
|
|
358
|
-
);
|
|
359
|
-
}
|
|
360
|
-
}
|
|
361
|
-
function appendFactToMarkdown(cwd, fact, targetDir = memoryDir(cwd)) {
|
|
362
|
-
return withCwdMutex(targetDir, async () => {
|
|
363
|
-
const text = redactSecrets(fact.text);
|
|
364
|
-
assertWritable(fact, text);
|
|
365
|
-
const title = fact.title?.trim() ?? titleForFact(text);
|
|
366
|
-
const base = fact.title !== void 0 ? slugForFact(fact.title) : slugForFact(text);
|
|
367
|
-
await mkdir(targetDir, { recursive: true });
|
|
368
|
-
const name = await resolveName(targetDir, base, text);
|
|
369
|
-
const description = fact.description?.trim() ?? text;
|
|
370
|
-
const observations = await nextObservationCount(targetDir, name, text);
|
|
371
|
-
await replaceFileAtomic(
|
|
372
|
-
join(targetDir, `${name}.md`),
|
|
373
|
-
renderMemoryFile({
|
|
374
|
-
name,
|
|
375
|
-
description,
|
|
376
|
-
...fact.kind !== void 0 ? { kind: fact.kind } : {},
|
|
377
|
-
modified: (/* @__PURE__ */ new Date()).toISOString(),
|
|
378
|
-
observations,
|
|
379
|
-
body: text
|
|
380
|
-
})
|
|
381
|
-
);
|
|
382
|
-
await replaceFileAtomic(
|
|
383
|
-
join(targetDir, "MEMORY.md"),
|
|
384
|
-
await nextIndex(targetDir, description, name, title)
|
|
385
|
-
);
|
|
386
|
-
});
|
|
387
|
-
}
|
|
388
|
-
async function resolveName(dir, base, text) {
|
|
389
|
-
const wanted = normalizeFactText(text);
|
|
390
|
-
for (let i = 1; i <= MAX_NAME_VARIANTS; i += 1) {
|
|
391
|
-
const candidate = i === 1 ? base : `${base}-${i}`;
|
|
392
|
-
let existing;
|
|
393
|
-
try {
|
|
394
|
-
existing = await readFile(join(dir, `${candidate}.md`), "utf8");
|
|
395
|
-
} catch {
|
|
396
|
-
return candidate;
|
|
397
|
-
}
|
|
398
|
-
const parsed = parseMemoryFile(existing);
|
|
399
|
-
if (parsed === void 0) return candidate;
|
|
400
|
-
if (normalizeFactText(parsed.body) === wanted) return candidate;
|
|
401
|
-
}
|
|
402
|
-
return slugForFact(text) === base ? safeFilenameForId(text) : slugForFact(text);
|
|
403
|
-
}
|
|
404
|
-
async function nextObservationCount(dir, name, text) {
|
|
405
|
-
let existing;
|
|
406
|
-
try {
|
|
407
|
-
existing = await readFile(join(dir, `${name}.md`), "utf8");
|
|
408
|
-
} catch {
|
|
409
|
-
return 1;
|
|
410
|
-
}
|
|
411
|
-
const parsed = parseMemoryFile(existing);
|
|
412
|
-
if (parsed === void 0) return 1;
|
|
413
|
-
const sameFact = normalizeFactText(parsed.body) === normalizeFactText(text);
|
|
414
|
-
if (!sameFact) return 1;
|
|
415
|
-
return (parsed.observations ?? 1) + 1;
|
|
416
|
-
}
|
|
417
|
-
function normalizeFactText(text) {
|
|
418
|
-
return text.trim().toLowerCase().replace(/\s+/g, " ").replace(/[.!?]+$/, "");
|
|
419
|
-
}
|
|
420
|
-
async function nextIndex(dir, text, name, title) {
|
|
421
|
-
let existing = "";
|
|
422
|
-
try {
|
|
423
|
-
existing = await readFile(join(dir, "MEMORY.md"), "utf8");
|
|
424
|
-
} catch {
|
|
425
|
-
existing = "";
|
|
426
|
-
}
|
|
427
|
-
const hook = text.replace(/\s+/g, " ").trim();
|
|
428
|
-
const entry = hook.length > 0 && hook !== title ? `- [${title}](${name}.md) \u2014 ${hook}` : `- [${title}](${name}.md)`;
|
|
429
|
-
const kept = existing.split("\n").filter((line) => !line.startsWith(`- [`) || !line.includes(`](${name}.md)`));
|
|
430
|
-
const body = kept.join("\n").trimEnd();
|
|
431
|
-
const head = body.length > 0 ? body : MEMORY_MD_HEADER;
|
|
432
|
-
return `${head}
|
|
433
|
-
${entry}
|
|
434
|
-
`;
|
|
435
|
-
}
|
|
436
|
-
var INDEX_ENTRY = /^\[[^\]]*\]\([^)]+\.md\)(?:\s+—\s.*)?$/;
|
|
437
|
-
function parseFactsSection(raw) {
|
|
438
|
-
const idx = raw.indexOf(FACTS_HEADING);
|
|
439
|
-
if (idx === -1) return [];
|
|
440
|
-
const tail = raw.slice(idx + FACTS_HEADING.length);
|
|
441
|
-
const nextHeading = tail.search(/\n#{1,2}\s/);
|
|
442
|
-
const block = nextHeading === -1 ? tail : tail.slice(0, nextHeading);
|
|
443
|
-
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 }));
|
|
444
|
-
}
|
|
445
|
-
async function readFacts(cwd, config, memoryHome) {
|
|
446
|
-
if (!config.enabled) return [];
|
|
447
|
-
return readFactsFromMarkdown(cwd, memoryHome);
|
|
448
|
-
}
|
|
449
|
-
async function appendFact(cwd, config, fact, memoryHome) {
|
|
450
|
-
if (!config.enabled) return;
|
|
451
|
-
await appendFactToMarkdown(cwd, fact, memoryWriteDir(cwd, memoryHome));
|
|
452
|
-
}
|
|
453
|
-
|
|
454
|
-
export { MEMORY_KINDS, appendFact, appendFactToMarkdown, claudeProjectMemoryDir, legacyMemoryJsonPath, memoryDir, memoryMdPath, memoryWriteDir, notesDir, readFacts, readFactsFromMarkdown };
|
|
455
|
-
//# sourceMappingURL=chunk-WCLDJSMY.js.map
|
|
456
|
-
//# sourceMappingURL=chunk-WCLDJSMY.js.map
|