opencode-memory-pro 1.3.6 → 1.3.7
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 +47 -1
- package/dist/index.js +1 -1
- package/dist/scope.js +12 -0
- package/dist/tools/episodic.js +6 -6
- package/dist/tools/feedback.js +5 -5
- package/dist/tools/memory.js +24 -23
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -40,7 +40,7 @@ Published on npm — install directly (requires OpenCode ≥ 1.x and Node.js ≥
|
|
|
40
40
|
opencode plugin opencode-memory-pro
|
|
41
41
|
```
|
|
42
42
|
|
|
43
|
-
The latest release is **v1.3.
|
|
43
|
+
The latest release is **v1.3.7** on [npm](https://www.npmjs.com/package/opencode-memory-pro); source and releases are on [GitHub](https://github.com/tman204-50/opencode-memory-pro).
|
|
44
44
|
|
|
45
45
|
Remove the old plugin pin at the same time:
|
|
46
46
|
|
|
@@ -408,6 +408,52 @@ so your memories and graph carry over untouched.
|
|
|
408
408
|
|
|
409
409
|
## Changelog
|
|
410
410
|
|
|
411
|
+
### v1.3.7 (2026-09-06)
|
|
412
|
+
|
|
413
|
+
Scope normalization — fixes lost memories when a `scope` argument is
|
|
414
|
+
explicitly passed to a tool while `scoping` is `"global"`:
|
|
415
|
+
|
|
416
|
+
- **Explicit scopes now collapse to `global` in global mode**: previously
|
|
417
|
+
`memory_remember(scope="project")` (and every other tool accepting a `scope`
|
|
418
|
+
arg) stored the row under the literal string `"project"` — but scope-filtered
|
|
419
|
+
reads derive the scope via `deriveProjectScope()`, which returns `"global"`
|
|
420
|
+
in global mode, so the memory was effectively lost (invisible to search,
|
|
421
|
+
promote, why, `memory_global_list`, ...; reachable only by passing
|
|
422
|
+
`scope="project"` explicitly).
|
|
423
|
+
- **New `resolveScope(scope, worktree)` helper** in `dist/scope.js` — collapses
|
|
424
|
+
any explicit scope to `"global"` in global mode and honors it in project
|
|
425
|
+
mode (falling back to the derived project scope when omitted). Applied to all
|
|
426
|
+
30 scope-arg sites across `dist/tools/memory.js`, `dist/tools/episodic.js`,
|
|
427
|
+
and `dist/tools/feedback.js`, including `memory_clear`, which previously
|
|
428
|
+
called `clearScope(args.scope)` without any normalization.
|
|
429
|
+
- **Tests**: two new unit tests cover the collapse-to-global and
|
|
430
|
+
honor-in-project-mode behavior.
|
|
431
|
+
|
|
432
|
+
### v1.3.6 (2026-09-06)
|
|
433
|
+
|
|
434
|
+
Compaction lock hardening — fixes the "Compaction commit failed; leaving N
|
|
435
|
+
rewritten fragment(s) in place for GC" warning reappearing on the TUI at
|
|
436
|
+
startup / first turn when two opencode instances share one store:
|
|
437
|
+
|
|
438
|
+
- **No more lock stealing during the owner's init window**: the owner creates
|
|
439
|
+
`.optimize.lock` with `open("wx")` and *then* writes its pid; a contender
|
|
440
|
+
reading in between saw an empty file, declared it stale, deleted it, and
|
|
441
|
+
created its own — so both processes "owned" the lock and raced `optimize()`
|
|
442
|
+
(the native LanceDB stderr line is uninterceptable by the plugin). The lock
|
|
443
|
+
now treats an empty file as "being initialized" for a short grace instead of
|
|
444
|
+
reclaiming it.
|
|
445
|
+
- **Contenders wait instead of giving up instantly**: when a live process holds
|
|
446
|
+
the lock, the second instance now polls up to 10s for it to finish (serializing
|
|
447
|
+
compaction across processes) before skipping this cycle and retrying next
|
|
448
|
+
interval, instead of racing it.
|
|
449
|
+
- **In-process guard set synchronously**: `maybeOptimizeAll` now sets
|
|
450
|
+
`optimizing = true` before any `await`, so overlapping calls in one process
|
|
451
|
+
(fire-and-forget write trigger + awaited explicit call on the first turn)
|
|
452
|
+
can no longer both run `optimize()` concurrently.
|
|
453
|
+
- **Tests**: two new unit tests cover the open→write TOCTOU (old lock returns
|
|
454
|
+
`true` and steals; new lock returns `false` and preserves ownership) and
|
|
455
|
+
stale-lock reclamation.
|
|
456
|
+
|
|
411
457
|
### v1.3.5 (2026-09-06)
|
|
412
458
|
|
|
413
459
|
Code-review hardening pass — bug fixes, no breaking changes:
|
package/dist/index.js
CHANGED
|
@@ -11,7 +11,7 @@ import { requestLLMCapture, isOwnSession } from "./llm.js";
|
|
|
11
11
|
import { createMemoryTools, createFeedbackTools, createEpisodicTools } from "./tools/index.js";
|
|
12
12
|
import { sweepExpiredMemories } from "./tools/memory.js";
|
|
13
13
|
import { createGraphStore } from "./graph.js";
|
|
14
|
-
const PLUGIN_VERSION = "1.3.
|
|
14
|
+
const PLUGIN_VERSION = "1.3.7";
|
|
15
15
|
const SCHEMA_VERSION = 1;
|
|
16
16
|
// Event-driven dedup: run consolidateDuplicates on session.idle (throttled to
|
|
17
17
|
// this interval so chatty sessions aren't re-scanning the store every turn)
|
package/dist/scope.js
CHANGED
|
@@ -26,6 +26,18 @@ export function buildScopeFilter(activeScope, includeGlobal) {
|
|
|
26
26
|
const scopes = includeGlobal ? [activeScope, "global"] : [activeScope];
|
|
27
27
|
return [...new Set(scopes)];
|
|
28
28
|
}
|
|
29
|
+
// SCOPE_NORMALIZE (1.3.7): resolves a caller-supplied scope argument against
|
|
30
|
+
// the active scoping mode. In "global" mode every explicit scope (e.g. a
|
|
31
|
+
// memory_remember(scope="project")) collapses to "global" — otherwise such
|
|
32
|
+
// rows would be stored under a literal scope that scope-filtered tools never
|
|
33
|
+
// query (the rows are effectively lost). In "project" mode the argument is
|
|
34
|
+
// honored, falling back to the derived project scope.
|
|
35
|
+
export function resolveScope(scope, worktree) {
|
|
36
|
+
if (resolveScoping(worktree) !== "project") {
|
|
37
|
+
return "global";
|
|
38
|
+
}
|
|
39
|
+
return scope ?? deriveProjectScope(worktree);
|
|
40
|
+
}
|
|
29
41
|
function resolveScoping(worktree) {
|
|
30
42
|
try {
|
|
31
43
|
return resolveMemoryConfig({}, worktree).scoping === "project" ? "project" : "global";
|
package/dist/tools/episodic.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { tool } from "@opencode-ai/plugin";
|
|
2
|
-
import { deriveProjectScope } from "../scope.js";
|
|
2
|
+
import { deriveProjectScope, resolveScope } from "../scope.js";
|
|
3
3
|
import { generateId, parseJsonObject } from "../utils.js";
|
|
4
4
|
function unavailableMessage(provider) {
|
|
5
5
|
return `Memory store unavailable (${provider} embedding may be offline). Will retry automatically.`;
|
|
@@ -17,7 +17,7 @@ export function createEpisodicTools(state) {
|
|
|
17
17
|
await state.ensureInitialized();
|
|
18
18
|
if (!state.initialized)
|
|
19
19
|
return unavailableMessage(state.config.embedding.provider);
|
|
20
|
-
const activeScope = args.scope
|
|
20
|
+
const activeScope = resolveScope(args.scope, context.directory || context.worktree);
|
|
21
21
|
const episode = {
|
|
22
22
|
id: generateId(),
|
|
23
23
|
sessionId: context.sessionID,
|
|
@@ -48,7 +48,7 @@ export function createEpisodicTools(state) {
|
|
|
48
48
|
await state.ensureInitialized();
|
|
49
49
|
if (!state.initialized)
|
|
50
50
|
return unavailableMessage(state.config.embedding.provider);
|
|
51
|
-
const activeScope = args.scope
|
|
51
|
+
const activeScope = resolveScope(args.scope, context.directory || context.worktree);
|
|
52
52
|
const stateFilter = args.state;
|
|
53
53
|
const episodes = await state.store.queryTaskEpisodes(activeScope, stateFilter);
|
|
54
54
|
if (episodes.length === 0) {
|
|
@@ -73,7 +73,7 @@ export function createEpisodicTools(state) {
|
|
|
73
73
|
await state.ensureInitialized();
|
|
74
74
|
if (!state.initialized)
|
|
75
75
|
return unavailableMessage(state.config.embedding.provider);
|
|
76
|
-
const activeScope = args.scope
|
|
76
|
+
const activeScope = resolveScope(args.scope, context.directory || context.worktree);
|
|
77
77
|
let queryVector = [];
|
|
78
78
|
try {
|
|
79
79
|
queryVector = await state.embedder.embed(args.query);
|
|
@@ -107,7 +107,7 @@ export function createEpisodicTools(state) {
|
|
|
107
107
|
await state.ensureInitialized();
|
|
108
108
|
if (!state.initialized)
|
|
109
109
|
return unavailableMessage(state.config.embedding.provider);
|
|
110
|
-
const activeScope = args.scope
|
|
110
|
+
const activeScope = resolveScope(args.scope, context.directory || context.worktree);
|
|
111
111
|
const result = await state.store.suggestRetryBudget(activeScope, args.minSamples ?? 3);
|
|
112
112
|
if (!result) {
|
|
113
113
|
return `Insufficient data for retry budget suggestion (need at least ${args.minSamples} failed tasks)`;
|
|
@@ -131,7 +131,7 @@ export function createEpisodicTools(state) {
|
|
|
131
131
|
await state.ensureInitialized();
|
|
132
132
|
if (!state.initialized)
|
|
133
133
|
return unavailableMessage(state.config.embedding.provider);
|
|
134
|
-
const activeScope = args.scope
|
|
134
|
+
const activeScope = resolveScope(args.scope, context.directory || context.worktree);
|
|
135
135
|
const strategies = await state.store.suggestRecoveryStrategies(activeScope, args.taskId);
|
|
136
136
|
if (strategies.length === 0) {
|
|
137
137
|
return `No recovery strategies found for task ${args.taskId}`;
|
package/dist/tools/feedback.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { tool } from "@opencode-ai/plugin";
|
|
2
|
-
import { deriveProjectScope, buildScopeFilter } from "../scope.js";
|
|
2
|
+
import { deriveProjectScope, buildScopeFilter, resolveScope } from "../scope.js";
|
|
3
3
|
import { generateId } from "../utils.js";
|
|
4
4
|
function unavailableMessage(provider) {
|
|
5
5
|
return `Memory store unavailable (${provider} embedding may be offline). Will retry automatically.`;
|
|
@@ -17,7 +17,7 @@ export function createFeedbackTools(state) {
|
|
|
17
17
|
await state.ensureInitialized();
|
|
18
18
|
if (!state.initialized)
|
|
19
19
|
return unavailableMessage(state.config.embedding.provider);
|
|
20
|
-
const scope = args.scope
|
|
20
|
+
const scope = resolveScope(args.scope, context.directory || context.worktree);
|
|
21
21
|
await state.store.putEvent({
|
|
22
22
|
id: generateId(),
|
|
23
23
|
type: "feedback",
|
|
@@ -43,7 +43,7 @@ export function createFeedbackTools(state) {
|
|
|
43
43
|
await state.ensureInitialized();
|
|
44
44
|
if (!state.initialized)
|
|
45
45
|
return unavailableMessage(state.config.embedding.provider);
|
|
46
|
-
const scope = args.scope
|
|
46
|
+
const scope = resolveScope(args.scope, context.directory || context.worktree);
|
|
47
47
|
const scopes = buildScopeFilter(scope, state.config.includeGlobalScope);
|
|
48
48
|
const exists = await state.store.hasMemory(args.id, scopes);
|
|
49
49
|
if (!exists) {
|
|
@@ -74,7 +74,7 @@ export function createFeedbackTools(state) {
|
|
|
74
74
|
await state.ensureInitialized();
|
|
75
75
|
if (!state.initialized)
|
|
76
76
|
return unavailableMessage(state.config.embedding.provider);
|
|
77
|
-
const scope = args.scope
|
|
77
|
+
const scope = resolveScope(args.scope, context.directory || context.worktree);
|
|
78
78
|
const scopes = buildScopeFilter(scope, state.config.includeGlobalScope);
|
|
79
79
|
const exists = await state.store.hasMemory(args.id, scopes);
|
|
80
80
|
if (!exists) {
|
|
@@ -103,7 +103,7 @@ export function createFeedbackTools(state) {
|
|
|
103
103
|
await state.ensureInitialized();
|
|
104
104
|
if (!state.initialized)
|
|
105
105
|
return unavailableMessage(state.config.embedding.provider);
|
|
106
|
-
const scope = args.scope
|
|
106
|
+
const scope = resolveScope(args.scope, context.directory || context.worktree);
|
|
107
107
|
const summary = await state.store.summarizeEvents(scope, state.config.includeGlobalScope);
|
|
108
108
|
return JSON.stringify(summary, null, 2);
|
|
109
109
|
},
|
package/dist/tools/memory.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { tool } from "@opencode-ai/plugin";
|
|
2
|
-
import { deriveProjectScope, buildScopeFilter } from "../scope.js";
|
|
2
|
+
import { deriveProjectScope, buildScopeFilter, resolveScope } from "../scope.js";
|
|
3
3
|
import { generateId } from "../utils.js";
|
|
4
4
|
import { getEmbedderHealth } from "../embedder.js";
|
|
5
5
|
import { extractiveDigest, retentionCandidates } from "../store.js";
|
|
@@ -43,7 +43,7 @@ export function createMemoryTools(state) {
|
|
|
43
43
|
await state.ensureInitialized();
|
|
44
44
|
if (!state.initialized)
|
|
45
45
|
return unavailableMessage(state.config.embedding.provider);
|
|
46
|
-
const activeScope = args.scope
|
|
46
|
+
const activeScope = resolveScope(args.scope, context.directory || context.worktree);
|
|
47
47
|
const scopes = buildScopeFilter(activeScope, state.config.includeGlobalScope);
|
|
48
48
|
let queryVector = [];
|
|
49
49
|
let embedderFailed = false;
|
|
@@ -208,7 +208,7 @@ export function createMemoryTools(state) {
|
|
|
208
208
|
if (!args.confirm) {
|
|
209
209
|
return "Rejected: memory_delete requires confirm=true.";
|
|
210
210
|
}
|
|
211
|
-
const activeScope = args.scope
|
|
211
|
+
const activeScope = resolveScope(args.scope, context.directory || context.worktree);
|
|
212
212
|
const scopes = buildScopeFilter(activeScope, state.config.includeGlobalScope);
|
|
213
213
|
const deleted = await state.store.deleteById(args.id, scopes);
|
|
214
214
|
return deleted ? `Deleted memory ${args.id}.` : `Memory ${args.id} not found in current scope.`;
|
|
@@ -220,15 +220,16 @@ export function createMemoryTools(state) {
|
|
|
220
220
|
scope: tool.schema.string(),
|
|
221
221
|
confirm: tool.schema.boolean().default(false),
|
|
222
222
|
},
|
|
223
|
-
execute: async (args) => {
|
|
223
|
+
execute: async (args, context) => {
|
|
224
224
|
await state.ensureInitialized();
|
|
225
225
|
if (!state.initialized)
|
|
226
226
|
return unavailableMessage(state.config.embedding.provider);
|
|
227
227
|
if (!args.confirm) {
|
|
228
228
|
return "Rejected: destructive clear requires confirm=true.";
|
|
229
229
|
}
|
|
230
|
-
const
|
|
231
|
-
|
|
230
|
+
const activeScope = resolveScope(args.scope, context.directory || context.worktree);
|
|
231
|
+
const count = await state.store.clearScope(activeScope);
|
|
232
|
+
return `Cleared ${count} memories from scope ${activeScope}.`;
|
|
232
233
|
},
|
|
233
234
|
}),
|
|
234
235
|
memory_stats: tool({
|
|
@@ -240,7 +241,7 @@ export function createMemoryTools(state) {
|
|
|
240
241
|
await state.ensureInitialized();
|
|
241
242
|
if (!state.initialized)
|
|
242
243
|
return unavailableMessage(state.config.embedding.provider);
|
|
243
|
-
const scope = args.scope
|
|
244
|
+
const scope = resolveScope(args.scope, context.directory || context.worktree);
|
|
244
245
|
const entries = await state.store.list(scope, 20);
|
|
245
246
|
const incompatibleVectors = await state.store.countIncompatibleVectors(buildScopeFilter(scope, state.config.includeGlobalScope), await state.embedder.dim());
|
|
246
247
|
const health = state.store.getIndexHealth();
|
|
@@ -303,7 +304,7 @@ export function createMemoryTools(state) {
|
|
|
303
304
|
// passed `args.scope` to cleanupExpiredEvents where `undefined`
|
|
304
305
|
// meant ALL scopes (and the store's `scope LIKE 'project:%'`
|
|
305
306
|
// matched every project scope).
|
|
306
|
-
const activeScope = args.scope
|
|
307
|
+
const activeScope = resolveScope(args.scope, context.directory || context.worktree);
|
|
307
308
|
const scopes = buildScopeFilter(activeScope, state.config.includeGlobalScope);
|
|
308
309
|
const cutoffTimestamp = Date.now() - status.retentionDays * 24 * 60 * 60 * 1000;
|
|
309
310
|
if (args.dryRun) {
|
|
@@ -370,7 +371,7 @@ export function createMemoryTools(state) {
|
|
|
370
371
|
if (args.text.length < state.config.minCaptureChars) {
|
|
371
372
|
return `Content too short (minimum ${state.config.minCaptureChars} characters).`;
|
|
372
373
|
}
|
|
373
|
-
const activeScope = args.scope
|
|
374
|
+
const activeScope = resolveScope(args.scope, context.directory || context.worktree);
|
|
374
375
|
let vector = [];
|
|
375
376
|
try {
|
|
376
377
|
vector = await state.embedder.embed(args.text);
|
|
@@ -443,7 +444,7 @@ export function createMemoryTools(state) {
|
|
|
443
444
|
await state.ensureInitialized();
|
|
444
445
|
if (!state.initialized)
|
|
445
446
|
return unavailableMessage(state.config.embedding.provider);
|
|
446
|
-
const activeScope = args.scope
|
|
447
|
+
const activeScope = resolveScope(args.scope, context.directory || context.worktree);
|
|
447
448
|
const scopes = buildScopeFilter(activeScope, state.config.includeGlobalScope);
|
|
448
449
|
if (args.force) {
|
|
449
450
|
const deleted = await state.store.deleteById(args.id, scopes);
|
|
@@ -499,7 +500,7 @@ export function createMemoryTools(state) {
|
|
|
499
500
|
await state.ensureInitialized();
|
|
500
501
|
if (!state.initialized)
|
|
501
502
|
return unavailableMessage(state.config.embedding.provider);
|
|
502
|
-
const activeScope = args.scope
|
|
503
|
+
const activeScope = resolveScope(args.scope, context.directory || context.worktree);
|
|
503
504
|
const scopes = buildScopeFilter(activeScope, state.config.includeGlobalScope);
|
|
504
505
|
const citation = await state.store.getCitation(args.id, scopes);
|
|
505
506
|
if (!citation) {
|
|
@@ -535,7 +536,7 @@ export function createMemoryTools(state) {
|
|
|
535
536
|
await state.ensureInitialized();
|
|
536
537
|
if (!state.initialized)
|
|
537
538
|
return unavailableMessage(state.config.embedding.provider);
|
|
538
|
-
const activeScope = args.scope
|
|
539
|
+
const activeScope = resolveScope(args.scope, context.directory || context.worktree);
|
|
539
540
|
const scopes = buildScopeFilter(activeScope, state.config.includeGlobalScope);
|
|
540
541
|
const result = await state.store.validateCitation(args.id, scopes);
|
|
541
542
|
return JSON.stringify({
|
|
@@ -556,7 +557,7 @@ export function createMemoryTools(state) {
|
|
|
556
557
|
await state.ensureInitialized();
|
|
557
558
|
if (!state.initialized)
|
|
558
559
|
return unavailableMessage(state.config.embedding.provider);
|
|
559
|
-
const activeScope = args.scope
|
|
560
|
+
const activeScope = resolveScope(args.scope, context.directory || context.worktree);
|
|
560
561
|
const sinceTimestamp = Date.now() - (args.days ?? 7) * 24 * 60 * 60 * 1000;
|
|
561
562
|
const memories = await state.store.listSince(activeScope, sinceTimestamp, 1000);
|
|
562
563
|
if (memories.length === 0) {
|
|
@@ -598,7 +599,7 @@ ${recentSamples}
|
|
|
598
599
|
await state.ensureInitialized();
|
|
599
600
|
if (!state.initialized)
|
|
600
601
|
return unavailableMessage(state.config.embedding.provider);
|
|
601
|
-
const activeScope = args.scope
|
|
602
|
+
const activeScope = resolveScope(args.scope, context.directory || context.worktree);
|
|
602
603
|
const scopes = buildScopeFilter(activeScope, state.config.includeGlobalScope);
|
|
603
604
|
const explanation = await state.store.explainMemory(args.id, scopes, activeScope, state.config.retrieval.recencyHalfLifeHours, state.config.globalDiscountFactor);
|
|
604
605
|
if (!explanation) {
|
|
@@ -637,7 +638,7 @@ Explanation:
|
|
|
637
638
|
if (!lastRecall) {
|
|
638
639
|
return "No recent recall to explain. Use memory_search or wait for auto-recall first.";
|
|
639
640
|
}
|
|
640
|
-
const activeScope = args.scope
|
|
641
|
+
const activeScope = resolveScope(args.scope, context.directory || context.worktree);
|
|
641
642
|
const scopes = buildScopeFilter(activeScope, state.config.includeGlobalScope);
|
|
642
643
|
const explanations = [];
|
|
643
644
|
for (const result of lastRecall.results) {
|
|
@@ -697,7 +698,7 @@ ${explanations.join("\n")}`;
|
|
|
697
698
|
if (!args.confirm) {
|
|
698
699
|
return "Rejected: memory_scope_demote requires confirm=true.";
|
|
699
700
|
}
|
|
700
|
-
const projectScope = args.scope
|
|
701
|
+
const projectScope = resolveScope(args.scope, context.directory || context.worktree);
|
|
701
702
|
const globalExists = await state.store.hasMemory(args.id, ["global"]);
|
|
702
703
|
if (!globalExists) {
|
|
703
704
|
return `Memory ${args.id} not found in global scope or is not a global memory.`;
|
|
@@ -774,7 +775,7 @@ ${explanations.join("\n")}`;
|
|
|
774
775
|
if (!args.confirm) {
|
|
775
776
|
return "Rejected: memory_consolidate requires confirm=true.";
|
|
776
777
|
}
|
|
777
|
-
const targetScope = args.scope
|
|
778
|
+
const targetScope = resolveScope(args.scope, context.directory || context.worktree);
|
|
778
779
|
if (state.consolidationInProgress.get(targetScope)) {
|
|
779
780
|
return JSON.stringify({ scope: targetScope, status: "already_in_progress", message: "Consolidation already in progress for this scope" });
|
|
780
781
|
}
|
|
@@ -980,7 +981,7 @@ ${explanations.join("\n")}`;
|
|
|
980
981
|
await state.ensureInitialized();
|
|
981
982
|
if (!state.initialized)
|
|
982
983
|
return unavailableMessage(state.config.embedding.provider);
|
|
983
|
-
const scope = args.scope
|
|
984
|
+
const scope = resolveScope(args.scope, context.directory || context.worktree);
|
|
984
985
|
const dashboard = await state.store.getWeeklyEffectivenessSummary(scope, state.config.includeGlobalScope, args.days ?? 7);
|
|
985
986
|
return JSON.stringify(dashboard, null, 2);
|
|
986
987
|
},
|
|
@@ -995,7 +996,7 @@ ${explanations.join("\n")}`;
|
|
|
995
996
|
await state.ensureInitialized();
|
|
996
997
|
if (!state.initialized)
|
|
997
998
|
return unavailableMessage(state.config.embedding.provider);
|
|
998
|
-
const scope = args.scope
|
|
999
|
+
const scope = resolveScope(args.scope, context.directory || context.worktree);
|
|
999
1000
|
const kpi = await state.store.getKpiSummary(scope, args.days ?? 30);
|
|
1000
1001
|
return JSON.stringify(kpi, null, 2);
|
|
1001
1002
|
},
|
|
@@ -1012,7 +1013,7 @@ ${explanations.join("\n")}`;
|
|
|
1012
1013
|
await state.ensureInitialized();
|
|
1013
1014
|
if (!state.initialized)
|
|
1014
1015
|
return unavailableMessage(state.config.embedding.provider);
|
|
1015
|
-
const activeScope = args.scope
|
|
1016
|
+
const activeScope = resolveScope(args.scope, context.directory || context.worktree);
|
|
1016
1017
|
const scopes = buildScopeFilter(activeScope, state.config.includeGlobalScope);
|
|
1017
1018
|
const records = await state.store.exportAllRecords(scopes);
|
|
1018
1019
|
if (args.dryRun) {
|
|
@@ -1073,7 +1074,7 @@ ${explanations.join("\n")}`;
|
|
|
1073
1074
|
if (!Array.isArray(payload?.memories)) {
|
|
1074
1075
|
return JSON.stringify({ error: "Not a memory_export backup (missing memories array)" }, null, 2);
|
|
1075
1076
|
}
|
|
1076
|
-
const activeScope = args.scope
|
|
1077
|
+
const activeScope = resolveScope(args.scope, context.directory || context.worktree);
|
|
1077
1078
|
const scopes = buildScopeFilter(activeScope, state.config.includeGlobalScope);
|
|
1078
1079
|
const source = payload?.memories ?? [];
|
|
1079
1080
|
let imported = 0;
|
|
@@ -1203,7 +1204,7 @@ ${explanations.join("\n")}`;
|
|
|
1203
1204
|
if (summarizeCfg.enabled === false) {
|
|
1204
1205
|
return JSON.stringify({ error: "Summarization disabled via config summarize.enabled=false" }, null, 2);
|
|
1205
1206
|
}
|
|
1206
|
-
const activeScope = args.scope
|
|
1207
|
+
const activeScope = resolveScope(args.scope, context.directory || context.worktree);
|
|
1207
1208
|
const scopes = buildScopeFilter(activeScope, state.config.includeGlobalScope);
|
|
1208
1209
|
const minAgeDays = args.minAgeDays ?? summarizeCfg.minAgeDays;
|
|
1209
1210
|
const minGroupSize = args.minGroupSize ?? summarizeCfg.minGroupSize;
|
|
@@ -1347,7 +1348,7 @@ ${explanations.join("\n")}`;
|
|
|
1347
1348
|
return JSON.stringify({ error: "Memory retention disabled via config retention.memory.enabled=false" }, null, 2);
|
|
1348
1349
|
}
|
|
1349
1350
|
const result = await sweepExpiredMemories(state, {
|
|
1350
|
-
scope: args.scope
|
|
1351
|
+
scope: resolveScope(args.scope, context.directory || context.worktree),
|
|
1351
1352
|
dryRun: args.dryRun === true,
|
|
1352
1353
|
unusedDays: args.unusedDays,
|
|
1353
1354
|
minAgeDays: args.minAgeDays,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "opencode-memory-pro",
|
|
3
|
-
"version": "1.3.
|
|
3
|
+
"version": "1.3.7",
|
|
4
4
|
"description": "LanceDB-backed long-term memory provider for OpenCode — standalone fork of lancedb-opencode-pro with entity graph, lifecycle, and retention",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|