@super-pocock-ai/memory-core 2.0.12 → 2.0.18

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.js CHANGED
@@ -248,7 +248,7 @@ var DEFAULT_CONFIG = {
248
248
  }
249
249
  },
250
250
  checkpoint: {
251
- thresholds: ["40%", "60%", "80%"],
251
+ thresholds: ["20%", "40%", "60%", "80%"],
252
252
  drain_timeout_ms: 12e4,
253
253
  idle_timeout_ms: 3e5
254
254
  },
@@ -316,21 +316,40 @@ var CheckpointPlugin = async ({ client, directory }) => {
316
316
  (0, import_fs4.mkdirSync)(projectDir, { recursive: true });
317
317
  let lastCheckpointRatio = 0;
318
318
  const THRESHOLDS = config.memory.checkpoint.thresholds.map((t) => parseFloat(t) / 100);
319
+ let currentSessionID = null;
319
320
  return {
320
321
  event: async ({ event }) => {
322
+ if (event.type === "session.created") {
323
+ const newSessionID = event.properties?.info?.id;
324
+ if (currentSessionID && currentSessionID !== newSessionID) {
325
+ await triggerCheckpoint(client, currentSessionID, directory, "new session created");
326
+ }
327
+ currentSessionID = newSessionID || null;
328
+ }
321
329
  if (event.type === "session.next.step.ended") {
322
330
  const ratio = event.properties.tokens / event.properties.contextLimit;
323
331
  const nextThreshold = THRESHOLDS.find((t) => t > lastCheckpointRatio);
324
332
  if (nextThreshold && ratio >= nextThreshold) {
325
333
  lastCheckpointRatio = ratio;
326
- await triggerCheckpoint(client, event.properties.sessionID, directory);
334
+ await triggerCheckpoint(client, event.properties.sessionID, directory, `token ratio ${Math.round(ratio * 100)}%`);
327
335
  }
328
336
  }
329
337
  if (event.type === "session.status" && event.properties?.status?.type === "idle") {
330
338
  setTimeout(async () => {
331
- await triggerCheckpoint(client, event.properties.sessionID, directory);
339
+ await triggerCheckpoint(client, event.properties.sessionID, directory, "idle timeout");
332
340
  }, config.memory.checkpoint.idle_timeout_ms);
333
341
  }
342
+ if (event.type === "session.idle") {
343
+ await triggerCheckpoint(client, event.properties.sessionID, directory, "session idle");
344
+ }
345
+ if (event.type === "session.deleted") {
346
+ await triggerCheckpoint(client, event.properties.info.id, directory, "session deleted");
347
+ }
348
+ if (event.type === "server.instance.disposed") {
349
+ if (currentSessionID) {
350
+ await triggerCheckpoint(client, currentSessionID, directory, "app exit");
351
+ }
352
+ }
334
353
  },
335
354
  "experimental.session.compacting": async (input, output) => {
336
355
  output.context.push(`
@@ -351,12 +370,19 @@ Extract and preserve these 11 fields:
351
370
  }
352
371
  };
353
372
  };
354
- async function triggerCheckpoint(client, sessionID, directory) {
373
+ async function triggerCheckpoint(client, sessionID, directory, reason) {
355
374
  const messages = await client.session.messages({ path: { id: sessionID } });
356
375
  const context = constructCheckpointContext(messages);
357
376
  const sessionDir = getSessionMemoryDir(directory, sessionID);
358
377
  (0, import_fs4.mkdirSync)(sessionDir, { recursive: true });
359
- await client.session.prompt({
378
+ await client.app.log({
379
+ body: {
380
+ service: "memory-core",
381
+ level: "info",
382
+ message: `Checkpoint triggered: ${reason || "unknown"} (session: ${sessionID})`
383
+ }
384
+ });
385
+ client.session.prompt({
360
386
  path: { id: sessionID },
361
387
  body: {
362
388
  agent: "checkpoint-writer",
@@ -370,6 +396,8 @@ Write checkpoint to:
370
396
  - Project: .super-pocock/memory/projects/<pid>/checkpoint.md`
371
397
  }]
372
398
  }
399
+ }).catch((err) => {
400
+ console.error("Checkpoint failed:", err);
373
401
  });
374
402
  }
375
403
  function constructCheckpointContext(messages) {
@@ -474,11 +502,17 @@ ${smartTruncate(memories.progress, budget.progress)}`);
474
502
  const latestSessionId = getLatestSessionId();
475
503
  const memories = loadMemoryFiles(latestSessionId);
476
504
  memoryCache.set(event.properties.sessionID, memories);
505
+ const memoryKeys = Object.keys(memories);
506
+ const totalTokens = Object.values(memories).reduce((sum, content) => sum + estimateTokens(content), 0);
507
+ console.log(`[memory-core] Loaded ${memoryKeys.length} memory files (${totalTokens} tokens) for session ${event.properties.sessionID}`);
477
508
  }
478
509
  },
479
510
  "experimental.chat.system.transform": async (input, output) => {
480
511
  const memories = memoryCache.get(input.sessionID);
481
- if (!memories) return;
512
+ if (!memories) {
513
+ console.log(`[memory-core] No memories found for session ${input.sessionID}`);
514
+ return;
515
+ }
482
516
  const totalBudget = config.memory.injection.total_budget;
483
517
  const allocation = config.memory.injection.allocation;
484
518
  const budget = {
@@ -489,6 +523,8 @@ ${smartTruncate(memories.progress, budget.progress)}`);
489
523
  };
490
524
  const memoryContext = formatMemory(memories, budget);
491
525
  if (memoryContext) {
526
+ const injectedTokens = estimateTokens(memoryContext);
527
+ console.log(`[memory-core] Injecting ${injectedTokens} tokens (budget: ${totalBudget}) into system prompt`);
492
528
  output.system.push(`
493
529
 
494
530
  # Injected Memory Context
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/tool.ts","../src/store.ts","../src/reconcile.ts","../src/config.ts","../src/paths.ts","../src/checkpoint-plugin.ts","../src/injection-plugin.ts","../src/dream-plugin.ts"],"sourcesContent":["import type { Plugin } from \"@opencode-ai/plugin\"\nimport { mkdirSync } from \"fs\"\nimport { join } from \"path\"\nimport { createMemoryTool } from \"./tool\"\nimport { CheckpointPlugin } from \"./checkpoint-plugin\"\nimport { MemoryInjectionPlugin } from \"./injection-plugin\"\nimport { DreamPlugin } from \"./dream-plugin\"\nimport { getMemoryRoot, getProjectMemoryDir, getGlobalMemoryDir, getDbPath } from \"./paths\"\nimport { ensureConfig } from \"./config\"\n\nexport const MemoryCorePlugin: Plugin = async (ctx) => {\n // 确保配置文件存在\n ensureConfig(ctx.directory)\n\n const memoryRoot = getMemoryRoot(ctx.directory)\n const projectDir = getProjectMemoryDir(ctx.directory)\n const globalDir = getGlobalMemoryDir(ctx.directory)\n\n // 创建目录结构\n mkdirSync(join(memoryRoot, \"global\"), { recursive: true })\n mkdirSync(join(projectDir, \"sessions\"), { recursive: true })\n mkdirSync(join(projectDir, \"tasks\"), { recursive: true })\n\n // 创建 memory 工具\n const memoryTool = createMemoryTool({\n memoryDir: memoryRoot,\n dbPath: getDbPath(ctx.directory),\n })\n\n // 初始化子插件\n const checkpointPlugin = await CheckpointPlugin(ctx)\n const injectionPlugin = await MemoryInjectionPlugin(ctx)\n const dreamPlugin = await DreamPlugin(ctx)\n\n return {\n tool: {\n memory: memoryTool,\n },\n event: async (input) => {\n await checkpointPlugin.event?.(input)\n await injectionPlugin.event?.(input)\n await dreamPlugin.event?.(input)\n },\n \"experimental.chat.system.transform\": async (input, output) => {\n await injectionPlugin[\"experimental.chat.system.transform\"]?.(input, output)\n },\n \"experimental.session.compacting\": async (input, output) => {\n await checkpointPlugin[\"experimental.session.compacting\"]?.(input, output)\n await injectionPlugin[\"experimental.session.compacting\"]?.(input, output)\n },\n }\n}\n\nexport default MemoryCorePlugin\n\n// 导出子模块\nexport { MemoryStore } from \"./store\"\nexport { createMemoryTool } from \"./tool\"\nexport { resolveProjectId, getMemoryRoot, getProjectMemoryDir, getGlobalMemoryDir } from \"./paths\"\nexport { loadConfig, DEFAULT_CONFIG } from \"./config\"\nexport type { MemoryConfig } from \"./config\"\nexport type { SearchResult, SearchFilters } from \"./store\"\n","import { tool } from \"@opencode-ai/plugin\"\nimport { z } from \"zod\"\nimport { MemoryStore } from \"./store\"\nimport { reconcileMemoryDir } from \"./reconcile\"\nimport { mkdirSync } from \"fs\"\n\nexport function createMemoryTool(ctx: { memoryDir: string; dbPath: string }) {\n let store: MemoryStore | null = null\n\n function ensureStore() {\n if (!store) {\n mkdirSync(ctx.memoryDir, { recursive: true })\n store = new MemoryStore(ctx.dbPath)\n reconcileMemoryDir(store, ctx.memoryDir)\n }\n return store\n }\n\n return tool({\n description: \"Search or write to the persistent memory store. Search returns ranked results across memory files. Write saves content to a memory file.\",\n args: {\n operation: z.enum([\"search\", \"write\", \"list\", \"forget\"]),\n query: z.string().optional(),\n scope: z.string().optional(),\n scope_id: z.string().optional(),\n type: z.string().optional(),\n limit: z.number().optional(),\n path: z.string().optional(),\n content: z.string().optional(),\n memory_id: z.string().optional(),\n },\n execute(args: any) {\n const s = ensureStore()\n\n if (args.operation === \"search\") {\n if (!args.query) return \"query is required for search\"\n const results = s.search(args.query, {\n scope: args.scope,\n scope_id: args.scope_id,\n type: args.type,\n limit: args.limit,\n })\n if (results.length === 0) return \"No results found\"\n return JSON.stringify(results, null, 2)\n }\n\n if (args.operation === \"write\") {\n if (!args.path) return \"path is required for write\"\n if (!args.content) return \"content is required for write\"\n s.write(\n args.path,\n args.scope ?? \"unknown\",\n args.scope_id ?? \"\",\n args.type ?? \"snapshot\",\n args.content,\n )\n return `Wrote to ${args.path}`\n }\n\n if (args.operation === \"list\") {\n const results = s.search(\"*\", {\n scope: args.scope,\n scope_id: args.scope_id,\n type: args.type,\n limit: args.limit ?? 50,\n })\n return JSON.stringify(results, null, 2)\n }\n\n if (args.operation === \"forget\") {\n if (!args.memory_id) return \"memory_id is required for forget\"\n s.forget(args.memory_id)\n return `Forgot ${args.memory_id}`\n }\n\n return \"Invalid operation\"\n },\n })\n}\n","import Database from \"better-sqlite3\"\n\nexport interface SearchFilters {\n scope?: string\n scope_id?: string\n type?: string\n limit?: number\n}\n\nexport interface SearchResult {\n path: string\n scope: string\n scope_id: string\n type: string\n snippet: string\n score: number\n}\n\nexport class MemoryStore {\n public db: Database.Database\n\n constructor(dbPath: string) {\n this.db = new Database(dbPath)\n this.db.pragma(\"journal_mode = WAL\")\n this.init()\n }\n\n private init() {\n this.db.exec(`\n CREATE TABLE IF NOT EXISTS memory_files (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n path TEXT NOT NULL UNIQUE,\n scope TEXT NOT NULL,\n scope_id TEXT NOT NULL DEFAULT '',\n type TEXT NOT NULL,\n fingerprint TEXT NOT NULL,\n last_indexed_at INTEGER NOT NULL\n )\n `)\n this.db.exec(`\n CREATE VIRTUAL TABLE IF NOT EXISTS memory_fts\n USING fts5(path, body, tokenize='unicode61')\n `)\n }\n\n search(query: string, filters: SearchFilters = {}): SearchResult[] {\n const tokens = query.split(/\\s+/).filter(Boolean).map(t => `\"${t}\"`)\n if (tokens.length === 0) return []\n const ftsQuery = tokens.join(\" OR \")\n const limit = filters.limit ?? 10\n\n let sql = `\n SELECT f.path, m.scope, m.scope_id, m.type,\n snippet(memory_fts, 1, '<<', '>>', '...', 32) AS snippet,\n bm25(memory_fts) AS score\n FROM memory_fts f\n JOIN memory_files m ON m.path = f.path\n WHERE memory_fts MATCH ?\n `\n const params: any[] = [ftsQuery]\n if (filters.scope) { sql += ` AND m.scope = ?`; params.push(filters.scope) }\n if (filters.scope_id) { sql += ` AND m.scope_id = ?`; params.push(filters.scope_id) }\n if (filters.type) { sql += ` AND m.type = ?`; params.push(filters.type) }\n sql += ` ORDER BY score LIMIT ?`\n params.push(limit)\n return this.db.prepare(sql).all(...params) as SearchResult[]\n }\n\n write(path: string, scope: string, scope_id: string, type: string, content: string) {\n const fingerprint = `${content.length}-${Date.now()}`\n const now = Date.now()\n\n this.db.prepare(`\n INSERT OR REPLACE INTO memory_files (path, scope, scope_id, type, fingerprint, last_indexed_at)\n VALUES (?, ?, ?, ?, ?, ?)\n `).run(path, scope, scope_id, type, fingerprint, now)\n\n this.db.prepare(`DELETE FROM memory_fts WHERE path = ?`).run(path)\n this.db.prepare(`INSERT INTO memory_fts (path, body) VALUES (?, ?)`).run(path, content)\n }\n\n forget(memoryId: string) {\n this.db.prepare(\"DELETE FROM memory_files WHERE path = ?\").run(memoryId)\n this.db.prepare(\"DELETE FROM memory_fts WHERE path = ?\").run(memoryId)\n }\n\n close() {\n this.db.close()\n }\n}\n","import { readdirSync, readFileSync } from \"fs\"\nimport { join, relative, sep } from \"path\"\nimport type { MemoryStore } from \"./store\"\n\nfunction parseScopeAndId(memoryRoot: string, filePath: string): { scope: string; scope_id: string } {\n const rel = relative(memoryRoot, filePath).split(sep)\n if (rel[0] === \"global\") return { scope: \"global\", scope_id: \"\" }\n if (rel[0] === \"projects\" && rel.length >= 3) return { scope: \"projects\", scope_id: rel[1] }\n if (rel[0] === \"sessions\" && rel.length >= 3) return { scope: \"sessions\", scope_id: rel[1] }\n return { scope: \"unknown\", scope_id: \"\" }\n}\n\nfunction walkMdFiles(dir: string): string[] {\n const results: string[] = []\n for (const entry of readdirSync(dir, { withFileTypes: true })) {\n const full = join(dir, entry.name)\n if (entry.isDirectory()) {\n results.push(...walkMdFiles(full))\n } else if (entry.name.endsWith(\".md\")) {\n results.push(full)\n }\n }\n return results\n}\n\nexport function reconcileMemoryDir(store: MemoryStore, memoryRoot: string) {\n const filesOnDisk = walkMdFiles(memoryRoot)\n const diskPaths = new Set<string>()\n\n for (const file of filesOnDisk) {\n diskPaths.add(file)\n const content = readFileSync(file, \"utf-8\")\n const { scope, scope_id } = parseScopeAndId(memoryRoot, file)\n store.write(file, scope, scope_id, \"snapshot\", content)\n }\n\n const indexed = store.db.prepare(\"SELECT path FROM memory_files\").all() as { path: string }[]\n for (const row of indexed) {\n if (!diskPaths.has(row.path)) {\n store.forget(row.path)\n }\n }\n}\n","import { readFileSync, existsSync, writeFileSync, mkdirSync } from \"fs\"\nimport { join, dirname } from \"path\"\n\nexport interface MemoryConfig {\n memory: {\n injection: {\n total_budget: number\n allocation: {\n checkpoint: number\n memory: number\n notes: number\n progress: number\n buffer: number\n }\n }\n checkpoint: {\n thresholds: string[]\n drain_timeout_ms: number\n idle_timeout_ms: number\n }\n dream: {\n auto: boolean\n interval_days: number\n }\n distill: {\n auto: boolean\n interval_days: number\n }\n }\n}\n\nexport const DEFAULT_CONFIG: MemoryConfig = {\n memory: {\n injection: {\n total_budget: 2000,\n allocation: {\n checkpoint: 0.30,\n memory: 0.25,\n notes: 0.20,\n progress: 0.15,\n buffer: 0.10\n }\n },\n checkpoint: {\n thresholds: [\"40%\", \"60%\", \"80%\"],\n drain_timeout_ms: 120000,\n idle_timeout_ms: 300000\n },\n dream: {\n auto: true,\n interval_days: 7\n },\n distill: {\n auto: true,\n interval_days: 30\n }\n }\n}\n\nexport function getConfigPath(projectRoot: string): string {\n return join(projectRoot, \".super-pocock\", \"config.json\")\n}\n\nexport function loadConfig(projectRoot: string): MemoryConfig {\n const configPath = getConfigPath(projectRoot)\n if (existsSync(configPath)) {\n const content = readFileSync(configPath, \"utf-8\")\n return { ...DEFAULT_CONFIG, ...JSON.parse(content) }\n }\n return DEFAULT_CONFIG\n}\n\nexport function ensureConfig(projectRoot: string): void {\n const configPath = getConfigPath(projectRoot)\n if (!existsSync(configPath)) {\n mkdirSync(dirname(configPath), { recursive: true })\n writeFileSync(configPath, JSON.stringify(DEFAULT_CONFIG, null, 2))\n }\n}\n","import { createHash } from \"crypto\"\nimport { join } from \"path\"\n\nexport type Scope = \"global\" | \"projects\" | \"sessions\"\n\nexport function resolveProjectId(absRepoPath: string): string {\n return createHash(\"sha256\").update(absRepoPath).digest(\"hex\").slice(0, 12)\n}\n\nexport function getMemoryRoot(projectRoot: string): string {\n return join(projectRoot, \".super-pocock\", \"memory\")\n}\n\nexport function getProjectMemoryDir(projectRoot: string): string {\n const projectId = resolveProjectId(projectRoot)\n return join(getMemoryRoot(projectRoot), \"projects\", projectId)\n}\n\nexport function getGlobalMemoryDir(projectRoot: string): string {\n return join(getMemoryRoot(projectRoot), \"global\")\n}\n\nexport function getSessionMemoryDir(projectRoot: string, sessionId: string): string {\n return join(getMemoryRoot(projectRoot), \"sessions\", sessionId)\n}\n\nexport function getDbPath(projectRoot: string): string {\n return join(getMemoryRoot(projectRoot), \"memory.db\")\n}\n","import type { Plugin } from \"@opencode-ai/plugin\"\nimport { loadConfig } from \"./config\"\nimport { getProjectMemoryDir, getSessionMemoryDir, getMemoryRoot } from \"./paths\"\nimport { mkdirSync } from \"fs\"\nimport { join } from \"path\"\n\nexport const CheckpointPlugin: Plugin = async ({ client, directory }) => {\n const config = loadConfig(directory)\n const memoryRoot = getMemoryRoot(directory)\n const projectDir = getProjectMemoryDir(directory)\n \n // 创建必要的目录\n mkdirSync(memoryRoot, { recursive: true })\n mkdirSync(join(memoryRoot, \"sessions\"), { recursive: true })\n mkdirSync(projectDir, { recursive: true })\n\n let lastCheckpointRatio = 0\n const THRESHOLDS = config.memory.checkpoint.thresholds.map(t => parseFloat(t) / 100)\n\n return {\n event: async ({ event }) => {\n // 触发 1: Token 比例阈值\n if (event.type === \"session.next.step.ended\") {\n const ratio = event.properties.tokens / event.properties.contextLimit\n const nextThreshold = THRESHOLDS.find(t => t > lastCheckpointRatio)\n if (nextThreshold && ratio >= nextThreshold) {\n lastCheckpointRatio = ratio\n await triggerCheckpoint(client, event.properties.sessionID, directory)\n }\n }\n\n // 触发 2: 会话结束(idle 超时)\n if (event.type === \"session.status\" && event.properties?.status?.type === \"idle\") {\n setTimeout(async () => {\n await triggerCheckpoint(client, event.properties.sessionID, directory)\n }, config.memory.checkpoint.idle_timeout_ms)\n }\n },\n\n \"experimental.session.compacting\": async (input, output) => {\n output.context.push(`\n## Checkpoint Instructions\nExtract and preserve these 11 fields:\n1. Intent (用户的核心目标)\n2. Actions (已执行的操作)\n3. Task Tree (子任务层级)\n4. Errors & Workarounds (遇到的问题及解决)\n5. Design Decisions (关键技术选择)\n6. Constraints (限制条件)\n7. Current State (任务进度)\n8. TODOs (剩余工作)\n9. Code Changes Summary (Git diff 概要)\n10. Key File Paths (涉及的核心文件)\n11. Timestamp (检查点创建时间)\n `)\n },\n }\n}\n\nasync function triggerCheckpoint(client: any, sessionID: string, directory: string) {\n const messages = await client.session.messages({ path: { id: sessionID } })\n const context = constructCheckpointContext(messages)\n\n // 创建会话目录\n const sessionDir = getSessionMemoryDir(directory, sessionID)\n mkdirSync(sessionDir, { recursive: true })\n\n await client.session.prompt({\n path: { id: sessionID },\n body: {\n agent: \"checkpoint-writer\",\n parts: [{\n type: \"text\",\n text: `Extract checkpoint from this context:\\n${context}\\n\\nWrite checkpoint to:\\n- Session: .super-pocock/memory/sessions/${sessionID}/checkpoint.md\\n- Project: .super-pocock/memory/projects/<pid>/checkpoint.md`\n }],\n },\n })\n}\n\nfunction constructCheckpointContext(messages: any[]): string {\n return messages.map(m => `[${m.role}]: ${m.content}`).join(\"\\n\")\n}\n","import type { Plugin } from \"@opencode-ai/plugin\"\nimport { loadConfig } from \"./config\"\nimport { getProjectMemoryDir, getGlobalMemoryDir, getSessionMemoryDir, getMemoryRoot } from \"./paths\"\nimport { existsSync, readFileSync, readdirSync } from \"fs\"\nimport { join } from \"path\"\n\nexport const MemoryInjectionPlugin: Plugin = async ({ directory }) => {\n const config = loadConfig(directory)\n const memoryCache = new Map<string, Record<string, string>>()\n\n function getLatestSessionId(): string | null {\n const sessionsDir = join(getMemoryRoot(directory), \"sessions\")\n if (!existsSync(sessionsDir)) return null\n \n const sessions = readdirSync(sessionsDir, { withFileTypes: true })\n .filter(d => d.isDirectory())\n .map(d => d.name)\n \n if (sessions.length === 0) return null\n \n // 返回最新的会话(按目录修改时间)\n let latestSession = sessions[0]\n let latestTime = 0\n \n for (const session of sessions) {\n const sessionPath = join(sessionsDir, session)\n const stat = require(\"fs\").statSync(sessionPath)\n if (stat.mtimeMs > latestTime) {\n latestTime = stat.mtimeMs\n latestSession = session\n }\n }\n \n return latestSession\n }\n\n function loadMemoryFiles(sessionId?: string) {\n const projectDir = getProjectMemoryDir(directory)\n const globalDir = getGlobalMemoryDir(directory)\n const memoryRoot = getMemoryRoot(directory)\n\n const memories: Record<string, string> = {}\n\n // 项目级记忆\n const files = [\n { key: \"memory\", path: join(projectDir, \"MEMORY.md\") },\n { key: \"notes\", path: join(projectDir, \"notes.md\") },\n { key: \"progress\", path: join(projectDir, \"tasks\", \"progress.md\") },\n { key: \"global_memory\", path: join(globalDir, \"MEMORY.md\") },\n ]\n\n for (const file of files) {\n if (existsSync(file.path)) {\n memories[file.key] = readFileSync(file.path, \"utf-8\")\n }\n }\n\n // 会话级 checkpoint(优先)\n if (sessionId) {\n const sessionCheckpoint = join(memoryRoot, \"sessions\", sessionId, \"checkpoint.md\")\n if (existsSync(sessionCheckpoint)) {\n memories.checkpoint = readFileSync(sessionCheckpoint, \"utf-8\")\n }\n }\n\n // 项目级 checkpoint(备选)\n if (!memories.checkpoint) {\n const projectCheckpoint = join(projectDir, \"checkpoint.md\")\n if (existsSync(projectCheckpoint)) {\n memories.checkpoint = readFileSync(projectCheckpoint, \"utf-8\")\n }\n }\n\n return memories\n }\n\n function estimateTokens(text: string): number {\n return Math.ceil(text.length / 4)\n }\n\n function smartTruncate(text: string, maxTokens: number): string {\n const estimatedTokens = estimateTokens(text)\n if (estimatedTokens <= maxTokens) return text\n\n const keepChars = maxTokens * 4 * 0.3\n const start = text.substring(0, keepChars)\n const end = text.substring(text.length - keepChars)\n\n return `${start}\\n\\n... [记忆已压缩,原 ${estimatedTokens} tokens] ...\\n\\n${end}`\n }\n\n function formatMemory(memories: Record<string, string>, budget: Record<string, number>): string {\n const sections = []\n\n if (memories.checkpoint && budget.checkpoint > 0) {\n sections.push(`## 检查点状态\\n${smartTruncate(memories.checkpoint, budget.checkpoint)}`)\n }\n if (memories.memory && budget.memory > 0) {\n sections.push(`## 项目记忆\\n${smartTruncate(memories.memory, budget.memory)}`)\n }\n if (memories.global_memory && budget.memory > 0) {\n sections.push(`## 全局记忆\\n${smartTruncate(memories.global_memory, budget.memory * 0.5)}`)\n }\n if (memories.notes && budget.notes > 0) {\n sections.push(`## 当前笔记\\n${smartTruncate(memories.notes, budget.notes)}`)\n }\n if (memories.progress && budget.progress > 0) {\n sections.push(`## 任务进度\\n${smartTruncate(memories.progress, budget.progress)}`)\n }\n\n return sections.join(\"\\n\\n\")\n }\n\n return {\n event: async ({ event }) => {\n if (event.type === \"session.created\") {\n // 获取最新的会话 ID\n const latestSessionId = getLatestSessionId()\n const memories = loadMemoryFiles(latestSessionId)\n memoryCache.set(event.properties.sessionID, memories)\n }\n },\n\n \"experimental.chat.system.transform\": async (input, output) => {\n const memories = memoryCache.get(input.sessionID)\n if (!memories) return\n\n const totalBudget = config.memory.injection.total_budget\n const allocation = config.memory.injection.allocation\n\n const budget = {\n checkpoint: Math.floor(totalBudget * allocation.checkpoint),\n memory: Math.floor(totalBudget * allocation.memory),\n notes: Math.floor(totalBudget * allocation.notes),\n progress: Math.floor(totalBudget * allocation.progress),\n }\n\n const memoryContext = formatMemory(memories, budget)\n\n if (memoryContext) {\n output.system.push(`\\n\\n# Injected Memory Context\\n${memoryContext}`)\n }\n },\n\n \"experimental.session.compacting\": async (input, output) => {\n const memories = memoryCache.get(input.sessionID)\n if (!memories) return\n\n const criticalMemory = []\n if (memories.checkpoint) {\n criticalMemory.push(`当前检查点: ${memories.checkpoint.substring(0, 500)}`)\n }\n if (memories.progress) {\n criticalMemory.push(`任务进度摘要: ${memories.progress.substring(0, 300)}`)\n }\n\n output.context.push(`## 保留的关键记忆\\n${criticalMemory.join(\"\\n\\n\")}`)\n },\n }\n}\n","import type { Plugin } from \"@opencode-ai/plugin\"\nimport { loadConfig } from \"./config\"\nimport { getProjectMemoryDir } from \"./paths\"\nimport { existsSync, readFileSync, writeFileSync, mkdirSync } from \"fs\"\nimport { join } from \"path\"\n\nexport const DreamPlugin: Plugin = async ({ client, directory }) => {\n const config = loadConfig(directory)\n const memoryDir = getProjectMemoryDir(directory)\n mkdirSync(memoryDir, { recursive: true })\n\n function getLastTimestamp(metaFile: string): number {\n const metaPath = join(memoryDir, metaFile)\n if (existsSync(metaPath)) {\n const meta = JSON.parse(readFileSync(metaPath, \"utf-8\"))\n return meta.timestamp ?? 0\n }\n return 0\n }\n\n function setLastTimestamp(metaFile: string) {\n const metaPath = join(memoryDir, metaFile)\n writeFileSync(metaPath, JSON.stringify({ timestamp: Date.now() }))\n }\n\n function shouldAutoRun(metaFile: string, intervalDays: number): boolean {\n const lastRun = getLastTimestamp(metaFile)\n const intervalMs = intervalDays * 24 * 60 * 60 * 1000\n return Date.now() - lastRun > intervalMs\n }\n\n return {\n event: async ({ event }) => {\n if (event.type === \"session.created\") {\n // 自动触发 dream\n if (config.memory.dream.auto && shouldAutoRun(\".dream-meta.json\", config.memory.dream.interval_days)) {\n await client.session.prompt({\n path: { id: event.properties.sessionID },\n body: {\n agent: \"dream\",\n parts: [{\n type: \"text\",\n text: \"Run automatic dream memory consolidation pass.\"\n }],\n },\n })\n setLastTimestamp(\".dream-meta.json\")\n }\n\n // 自动触发 distill\n if (config.memory.distill.auto && shouldAutoRun(\".distill-meta.json\", config.memory.distill.interval_days)) {\n await client.session.prompt({\n path: { id: event.properties.sessionID },\n body: {\n agent: \"distill\",\n parts: [{\n type: \"text\",\n text: \"Run automatic distill pass.\"\n }],\n },\n })\n setLastTimestamp(\".distill-meta.json\")\n }\n }\n },\n }\n}\n"],"mappings":"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","names":["import_fs","import_path","Database","import_fs","import_fs","import_path","import_path","import_fs","import_path","import_fs","import_path","import_fs","import_path"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/tool.ts","../src/store.ts","../src/reconcile.ts","../src/config.ts","../src/paths.ts","../src/checkpoint-plugin.ts","../src/injection-plugin.ts","../src/dream-plugin.ts"],"sourcesContent":["import type { Plugin } from \"@opencode-ai/plugin\"\nimport { mkdirSync } from \"fs\"\nimport { join } from \"path\"\nimport { createMemoryTool } from \"./tool\"\nimport { CheckpointPlugin } from \"./checkpoint-plugin\"\nimport { MemoryInjectionPlugin } from \"./injection-plugin\"\nimport { DreamPlugin } from \"./dream-plugin\"\nimport { getMemoryRoot, getProjectMemoryDir, getGlobalMemoryDir, getDbPath } from \"./paths\"\nimport { ensureConfig } from \"./config\"\n\nexport const MemoryCorePlugin: Plugin = async (ctx) => {\n // 确保配置文件存在\n ensureConfig(ctx.directory)\n\n const memoryRoot = getMemoryRoot(ctx.directory)\n const projectDir = getProjectMemoryDir(ctx.directory)\n const globalDir = getGlobalMemoryDir(ctx.directory)\n\n // 创建目录结构\n mkdirSync(join(memoryRoot, \"global\"), { recursive: true })\n mkdirSync(join(projectDir, \"sessions\"), { recursive: true })\n mkdirSync(join(projectDir, \"tasks\"), { recursive: true })\n\n // 创建 memory 工具\n const memoryTool = createMemoryTool({\n memoryDir: memoryRoot,\n dbPath: getDbPath(ctx.directory),\n })\n\n // 初始化子插件\n const checkpointPlugin = await CheckpointPlugin(ctx)\n const injectionPlugin = await MemoryInjectionPlugin(ctx)\n const dreamPlugin = await DreamPlugin(ctx)\n\n return {\n tool: {\n memory: memoryTool,\n },\n event: async (input) => {\n await checkpointPlugin.event?.(input)\n await injectionPlugin.event?.(input)\n await dreamPlugin.event?.(input)\n },\n \"experimental.chat.system.transform\": async (input, output) => {\n await injectionPlugin[\"experimental.chat.system.transform\"]?.(input, output)\n },\n \"experimental.session.compacting\": async (input, output) => {\n await checkpointPlugin[\"experimental.session.compacting\"]?.(input, output)\n await injectionPlugin[\"experimental.session.compacting\"]?.(input, output)\n },\n }\n}\n\nexport default MemoryCorePlugin\n\n// 导出子模块\nexport { MemoryStore } from \"./store\"\nexport { createMemoryTool } from \"./tool\"\nexport { resolveProjectId, getMemoryRoot, getProjectMemoryDir, getGlobalMemoryDir } from \"./paths\"\nexport { loadConfig, DEFAULT_CONFIG } from \"./config\"\nexport type { MemoryConfig } from \"./config\"\nexport type { SearchResult, SearchFilters } from \"./store\"\n","import { tool } from \"@opencode-ai/plugin\"\nimport { z } from \"zod\"\nimport { MemoryStore } from \"./store\"\nimport { reconcileMemoryDir } from \"./reconcile\"\nimport { mkdirSync } from \"fs\"\n\nexport function createMemoryTool(ctx: { memoryDir: string; dbPath: string }) {\n let store: MemoryStore | null = null\n\n function ensureStore() {\n if (!store) {\n mkdirSync(ctx.memoryDir, { recursive: true })\n store = new MemoryStore(ctx.dbPath)\n reconcileMemoryDir(store, ctx.memoryDir)\n }\n return store\n }\n\n return tool({\n description: \"Search or write to the persistent memory store. Search returns ranked results across memory files. Write saves content to a memory file.\",\n args: {\n operation: z.enum([\"search\", \"write\", \"list\", \"forget\"]),\n query: z.string().optional(),\n scope: z.string().optional(),\n scope_id: z.string().optional(),\n type: z.string().optional(),\n limit: z.number().optional(),\n path: z.string().optional(),\n content: z.string().optional(),\n memory_id: z.string().optional(),\n },\n execute(args: any) {\n const s = ensureStore()\n\n if (args.operation === \"search\") {\n if (!args.query) return \"query is required for search\"\n const results = s.search(args.query, {\n scope: args.scope,\n scope_id: args.scope_id,\n type: args.type,\n limit: args.limit,\n })\n if (results.length === 0) return \"No results found\"\n return JSON.stringify(results, null, 2)\n }\n\n if (args.operation === \"write\") {\n if (!args.path) return \"path is required for write\"\n if (!args.content) return \"content is required for write\"\n s.write(\n args.path,\n args.scope ?? \"unknown\",\n args.scope_id ?? \"\",\n args.type ?? \"snapshot\",\n args.content,\n )\n return `Wrote to ${args.path}`\n }\n\n if (args.operation === \"list\") {\n const results = s.search(\"*\", {\n scope: args.scope,\n scope_id: args.scope_id,\n type: args.type,\n limit: args.limit ?? 50,\n })\n return JSON.stringify(results, null, 2)\n }\n\n if (args.operation === \"forget\") {\n if (!args.memory_id) return \"memory_id is required for forget\"\n s.forget(args.memory_id)\n return `Forgot ${args.memory_id}`\n }\n\n return \"Invalid operation\"\n },\n })\n}\n","import Database from \"better-sqlite3\"\n\nexport interface SearchFilters {\n scope?: string\n scope_id?: string\n type?: string\n limit?: number\n}\n\nexport interface SearchResult {\n path: string\n scope: string\n scope_id: string\n type: string\n snippet: string\n score: number\n}\n\nexport class MemoryStore {\n public db: Database.Database\n\n constructor(dbPath: string) {\n this.db = new Database(dbPath)\n this.db.pragma(\"journal_mode = WAL\")\n this.init()\n }\n\n private init() {\n this.db.exec(`\n CREATE TABLE IF NOT EXISTS memory_files (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n path TEXT NOT NULL UNIQUE,\n scope TEXT NOT NULL,\n scope_id TEXT NOT NULL DEFAULT '',\n type TEXT NOT NULL,\n fingerprint TEXT NOT NULL,\n last_indexed_at INTEGER NOT NULL\n )\n `)\n this.db.exec(`\n CREATE VIRTUAL TABLE IF NOT EXISTS memory_fts\n USING fts5(path, body, tokenize='unicode61')\n `)\n }\n\n search(query: string, filters: SearchFilters = {}): SearchResult[] {\n const tokens = query.split(/\\s+/).filter(Boolean).map(t => `\"${t}\"`)\n if (tokens.length === 0) return []\n const ftsQuery = tokens.join(\" OR \")\n const limit = filters.limit ?? 10\n\n let sql = `\n SELECT f.path, m.scope, m.scope_id, m.type,\n snippet(memory_fts, 1, '<<', '>>', '...', 32) AS snippet,\n bm25(memory_fts) AS score\n FROM memory_fts f\n JOIN memory_files m ON m.path = f.path\n WHERE memory_fts MATCH ?\n `\n const params: any[] = [ftsQuery]\n if (filters.scope) { sql += ` AND m.scope = ?`; params.push(filters.scope) }\n if (filters.scope_id) { sql += ` AND m.scope_id = ?`; params.push(filters.scope_id) }\n if (filters.type) { sql += ` AND m.type = ?`; params.push(filters.type) }\n sql += ` ORDER BY score LIMIT ?`\n params.push(limit)\n return this.db.prepare(sql).all(...params) as SearchResult[]\n }\n\n write(path: string, scope: string, scope_id: string, type: string, content: string) {\n const fingerprint = `${content.length}-${Date.now()}`\n const now = Date.now()\n\n this.db.prepare(`\n INSERT OR REPLACE INTO memory_files (path, scope, scope_id, type, fingerprint, last_indexed_at)\n VALUES (?, ?, ?, ?, ?, ?)\n `).run(path, scope, scope_id, type, fingerprint, now)\n\n this.db.prepare(`DELETE FROM memory_fts WHERE path = ?`).run(path)\n this.db.prepare(`INSERT INTO memory_fts (path, body) VALUES (?, ?)`).run(path, content)\n }\n\n forget(memoryId: string) {\n this.db.prepare(\"DELETE FROM memory_files WHERE path = ?\").run(memoryId)\n this.db.prepare(\"DELETE FROM memory_fts WHERE path = ?\").run(memoryId)\n }\n\n close() {\n this.db.close()\n }\n}\n","import { readdirSync, readFileSync } from \"fs\"\nimport { join, relative, sep } from \"path\"\nimport type { MemoryStore } from \"./store\"\n\nfunction parseScopeAndId(memoryRoot: string, filePath: string): { scope: string; scope_id: string } {\n const rel = relative(memoryRoot, filePath).split(sep)\n if (rel[0] === \"global\") return { scope: \"global\", scope_id: \"\" }\n if (rel[0] === \"projects\" && rel.length >= 3) return { scope: \"projects\", scope_id: rel[1] }\n if (rel[0] === \"sessions\" && rel.length >= 3) return { scope: \"sessions\", scope_id: rel[1] }\n return { scope: \"unknown\", scope_id: \"\" }\n}\n\nfunction walkMdFiles(dir: string): string[] {\n const results: string[] = []\n for (const entry of readdirSync(dir, { withFileTypes: true })) {\n const full = join(dir, entry.name)\n if (entry.isDirectory()) {\n results.push(...walkMdFiles(full))\n } else if (entry.name.endsWith(\".md\")) {\n results.push(full)\n }\n }\n return results\n}\n\nexport function reconcileMemoryDir(store: MemoryStore, memoryRoot: string) {\n const filesOnDisk = walkMdFiles(memoryRoot)\n const diskPaths = new Set<string>()\n\n for (const file of filesOnDisk) {\n diskPaths.add(file)\n const content = readFileSync(file, \"utf-8\")\n const { scope, scope_id } = parseScopeAndId(memoryRoot, file)\n store.write(file, scope, scope_id, \"snapshot\", content)\n }\n\n const indexed = store.db.prepare(\"SELECT path FROM memory_files\").all() as { path: string }[]\n for (const row of indexed) {\n if (!diskPaths.has(row.path)) {\n store.forget(row.path)\n }\n }\n}\n","import { readFileSync, existsSync, writeFileSync, mkdirSync } from \"fs\"\nimport { join, dirname } from \"path\"\n\nexport interface MemoryConfig {\n memory: {\n injection: {\n total_budget: number\n allocation: {\n checkpoint: number\n memory: number\n notes: number\n progress: number\n buffer: number\n }\n }\n checkpoint: {\n thresholds: string[]\n drain_timeout_ms: number\n idle_timeout_ms: number\n }\n dream: {\n auto: boolean\n interval_days: number\n }\n distill: {\n auto: boolean\n interval_days: number\n }\n }\n}\n\nexport const DEFAULT_CONFIG: MemoryConfig = {\n memory: {\n injection: {\n total_budget: 2000,\n allocation: {\n checkpoint: 0.30,\n memory: 0.25,\n notes: 0.20,\n progress: 0.15,\n buffer: 0.10\n }\n },\n checkpoint: {\n thresholds: [\"20%\", \"40%\", \"60%\", \"80%\"],\n drain_timeout_ms: 120000,\n idle_timeout_ms: 300000\n },\n dream: {\n auto: true,\n interval_days: 7\n },\n distill: {\n auto: true,\n interval_days: 30\n }\n }\n}\n\nexport function getConfigPath(projectRoot: string): string {\n return join(projectRoot, \".super-pocock\", \"config.json\")\n}\n\nexport function loadConfig(projectRoot: string): MemoryConfig {\n const configPath = getConfigPath(projectRoot)\n if (existsSync(configPath)) {\n const content = readFileSync(configPath, \"utf-8\")\n return { ...DEFAULT_CONFIG, ...JSON.parse(content) }\n }\n return DEFAULT_CONFIG\n}\n\nexport function ensureConfig(projectRoot: string): void {\n const configPath = getConfigPath(projectRoot)\n if (!existsSync(configPath)) {\n mkdirSync(dirname(configPath), { recursive: true })\n writeFileSync(configPath, JSON.stringify(DEFAULT_CONFIG, null, 2))\n }\n}\n","import { createHash } from \"crypto\"\nimport { join } from \"path\"\n\nexport type Scope = \"global\" | \"projects\" | \"sessions\"\n\nexport function resolveProjectId(absRepoPath: string): string {\n return createHash(\"sha256\").update(absRepoPath).digest(\"hex\").slice(0, 12)\n}\n\nexport function getMemoryRoot(projectRoot: string): string {\n return join(projectRoot, \".super-pocock\", \"memory\")\n}\n\nexport function getProjectMemoryDir(projectRoot: string): string {\n const projectId = resolveProjectId(projectRoot)\n return join(getMemoryRoot(projectRoot), \"projects\", projectId)\n}\n\nexport function getGlobalMemoryDir(projectRoot: string): string {\n return join(getMemoryRoot(projectRoot), \"global\")\n}\n\nexport function getSessionMemoryDir(projectRoot: string, sessionId: string): string {\n return join(getMemoryRoot(projectRoot), \"sessions\", sessionId)\n}\n\nexport function getDbPath(projectRoot: string): string {\n return join(getMemoryRoot(projectRoot), \"memory.db\")\n}\n","import type { Plugin } from \"@opencode-ai/plugin\"\nimport { loadConfig } from \"./config\"\nimport { getProjectMemoryDir, getSessionMemoryDir, getMemoryRoot } from \"./paths\"\nimport { mkdirSync } from \"fs\"\nimport { join } from \"path\"\n\nexport const CheckpointPlugin: Plugin = async ({ client, directory }) => {\n const config = loadConfig(directory)\n const memoryRoot = getMemoryRoot(directory)\n const projectDir = getProjectMemoryDir(directory)\n \n // 创建必要的目录\n mkdirSync(memoryRoot, { recursive: true })\n mkdirSync(join(memoryRoot, \"sessions\"), { recursive: true })\n mkdirSync(projectDir, { recursive: true })\n\n let lastCheckpointRatio = 0\n const THRESHOLDS = config.memory.checkpoint.thresholds.map(t => parseFloat(t) / 100)\n let currentSessionID: string | null = null\n\n return {\n event: async ({ event }) => {\n // 记录当前会话 ID\n if (event.type === \"session.created\") {\n const newSessionID = event.properties?.info?.id\n \n // 触发 1: 新建会话时,保存上一个会话的 checkpoint\n if (currentSessionID && currentSessionID !== newSessionID) {\n await triggerCheckpoint(client, currentSessionID, directory, \"new session created\")\n }\n \n currentSessionID = newSessionID || null\n }\n\n // 触发 2: Token 比例阈值\n if (event.type === \"session.next.step.ended\") {\n const ratio = event.properties.tokens / event.properties.contextLimit\n const nextThreshold = THRESHOLDS.find(t => t > lastCheckpointRatio)\n if (nextThreshold && ratio >= nextThreshold) {\n lastCheckpointRatio = ratio\n await triggerCheckpoint(client, event.properties.sessionID, directory, `token ratio ${Math.round(ratio * 100)}%`)\n }\n }\n\n // 触发 3: 会话结束(idle 超时)\n if (event.type === \"session.status\" && event.properties?.status?.type === \"idle\") {\n setTimeout(async () => {\n await triggerCheckpoint(client, event.properties.sessionID, directory, \"idle timeout\")\n }, config.memory.checkpoint.idle_timeout_ms)\n }\n\n // 触发 4: 会话空闲\n if (event.type === \"session.idle\") {\n await triggerCheckpoint(client, event.properties.sessionID, directory, \"session idle\")\n }\n\n // 触发 5: 会话删除时保存 checkpoint\n if (event.type === \"session.deleted\") {\n await triggerCheckpoint(client, event.properties.info.id, directory, \"session deleted\")\n }\n\n // 触发 6: 退出程序时保存当前会话 checkpoint\n if (event.type === \"server.instance.disposed\") {\n if (currentSessionID) {\n await triggerCheckpoint(client, currentSessionID, directory, \"app exit\")\n }\n }\n },\n\n \"experimental.session.compacting\": async (input, output) => {\n output.context.push(`\n## Checkpoint Instructions\nExtract and preserve these 11 fields:\n1. Intent (用户的核心目标)\n2. Actions (已执行的操作)\n3. Task Tree (子任务层级)\n4. Errors & Workarounds (遇到的问题及解决)\n5. Design Decisions (关键技术选择)\n6. Constraints (限制条件)\n7. Current State (任务进度)\n8. TODOs (剩余工作)\n9. Code Changes Summary (Git diff 概要)\n10. Key File Paths (涉及的核心文件)\n11. Timestamp (检查点创建时间)\n `)\n },\n }\n}\n\nasync function triggerCheckpoint(client: any, sessionID: string, directory: string, reason?: string) {\n const messages = await client.session.messages({ path: { id: sessionID } })\n const context = constructCheckpointContext(messages)\n\n // 创建会话目录\n const sessionDir = getSessionMemoryDir(directory, sessionID)\n mkdirSync(sessionDir, { recursive: true })\n\n // 记录日志\n await client.app.log({\n body: {\n service: 'memory-core',\n level: 'info',\n message: `Checkpoint triggered: ${reason || 'unknown'} (session: ${sessionID})`\n }\n })\n\n // 非阻塞调用,不等待完成\n client.session.prompt({\n path: { id: sessionID },\n body: {\n agent: \"checkpoint-writer\",\n parts: [{\n type: \"text\",\n text: `Extract checkpoint from this context:\\n${context}\\n\\nWrite checkpoint to:\\n- Session: .super-pocock/memory/sessions/${sessionID}/checkpoint.md\\n- Project: .super-pocock/memory/projects/<pid>/checkpoint.md`\n }],\n },\n }).catch((err: any) => {\n // 静默处理错误,不影响主 agent\n console.error('Checkpoint failed:', err)\n })\n}\n\nfunction constructCheckpointContext(messages: any[]): string {\n return messages.map(m => `[${m.role}]: ${m.content}`).join(\"\\n\")\n}\n","import type { Plugin } from \"@opencode-ai/plugin\"\nimport { loadConfig } from \"./config\"\nimport { getProjectMemoryDir, getGlobalMemoryDir, getSessionMemoryDir, getMemoryRoot } from \"./paths\"\nimport { existsSync, readFileSync, readdirSync } from \"fs\"\nimport { join } from \"path\"\n\nexport const MemoryInjectionPlugin: Plugin = async ({ directory }) => {\n const config = loadConfig(directory)\n const memoryCache = new Map<string, Record<string, string>>()\n\n function getLatestSessionId(): string | null {\n const sessionsDir = join(getMemoryRoot(directory), \"sessions\")\n if (!existsSync(sessionsDir)) return null\n \n const sessions = readdirSync(sessionsDir, { withFileTypes: true })\n .filter(d => d.isDirectory())\n .map(d => d.name)\n \n if (sessions.length === 0) return null\n \n // 返回最新的会话(按目录修改时间)\n let latestSession = sessions[0]\n let latestTime = 0\n \n for (const session of sessions) {\n const sessionPath = join(sessionsDir, session)\n const stat = require(\"fs\").statSync(sessionPath)\n if (stat.mtimeMs > latestTime) {\n latestTime = stat.mtimeMs\n latestSession = session\n }\n }\n \n return latestSession\n }\n\n function loadMemoryFiles(sessionId?: string) {\n const projectDir = getProjectMemoryDir(directory)\n const globalDir = getGlobalMemoryDir(directory)\n const memoryRoot = getMemoryRoot(directory)\n\n const memories: Record<string, string> = {}\n\n // 项目级记忆\n const files = [\n { key: \"memory\", path: join(projectDir, \"MEMORY.md\") },\n { key: \"notes\", path: join(projectDir, \"notes.md\") },\n { key: \"progress\", path: join(projectDir, \"tasks\", \"progress.md\") },\n { key: \"global_memory\", path: join(globalDir, \"MEMORY.md\") },\n ]\n\n for (const file of files) {\n if (existsSync(file.path)) {\n memories[file.key] = readFileSync(file.path, \"utf-8\")\n }\n }\n\n // 会话级 checkpoint(优先)\n if (sessionId) {\n const sessionCheckpoint = join(memoryRoot, \"sessions\", sessionId, \"checkpoint.md\")\n if (existsSync(sessionCheckpoint)) {\n memories.checkpoint = readFileSync(sessionCheckpoint, \"utf-8\")\n }\n }\n\n // 项目级 checkpoint(备选)\n if (!memories.checkpoint) {\n const projectCheckpoint = join(projectDir, \"checkpoint.md\")\n if (existsSync(projectCheckpoint)) {\n memories.checkpoint = readFileSync(projectCheckpoint, \"utf-8\")\n }\n }\n\n return memories\n }\n\n function estimateTokens(text: string): number {\n return Math.ceil(text.length / 4)\n }\n\n function smartTruncate(text: string, maxTokens: number): string {\n const estimatedTokens = estimateTokens(text)\n if (estimatedTokens <= maxTokens) return text\n\n const keepChars = maxTokens * 4 * 0.3\n const start = text.substring(0, keepChars)\n const end = text.substring(text.length - keepChars)\n\n return `${start}\\n\\n... [记忆已压缩,原 ${estimatedTokens} tokens] ...\\n\\n${end}`\n }\n\n function formatMemory(memories: Record<string, string>, budget: Record<string, number>): string {\n const sections = []\n\n if (memories.checkpoint && budget.checkpoint > 0) {\n sections.push(`## 检查点状态\\n${smartTruncate(memories.checkpoint, budget.checkpoint)}`)\n }\n if (memories.memory && budget.memory > 0) {\n sections.push(`## 项目记忆\\n${smartTruncate(memories.memory, budget.memory)}`)\n }\n if (memories.global_memory && budget.memory > 0) {\n sections.push(`## 全局记忆\\n${smartTruncate(memories.global_memory, budget.memory * 0.5)}`)\n }\n if (memories.notes && budget.notes > 0) {\n sections.push(`## 当前笔记\\n${smartTruncate(memories.notes, budget.notes)}`)\n }\n if (memories.progress && budget.progress > 0) {\n sections.push(`## 任务进度\\n${smartTruncate(memories.progress, budget.progress)}`)\n }\n\n return sections.join(\"\\n\\n\")\n }\n\n return {\n event: async ({ event }) => {\n if (event.type === \"session.created\") {\n // 获取最新的会话 ID\n const latestSessionId = getLatestSessionId()\n const memories = loadMemoryFiles(latestSessionId)\n memoryCache.set(event.properties.sessionID, memories)\n \n // 记录注入状态\n const memoryKeys = Object.keys(memories)\n const totalTokens = Object.values(memories).reduce((sum, content) => sum + estimateTokens(content), 0)\n console.log(`[memory-core] Loaded ${memoryKeys.length} memory files (${totalTokens} tokens) for session ${event.properties.sessionID}`)\n }\n },\n\n \"experimental.chat.system.transform\": async (input, output) => {\n const memories = memoryCache.get(input.sessionID)\n if (!memories) {\n console.log(`[memory-core] No memories found for session ${input.sessionID}`)\n return\n }\n\n const totalBudget = config.memory.injection.total_budget\n const allocation = config.memory.injection.allocation\n\n const budget = {\n checkpoint: Math.floor(totalBudget * allocation.checkpoint),\n memory: Math.floor(totalBudget * allocation.memory),\n notes: Math.floor(totalBudget * allocation.notes),\n progress: Math.floor(totalBudget * allocation.progress),\n }\n\n const memoryContext = formatMemory(memories, budget)\n\n if (memoryContext) {\n const injectedTokens = estimateTokens(memoryContext)\n console.log(`[memory-core] Injecting ${injectedTokens} tokens (budget: ${totalBudget}) into system prompt`)\n output.system.push(`\\n\\n# Injected Memory Context\\n${memoryContext}`)\n }\n },\n\n \"experimental.session.compacting\": async (input, output) => {\n const memories = memoryCache.get(input.sessionID)\n if (!memories) return\n\n const criticalMemory = []\n if (memories.checkpoint) {\n criticalMemory.push(`当前检查点: ${memories.checkpoint.substring(0, 500)}`)\n }\n if (memories.progress) {\n criticalMemory.push(`任务进度摘要: ${memories.progress.substring(0, 300)}`)\n }\n\n output.context.push(`## 保留的关键记忆\\n${criticalMemory.join(\"\\n\\n\")}`)\n },\n }\n}\n","import type { Plugin } from \"@opencode-ai/plugin\"\nimport { loadConfig } from \"./config\"\nimport { getProjectMemoryDir } from \"./paths\"\nimport { existsSync, readFileSync, writeFileSync, mkdirSync } from \"fs\"\nimport { join } from \"path\"\n\nexport const DreamPlugin: Plugin = async ({ client, directory }) => {\n const config = loadConfig(directory)\n const memoryDir = getProjectMemoryDir(directory)\n mkdirSync(memoryDir, { recursive: true })\n\n function getLastTimestamp(metaFile: string): number {\n const metaPath = join(memoryDir, metaFile)\n if (existsSync(metaPath)) {\n const meta = JSON.parse(readFileSync(metaPath, \"utf-8\"))\n return meta.timestamp ?? 0\n }\n return 0\n }\n\n function setLastTimestamp(metaFile: string) {\n const metaPath = join(memoryDir, metaFile)\n writeFileSync(metaPath, JSON.stringify({ timestamp: Date.now() }))\n }\n\n function shouldAutoRun(metaFile: string, intervalDays: number): boolean {\n const lastRun = getLastTimestamp(metaFile)\n const intervalMs = intervalDays * 24 * 60 * 60 * 1000\n return Date.now() - lastRun > intervalMs\n }\n\n return {\n event: async ({ event }) => {\n if (event.type === \"session.created\") {\n // 自动触发 dream\n if (config.memory.dream.auto && shouldAutoRun(\".dream-meta.json\", config.memory.dream.interval_days)) {\n await client.session.prompt({\n path: { id: event.properties.sessionID },\n body: {\n agent: \"dream\",\n parts: [{\n type: \"text\",\n text: \"Run automatic dream memory consolidation pass.\"\n }],\n },\n })\n setLastTimestamp(\".dream-meta.json\")\n }\n\n // 自动触发 distill\n if (config.memory.distill.auto && shouldAutoRun(\".distill-meta.json\", config.memory.distill.interval_days)) {\n await client.session.prompt({\n path: { id: event.properties.sessionID },\n body: {\n agent: \"distill\",\n parts: [{\n type: \"text\",\n text: \"Run automatic distill pass.\"\n }],\n },\n })\n setLastTimestamp(\".distill-meta.json\")\n }\n }\n },\n }\n}\n"],"mappings":"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","names":["import_fs","import_path","Database","import_fs","import_fs","import_path","import_path","import_fs","import_path","import_fs","import_path","import_fs","import_path"]}
package/dist/index.mjs CHANGED
@@ -212,7 +212,7 @@ var DEFAULT_CONFIG = {
212
212
  }
213
213
  },
214
214
  checkpoint: {
215
- thresholds: ["40%", "60%", "80%"],
215
+ thresholds: ["20%", "40%", "60%", "80%"],
216
216
  drain_timeout_ms: 12e4,
217
217
  idle_timeout_ms: 3e5
218
218
  },
@@ -280,21 +280,40 @@ var CheckpointPlugin = async ({ client, directory }) => {
280
280
  mkdirSync3(projectDir, { recursive: true });
281
281
  let lastCheckpointRatio = 0;
282
282
  const THRESHOLDS = config.memory.checkpoint.thresholds.map((t) => parseFloat(t) / 100);
283
+ let currentSessionID = null;
283
284
  return {
284
285
  event: async ({ event }) => {
286
+ if (event.type === "session.created") {
287
+ const newSessionID = event.properties?.info?.id;
288
+ if (currentSessionID && currentSessionID !== newSessionID) {
289
+ await triggerCheckpoint(client, currentSessionID, directory, "new session created");
290
+ }
291
+ currentSessionID = newSessionID || null;
292
+ }
285
293
  if (event.type === "session.next.step.ended") {
286
294
  const ratio = event.properties.tokens / event.properties.contextLimit;
287
295
  const nextThreshold = THRESHOLDS.find((t) => t > lastCheckpointRatio);
288
296
  if (nextThreshold && ratio >= nextThreshold) {
289
297
  lastCheckpointRatio = ratio;
290
- await triggerCheckpoint(client, event.properties.sessionID, directory);
298
+ await triggerCheckpoint(client, event.properties.sessionID, directory, `token ratio ${Math.round(ratio * 100)}%`);
291
299
  }
292
300
  }
293
301
  if (event.type === "session.status" && event.properties?.status?.type === "idle") {
294
302
  setTimeout(async () => {
295
- await triggerCheckpoint(client, event.properties.sessionID, directory);
303
+ await triggerCheckpoint(client, event.properties.sessionID, directory, "idle timeout");
296
304
  }, config.memory.checkpoint.idle_timeout_ms);
297
305
  }
306
+ if (event.type === "session.idle") {
307
+ await triggerCheckpoint(client, event.properties.sessionID, directory, "session idle");
308
+ }
309
+ if (event.type === "session.deleted") {
310
+ await triggerCheckpoint(client, event.properties.info.id, directory, "session deleted");
311
+ }
312
+ if (event.type === "server.instance.disposed") {
313
+ if (currentSessionID) {
314
+ await triggerCheckpoint(client, currentSessionID, directory, "app exit");
315
+ }
316
+ }
298
317
  },
299
318
  "experimental.session.compacting": async (input, output) => {
300
319
  output.context.push(`
@@ -315,12 +334,19 @@ Extract and preserve these 11 fields:
315
334
  }
316
335
  };
317
336
  };
318
- async function triggerCheckpoint(client, sessionID, directory) {
337
+ async function triggerCheckpoint(client, sessionID, directory, reason) {
319
338
  const messages = await client.session.messages({ path: { id: sessionID } });
320
339
  const context = constructCheckpointContext(messages);
321
340
  const sessionDir = getSessionMemoryDir(directory, sessionID);
322
341
  mkdirSync3(sessionDir, { recursive: true });
323
- await client.session.prompt({
342
+ await client.app.log({
343
+ body: {
344
+ service: "memory-core",
345
+ level: "info",
346
+ message: `Checkpoint triggered: ${reason || "unknown"} (session: ${sessionID})`
347
+ }
348
+ });
349
+ client.session.prompt({
324
350
  path: { id: sessionID },
325
351
  body: {
326
352
  agent: "checkpoint-writer",
@@ -334,6 +360,8 @@ Write checkpoint to:
334
360
  - Project: .super-pocock/memory/projects/<pid>/checkpoint.md`
335
361
  }]
336
362
  }
363
+ }).catch((err) => {
364
+ console.error("Checkpoint failed:", err);
337
365
  });
338
366
  }
339
367
  function constructCheckpointContext(messages) {
@@ -438,11 +466,17 @@ ${smartTruncate(memories.progress, budget.progress)}`);
438
466
  const latestSessionId = getLatestSessionId();
439
467
  const memories = loadMemoryFiles(latestSessionId);
440
468
  memoryCache.set(event.properties.sessionID, memories);
469
+ const memoryKeys = Object.keys(memories);
470
+ const totalTokens = Object.values(memories).reduce((sum, content) => sum + estimateTokens(content), 0);
471
+ console.log(`[memory-core] Loaded ${memoryKeys.length} memory files (${totalTokens} tokens) for session ${event.properties.sessionID}`);
441
472
  }
442
473
  },
443
474
  "experimental.chat.system.transform": async (input, output) => {
444
475
  const memories = memoryCache.get(input.sessionID);
445
- if (!memories) return;
476
+ if (!memories) {
477
+ console.log(`[memory-core] No memories found for session ${input.sessionID}`);
478
+ return;
479
+ }
446
480
  const totalBudget = config.memory.injection.total_budget;
447
481
  const allocation = config.memory.injection.allocation;
448
482
  const budget = {
@@ -453,6 +487,8 @@ ${smartTruncate(memories.progress, budget.progress)}`);
453
487
  };
454
488
  const memoryContext = formatMemory(memories, budget);
455
489
  if (memoryContext) {
490
+ const injectedTokens = estimateTokens(memoryContext);
491
+ console.log(`[memory-core] Injecting ${injectedTokens} tokens (budget: ${totalBudget}) into system prompt`);
456
492
  output.system.push(`
457
493
 
458
494
  # Injected Memory Context
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/tool.ts","../src/store.ts","../src/reconcile.ts","../src/config.ts","../src/paths.ts","../src/checkpoint-plugin.ts","../src/injection-plugin.ts","../src/dream-plugin.ts"],"sourcesContent":["import type { Plugin } from \"@opencode-ai/plugin\"\nimport { mkdirSync } from \"fs\"\nimport { join } from \"path\"\nimport { createMemoryTool } from \"./tool\"\nimport { CheckpointPlugin } from \"./checkpoint-plugin\"\nimport { MemoryInjectionPlugin } from \"./injection-plugin\"\nimport { DreamPlugin } from \"./dream-plugin\"\nimport { getMemoryRoot, getProjectMemoryDir, getGlobalMemoryDir, getDbPath } from \"./paths\"\nimport { ensureConfig } from \"./config\"\n\nexport const MemoryCorePlugin: Plugin = async (ctx) => {\n // 确保配置文件存在\n ensureConfig(ctx.directory)\n\n const memoryRoot = getMemoryRoot(ctx.directory)\n const projectDir = getProjectMemoryDir(ctx.directory)\n const globalDir = getGlobalMemoryDir(ctx.directory)\n\n // 创建目录结构\n mkdirSync(join(memoryRoot, \"global\"), { recursive: true })\n mkdirSync(join(projectDir, \"sessions\"), { recursive: true })\n mkdirSync(join(projectDir, \"tasks\"), { recursive: true })\n\n // 创建 memory 工具\n const memoryTool = createMemoryTool({\n memoryDir: memoryRoot,\n dbPath: getDbPath(ctx.directory),\n })\n\n // 初始化子插件\n const checkpointPlugin = await CheckpointPlugin(ctx)\n const injectionPlugin = await MemoryInjectionPlugin(ctx)\n const dreamPlugin = await DreamPlugin(ctx)\n\n return {\n tool: {\n memory: memoryTool,\n },\n event: async (input) => {\n await checkpointPlugin.event?.(input)\n await injectionPlugin.event?.(input)\n await dreamPlugin.event?.(input)\n },\n \"experimental.chat.system.transform\": async (input, output) => {\n await injectionPlugin[\"experimental.chat.system.transform\"]?.(input, output)\n },\n \"experimental.session.compacting\": async (input, output) => {\n await checkpointPlugin[\"experimental.session.compacting\"]?.(input, output)\n await injectionPlugin[\"experimental.session.compacting\"]?.(input, output)\n },\n }\n}\n\nexport default MemoryCorePlugin\n\n// 导出子模块\nexport { MemoryStore } from \"./store\"\nexport { createMemoryTool } from \"./tool\"\nexport { resolveProjectId, getMemoryRoot, getProjectMemoryDir, getGlobalMemoryDir } from \"./paths\"\nexport { loadConfig, DEFAULT_CONFIG } from \"./config\"\nexport type { MemoryConfig } from \"./config\"\nexport type { SearchResult, SearchFilters } from \"./store\"\n","import { tool } from \"@opencode-ai/plugin\"\nimport { z } from \"zod\"\nimport { MemoryStore } from \"./store\"\nimport { reconcileMemoryDir } from \"./reconcile\"\nimport { mkdirSync } from \"fs\"\n\nexport function createMemoryTool(ctx: { memoryDir: string; dbPath: string }) {\n let store: MemoryStore | null = null\n\n function ensureStore() {\n if (!store) {\n mkdirSync(ctx.memoryDir, { recursive: true })\n store = new MemoryStore(ctx.dbPath)\n reconcileMemoryDir(store, ctx.memoryDir)\n }\n return store\n }\n\n return tool({\n description: \"Search or write to the persistent memory store. Search returns ranked results across memory files. Write saves content to a memory file.\",\n args: {\n operation: z.enum([\"search\", \"write\", \"list\", \"forget\"]),\n query: z.string().optional(),\n scope: z.string().optional(),\n scope_id: z.string().optional(),\n type: z.string().optional(),\n limit: z.number().optional(),\n path: z.string().optional(),\n content: z.string().optional(),\n memory_id: z.string().optional(),\n },\n execute(args: any) {\n const s = ensureStore()\n\n if (args.operation === \"search\") {\n if (!args.query) return \"query is required for search\"\n const results = s.search(args.query, {\n scope: args.scope,\n scope_id: args.scope_id,\n type: args.type,\n limit: args.limit,\n })\n if (results.length === 0) return \"No results found\"\n return JSON.stringify(results, null, 2)\n }\n\n if (args.operation === \"write\") {\n if (!args.path) return \"path is required for write\"\n if (!args.content) return \"content is required for write\"\n s.write(\n args.path,\n args.scope ?? \"unknown\",\n args.scope_id ?? \"\",\n args.type ?? \"snapshot\",\n args.content,\n )\n return `Wrote to ${args.path}`\n }\n\n if (args.operation === \"list\") {\n const results = s.search(\"*\", {\n scope: args.scope,\n scope_id: args.scope_id,\n type: args.type,\n limit: args.limit ?? 50,\n })\n return JSON.stringify(results, null, 2)\n }\n\n if (args.operation === \"forget\") {\n if (!args.memory_id) return \"memory_id is required for forget\"\n s.forget(args.memory_id)\n return `Forgot ${args.memory_id}`\n }\n\n return \"Invalid operation\"\n },\n })\n}\n","import Database from \"better-sqlite3\"\n\nexport interface SearchFilters {\n scope?: string\n scope_id?: string\n type?: string\n limit?: number\n}\n\nexport interface SearchResult {\n path: string\n scope: string\n scope_id: string\n type: string\n snippet: string\n score: number\n}\n\nexport class MemoryStore {\n public db: Database.Database\n\n constructor(dbPath: string) {\n this.db = new Database(dbPath)\n this.db.pragma(\"journal_mode = WAL\")\n this.init()\n }\n\n private init() {\n this.db.exec(`\n CREATE TABLE IF NOT EXISTS memory_files (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n path TEXT NOT NULL UNIQUE,\n scope TEXT NOT NULL,\n scope_id TEXT NOT NULL DEFAULT '',\n type TEXT NOT NULL,\n fingerprint TEXT NOT NULL,\n last_indexed_at INTEGER NOT NULL\n )\n `)\n this.db.exec(`\n CREATE VIRTUAL TABLE IF NOT EXISTS memory_fts\n USING fts5(path, body, tokenize='unicode61')\n `)\n }\n\n search(query: string, filters: SearchFilters = {}): SearchResult[] {\n const tokens = query.split(/\\s+/).filter(Boolean).map(t => `\"${t}\"`)\n if (tokens.length === 0) return []\n const ftsQuery = tokens.join(\" OR \")\n const limit = filters.limit ?? 10\n\n let sql = `\n SELECT f.path, m.scope, m.scope_id, m.type,\n snippet(memory_fts, 1, '<<', '>>', '...', 32) AS snippet,\n bm25(memory_fts) AS score\n FROM memory_fts f\n JOIN memory_files m ON m.path = f.path\n WHERE memory_fts MATCH ?\n `\n const params: any[] = [ftsQuery]\n if (filters.scope) { sql += ` AND m.scope = ?`; params.push(filters.scope) }\n if (filters.scope_id) { sql += ` AND m.scope_id = ?`; params.push(filters.scope_id) }\n if (filters.type) { sql += ` AND m.type = ?`; params.push(filters.type) }\n sql += ` ORDER BY score LIMIT ?`\n params.push(limit)\n return this.db.prepare(sql).all(...params) as SearchResult[]\n }\n\n write(path: string, scope: string, scope_id: string, type: string, content: string) {\n const fingerprint = `${content.length}-${Date.now()}`\n const now = Date.now()\n\n this.db.prepare(`\n INSERT OR REPLACE INTO memory_files (path, scope, scope_id, type, fingerprint, last_indexed_at)\n VALUES (?, ?, ?, ?, ?, ?)\n `).run(path, scope, scope_id, type, fingerprint, now)\n\n this.db.prepare(`DELETE FROM memory_fts WHERE path = ?`).run(path)\n this.db.prepare(`INSERT INTO memory_fts (path, body) VALUES (?, ?)`).run(path, content)\n }\n\n forget(memoryId: string) {\n this.db.prepare(\"DELETE FROM memory_files WHERE path = ?\").run(memoryId)\n this.db.prepare(\"DELETE FROM memory_fts WHERE path = ?\").run(memoryId)\n }\n\n close() {\n this.db.close()\n }\n}\n","import { readdirSync, readFileSync } from \"fs\"\nimport { join, relative, sep } from \"path\"\nimport type { MemoryStore } from \"./store\"\n\nfunction parseScopeAndId(memoryRoot: string, filePath: string): { scope: string; scope_id: string } {\n const rel = relative(memoryRoot, filePath).split(sep)\n if (rel[0] === \"global\") return { scope: \"global\", scope_id: \"\" }\n if (rel[0] === \"projects\" && rel.length >= 3) return { scope: \"projects\", scope_id: rel[1] }\n if (rel[0] === \"sessions\" && rel.length >= 3) return { scope: \"sessions\", scope_id: rel[1] }\n return { scope: \"unknown\", scope_id: \"\" }\n}\n\nfunction walkMdFiles(dir: string): string[] {\n const results: string[] = []\n for (const entry of readdirSync(dir, { withFileTypes: true })) {\n const full = join(dir, entry.name)\n if (entry.isDirectory()) {\n results.push(...walkMdFiles(full))\n } else if (entry.name.endsWith(\".md\")) {\n results.push(full)\n }\n }\n return results\n}\n\nexport function reconcileMemoryDir(store: MemoryStore, memoryRoot: string) {\n const filesOnDisk = walkMdFiles(memoryRoot)\n const diskPaths = new Set<string>()\n\n for (const file of filesOnDisk) {\n diskPaths.add(file)\n const content = readFileSync(file, \"utf-8\")\n const { scope, scope_id } = parseScopeAndId(memoryRoot, file)\n store.write(file, scope, scope_id, \"snapshot\", content)\n }\n\n const indexed = store.db.prepare(\"SELECT path FROM memory_files\").all() as { path: string }[]\n for (const row of indexed) {\n if (!diskPaths.has(row.path)) {\n store.forget(row.path)\n }\n }\n}\n","import { readFileSync, existsSync, writeFileSync, mkdirSync } from \"fs\"\nimport { join, dirname } from \"path\"\n\nexport interface MemoryConfig {\n memory: {\n injection: {\n total_budget: number\n allocation: {\n checkpoint: number\n memory: number\n notes: number\n progress: number\n buffer: number\n }\n }\n checkpoint: {\n thresholds: string[]\n drain_timeout_ms: number\n idle_timeout_ms: number\n }\n dream: {\n auto: boolean\n interval_days: number\n }\n distill: {\n auto: boolean\n interval_days: number\n }\n }\n}\n\nexport const DEFAULT_CONFIG: MemoryConfig = {\n memory: {\n injection: {\n total_budget: 2000,\n allocation: {\n checkpoint: 0.30,\n memory: 0.25,\n notes: 0.20,\n progress: 0.15,\n buffer: 0.10\n }\n },\n checkpoint: {\n thresholds: [\"40%\", \"60%\", \"80%\"],\n drain_timeout_ms: 120000,\n idle_timeout_ms: 300000\n },\n dream: {\n auto: true,\n interval_days: 7\n },\n distill: {\n auto: true,\n interval_days: 30\n }\n }\n}\n\nexport function getConfigPath(projectRoot: string): string {\n return join(projectRoot, \".super-pocock\", \"config.json\")\n}\n\nexport function loadConfig(projectRoot: string): MemoryConfig {\n const configPath = getConfigPath(projectRoot)\n if (existsSync(configPath)) {\n const content = readFileSync(configPath, \"utf-8\")\n return { ...DEFAULT_CONFIG, ...JSON.parse(content) }\n }\n return DEFAULT_CONFIG\n}\n\nexport function ensureConfig(projectRoot: string): void {\n const configPath = getConfigPath(projectRoot)\n if (!existsSync(configPath)) {\n mkdirSync(dirname(configPath), { recursive: true })\n writeFileSync(configPath, JSON.stringify(DEFAULT_CONFIG, null, 2))\n }\n}\n","import { createHash } from \"crypto\"\nimport { join } from \"path\"\n\nexport type Scope = \"global\" | \"projects\" | \"sessions\"\n\nexport function resolveProjectId(absRepoPath: string): string {\n return createHash(\"sha256\").update(absRepoPath).digest(\"hex\").slice(0, 12)\n}\n\nexport function getMemoryRoot(projectRoot: string): string {\n return join(projectRoot, \".super-pocock\", \"memory\")\n}\n\nexport function getProjectMemoryDir(projectRoot: string): string {\n const projectId = resolveProjectId(projectRoot)\n return join(getMemoryRoot(projectRoot), \"projects\", projectId)\n}\n\nexport function getGlobalMemoryDir(projectRoot: string): string {\n return join(getMemoryRoot(projectRoot), \"global\")\n}\n\nexport function getSessionMemoryDir(projectRoot: string, sessionId: string): string {\n return join(getMemoryRoot(projectRoot), \"sessions\", sessionId)\n}\n\nexport function getDbPath(projectRoot: string): string {\n return join(getMemoryRoot(projectRoot), \"memory.db\")\n}\n","import type { Plugin } from \"@opencode-ai/plugin\"\nimport { loadConfig } from \"./config\"\nimport { getProjectMemoryDir, getSessionMemoryDir, getMemoryRoot } from \"./paths\"\nimport { mkdirSync } from \"fs\"\nimport { join } from \"path\"\n\nexport const CheckpointPlugin: Plugin = async ({ client, directory }) => {\n const config = loadConfig(directory)\n const memoryRoot = getMemoryRoot(directory)\n const projectDir = getProjectMemoryDir(directory)\n \n // 创建必要的目录\n mkdirSync(memoryRoot, { recursive: true })\n mkdirSync(join(memoryRoot, \"sessions\"), { recursive: true })\n mkdirSync(projectDir, { recursive: true })\n\n let lastCheckpointRatio = 0\n const THRESHOLDS = config.memory.checkpoint.thresholds.map(t => parseFloat(t) / 100)\n\n return {\n event: async ({ event }) => {\n // 触发 1: Token 比例阈值\n if (event.type === \"session.next.step.ended\") {\n const ratio = event.properties.tokens / event.properties.contextLimit\n const nextThreshold = THRESHOLDS.find(t => t > lastCheckpointRatio)\n if (nextThreshold && ratio >= nextThreshold) {\n lastCheckpointRatio = ratio\n await triggerCheckpoint(client, event.properties.sessionID, directory)\n }\n }\n\n // 触发 2: 会话结束(idle 超时)\n if (event.type === \"session.status\" && event.properties?.status?.type === \"idle\") {\n setTimeout(async () => {\n await triggerCheckpoint(client, event.properties.sessionID, directory)\n }, config.memory.checkpoint.idle_timeout_ms)\n }\n },\n\n \"experimental.session.compacting\": async (input, output) => {\n output.context.push(`\n## Checkpoint Instructions\nExtract and preserve these 11 fields:\n1. Intent (用户的核心目标)\n2. Actions (已执行的操作)\n3. Task Tree (子任务层级)\n4. Errors & Workarounds (遇到的问题及解决)\n5. Design Decisions (关键技术选择)\n6. Constraints (限制条件)\n7. Current State (任务进度)\n8. TODOs (剩余工作)\n9. Code Changes Summary (Git diff 概要)\n10. Key File Paths (涉及的核心文件)\n11. Timestamp (检查点创建时间)\n `)\n },\n }\n}\n\nasync function triggerCheckpoint(client: any, sessionID: string, directory: string) {\n const messages = await client.session.messages({ path: { id: sessionID } })\n const context = constructCheckpointContext(messages)\n\n // 创建会话目录\n const sessionDir = getSessionMemoryDir(directory, sessionID)\n mkdirSync(sessionDir, { recursive: true })\n\n await client.session.prompt({\n path: { id: sessionID },\n body: {\n agent: \"checkpoint-writer\",\n parts: [{\n type: \"text\",\n text: `Extract checkpoint from this context:\\n${context}\\n\\nWrite checkpoint to:\\n- Session: .super-pocock/memory/sessions/${sessionID}/checkpoint.md\\n- Project: .super-pocock/memory/projects/<pid>/checkpoint.md`\n }],\n },\n })\n}\n\nfunction constructCheckpointContext(messages: any[]): string {\n return messages.map(m => `[${m.role}]: ${m.content}`).join(\"\\n\")\n}\n","import type { Plugin } from \"@opencode-ai/plugin\"\nimport { loadConfig } from \"./config\"\nimport { getProjectMemoryDir, getGlobalMemoryDir, getSessionMemoryDir, getMemoryRoot } from \"./paths\"\nimport { existsSync, readFileSync, readdirSync } from \"fs\"\nimport { join } from \"path\"\n\nexport const MemoryInjectionPlugin: Plugin = async ({ directory }) => {\n const config = loadConfig(directory)\n const memoryCache = new Map<string, Record<string, string>>()\n\n function getLatestSessionId(): string | null {\n const sessionsDir = join(getMemoryRoot(directory), \"sessions\")\n if (!existsSync(sessionsDir)) return null\n \n const sessions = readdirSync(sessionsDir, { withFileTypes: true })\n .filter(d => d.isDirectory())\n .map(d => d.name)\n \n if (sessions.length === 0) return null\n \n // 返回最新的会话(按目录修改时间)\n let latestSession = sessions[0]\n let latestTime = 0\n \n for (const session of sessions) {\n const sessionPath = join(sessionsDir, session)\n const stat = require(\"fs\").statSync(sessionPath)\n if (stat.mtimeMs > latestTime) {\n latestTime = stat.mtimeMs\n latestSession = session\n }\n }\n \n return latestSession\n }\n\n function loadMemoryFiles(sessionId?: string) {\n const projectDir = getProjectMemoryDir(directory)\n const globalDir = getGlobalMemoryDir(directory)\n const memoryRoot = getMemoryRoot(directory)\n\n const memories: Record<string, string> = {}\n\n // 项目级记忆\n const files = [\n { key: \"memory\", path: join(projectDir, \"MEMORY.md\") },\n { key: \"notes\", path: join(projectDir, \"notes.md\") },\n { key: \"progress\", path: join(projectDir, \"tasks\", \"progress.md\") },\n { key: \"global_memory\", path: join(globalDir, \"MEMORY.md\") },\n ]\n\n for (const file of files) {\n if (existsSync(file.path)) {\n memories[file.key] = readFileSync(file.path, \"utf-8\")\n }\n }\n\n // 会话级 checkpoint(优先)\n if (sessionId) {\n const sessionCheckpoint = join(memoryRoot, \"sessions\", sessionId, \"checkpoint.md\")\n if (existsSync(sessionCheckpoint)) {\n memories.checkpoint = readFileSync(sessionCheckpoint, \"utf-8\")\n }\n }\n\n // 项目级 checkpoint(备选)\n if (!memories.checkpoint) {\n const projectCheckpoint = join(projectDir, \"checkpoint.md\")\n if (existsSync(projectCheckpoint)) {\n memories.checkpoint = readFileSync(projectCheckpoint, \"utf-8\")\n }\n }\n\n return memories\n }\n\n function estimateTokens(text: string): number {\n return Math.ceil(text.length / 4)\n }\n\n function smartTruncate(text: string, maxTokens: number): string {\n const estimatedTokens = estimateTokens(text)\n if (estimatedTokens <= maxTokens) return text\n\n const keepChars = maxTokens * 4 * 0.3\n const start = text.substring(0, keepChars)\n const end = text.substring(text.length - keepChars)\n\n return `${start}\\n\\n... [记忆已压缩,原 ${estimatedTokens} tokens] ...\\n\\n${end}`\n }\n\n function formatMemory(memories: Record<string, string>, budget: Record<string, number>): string {\n const sections = []\n\n if (memories.checkpoint && budget.checkpoint > 0) {\n sections.push(`## 检查点状态\\n${smartTruncate(memories.checkpoint, budget.checkpoint)}`)\n }\n if (memories.memory && budget.memory > 0) {\n sections.push(`## 项目记忆\\n${smartTruncate(memories.memory, budget.memory)}`)\n }\n if (memories.global_memory && budget.memory > 0) {\n sections.push(`## 全局记忆\\n${smartTruncate(memories.global_memory, budget.memory * 0.5)}`)\n }\n if (memories.notes && budget.notes > 0) {\n sections.push(`## 当前笔记\\n${smartTruncate(memories.notes, budget.notes)}`)\n }\n if (memories.progress && budget.progress > 0) {\n sections.push(`## 任务进度\\n${smartTruncate(memories.progress, budget.progress)}`)\n }\n\n return sections.join(\"\\n\\n\")\n }\n\n return {\n event: async ({ event }) => {\n if (event.type === \"session.created\") {\n // 获取最新的会话 ID\n const latestSessionId = getLatestSessionId()\n const memories = loadMemoryFiles(latestSessionId)\n memoryCache.set(event.properties.sessionID, memories)\n }\n },\n\n \"experimental.chat.system.transform\": async (input, output) => {\n const memories = memoryCache.get(input.sessionID)\n if (!memories) return\n\n const totalBudget = config.memory.injection.total_budget\n const allocation = config.memory.injection.allocation\n\n const budget = {\n checkpoint: Math.floor(totalBudget * allocation.checkpoint),\n memory: Math.floor(totalBudget * allocation.memory),\n notes: Math.floor(totalBudget * allocation.notes),\n progress: Math.floor(totalBudget * allocation.progress),\n }\n\n const memoryContext = formatMemory(memories, budget)\n\n if (memoryContext) {\n output.system.push(`\\n\\n# Injected Memory Context\\n${memoryContext}`)\n }\n },\n\n \"experimental.session.compacting\": async (input, output) => {\n const memories = memoryCache.get(input.sessionID)\n if (!memories) return\n\n const criticalMemory = []\n if (memories.checkpoint) {\n criticalMemory.push(`当前检查点: ${memories.checkpoint.substring(0, 500)}`)\n }\n if (memories.progress) {\n criticalMemory.push(`任务进度摘要: ${memories.progress.substring(0, 300)}`)\n }\n\n output.context.push(`## 保留的关键记忆\\n${criticalMemory.join(\"\\n\\n\")}`)\n },\n }\n}\n","import type { Plugin } from \"@opencode-ai/plugin\"\nimport { loadConfig } from \"./config\"\nimport { getProjectMemoryDir } from \"./paths\"\nimport { existsSync, readFileSync, writeFileSync, mkdirSync } from \"fs\"\nimport { join } from \"path\"\n\nexport const DreamPlugin: Plugin = async ({ client, directory }) => {\n const config = loadConfig(directory)\n const memoryDir = getProjectMemoryDir(directory)\n mkdirSync(memoryDir, { recursive: true })\n\n function getLastTimestamp(metaFile: string): number {\n const metaPath = join(memoryDir, metaFile)\n if (existsSync(metaPath)) {\n const meta = JSON.parse(readFileSync(metaPath, \"utf-8\"))\n return meta.timestamp ?? 0\n }\n return 0\n }\n\n function setLastTimestamp(metaFile: string) {\n const metaPath = join(memoryDir, metaFile)\n writeFileSync(metaPath, JSON.stringify({ timestamp: Date.now() }))\n }\n\n function shouldAutoRun(metaFile: string, intervalDays: number): boolean {\n const lastRun = getLastTimestamp(metaFile)\n const intervalMs = intervalDays * 24 * 60 * 60 * 1000\n return Date.now() - lastRun > intervalMs\n }\n\n return {\n event: async ({ event }) => {\n if (event.type === \"session.created\") {\n // 自动触发 dream\n if (config.memory.dream.auto && shouldAutoRun(\".dream-meta.json\", config.memory.dream.interval_days)) {\n await client.session.prompt({\n path: { id: event.properties.sessionID },\n body: {\n agent: \"dream\",\n parts: [{\n type: \"text\",\n text: \"Run automatic dream memory consolidation pass.\"\n }],\n },\n })\n setLastTimestamp(\".dream-meta.json\")\n }\n\n // 自动触发 distill\n if (config.memory.distill.auto && shouldAutoRun(\".distill-meta.json\", config.memory.distill.interval_days)) {\n await client.session.prompt({\n path: { id: event.properties.sessionID },\n body: {\n agent: \"distill\",\n parts: [{\n type: \"text\",\n text: \"Run automatic distill pass.\"\n }],\n },\n })\n setLastTimestamp(\".distill-meta.json\")\n }\n }\n },\n }\n}\n"],"mappings":"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","names":["mkdirSync","join","readFileSync","mkdirSync","join","join","mkdirSync","join","existsSync","readFileSync","readdirSync","join","existsSync","readFileSync","writeFileSync","mkdirSync","join","mkdirSync","join"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/tool.ts","../src/store.ts","../src/reconcile.ts","../src/config.ts","../src/paths.ts","../src/checkpoint-plugin.ts","../src/injection-plugin.ts","../src/dream-plugin.ts"],"sourcesContent":["import type { Plugin } from \"@opencode-ai/plugin\"\nimport { mkdirSync } from \"fs\"\nimport { join } from \"path\"\nimport { createMemoryTool } from \"./tool\"\nimport { CheckpointPlugin } from \"./checkpoint-plugin\"\nimport { MemoryInjectionPlugin } from \"./injection-plugin\"\nimport { DreamPlugin } from \"./dream-plugin\"\nimport { getMemoryRoot, getProjectMemoryDir, getGlobalMemoryDir, getDbPath } from \"./paths\"\nimport { ensureConfig } from \"./config\"\n\nexport const MemoryCorePlugin: Plugin = async (ctx) => {\n // 确保配置文件存在\n ensureConfig(ctx.directory)\n\n const memoryRoot = getMemoryRoot(ctx.directory)\n const projectDir = getProjectMemoryDir(ctx.directory)\n const globalDir = getGlobalMemoryDir(ctx.directory)\n\n // 创建目录结构\n mkdirSync(join(memoryRoot, \"global\"), { recursive: true })\n mkdirSync(join(projectDir, \"sessions\"), { recursive: true })\n mkdirSync(join(projectDir, \"tasks\"), { recursive: true })\n\n // 创建 memory 工具\n const memoryTool = createMemoryTool({\n memoryDir: memoryRoot,\n dbPath: getDbPath(ctx.directory),\n })\n\n // 初始化子插件\n const checkpointPlugin = await CheckpointPlugin(ctx)\n const injectionPlugin = await MemoryInjectionPlugin(ctx)\n const dreamPlugin = await DreamPlugin(ctx)\n\n return {\n tool: {\n memory: memoryTool,\n },\n event: async (input) => {\n await checkpointPlugin.event?.(input)\n await injectionPlugin.event?.(input)\n await dreamPlugin.event?.(input)\n },\n \"experimental.chat.system.transform\": async (input, output) => {\n await injectionPlugin[\"experimental.chat.system.transform\"]?.(input, output)\n },\n \"experimental.session.compacting\": async (input, output) => {\n await checkpointPlugin[\"experimental.session.compacting\"]?.(input, output)\n await injectionPlugin[\"experimental.session.compacting\"]?.(input, output)\n },\n }\n}\n\nexport default MemoryCorePlugin\n\n// 导出子模块\nexport { MemoryStore } from \"./store\"\nexport { createMemoryTool } from \"./tool\"\nexport { resolveProjectId, getMemoryRoot, getProjectMemoryDir, getGlobalMemoryDir } from \"./paths\"\nexport { loadConfig, DEFAULT_CONFIG } from \"./config\"\nexport type { MemoryConfig } from \"./config\"\nexport type { SearchResult, SearchFilters } from \"./store\"\n","import { tool } from \"@opencode-ai/plugin\"\nimport { z } from \"zod\"\nimport { MemoryStore } from \"./store\"\nimport { reconcileMemoryDir } from \"./reconcile\"\nimport { mkdirSync } from \"fs\"\n\nexport function createMemoryTool(ctx: { memoryDir: string; dbPath: string }) {\n let store: MemoryStore | null = null\n\n function ensureStore() {\n if (!store) {\n mkdirSync(ctx.memoryDir, { recursive: true })\n store = new MemoryStore(ctx.dbPath)\n reconcileMemoryDir(store, ctx.memoryDir)\n }\n return store\n }\n\n return tool({\n description: \"Search or write to the persistent memory store. Search returns ranked results across memory files. Write saves content to a memory file.\",\n args: {\n operation: z.enum([\"search\", \"write\", \"list\", \"forget\"]),\n query: z.string().optional(),\n scope: z.string().optional(),\n scope_id: z.string().optional(),\n type: z.string().optional(),\n limit: z.number().optional(),\n path: z.string().optional(),\n content: z.string().optional(),\n memory_id: z.string().optional(),\n },\n execute(args: any) {\n const s = ensureStore()\n\n if (args.operation === \"search\") {\n if (!args.query) return \"query is required for search\"\n const results = s.search(args.query, {\n scope: args.scope,\n scope_id: args.scope_id,\n type: args.type,\n limit: args.limit,\n })\n if (results.length === 0) return \"No results found\"\n return JSON.stringify(results, null, 2)\n }\n\n if (args.operation === \"write\") {\n if (!args.path) return \"path is required for write\"\n if (!args.content) return \"content is required for write\"\n s.write(\n args.path,\n args.scope ?? \"unknown\",\n args.scope_id ?? \"\",\n args.type ?? \"snapshot\",\n args.content,\n )\n return `Wrote to ${args.path}`\n }\n\n if (args.operation === \"list\") {\n const results = s.search(\"*\", {\n scope: args.scope,\n scope_id: args.scope_id,\n type: args.type,\n limit: args.limit ?? 50,\n })\n return JSON.stringify(results, null, 2)\n }\n\n if (args.operation === \"forget\") {\n if (!args.memory_id) return \"memory_id is required for forget\"\n s.forget(args.memory_id)\n return `Forgot ${args.memory_id}`\n }\n\n return \"Invalid operation\"\n },\n })\n}\n","import Database from \"better-sqlite3\"\n\nexport interface SearchFilters {\n scope?: string\n scope_id?: string\n type?: string\n limit?: number\n}\n\nexport interface SearchResult {\n path: string\n scope: string\n scope_id: string\n type: string\n snippet: string\n score: number\n}\n\nexport class MemoryStore {\n public db: Database.Database\n\n constructor(dbPath: string) {\n this.db = new Database(dbPath)\n this.db.pragma(\"journal_mode = WAL\")\n this.init()\n }\n\n private init() {\n this.db.exec(`\n CREATE TABLE IF NOT EXISTS memory_files (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n path TEXT NOT NULL UNIQUE,\n scope TEXT NOT NULL,\n scope_id TEXT NOT NULL DEFAULT '',\n type TEXT NOT NULL,\n fingerprint TEXT NOT NULL,\n last_indexed_at INTEGER NOT NULL\n )\n `)\n this.db.exec(`\n CREATE VIRTUAL TABLE IF NOT EXISTS memory_fts\n USING fts5(path, body, tokenize='unicode61')\n `)\n }\n\n search(query: string, filters: SearchFilters = {}): SearchResult[] {\n const tokens = query.split(/\\s+/).filter(Boolean).map(t => `\"${t}\"`)\n if (tokens.length === 0) return []\n const ftsQuery = tokens.join(\" OR \")\n const limit = filters.limit ?? 10\n\n let sql = `\n SELECT f.path, m.scope, m.scope_id, m.type,\n snippet(memory_fts, 1, '<<', '>>', '...', 32) AS snippet,\n bm25(memory_fts) AS score\n FROM memory_fts f\n JOIN memory_files m ON m.path = f.path\n WHERE memory_fts MATCH ?\n `\n const params: any[] = [ftsQuery]\n if (filters.scope) { sql += ` AND m.scope = ?`; params.push(filters.scope) }\n if (filters.scope_id) { sql += ` AND m.scope_id = ?`; params.push(filters.scope_id) }\n if (filters.type) { sql += ` AND m.type = ?`; params.push(filters.type) }\n sql += ` ORDER BY score LIMIT ?`\n params.push(limit)\n return this.db.prepare(sql).all(...params) as SearchResult[]\n }\n\n write(path: string, scope: string, scope_id: string, type: string, content: string) {\n const fingerprint = `${content.length}-${Date.now()}`\n const now = Date.now()\n\n this.db.prepare(`\n INSERT OR REPLACE INTO memory_files (path, scope, scope_id, type, fingerprint, last_indexed_at)\n VALUES (?, ?, ?, ?, ?, ?)\n `).run(path, scope, scope_id, type, fingerprint, now)\n\n this.db.prepare(`DELETE FROM memory_fts WHERE path = ?`).run(path)\n this.db.prepare(`INSERT INTO memory_fts (path, body) VALUES (?, ?)`).run(path, content)\n }\n\n forget(memoryId: string) {\n this.db.prepare(\"DELETE FROM memory_files WHERE path = ?\").run(memoryId)\n this.db.prepare(\"DELETE FROM memory_fts WHERE path = ?\").run(memoryId)\n }\n\n close() {\n this.db.close()\n }\n}\n","import { readdirSync, readFileSync } from \"fs\"\nimport { join, relative, sep } from \"path\"\nimport type { MemoryStore } from \"./store\"\n\nfunction parseScopeAndId(memoryRoot: string, filePath: string): { scope: string; scope_id: string } {\n const rel = relative(memoryRoot, filePath).split(sep)\n if (rel[0] === \"global\") return { scope: \"global\", scope_id: \"\" }\n if (rel[0] === \"projects\" && rel.length >= 3) return { scope: \"projects\", scope_id: rel[1] }\n if (rel[0] === \"sessions\" && rel.length >= 3) return { scope: \"sessions\", scope_id: rel[1] }\n return { scope: \"unknown\", scope_id: \"\" }\n}\n\nfunction walkMdFiles(dir: string): string[] {\n const results: string[] = []\n for (const entry of readdirSync(dir, { withFileTypes: true })) {\n const full = join(dir, entry.name)\n if (entry.isDirectory()) {\n results.push(...walkMdFiles(full))\n } else if (entry.name.endsWith(\".md\")) {\n results.push(full)\n }\n }\n return results\n}\n\nexport function reconcileMemoryDir(store: MemoryStore, memoryRoot: string) {\n const filesOnDisk = walkMdFiles(memoryRoot)\n const diskPaths = new Set<string>()\n\n for (const file of filesOnDisk) {\n diskPaths.add(file)\n const content = readFileSync(file, \"utf-8\")\n const { scope, scope_id } = parseScopeAndId(memoryRoot, file)\n store.write(file, scope, scope_id, \"snapshot\", content)\n }\n\n const indexed = store.db.prepare(\"SELECT path FROM memory_files\").all() as { path: string }[]\n for (const row of indexed) {\n if (!diskPaths.has(row.path)) {\n store.forget(row.path)\n }\n }\n}\n","import { readFileSync, existsSync, writeFileSync, mkdirSync } from \"fs\"\nimport { join, dirname } from \"path\"\n\nexport interface MemoryConfig {\n memory: {\n injection: {\n total_budget: number\n allocation: {\n checkpoint: number\n memory: number\n notes: number\n progress: number\n buffer: number\n }\n }\n checkpoint: {\n thresholds: string[]\n drain_timeout_ms: number\n idle_timeout_ms: number\n }\n dream: {\n auto: boolean\n interval_days: number\n }\n distill: {\n auto: boolean\n interval_days: number\n }\n }\n}\n\nexport const DEFAULT_CONFIG: MemoryConfig = {\n memory: {\n injection: {\n total_budget: 2000,\n allocation: {\n checkpoint: 0.30,\n memory: 0.25,\n notes: 0.20,\n progress: 0.15,\n buffer: 0.10\n }\n },\n checkpoint: {\n thresholds: [\"20%\", \"40%\", \"60%\", \"80%\"],\n drain_timeout_ms: 120000,\n idle_timeout_ms: 300000\n },\n dream: {\n auto: true,\n interval_days: 7\n },\n distill: {\n auto: true,\n interval_days: 30\n }\n }\n}\n\nexport function getConfigPath(projectRoot: string): string {\n return join(projectRoot, \".super-pocock\", \"config.json\")\n}\n\nexport function loadConfig(projectRoot: string): MemoryConfig {\n const configPath = getConfigPath(projectRoot)\n if (existsSync(configPath)) {\n const content = readFileSync(configPath, \"utf-8\")\n return { ...DEFAULT_CONFIG, ...JSON.parse(content) }\n }\n return DEFAULT_CONFIG\n}\n\nexport function ensureConfig(projectRoot: string): void {\n const configPath = getConfigPath(projectRoot)\n if (!existsSync(configPath)) {\n mkdirSync(dirname(configPath), { recursive: true })\n writeFileSync(configPath, JSON.stringify(DEFAULT_CONFIG, null, 2))\n }\n}\n","import { createHash } from \"crypto\"\nimport { join } from \"path\"\n\nexport type Scope = \"global\" | \"projects\" | \"sessions\"\n\nexport function resolveProjectId(absRepoPath: string): string {\n return createHash(\"sha256\").update(absRepoPath).digest(\"hex\").slice(0, 12)\n}\n\nexport function getMemoryRoot(projectRoot: string): string {\n return join(projectRoot, \".super-pocock\", \"memory\")\n}\n\nexport function getProjectMemoryDir(projectRoot: string): string {\n const projectId = resolveProjectId(projectRoot)\n return join(getMemoryRoot(projectRoot), \"projects\", projectId)\n}\n\nexport function getGlobalMemoryDir(projectRoot: string): string {\n return join(getMemoryRoot(projectRoot), \"global\")\n}\n\nexport function getSessionMemoryDir(projectRoot: string, sessionId: string): string {\n return join(getMemoryRoot(projectRoot), \"sessions\", sessionId)\n}\n\nexport function getDbPath(projectRoot: string): string {\n return join(getMemoryRoot(projectRoot), \"memory.db\")\n}\n","import type { Plugin } from \"@opencode-ai/plugin\"\nimport { loadConfig } from \"./config\"\nimport { getProjectMemoryDir, getSessionMemoryDir, getMemoryRoot } from \"./paths\"\nimport { mkdirSync } from \"fs\"\nimport { join } from \"path\"\n\nexport const CheckpointPlugin: Plugin = async ({ client, directory }) => {\n const config = loadConfig(directory)\n const memoryRoot = getMemoryRoot(directory)\n const projectDir = getProjectMemoryDir(directory)\n \n // 创建必要的目录\n mkdirSync(memoryRoot, { recursive: true })\n mkdirSync(join(memoryRoot, \"sessions\"), { recursive: true })\n mkdirSync(projectDir, { recursive: true })\n\n let lastCheckpointRatio = 0\n const THRESHOLDS = config.memory.checkpoint.thresholds.map(t => parseFloat(t) / 100)\n let currentSessionID: string | null = null\n\n return {\n event: async ({ event }) => {\n // 记录当前会话 ID\n if (event.type === \"session.created\") {\n const newSessionID = event.properties?.info?.id\n \n // 触发 1: 新建会话时,保存上一个会话的 checkpoint\n if (currentSessionID && currentSessionID !== newSessionID) {\n await triggerCheckpoint(client, currentSessionID, directory, \"new session created\")\n }\n \n currentSessionID = newSessionID || null\n }\n\n // 触发 2: Token 比例阈值\n if (event.type === \"session.next.step.ended\") {\n const ratio = event.properties.tokens / event.properties.contextLimit\n const nextThreshold = THRESHOLDS.find(t => t > lastCheckpointRatio)\n if (nextThreshold && ratio >= nextThreshold) {\n lastCheckpointRatio = ratio\n await triggerCheckpoint(client, event.properties.sessionID, directory, `token ratio ${Math.round(ratio * 100)}%`)\n }\n }\n\n // 触发 3: 会话结束(idle 超时)\n if (event.type === \"session.status\" && event.properties?.status?.type === \"idle\") {\n setTimeout(async () => {\n await triggerCheckpoint(client, event.properties.sessionID, directory, \"idle timeout\")\n }, config.memory.checkpoint.idle_timeout_ms)\n }\n\n // 触发 4: 会话空闲\n if (event.type === \"session.idle\") {\n await triggerCheckpoint(client, event.properties.sessionID, directory, \"session idle\")\n }\n\n // 触发 5: 会话删除时保存 checkpoint\n if (event.type === \"session.deleted\") {\n await triggerCheckpoint(client, event.properties.info.id, directory, \"session deleted\")\n }\n\n // 触发 6: 退出程序时保存当前会话 checkpoint\n if (event.type === \"server.instance.disposed\") {\n if (currentSessionID) {\n await triggerCheckpoint(client, currentSessionID, directory, \"app exit\")\n }\n }\n },\n\n \"experimental.session.compacting\": async (input, output) => {\n output.context.push(`\n## Checkpoint Instructions\nExtract and preserve these 11 fields:\n1. Intent (用户的核心目标)\n2. Actions (已执行的操作)\n3. Task Tree (子任务层级)\n4. Errors & Workarounds (遇到的问题及解决)\n5. Design Decisions (关键技术选择)\n6. Constraints (限制条件)\n7. Current State (任务进度)\n8. TODOs (剩余工作)\n9. Code Changes Summary (Git diff 概要)\n10. Key File Paths (涉及的核心文件)\n11. Timestamp (检查点创建时间)\n `)\n },\n }\n}\n\nasync function triggerCheckpoint(client: any, sessionID: string, directory: string, reason?: string) {\n const messages = await client.session.messages({ path: { id: sessionID } })\n const context = constructCheckpointContext(messages)\n\n // 创建会话目录\n const sessionDir = getSessionMemoryDir(directory, sessionID)\n mkdirSync(sessionDir, { recursive: true })\n\n // 记录日志\n await client.app.log({\n body: {\n service: 'memory-core',\n level: 'info',\n message: `Checkpoint triggered: ${reason || 'unknown'} (session: ${sessionID})`\n }\n })\n\n // 非阻塞调用,不等待完成\n client.session.prompt({\n path: { id: sessionID },\n body: {\n agent: \"checkpoint-writer\",\n parts: [{\n type: \"text\",\n text: `Extract checkpoint from this context:\\n${context}\\n\\nWrite checkpoint to:\\n- Session: .super-pocock/memory/sessions/${sessionID}/checkpoint.md\\n- Project: .super-pocock/memory/projects/<pid>/checkpoint.md`\n }],\n },\n }).catch((err: any) => {\n // 静默处理错误,不影响主 agent\n console.error('Checkpoint failed:', err)\n })\n}\n\nfunction constructCheckpointContext(messages: any[]): string {\n return messages.map(m => `[${m.role}]: ${m.content}`).join(\"\\n\")\n}\n","import type { Plugin } from \"@opencode-ai/plugin\"\nimport { loadConfig } from \"./config\"\nimport { getProjectMemoryDir, getGlobalMemoryDir, getSessionMemoryDir, getMemoryRoot } from \"./paths\"\nimport { existsSync, readFileSync, readdirSync } from \"fs\"\nimport { join } from \"path\"\n\nexport const MemoryInjectionPlugin: Plugin = async ({ directory }) => {\n const config = loadConfig(directory)\n const memoryCache = new Map<string, Record<string, string>>()\n\n function getLatestSessionId(): string | null {\n const sessionsDir = join(getMemoryRoot(directory), \"sessions\")\n if (!existsSync(sessionsDir)) return null\n \n const sessions = readdirSync(sessionsDir, { withFileTypes: true })\n .filter(d => d.isDirectory())\n .map(d => d.name)\n \n if (sessions.length === 0) return null\n \n // 返回最新的会话(按目录修改时间)\n let latestSession = sessions[0]\n let latestTime = 0\n \n for (const session of sessions) {\n const sessionPath = join(sessionsDir, session)\n const stat = require(\"fs\").statSync(sessionPath)\n if (stat.mtimeMs > latestTime) {\n latestTime = stat.mtimeMs\n latestSession = session\n }\n }\n \n return latestSession\n }\n\n function loadMemoryFiles(sessionId?: string) {\n const projectDir = getProjectMemoryDir(directory)\n const globalDir = getGlobalMemoryDir(directory)\n const memoryRoot = getMemoryRoot(directory)\n\n const memories: Record<string, string> = {}\n\n // 项目级记忆\n const files = [\n { key: \"memory\", path: join(projectDir, \"MEMORY.md\") },\n { key: \"notes\", path: join(projectDir, \"notes.md\") },\n { key: \"progress\", path: join(projectDir, \"tasks\", \"progress.md\") },\n { key: \"global_memory\", path: join(globalDir, \"MEMORY.md\") },\n ]\n\n for (const file of files) {\n if (existsSync(file.path)) {\n memories[file.key] = readFileSync(file.path, \"utf-8\")\n }\n }\n\n // 会话级 checkpoint(优先)\n if (sessionId) {\n const sessionCheckpoint = join(memoryRoot, \"sessions\", sessionId, \"checkpoint.md\")\n if (existsSync(sessionCheckpoint)) {\n memories.checkpoint = readFileSync(sessionCheckpoint, \"utf-8\")\n }\n }\n\n // 项目级 checkpoint(备选)\n if (!memories.checkpoint) {\n const projectCheckpoint = join(projectDir, \"checkpoint.md\")\n if (existsSync(projectCheckpoint)) {\n memories.checkpoint = readFileSync(projectCheckpoint, \"utf-8\")\n }\n }\n\n return memories\n }\n\n function estimateTokens(text: string): number {\n return Math.ceil(text.length / 4)\n }\n\n function smartTruncate(text: string, maxTokens: number): string {\n const estimatedTokens = estimateTokens(text)\n if (estimatedTokens <= maxTokens) return text\n\n const keepChars = maxTokens * 4 * 0.3\n const start = text.substring(0, keepChars)\n const end = text.substring(text.length - keepChars)\n\n return `${start}\\n\\n... [记忆已压缩,原 ${estimatedTokens} tokens] ...\\n\\n${end}`\n }\n\n function formatMemory(memories: Record<string, string>, budget: Record<string, number>): string {\n const sections = []\n\n if (memories.checkpoint && budget.checkpoint > 0) {\n sections.push(`## 检查点状态\\n${smartTruncate(memories.checkpoint, budget.checkpoint)}`)\n }\n if (memories.memory && budget.memory > 0) {\n sections.push(`## 项目记忆\\n${smartTruncate(memories.memory, budget.memory)}`)\n }\n if (memories.global_memory && budget.memory > 0) {\n sections.push(`## 全局记忆\\n${smartTruncate(memories.global_memory, budget.memory * 0.5)}`)\n }\n if (memories.notes && budget.notes > 0) {\n sections.push(`## 当前笔记\\n${smartTruncate(memories.notes, budget.notes)}`)\n }\n if (memories.progress && budget.progress > 0) {\n sections.push(`## 任务进度\\n${smartTruncate(memories.progress, budget.progress)}`)\n }\n\n return sections.join(\"\\n\\n\")\n }\n\n return {\n event: async ({ event }) => {\n if (event.type === \"session.created\") {\n // 获取最新的会话 ID\n const latestSessionId = getLatestSessionId()\n const memories = loadMemoryFiles(latestSessionId)\n memoryCache.set(event.properties.sessionID, memories)\n \n // 记录注入状态\n const memoryKeys = Object.keys(memories)\n const totalTokens = Object.values(memories).reduce((sum, content) => sum + estimateTokens(content), 0)\n console.log(`[memory-core] Loaded ${memoryKeys.length} memory files (${totalTokens} tokens) for session ${event.properties.sessionID}`)\n }\n },\n\n \"experimental.chat.system.transform\": async (input, output) => {\n const memories = memoryCache.get(input.sessionID)\n if (!memories) {\n console.log(`[memory-core] No memories found for session ${input.sessionID}`)\n return\n }\n\n const totalBudget = config.memory.injection.total_budget\n const allocation = config.memory.injection.allocation\n\n const budget = {\n checkpoint: Math.floor(totalBudget * allocation.checkpoint),\n memory: Math.floor(totalBudget * allocation.memory),\n notes: Math.floor(totalBudget * allocation.notes),\n progress: Math.floor(totalBudget * allocation.progress),\n }\n\n const memoryContext = formatMemory(memories, budget)\n\n if (memoryContext) {\n const injectedTokens = estimateTokens(memoryContext)\n console.log(`[memory-core] Injecting ${injectedTokens} tokens (budget: ${totalBudget}) into system prompt`)\n output.system.push(`\\n\\n# Injected Memory Context\\n${memoryContext}`)\n }\n },\n\n \"experimental.session.compacting\": async (input, output) => {\n const memories = memoryCache.get(input.sessionID)\n if (!memories) return\n\n const criticalMemory = []\n if (memories.checkpoint) {\n criticalMemory.push(`当前检查点: ${memories.checkpoint.substring(0, 500)}`)\n }\n if (memories.progress) {\n criticalMemory.push(`任务进度摘要: ${memories.progress.substring(0, 300)}`)\n }\n\n output.context.push(`## 保留的关键记忆\\n${criticalMemory.join(\"\\n\\n\")}`)\n },\n }\n}\n","import type { Plugin } from \"@opencode-ai/plugin\"\nimport { loadConfig } from \"./config\"\nimport { getProjectMemoryDir } from \"./paths\"\nimport { existsSync, readFileSync, writeFileSync, mkdirSync } from \"fs\"\nimport { join } from \"path\"\n\nexport const DreamPlugin: Plugin = async ({ client, directory }) => {\n const config = loadConfig(directory)\n const memoryDir = getProjectMemoryDir(directory)\n mkdirSync(memoryDir, { recursive: true })\n\n function getLastTimestamp(metaFile: string): number {\n const metaPath = join(memoryDir, metaFile)\n if (existsSync(metaPath)) {\n const meta = JSON.parse(readFileSync(metaPath, \"utf-8\"))\n return meta.timestamp ?? 0\n }\n return 0\n }\n\n function setLastTimestamp(metaFile: string) {\n const metaPath = join(memoryDir, metaFile)\n writeFileSync(metaPath, JSON.stringify({ timestamp: Date.now() }))\n }\n\n function shouldAutoRun(metaFile: string, intervalDays: number): boolean {\n const lastRun = getLastTimestamp(metaFile)\n const intervalMs = intervalDays * 24 * 60 * 60 * 1000\n return Date.now() - lastRun > intervalMs\n }\n\n return {\n event: async ({ event }) => {\n if (event.type === \"session.created\") {\n // 自动触发 dream\n if (config.memory.dream.auto && shouldAutoRun(\".dream-meta.json\", config.memory.dream.interval_days)) {\n await client.session.prompt({\n path: { id: event.properties.sessionID },\n body: {\n agent: \"dream\",\n parts: [{\n type: \"text\",\n text: \"Run automatic dream memory consolidation pass.\"\n }],\n },\n })\n setLastTimestamp(\".dream-meta.json\")\n }\n\n // 自动触发 distill\n if (config.memory.distill.auto && shouldAutoRun(\".distill-meta.json\", config.memory.distill.interval_days)) {\n await client.session.prompt({\n path: { id: event.properties.sessionID },\n body: {\n agent: \"distill\",\n parts: [{\n type: \"text\",\n text: \"Run automatic distill pass.\"\n }],\n },\n })\n setLastTimestamp(\".distill-meta.json\")\n }\n }\n },\n }\n}\n"],"mappings":"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","names":["mkdirSync","join","readFileSync","mkdirSync","join","join","mkdirSync","join","existsSync","readFileSync","readdirSync","join","existsSync","readFileSync","writeFileSync","mkdirSync","join","mkdirSync","join"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@super-pocock-ai/memory-core",
3
- "version": "2.0.12",
3
+ "version": "2.0.18",
4
4
  "description": "持久化记忆系统,基于 SQLite FTS5 和 BM25 搜索",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",