opencode-memoir 2.0.4 → 2.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +12 -1
- package/dist/index.js.map +2 -2
- package/package.json +1 -1
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAkB,YAAY,EAAE,MAAM,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAkB,YAAY,EAAE,MAAM,qBAAqB,CAAC;AA2JxE,QAAA,MAAM,MAAM,EAAE,YAGb,CAAC;AAEF,eAAe,MAAM,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -120,7 +120,18 @@ var MemoirOpenCode = async (_input, rawOptions) => {
|
|
|
120
120
|
const opts = rawOptions ?? {};
|
|
121
121
|
if (opts.store) setPluginStoreOverride(opts.store);
|
|
122
122
|
const storePath = deriveStorePath();
|
|
123
|
-
const
|
|
123
|
+
const mcpFailover = 'exec memoir-mcp "$@" 2>/dev/null || exec python -c "from memoir.mcp.server import main; main()" "$@"';
|
|
124
|
+
const mcpCommand = [
|
|
125
|
+
"uvx",
|
|
126
|
+
"--python",
|
|
127
|
+
UVX_PYTHON,
|
|
128
|
+
"--from",
|
|
129
|
+
"memoir-ai[mcp]",
|
|
130
|
+
"sh",
|
|
131
|
+
"-c",
|
|
132
|
+
mcpFailover,
|
|
133
|
+
"memoir-mcp"
|
|
134
|
+
];
|
|
124
135
|
if (storePath) {
|
|
125
136
|
mcpCommand.push("--store", storePath);
|
|
126
137
|
}
|
package/dist/index.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/debug.ts", "../src/memory-saver.ts", "../src/store.ts", "../src/index.ts"],
|
|
4
|
-
"sourcesContent": ["/**\n * Debug logger writing to stderr. Prefixes with [memoir] for easy filtering.\n * Only writes when MEMOIR_DEBUG=1 is set.\n */\nexport function debugLog(...args: unknown[]): void {\n if (process.env.MEMOIR_DEBUG !== \"1\") return;\n const ts = new Date().toISOString();\n process.stderr.write(`[memoir ${ts}] ${args.map((a) => String(a)).join(\" \")}\\n`);\n}\n", "/** Per-session message count for periodic reminders. */\nexport const sessionMsgCount = new Map<string, number>();\n\nconst REMINDER_INTERVAL = Math.max(0, parseInt(process.env.MEMOIR_REMINDER_INTERVAL ?? \"5\", 10));\n\nexport function incrementMsgCount(sessionID: string): number {\n const count = (sessionMsgCount.get(sessionID) ?? 0) + 1;\n sessionMsgCount.set(sessionID, count);\n return count;\n}\n\nexport function shouldRemind(count: number): boolean {\n return REMINDER_INTERVAL > 0 && count > 1 && count % REMINDER_INTERVAL === 0;\n}\n\nexport function pruneAll(): void {\n sessionMsgCount.clear();\n}\n", "import { execFile, execFileSync } from \"node:child_process\";\nimport { homedir } from \"node:os\";\nimport { join, resolve } from \"node:path\";\nimport { promisify } from \"node:util\";\nimport { debugLog } from \"./debug.js\";\n\n/** Python version pinned for uvx to avoid litellm build failure on 3.14+. */\nexport const UVX_PYTHON = \"3.13\" as const;\n\nconst execFileAsync = promisify(execFile);\n\nfunction errorMessage(e: unknown): string {\n return e instanceof Error ? e.message : String(e);\n}\n\n/** Resolve memoir store path.\n * 1. Plugin `store` option override\n * 2. MEMOIR_STORE env var\n * 3. Git root \u2192 `~/.memoir/<slug>` (all worktrees share one store)\n * 4. Resolved cwd \u2192 `~/.memoir/<slug>` for non-git dirs\n */\nexport function deriveStorePath(cwd = process.cwd()): string {\n if (pluginStoreOverride) return pluginStoreOverride;\n const envStore = process.env.MEMOIR_STORE;\n if (envStore) return envStore;\n\n let projectDir: string;\n try {\n const gitRoot = execFileSync(\"git\", [\"rev-parse\", \"--show-toplevel\"], {\n cwd,\n encoding: \"utf8\",\n timeout: 3_000,\n }).trim();\n projectDir = gitRoot;\n } catch {\n projectDir = resolve(cwd);\n }\n\n const slug = projectDir.replace(/[/.]/g, \"-\");\n return join(homedir(), \".memoir\", slug);\n}\n\nexport let pluginStoreOverride: string | undefined;\n\nexport function setPluginStoreOverride(store: string | undefined): void {\n pluginStoreOverride = store;\n}\n\n/** Get current git branch (empty string if not in a git repo). */\nexport function currentGitBranch(cwd = process.cwd()): string {\n try {\n return execFileSync(\"git\", [\"branch\", \"--show-current\"], {\n cwd,\n encoding: \"utf8\",\n timeout: 3_000,\n }).trim();\n } catch {\n return \"\";\n }\n}\n\nconst branchCache = new Map<string, string>();\n\nexport function getCachedBranch(sessionID: string): string {\n return branchCache.get(sessionID) ?? \"\";\n}\n\nexport function setCachedBranch(sessionID: string, branch: string): void {\n branchCache.set(sessionID, branch);\n}\n\n/** Call the memoir CLI via uvx. */\nexport async function callMemoir(args: string[], store: string): Promise<string | null> {\n try {\n const { stdout } = (await execFileAsync(\n \"uvx\",\n [\"--python\", UVX_PYTHON, \"--from\", \"memoir-ai\", \"memoir\", \"--store\", store, ...args],\n {\n encoding: \"utf8\",\n timeout: 15_000,\n maxBuffer: 1_024 * 1_024,\n },\n )) as { stdout: string };\n return stdout.trim();\n } catch (e) {\n debugLog(\"callMemoir failed:\", errorMessage(e));\n return null;\n }\n}\n\nexport async function autoMatchMemoirBranch(store: string, sessionID: string): Promise<void> {\n const codeBranch = currentGitBranch();\n if (!codeBranch) return;\n\n const cached = getCachedBranch(sessionID);\n if (cached === codeBranch) return;\n\n // Check if branch exists in memoir\n const branchResult = await callMemoir([\"--json\", \"branch\"], store);\n if (branchResult === null) return;\n\n try {\n const data = JSON.parse(branchResult);\n const branches: string[] = data?.branches ?? [];\n if (!branches.includes(codeBranch)) {\n await callMemoir([\"branch\", codeBranch], store);\n }\n await callMemoir([\"checkout\", codeBranch], store);\n setCachedBranch(sessionID, codeBranch);\n } catch (e) {\n debugLog(\"autoMatchMemoirBranch: parsing failed:\", errorMessage(e));\n }\n}\n\nexport function pruneBranchCache(): void {\n branchCache.clear();\n}\n", "import type { Config, Plugin, PluginModule } from \"@opencode-ai/plugin\";\nimport { debugLog } from \"./debug.js\";\nimport { incrementMsgCount, pruneAll, sessionMsgCount, shouldRemind } from \"./memory-saver.js\";\nimport {\n autoMatchMemoirBranch,\n callMemoir,\n deriveStorePath,\n pruneBranchCache,\n setPluginStoreOverride,\n UVX_PYTHON,\n} from \"./store.js\";\n\nconst sessionsWithStartupHint = new Set<string>();\n\nfunction errorMessage(e: unknown): string {\n return e instanceof Error ? e.message : String(e);\n}\n\nconst MemoirOpenCode: Plugin = async (_input, rawOptions) => {\n const opts = (rawOptions ?? {}) as { store?: string };\n if (opts.store) setPluginStoreOverride(opts.store);\n\n const storePath = deriveStorePath();\n\n const mcpCommand = [\"uvx\", \"--python\", UVX_PYTHON, \"--from\", \"memoir-ai[mcp]\", \"memoir-mcp\"];\n if (storePath) {\n mcpCommand.push(\"--store\", storePath);\n }\n\n const hooks: Record<string, unknown> = {\n name: \"memoir\",\n\n config: async (config: Config): Promise<void> => {\n config.command = config.command ?? {};\n config.command[\"memoir:onboard\"] = {\n description: \"Populate or refresh Memoir onboarding for this project\",\n template: `Populate or refresh Memoir onboarding for the current project.\n\nWorkflow:\n- First obtain a project file tree to understand structure.\n- Start studying from project documentation.\n- Continue only based on what the tree and documentation show.\n\nMemory rules:\n- Record only verified facts from files/docs/code or explicit user statements.\n- Do not write inferred user thoughts, intentions, preferences, or opinions.\n- Do not use preferences.* paths unless the user explicitly stated a preference.\n- If a fact is your interpretation, do not save it; report it as uncertain instead.\n\nThen call memoir_memoir_remember with replace=true for durable onboarding facts. Use namespace codebase:onboard in git repositories and project:onboard outside git.`,\n };\n\n // Register memoir MCP server\n const mcp = config.mcp ?? {};\n mcp.memoir = {\n type: \"local\" as const,\n command: mcpCommand,\n environment: storePath ? { MEMOIR_STORE: storePath } : undefined,\n };\n config.mcp = mcp;\n },\n\n \"shell.env\": async (\n _input: unknown,\n output: { env: Record<string, string> },\n ): Promise<void> => {\n try {\n if (storePath) {\n output.env.MEMOIR_STORE = storePath;\n }\n } catch (e) {\n debugLog(\"shell.env: failed:\", errorMessage(e));\n }\n },\n\n \"chat.message\": async (\n input: { sessionID?: string },\n _output: { parts?: Array<{ type: string; text: string }> },\n ): Promise<void> => {\n try {\n const sid = input.sessionID ?? \"default\";\n incrementMsgCount(sid);\n\n await autoMatchMemoirBranch(storePath, sid);\n } catch (e) {\n debugLog(\"chat.message: failed:\", errorMessage(e));\n }\n },\n\n \"experimental.chat.system.transform\": async (\n input: { sessionID?: string },\n output: { system?: string[] },\n ): Promise<void> => {\n try {\n const sid = input.sessionID ?? \"default\";\n\n if (input.sessionID && !sessionsWithStartupHint.has(sid)) {\n sessionsWithStartupHint.add(sid);\n output.system?.unshift(\n '[memoir] You have Memoir MCP tools (memoir_memoir_recall, memoir_memoir_remember, memoir_memoir_get, memoir_memoir_summarize, memoir_memoir_status, memoir_memoir_branches, memoir_memoir_checkout).\\nSAVE (memoir_memoir_remember) after: task completion, user stating preferences/constraints, discovering project facts. RECALL (memoir_memoir_recall \\u2192 memoir_memoir_get) at session start for prior context, when user asks about prior work.\\nNamespaces: \"default\" (user context), \"codebase:onboard\" (project facts in git repos). Taxonomy paths: preferences.*, project.*, codebase.*, decisions.*, learning.*.',\n );\n }\n\n const count = sessionMsgCount.get(sid) ?? 0;\n if (shouldRemind(count)) {\n output.system?.push(\n \"\\n[memoir] Reminder: Use memoir_memoir_remember to save context, memoir_memoir_recall to retrieve prior context.\",\n );\n }\n } catch (e) {\n debugLog(\"system.transform: failed:\", errorMessage(e));\n }\n },\n\n dispose: async (): Promise<void> => {\n try {\n if (process.env.MEMOIR_AUTO_SAVE === \"1\") {\n for (const [sid, count] of sessionMsgCount) {\n await callMemoir(\n [\n \"remember\",\n `session.${sid}`,\n \"--message\",\n `Session ended \u2014 ${count} user messages exchanged`,\n ],\n storePath,\n );\n }\n }\n } catch (e) {\n debugLog(\"dispose: save failed:\", errorMessage(e));\n }\n sessionsWithStartupHint.clear();\n pruneBranchCache();\n pruneAll();\n },\n };\n\n return hooks;\n};\n\nconst plugin: PluginModule = {\n id: \"opencode-memoir\",\n server: MemoirOpenCode,\n};\n\nexport default plugin;\n"],
|
|
5
|
-
"mappings": "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
|
|
4
|
+
"sourcesContent": ["/**\n * Debug logger writing to stderr. Prefixes with [memoir] for easy filtering.\n * Only writes when MEMOIR_DEBUG=1 is set.\n */\nexport function debugLog(...args: unknown[]): void {\n if (process.env.MEMOIR_DEBUG !== \"1\") return;\n const ts = new Date().toISOString();\n process.stderr.write(`[memoir ${ts}] ${args.map((a) => String(a)).join(\" \")}\\n`);\n}\n", "/** Per-session message count for periodic reminders. */\nexport const sessionMsgCount = new Map<string, number>();\n\nconst REMINDER_INTERVAL = Math.max(0, parseInt(process.env.MEMOIR_REMINDER_INTERVAL ?? \"5\", 10));\n\nexport function incrementMsgCount(sessionID: string): number {\n const count = (sessionMsgCount.get(sessionID) ?? 0) + 1;\n sessionMsgCount.set(sessionID, count);\n return count;\n}\n\nexport function shouldRemind(count: number): boolean {\n return REMINDER_INTERVAL > 0 && count > 1 && count % REMINDER_INTERVAL === 0;\n}\n\nexport function pruneAll(): void {\n sessionMsgCount.clear();\n}\n", "import { execFile, execFileSync } from \"node:child_process\";\nimport { homedir } from \"node:os\";\nimport { join, resolve } from \"node:path\";\nimport { promisify } from \"node:util\";\nimport { debugLog } from \"./debug.js\";\n\n/** Python version pinned for uvx to avoid litellm build failure on 3.14+. */\nexport const UVX_PYTHON = \"3.13\" as const;\n\nconst execFileAsync = promisify(execFile);\n\nfunction errorMessage(e: unknown): string {\n return e instanceof Error ? e.message : String(e);\n}\n\n/** Resolve memoir store path.\n * 1. Plugin `store` option override\n * 2. MEMOIR_STORE env var\n * 3. Git root \u2192 `~/.memoir/<slug>` (all worktrees share one store)\n * 4. Resolved cwd \u2192 `~/.memoir/<slug>` for non-git dirs\n */\nexport function deriveStorePath(cwd = process.cwd()): string {\n if (pluginStoreOverride) return pluginStoreOverride;\n const envStore = process.env.MEMOIR_STORE;\n if (envStore) return envStore;\n\n let projectDir: string;\n try {\n const gitRoot = execFileSync(\"git\", [\"rev-parse\", \"--show-toplevel\"], {\n cwd,\n encoding: \"utf8\",\n timeout: 3_000,\n }).trim();\n projectDir = gitRoot;\n } catch {\n projectDir = resolve(cwd);\n }\n\n const slug = projectDir.replace(/[/.]/g, \"-\");\n return join(homedir(), \".memoir\", slug);\n}\n\nexport let pluginStoreOverride: string | undefined;\n\nexport function setPluginStoreOverride(store: string | undefined): void {\n pluginStoreOverride = store;\n}\n\n/** Get current git branch (empty string if not in a git repo). */\nexport function currentGitBranch(cwd = process.cwd()): string {\n try {\n return execFileSync(\"git\", [\"branch\", \"--show-current\"], {\n cwd,\n encoding: \"utf8\",\n timeout: 3_000,\n }).trim();\n } catch {\n return \"\";\n }\n}\n\nconst branchCache = new Map<string, string>();\n\nexport function getCachedBranch(sessionID: string): string {\n return branchCache.get(sessionID) ?? \"\";\n}\n\nexport function setCachedBranch(sessionID: string, branch: string): void {\n branchCache.set(sessionID, branch);\n}\n\n/** Call the memoir CLI via uvx. */\nexport async function callMemoir(args: string[], store: string): Promise<string | null> {\n try {\n const { stdout } = (await execFileAsync(\n \"uvx\",\n [\"--python\", UVX_PYTHON, \"--from\", \"memoir-ai\", \"memoir\", \"--store\", store, ...args],\n {\n encoding: \"utf8\",\n timeout: 15_000,\n maxBuffer: 1_024 * 1_024,\n },\n )) as { stdout: string };\n return stdout.trim();\n } catch (e) {\n debugLog(\"callMemoir failed:\", errorMessage(e));\n return null;\n }\n}\n\nexport async function autoMatchMemoirBranch(store: string, sessionID: string): Promise<void> {\n const codeBranch = currentGitBranch();\n if (!codeBranch) return;\n\n const cached = getCachedBranch(sessionID);\n if (cached === codeBranch) return;\n\n // Check if branch exists in memoir\n const branchResult = await callMemoir([\"--json\", \"branch\"], store);\n if (branchResult === null) return;\n\n try {\n const data = JSON.parse(branchResult);\n const branches: string[] = data?.branches ?? [];\n if (!branches.includes(codeBranch)) {\n await callMemoir([\"branch\", codeBranch], store);\n }\n await callMemoir([\"checkout\", codeBranch], store);\n setCachedBranch(sessionID, codeBranch);\n } catch (e) {\n debugLog(\"autoMatchMemoirBranch: parsing failed:\", errorMessage(e));\n }\n}\n\nexport function pruneBranchCache(): void {\n branchCache.clear();\n}\n", "import type { Config, Plugin, PluginModule } from \"@opencode-ai/plugin\";\nimport { debugLog } from \"./debug.js\";\nimport { incrementMsgCount, pruneAll, sessionMsgCount, shouldRemind } from \"./memory-saver.js\";\nimport {\n autoMatchMemoirBranch,\n callMemoir,\n deriveStorePath,\n pruneBranchCache,\n setPluginStoreOverride,\n UVX_PYTHON,\n} from \"./store.js\";\n\nconst sessionsWithStartupHint = new Set<string>();\n\nfunction errorMessage(e: unknown): string {\n return e instanceof Error ? e.message : String(e);\n}\n\nconst MemoirOpenCode: Plugin = async (_input, rawOptions) => {\n const opts = (rawOptions ?? {}) as { store?: string };\n if (opts.store) setPluginStoreOverride(opts.store);\n\n const storePath = deriveStorePath();\n\n // Failover: try `memoir-mcp` console script first (works once upstream\n // registers [project.scripts]), fall back to direct python -c invocation.\n const mcpFailover =\n 'exec memoir-mcp \"$@\" 2>/dev/null || exec python -c \"from memoir.mcp.server import main; main()\" \"$@\"';\n const mcpCommand = [\n \"uvx\",\n \"--python\",\n UVX_PYTHON,\n \"--from\",\n \"memoir-ai[mcp]\",\n \"sh\",\n \"-c\",\n mcpFailover,\n \"memoir-mcp\",\n ];\n if (storePath) {\n mcpCommand.push(\"--store\", storePath);\n }\n\n const hooks: Record<string, unknown> = {\n name: \"memoir\",\n\n config: async (config: Config): Promise<void> => {\n config.command = config.command ?? {};\n config.command[\"memoir:onboard\"] = {\n description: \"Populate or refresh Memoir onboarding for this project\",\n template: `Populate or refresh Memoir onboarding for the current project.\n\nWorkflow:\n- First obtain a project file tree to understand structure.\n- Start studying from project documentation.\n- Continue only based on what the tree and documentation show.\n\nMemory rules:\n- Record only verified facts from files/docs/code or explicit user statements.\n- Do not write inferred user thoughts, intentions, preferences, or opinions.\n- Do not use preferences.* paths unless the user explicitly stated a preference.\n- If a fact is your interpretation, do not save it; report it as uncertain instead.\n\nThen call memoir_memoir_remember with replace=true for durable onboarding facts. Use namespace codebase:onboard in git repositories and project:onboard outside git.`,\n };\n\n // Register memoir MCP server\n const mcp = config.mcp ?? {};\n mcp.memoir = {\n type: \"local\" as const,\n command: mcpCommand,\n environment: storePath ? { MEMOIR_STORE: storePath } : undefined,\n };\n config.mcp = mcp;\n },\n\n \"shell.env\": async (\n _input: unknown,\n output: { env: Record<string, string> },\n ): Promise<void> => {\n try {\n if (storePath) {\n output.env.MEMOIR_STORE = storePath;\n }\n } catch (e) {\n debugLog(\"shell.env: failed:\", errorMessage(e));\n }\n },\n\n \"chat.message\": async (\n input: { sessionID?: string },\n _output: { parts?: Array<{ type: string; text: string }> },\n ): Promise<void> => {\n try {\n const sid = input.sessionID ?? \"default\";\n incrementMsgCount(sid);\n\n await autoMatchMemoirBranch(storePath, sid);\n } catch (e) {\n debugLog(\"chat.message: failed:\", errorMessage(e));\n }\n },\n\n \"experimental.chat.system.transform\": async (\n input: { sessionID?: string },\n output: { system?: string[] },\n ): Promise<void> => {\n try {\n const sid = input.sessionID ?? \"default\";\n\n if (input.sessionID && !sessionsWithStartupHint.has(sid)) {\n sessionsWithStartupHint.add(sid);\n output.system?.unshift(\n '[memoir] You have Memoir MCP tools (memoir_memoir_recall, memoir_memoir_remember, memoir_memoir_get, memoir_memoir_summarize, memoir_memoir_status, memoir_memoir_branches, memoir_memoir_checkout).\\nSAVE (memoir_memoir_remember) after: task completion, user stating preferences/constraints, discovering project facts. RECALL (memoir_memoir_recall \\u2192 memoir_memoir_get) at session start for prior context, when user asks about prior work.\\nNamespaces: \"default\" (user context), \"codebase:onboard\" (project facts in git repos). Taxonomy paths: preferences.*, project.*, codebase.*, decisions.*, learning.*.',\n );\n }\n\n const count = sessionMsgCount.get(sid) ?? 0;\n if (shouldRemind(count)) {\n output.system?.push(\n \"\\n[memoir] Reminder: Use memoir_memoir_remember to save context, memoir_memoir_recall to retrieve prior context.\",\n );\n }\n } catch (e) {\n debugLog(\"system.transform: failed:\", errorMessage(e));\n }\n },\n\n dispose: async (): Promise<void> => {\n try {\n if (process.env.MEMOIR_AUTO_SAVE === \"1\") {\n for (const [sid, count] of sessionMsgCount) {\n await callMemoir(\n [\n \"remember\",\n `session.${sid}`,\n \"--message\",\n `Session ended \u2014 ${count} user messages exchanged`,\n ],\n storePath,\n );\n }\n }\n } catch (e) {\n debugLog(\"dispose: save failed:\", errorMessage(e));\n }\n sessionsWithStartupHint.clear();\n pruneBranchCache();\n pruneAll();\n },\n };\n\n return hooks;\n};\n\nconst plugin: PluginModule = {\n id: \"opencode-memoir\",\n server: MemoirOpenCode,\n};\n\nexport default plugin;\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": ["errorMessage", "_input"]
|
|
7
7
|
}
|