opencode-lore 0.1.2 → 0.1.4

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/README.md CHANGED
@@ -94,6 +94,17 @@ To use a local clone instead of the published package:
94
94
  }
95
95
  ```
96
96
 
97
+ ## What to expect
98
+
99
+ Once Lore is active, you should notice several changes:
100
+
101
+ - **Higher cache reuse** — Lore keeps your context stable across turns, so the provider cache hits more often. You'll see higher cache read rates and lower costs.
102
+ - **No more compactions** — Lore disables the built-in compaction system and replaces it with incremental distillation. Your context never gets wiped and rebuilt from a lossy summary.
103
+ - **Steady context usage around 70–80%** — the gradient context manager dynamically balances distilled history, raw messages, and knowledge to keep you in the sweet spot — enough room for the model to work, but no wasted context.
104
+ - **Agent doesn't degrade in long sessions** — instead of getting progressively dumber as compaction loses details, the agent stays sharp because distillation preserves the operational facts that matter.
105
+ - **Better recall across and within sessions** — the agent remembers specific details from earlier in the conversation and from previous sessions, including file paths, decisions, error messages, and why things were done a certain way.
106
+ - **Automatic `AGENTS.md` export** — Lore periodically exports curated knowledge to an `AGENTS.md` file in your repo. This is the [universal format](https://agenticaistandard.org/) read by 16+ AI coding tools (Codex, Jules, Cursor, Copilot, Windsurf, and more), so the knowledge benefits every tool — not just OpenCode.
107
+
97
108
  ## What gets stored
98
109
 
99
110
  All data lives locally in `~/.local/share/opencode-lore/lore.db`:
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opencode-lore",
3
- "version": "0.1.2",
3
+ "version": "0.1.4",
4
4
  "type": "module",
5
5
  "license": "MIT",
6
6
  "description": "Three-tier memory architecture for OpenCode — distillation, not summarization",
package/src/db.ts CHANGED
@@ -196,3 +196,14 @@ export function projectId(path: string): string | undefined {
196
196
  .get(path) as { id: string } | null;
197
197
  return row?.id;
198
198
  }
199
+
200
+ /**
201
+ * Returns true if Lore has never been used before (no projects in the DB).
202
+ * Must be called before ensureProject() to get an accurate result.
203
+ */
204
+ export function isFirstRun(): boolean {
205
+ const row = db()
206
+ .query("SELECT COUNT(*) as count FROM projects")
207
+ .get() as { count: number };
208
+ return row.count === 0;
209
+ }
package/src/index.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import type { Plugin } from "@opencode-ai/plugin";
2
2
  import { load, config } from "./config";
3
- import { ensureProject } from "./db";
3
+ import { ensureProject, isFirstRun } from "./db";
4
4
  import * as temporal from "./temporal";
5
5
  import * as ltm from "./ltm";
6
6
  import * as distillation from "./distillation";
@@ -20,8 +20,19 @@ import { createRecallTool } from "./reflect";
20
20
  export const LorePlugin: Plugin = async (ctx) => {
21
21
  const projectPath = ctx.worktree || ctx.directory;
22
22
  await load(ctx.directory);
23
+ let firstRun = isFirstRun();
23
24
  ensureProject(projectPath);
24
25
 
26
+ if (firstRun) {
27
+ ctx.client.tui.showToast({
28
+ body: {
29
+ message: "Lore is active — your agent will get smarter every session",
30
+ variant: "success",
31
+ duration: 5000,
32
+ },
33
+ }).catch(() => {});
34
+ }
35
+
25
36
  // Prune any corrupted/oversized knowledge entries left by the AGENTS.md
26
37
  // backslash-escaping bug or curator hallucinations. Sets confidence → 0
27
38
  // (below the 0.2 query threshold) so they stop polluting the context.
@@ -209,6 +220,18 @@ export const LorePlugin: Plugin = async (ctx) => {
209
220
 
210
221
  // Inject LTM knowledge into system prompt — relevance-ranked and budget-capped.
211
222
  "experimental.chat.system.transform": async (input, output) => {
223
+ // One-time first-run note so the agent acknowledges Lore is active.
224
+ // Cleared after first injection to avoid repeating on subsequent turns.
225
+ if (firstRun) {
226
+ output.system.push(
227
+ "[Lore plugin] This is the first time Lore has been activated. " +
228
+ "Briefly let the user know that Lore is now active and their " +
229
+ "coding agent will get progressively smarter on this codebase " +
230
+ "over time as knowledge accumulates across sessions.",
231
+ );
232
+ firstRun = false;
233
+ }
234
+
212
235
  if (input.model?.limit) {
213
236
  setModelLimits(input.model.limit);
214
237
  }
@@ -289,23 +312,28 @@ export const LorePlugin: Plugin = async (ctx) => {
289
312
  rawBudget: result.rawBudget,
290
313
  updatedAt: Date.now(),
291
314
  };
292
- const url = new URL(
293
- `/session/${sessionID}/message/${lastUserMsg.info.id}/part/${statsPart.id}`,
294
- ctx.serverUrl,
295
- );
296
- const updatedPart = {
297
- ...(statsPart as Record<string, unknown>),
298
- metadata: {
299
- ...((statsPart as { metadata?: Record<string, unknown> }).metadata ?? {}),
300
- lore: loreMeta,
315
+ // Use the SDK's internal HTTP client so the request goes through
316
+ // the same base URL, custom fetch, and interceptors that OpenCode
317
+ // configured — no dependency on ctx.serverUrl being reachable.
318
+ const httpClient = (ctx.client as any)._client;
319
+ httpClient.patch({
320
+ url: "/session/{sessionID}/message/{messageID}/part/{partID}",
321
+ path: {
322
+ sessionID,
323
+ messageID: lastUserMsg.info.id,
324
+ partID: statsPart.id,
325
+ },
326
+ body: {
327
+ ...(statsPart as Record<string, unknown>),
328
+ metadata: {
329
+ ...((statsPart as { metadata?: Record<string, unknown> }).metadata ?? {}),
330
+ lore: loreMeta,
331
+ },
301
332
  },
302
- };
303
- fetch(url, {
304
- method: "PATCH",
305
333
  headers: { "Content-Type": "application/json" },
306
- body: JSON.stringify(updatedPart),
307
- }).catch((e: unknown) => {
308
- console.error("[lore] failed to write gradient stats to part metadata:", e);
334
+ }).catch(() => {
335
+ // Non-critical: gradient stats metadata is for UI display only.
336
+ // Server may not be reachable (e.g. TUI-only mode). Silently ignore.
309
337
  });
310
338
  }
311
339
  },