{"version":3,"file":"index.cjs","names":["join","readFile","mkdir","dirname","LibSQLStore","ObservationalMemory","optimizeObservationsForContext","getObservationContextPrompt","OBSERVATION_CONTEXT_INSTRUCTIONS","OBSERVATION_CONTINUATION_HINT","tool","TokenCounter"],"sources":["../src/index.ts"],"sourcesContent":["/**\n * @mastra/opencode\n *\n * OpenCode plugin that brings Mastra Observational Memory into opencode sessions.\n *\n * Mastra OM compresses long conversation history into structured observations\n * using an Observer (extract) and Reflector (condense) architecture.\n *\n * Configuration is read from .opencode/mastra.json in the project root.\n *\n * @example .opencode/mastra.json\n * ```json\n * {\n *   \"model\": \"google/gemini-2.5-flash\",\n *   \"observation\": { \"messageTokens\": 20000 },\n *   \"reflection\": { \"observationTokens\": 90000 },\n *   \"storagePath\": \".opencode/memory/observations.db\"\n * }\n * ```\n */\n\nimport { readFile, mkdir } from 'node:fs/promises';\nimport { join, dirname } from 'node:path';\nimport type { ObservationalMemoryOptions } from '@mastra/core/memory';\nimport { LibSQLStore } from '@mastra/libsql';\nimport {\n  ObservationalMemory,\n  TokenCounter,\n  optimizeObservationsForContext,\n  OBSERVATION_CONTINUATION_HINT,\n  getObservationContextPrompt,\n  OBSERVATION_CONTEXT_INSTRUCTIONS,\n} from '@mastra/memory/processors';\nimport type { Plugin } from '@opencode-ai/plugin';\nimport { tool } from '@opencode-ai/plugin';\nimport type { Message, Part } from '@opencode-ai/sdk';\n\nexport type { ObservationalMemoryOptions };\n\n/**\n * Plugin config read from .opencode/mastra.json.\n * Extends Mastra's ObservationalMemoryOptions with opencode-specific fields.\n *\n * In the opencode plugin context, pass string model IDs\n * (e.g., 'google/gemini-2.5-flash') — Mastra's provider registry resolves them.\n */\nexport interface MastraOMPluginConfig extends ObservationalMemoryOptions {\n  /**\n   * Path to the SQLite database file for observation storage.\n   * Relative to the project root.\n   *\n   * @default '.opencode/memory/observations.db'\n   */\n  storagePath?: string;\n}\n\nconst CONFIG_FILE = '.opencode/mastra.json';\nconst DEFAULT_STORAGE_PATH = '.opencode/memory/observations.db';\n\nasync function loadConfig(directory: string): Promise<MastraOMPluginConfig> {\n  try {\n    const configPath = join(directory, CONFIG_FILE);\n    const raw = await readFile(configPath, 'utf-8');\n    return JSON.parse(raw) as MastraOMPluginConfig;\n  } catch {\n    // No config file or invalid JSON — use defaults\n    return {};\n  }\n}\n\n/** Convert opencode messages to MastraDBMessage format.\n * Preserves all part types including tool invocations, files, images, and reasoning.\n */\nfunction convertMessages(messages: { info: Message; parts: Part[] }[], sessionId: string) {\n  return messages\n    .map(({ info, parts }) => {\n      // Convert ALL part types, not just text\n      // Use type assertions since Part union type is restrictive\n      const convertedParts = parts\n        .map((part): any => {\n          const p = part as any;\n          const type = p.type as string;\n\n          if (type === 'text' && p.text) {\n            return { type: 'text', text: p.text };\n          }\n\n          if (type === 'tool-invocation') {\n            return {\n              type: 'tool-invocation',\n              toolInvocation: {\n                toolCallId: p.toolCallId,\n                toolName: p.toolName,\n                args: p.args,\n                result: p.result,\n                state: p.state,\n              },\n            };\n          }\n\n          if (type === 'file') {\n            return {\n              type: 'file',\n              url: p.url,\n              mediaType: p.mediaType,\n            };\n          }\n\n          if (type === 'image') {\n            return {\n              type: 'image',\n              image: p.image,\n            };\n          }\n\n          if (type === 'reasoning' && p.reasoning) {\n            return { type: 'reasoning', reasoning: p.reasoning };\n          }\n\n          // Skip unknown or internal part types\n          if (type?.startsWith('data-om-')) {\n            return null;\n          }\n\n          return null;\n        })\n        .filter((p): p is NonNullable<typeof p> => p !== null);\n\n      if (convertedParts.length === 0) return null;\n      if (info.role !== 'user' && info.role !== 'assistant') return null;\n\n      return {\n        id: info.id,\n        role: info.role,\n        // opencode timestamps are already in milliseconds (JavaScript Date)\n        createdAt: new Date(info.time.created),\n        threadId: sessionId,\n        resourceId: sessionId,\n        content: {\n          format: 2 as const,\n          parts: convertedParts,\n        },\n      };\n    })\n    .filter((m): m is NonNullable<typeof m> => m !== null);\n}\n\nfunction progressBar(current: number, total: number, width = 20): string {\n  const pct = total > 0 ? Math.min(current / total, 1) : 0;\n  const filled = Math.round(pct * width);\n  return `[${'█'.repeat(filled)}${'░'.repeat(width - filled)}] ${(pct * 100).toFixed(1)}%`;\n}\n\nfunction formatTokens(n: number): string {\n  return n >= 1000 ? `${(n / 1000).toFixed(1)}k` : String(n);\n}\n\nfunction resolveThreshold(t: number | { min: number; max: number }): number {\n  return typeof t === 'number' ? t : t.max;\n}\n\nexport const MastraPlugin: Plugin = async ctx => {\n  // Load config from .opencode/mastra.json\n  const config = await loadConfig(ctx.directory);\n\n  // Resolve API keys from opencode's provider store (deferred so it doesn't block plugin init).\n  // .env takes priority — opencode keys only fill in gaps.\n  let credentialsReady = false;\n  const resolveCredentials = async () => {\n    if (credentialsReady) return;\n    try {\n      const providersResponse = await ctx.client.config.providers();\n      if (providersResponse.data) {\n        for (const provider of providersResponse.data.providers) {\n          if (provider.key && provider.env) {\n            for (const envVar of provider.env) {\n              if (!process.env[envVar]) {\n                process.env[envVar] = provider.key;\n              }\n            }\n          }\n        }\n      }\n    } catch {\n      // Credentials not available from opencode — rely on .env\n    }\n    credentialsReady = true;\n  };\n\n  // Storage: SQLite via Mastra's LibSQLStore\n  const dbRelativePath = config.storagePath ?? DEFAULT_STORAGE_PATH;\n  const dbAbsolutePath = join(ctx.directory, dbRelativePath);\n  await mkdir(dirname(dbAbsolutePath), { recursive: true });\n  const storagePath = `file:${dbAbsolutePath}`;\n  const store = new LibSQLStore({ id: 'mastra-om', url: storagePath });\n  await store.init();\n  const storage = await store.getStore('memory');\n  if (!storage) {\n    throw new Error(`@mastra/opencode: failed to initialize memory storage from ${storagePath}`);\n  }\n\n  // Observational Memory: uses Mastra's full OM class\n  // Model string IDs (e.g., 'google/gemini-2.5-flash') are resolved by Mastra's provider registry.\n  const om = new ObservationalMemory({\n    storage,\n    model: config.model,\n    observation: config.observation,\n    reflection: config.reflection,\n    scope: config.scope,\n    shareTokenBudget: config.shareTokenBudget,\n  });\n\n  // Notify user that OM is active (delayed to let TUI initialize)\n  setTimeout(() => {\n    void ctx.client.tui.showToast({\n      body: {\n        title: 'Mastra',\n        message: 'Observational Memory activated',\n        variant: 'success',\n        duration: 3000,\n      },\n    });\n  }, 500);\n\n  return {\n    // Hook: Eagerly initialize OM record on session creation\n    // so diagnostic tools work immediately (before first observation cycle).\n    event: async ({ event }) => {\n      if (event.type === 'session.created') {\n        const sessionId = event.properties.info.id;\n        try {\n          await om.getOrCreateRecord(sessionId);\n        } catch (err) {\n          void ctx.client.tui.showToast({\n            body: {\n              title: 'Mastra',\n              message: `Failed to initialize Observational Memory: ${err instanceof Error ? err.message : String(err)}`,\n              variant: 'error',\n              duration: 5000,\n            },\n          });\n        }\n      }\n    },\n\n    // Hook: Transform messages before they reach the model.\n    // This is the core integration point — observe and shape context in one pass:\n    // 1. Convert opencode messages → MastraDBMessage format\n    // 2. Run observation if threshold is met (with toast notifications)\n    // 3. Inject observation summary and filter out already-observed messages\n    'experimental.chat.messages.transform': async (_input, output) => {\n      const sessionId = output.messages[0]?.info.sessionID;\n      if (!sessionId) return;\n\n      // Ensure API keys are resolved before observation needs a model\n      await resolveCredentials();\n\n      try {\n        const mastraMessages = convertMessages(output.messages, sessionId);\n\n        // Run observation — OM filters for unobserved messages and checks thresholds\n        if (mastraMessages.length > 0) {\n          await om.observe({\n            threadId: sessionId,\n            messages: mastraMessages,\n            hooks: {\n              onObservationStart: () => {\n                void ctx.client.tui.showToast({\n                  body: {\n                    title: 'Mastra',\n                    message: 'Observing conversation...',\n                    variant: 'info',\n                    duration: 10000,\n                  },\n                });\n              },\n              onObservationEnd: () => {\n                void ctx.client.tui.showToast({\n                  body: {\n                    title: 'Mastra',\n                    message: 'Observation complete',\n                    variant: 'success',\n                    duration: 3000,\n                  },\n                });\n              },\n              onReflectionStart: () => {\n                void ctx.client.tui.showToast({\n                  body: {\n                    title: 'Mastra',\n                    message: 'Reflecting on observations...',\n                    variant: 'info',\n                    duration: 10000,\n                  },\n                });\n              },\n              onReflectionEnd: () => {\n                void ctx.client.tui.showToast({\n                  body: {\n                    title: 'Mastra',\n                    message: 'Reflection complete',\n                    variant: 'success',\n                    duration: 3000,\n                  },\n                });\n              },\n            },\n          });\n        }\n\n        // Discard already-observed messages — observations replace them\n        const record = await om.getRecord(sessionId);\n        if (record?.lastObservedAt) {\n          const lastObservedAt = new Date(record.lastObservedAt);\n          output.messages = output.messages.filter(({ info }) => {\n            // opencode timestamps are already in milliseconds\n            const msgTime = new Date(info.time.created);\n            return msgTime > lastObservedAt;\n          });\n        }\n      } catch (err) {\n        void ctx.client.tui.showToast({\n          body: {\n            title: 'Mastra',\n            message: `Observational Memory error: ${err instanceof Error ? err.message : String(err)}`,\n            variant: 'error',\n            duration: 5000,\n          },\n        });\n      }\n    },\n\n    // Hook: Inject observations into the system prompt so the model has compressed context.\n    'experimental.chat.system.transform': async (input, output) => {\n      const sessionId = input.sessionID;\n      if (!sessionId) return;\n\n      try {\n        const observations = await om.getObservations(sessionId);\n        if (!observations) return;\n\n        const optimized = optimizeObservationsForContext(observations);\n        output.system.push(\n          `${getObservationContextPrompt(config.scope)}\\n\\n<observations>\\n${optimized}\\n</observations>\\n\\n${OBSERVATION_CONTEXT_INSTRUCTIONS}\\n\\n${OBSERVATION_CONTINUATION_HINT}`,\n        );\n      } catch {\n        // Non-fatal — model proceeds without observations\n      }\n    },\n\n    // Diagnostic tools for inspecting OM state\n    tool: {\n      memory_status: tool({\n        description: 'Show Observational Memory progress — how close the session is to the next observation and reflection cycle.',\n        args: {},\n        async execute(_args, context) {\n          const threadId = context.sessionID;\n          const record = await om.getRecord(threadId);\n          if (!record) {\n            return 'No Observational Memory record found for this session.';\n          }\n\n          const omConfig = om.config;\n          const obsThreshold = resolveThreshold(omConfig.observation.messageTokens);\n          const refThreshold = resolveThreshold(omConfig.reflection.observationTokens);\n          const obsTokens = record.observationTokenCount ?? 0;\n\n          // Fetch live messages to compute unobserved token count\n          const tokenCounter = new TokenCounter();\n          let unobservedTokens = 0;\n          try {\n            const resp = await ctx.client.session.messages({ path: { id: threadId } });\n            if (resp.data) {\n              const allMastra = convertMessages(resp.data, threadId);\n              const unobserved = record.lastObservedAt\n                ? allMastra.filter(m => m.createdAt > new Date(record.lastObservedAt!))\n                : allMastra;\n              unobservedTokens = tokenCounter.countMessages(unobserved);\n            }\n          } catch {\n            // Fall back to record's pending count\n            unobservedTokens = record.pendingMessageTokens ?? 0;\n          }\n\n          const lines = [\n            `Observational Memory`,\n            `Scope: ${record.scope}  |  Generations: ${record.generationCount ?? 0}`,\n            ``,\n            `── Observation ──────────────────────────────`,\n            `Unobserved: ${formatTokens(unobservedTokens)} / ${formatTokens(obsThreshold)} tokens`,\n            progressBar(unobservedTokens, obsThreshold),\n            ``,\n            `── Reflection ──────────────────────────────`,\n            `Observations: ${formatTokens(obsTokens)} / ${formatTokens(refThreshold)} tokens`,\n            progressBar(obsTokens, refThreshold),\n            ``,\n            `── Status ──────────────────────────────────`,\n            `Last observed: ${record.lastObservedAt ?? 'never'}`,\n            `Observing: ${record.isObserving ? 'yes' : 'no'}  |  Reflecting: ${record.isReflecting ? 'yes' : 'no'}`,\n          ];\n\n          return lines.join('\\n');\n        },\n      }),\n\n      memory_observations: tool({\n        description: 'Show the current active observations stored in Observational Memory.',\n        args: {},\n        async execute(_args, context) {\n          const threadId = context.sessionID;\n          const observations = await om.getObservations(threadId);\n          return observations ?? 'No observations stored yet.';\n        },\n      }),\n    },\n  };\n};\n"],"mappings":"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"}