opencode-memory-pro 1.3.0
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/LICENSE +24 -0
- package/README.md +409 -0
- package/dist/config.d.ts +3 -0
- package/dist/config.js +398 -0
- package/dist/embedder.d.ts +26 -0
- package/dist/embedder.js +260 -0
- package/dist/extract.d.ts +4 -0
- package/dist/extract.js +181 -0
- package/dist/graph.js +701 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +953 -0
- package/dist/llm.d.ts +14 -0
- package/dist/llm.js +212 -0
- package/dist/logger.d.ts +9 -0
- package/dist/logger.js +126 -0
- package/dist/ports.d.ts +34 -0
- package/dist/ports.js +129 -0
- package/dist/preference.d.ts +10 -0
- package/dist/preference.js +125 -0
- package/dist/scope.d.ts +2 -0
- package/dist/scope.js +48 -0
- package/dist/store.d.ts +194 -0
- package/dist/store.js +2738 -0
- package/dist/summarize.d.ts +52 -0
- package/dist/summarize.js +350 -0
- package/dist/tools/episodic.d.ts +68 -0
- package/dist/tools/episodic.js +145 -0
- package/dist/tools/feedback.d.ts +51 -0
- package/dist/tools/feedback.js +112 -0
- package/dist/tools/index.d.ts +3 -0
- package/dist/tools/index.js +3 -0
- package/dist/tools/memory.d.ts +293 -0
- package/dist/tools/memory.js +1487 -0
- package/dist/types.d.ts +489 -0
- package/dist/types.js +54 -0
- package/dist/utils.d.ts +18 -0
- package/dist/utils.js +214 -0
- package/package.json +49 -0
package/dist/scope.js
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { execFileSync } from "node:child_process";
|
|
2
|
+
import { stableHash } from "./utils.js";
|
|
3
|
+
import { resolveMemoryConfig } from "./config.js";
|
|
4
|
+
// SCOPING_TOGGLE: runtime switch between two scoping modes, driven by the
|
|
5
|
+
// plugin config key `scoping` (env override: OPENCODE_MEMORY_PRO_SCOPING):
|
|
6
|
+
// "global" (default) — single-user personal assistant: every scope
|
|
7
|
+
// collapses to "global", so ALL memories are searchable from
|
|
8
|
+
// any session/directory. (This supersedes the old
|
|
9
|
+
// SINGLE_USER_GLOBAL_SCOPE hardcode.)
|
|
10
|
+
// "project" — upstream behavior: memories are partitioned per project by
|
|
11
|
+
// git remote URL (or local directory path hash); the "global"
|
|
12
|
+
// scope is still searched when includeGlobalScope is enabled.
|
|
13
|
+
// The mode is re-read on every call (cheap sidecar read), so flipping the
|
|
14
|
+
// config file takes effect in running processes without a restart.
|
|
15
|
+
export function deriveProjectScope(worktree) {
|
|
16
|
+
if (resolveScoping(worktree) !== "project") {
|
|
17
|
+
return "global";
|
|
18
|
+
}
|
|
19
|
+
const remote = tryGetGitRemote(worktree);
|
|
20
|
+
if (remote) {
|
|
21
|
+
return `project:${stableHash(remote).slice(0, 16)}`;
|
|
22
|
+
}
|
|
23
|
+
return `project:local:${stableHash(worktree).slice(0, 16)}`;
|
|
24
|
+
}
|
|
25
|
+
export function buildScopeFilter(activeScope, includeGlobal) {
|
|
26
|
+
const scopes = includeGlobal ? [activeScope, "global"] : [activeScope];
|
|
27
|
+
return [...new Set(scopes)];
|
|
28
|
+
}
|
|
29
|
+
function resolveScoping(worktree) {
|
|
30
|
+
try {
|
|
31
|
+
return resolveMemoryConfig({}, worktree).scoping === "project" ? "project" : "global";
|
|
32
|
+
}
|
|
33
|
+
catch {
|
|
34
|
+
return "global";
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
function tryGetGitRemote(worktree) {
|
|
38
|
+
try {
|
|
39
|
+
const output = execFileSync("git", ["-C", worktree, "config", "--get", "remote.origin.url"], {
|
|
40
|
+
encoding: "utf8",
|
|
41
|
+
stdio: ["ignore", "pipe", "ignore"],
|
|
42
|
+
}).trim();
|
|
43
|
+
return output.length > 0 ? output : null;
|
|
44
|
+
}
|
|
45
|
+
catch {
|
|
46
|
+
return null;
|
|
47
|
+
}
|
|
48
|
+
}
|
package/dist/store.d.ts
ADDED
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
import type { CitationSource, CitationStatus, DashboardSummary, EffectivenessSummary, EpisodicTaskRecord, MemoryEffectivenessEvent, MemoryExplanation, MemoryFeedbackStats, MemoryRecord, SearchResult, SuccessPattern, TaskState, ValidationOutcome } from "./types.js";
|
|
2
|
+
interface ScopeCacheConfig {
|
|
3
|
+
maxScopes: number;
|
|
4
|
+
maxRecordsPerScope: number;
|
|
5
|
+
enabled: boolean;
|
|
6
|
+
}
|
|
7
|
+
export declare function storeFastCosine(a: number[], b: number[], normA: number, normB: number): number;
|
|
8
|
+
export declare class MemoryStore {
|
|
9
|
+
private readonly dbPath;
|
|
10
|
+
private static readonly MIN_ROWS_FOR_INDEX;
|
|
11
|
+
private lancedb;
|
|
12
|
+
private connection;
|
|
13
|
+
private table;
|
|
14
|
+
private eventTable;
|
|
15
|
+
private episodicTaskTable;
|
|
16
|
+
private indexState;
|
|
17
|
+
private scopeCache;
|
|
18
|
+
private cacheConfig;
|
|
19
|
+
private cacheStats;
|
|
20
|
+
constructor(dbPath: string, cacheConfig?: Partial<ScopeCacheConfig>);
|
|
21
|
+
init(vectorDim: number): Promise<void>;
|
|
22
|
+
close(): void;
|
|
23
|
+
private retentionConfig;
|
|
24
|
+
setRetentionConfig(config: {
|
|
25
|
+
effectivenessEventsDays: number;
|
|
26
|
+
} | undefined): void;
|
|
27
|
+
cleanupExpiredEvents(scopes?: string[], retentionDaysOverride?: number): Promise<number>;
|
|
28
|
+
getEventTtlStatus(): Promise<{
|
|
29
|
+
enabled: boolean;
|
|
30
|
+
retentionDays: number;
|
|
31
|
+
expiredCount: number;
|
|
32
|
+
scopeBreakdown: Record<string, number>;
|
|
33
|
+
}>;
|
|
34
|
+
put(record: MemoryRecord): Promise<void>;
|
|
35
|
+
putEvent(event: MemoryEffectivenessEvent): Promise<void>;
|
|
36
|
+
search(params: {
|
|
37
|
+
query: string;
|
|
38
|
+
queryVector: number[];
|
|
39
|
+
scopes: string[];
|
|
40
|
+
limit: number;
|
|
41
|
+
vectorWeight: number;
|
|
42
|
+
bm25Weight: number;
|
|
43
|
+
minScore: number;
|
|
44
|
+
rrfK?: number;
|
|
45
|
+
recencyBoost?: boolean;
|
|
46
|
+
recencyHalfLifeHours?: number;
|
|
47
|
+
importanceWeight?: number;
|
|
48
|
+
feedbackWeight?: number;
|
|
49
|
+
globalDiscountFactor?: number;
|
|
50
|
+
}): Promise<SearchResult[]>;
|
|
51
|
+
deleteById(id: string, scopes: string[]): Promise<boolean>;
|
|
52
|
+
softDeleteMemory(id: string, scopes: string[]): Promise<boolean>;
|
|
53
|
+
updateMemoryScope(id: string, newScope: string, scopes: string[]): Promise<boolean>;
|
|
54
|
+
readGlobalMemories(limit?: number): Promise<MemoryRecord[]>;
|
|
55
|
+
getUnusedGlobalMemories(unusedDaysThreshold: number, limit?: number): Promise<MemoryRecord[]>;
|
|
56
|
+
clearScope(scope: string): Promise<number>;
|
|
57
|
+
list(scope: string, limit: number): Promise<MemoryRecord[]>;
|
|
58
|
+
listSince(scope: string, sinceTimestamp: number, limit?: number): Promise<MemoryRecord[]>;
|
|
59
|
+
pruneScope(scope: string, maxEntries: number): Promise<number>;
|
|
60
|
+
consolidateDuplicates(scope: string, threshold: number, candidateLimit?: number): Promise<{
|
|
61
|
+
mergedPairs: number;
|
|
62
|
+
updatedRecords: number;
|
|
63
|
+
skippedRecords: number;
|
|
64
|
+
}>;
|
|
65
|
+
private findSimilarVectors;
|
|
66
|
+
countIncompatibleVectors(scopes: string[], expectedDim: number): Promise<number>;
|
|
67
|
+
private matchesId;
|
|
68
|
+
hasMemory(id: string, scopes: string[]): Promise<boolean>;
|
|
69
|
+
updateMemoryUsage(id: string, projectScope: string, scopes: string[]): Promise<void>;
|
|
70
|
+
getCitation(id: string, scopes: string[]): Promise<{
|
|
71
|
+
source: CitationSource;
|
|
72
|
+
timestamp: number;
|
|
73
|
+
status: CitationStatus;
|
|
74
|
+
chain: string[];
|
|
75
|
+
} | null>;
|
|
76
|
+
updateCitation(id: string, scopes: string[], updates: {
|
|
77
|
+
status?: CitationStatus;
|
|
78
|
+
chain?: string[];
|
|
79
|
+
}): Promise<boolean>;
|
|
80
|
+
validateCitation(id: string, scopes: string[]): Promise<{
|
|
81
|
+
valid: boolean;
|
|
82
|
+
status: CitationStatus;
|
|
83
|
+
reason?: string;
|
|
84
|
+
}>;
|
|
85
|
+
explainMemory(id: string, scopes: string[], currentScope: string, recencyHalfLifeHours?: number, globalDiscountFactor?: number): Promise<MemoryExplanation | null>;
|
|
86
|
+
refreshExpiredCitations(scope: string, maxAgeDays?: number): Promise<number>;
|
|
87
|
+
listEvents(scopes: string[], limit: number): Promise<MemoryEffectivenessEvent[]>;
|
|
88
|
+
summarizeEvents(scope: string, includeGlobalScope: boolean): Promise<EffectivenessSummary>;
|
|
89
|
+
getWeeklyEffectivenessSummary(scope: string, includeGlobalScope: boolean, days?: number): Promise<DashboardSummary>;
|
|
90
|
+
private aggregateEvents;
|
|
91
|
+
private calculateTrend;
|
|
92
|
+
private generateInsights;
|
|
93
|
+
getIndexHealth(): {
|
|
94
|
+
vector: boolean;
|
|
95
|
+
fts: boolean;
|
|
96
|
+
ftsError?: string;
|
|
97
|
+
vectorRetries?: number;
|
|
98
|
+
ftsRetries?: number;
|
|
99
|
+
};
|
|
100
|
+
private invalidateScope;
|
|
101
|
+
private getCachedScopes;
|
|
102
|
+
private enforceMaxScopes;
|
|
103
|
+
private requireTable;
|
|
104
|
+
private requireEventTable;
|
|
105
|
+
private ensureEpisodicTaskTable;
|
|
106
|
+
private requireEpisodicTaskTable;
|
|
107
|
+
createTaskEpisode(record: EpisodicTaskRecord): Promise<void>;
|
|
108
|
+
updateTaskState(taskId: string, state: TaskState, scope: string, failureType?: string, errorMessage?: string): Promise<boolean>;
|
|
109
|
+
getTaskEpisode(taskId: string, scope: string): Promise<EpisodicTaskRecord | null>;
|
|
110
|
+
queryTaskEpisodes(scope: string, state?: TaskState, sinceTimestamp?: number): Promise<EpisodicTaskRecord[]>;
|
|
111
|
+
/**
|
|
112
|
+
* Generic helper for appending items to an episodic task's JSON array field.
|
|
113
|
+
* Centralizes the read-parse-push-write pattern across all add*Episode methods.
|
|
114
|
+
*/
|
|
115
|
+
private appendToEpisodeField;
|
|
116
|
+
addCommandToEpisode(taskId: string, scope: string, command: string): Promise<boolean>;
|
|
117
|
+
addValidationOutcome(taskId: string, scope: string, outcome: ValidationOutcome): Promise<boolean>;
|
|
118
|
+
addSuccessPatterns(taskId: string, scope: string, patterns: SuccessPattern[]): Promise<boolean>;
|
|
119
|
+
findSimilarTasks(scope: string, taskDescription: string, minSimilarity?: number, queryVector?: number[]): Promise<EpisodicTaskRecord[]>;
|
|
120
|
+
extractSuccessPatternsFromScope(scope: string): Promise<{
|
|
121
|
+
pattern: SuccessPattern;
|
|
122
|
+
count: number;
|
|
123
|
+
}[]>;
|
|
124
|
+
addRetryAttempt(taskId: string, scope: string, attempt: {
|
|
125
|
+
attemptNumber: number;
|
|
126
|
+
outcome: "success" | "failed" | "abandoned";
|
|
127
|
+
errorMessage?: string;
|
|
128
|
+
failureType?: string;
|
|
129
|
+
}): Promise<boolean>;
|
|
130
|
+
addRecoveryStrategy(taskId: string, scope: string, strategy: {
|
|
131
|
+
name: string;
|
|
132
|
+
succeeded: boolean;
|
|
133
|
+
}): Promise<boolean>;
|
|
134
|
+
suggestRetryBudget(scope: string, minSamples?: number): Promise<{
|
|
135
|
+
suggestedRetries: number;
|
|
136
|
+
confidence: number;
|
|
137
|
+
basedOnCount: number;
|
|
138
|
+
shouldStop: boolean;
|
|
139
|
+
stopReason?: string;
|
|
140
|
+
} | null>;
|
|
141
|
+
suggestRecoveryStrategies(scope: string, taskId: string): Promise<{
|
|
142
|
+
strategy: string;
|
|
143
|
+
reason: string;
|
|
144
|
+
confidence: number;
|
|
145
|
+
basedOnTask?: string;
|
|
146
|
+
}[]>;
|
|
147
|
+
calculateRetryToSuccessRate(scope: string, days?: number): Promise<{
|
|
148
|
+
status: "ok" | "insufficient-data" | "no-failed-tasks";
|
|
149
|
+
rate: number;
|
|
150
|
+
totalFailedTasks: number;
|
|
151
|
+
succeededAfterRetry: number;
|
|
152
|
+
sampleCount: number;
|
|
153
|
+
}>;
|
|
154
|
+
calculateMemoryLift(scope: string, days?: number): Promise<{
|
|
155
|
+
status: "ok" | "insufficient-data" | "no-recall-data";
|
|
156
|
+
lift: number;
|
|
157
|
+
successRateWithRecall: number;
|
|
158
|
+
successRateWithoutRecall: number;
|
|
159
|
+
withRecallCount: number;
|
|
160
|
+
withoutRecallCount: number;
|
|
161
|
+
}>;
|
|
162
|
+
private taskUsedRecall;
|
|
163
|
+
getKpiSummary(scope: string, days?: number): Promise<import("./types.js").KpiSummary>;
|
|
164
|
+
readEventsByScopes(scopes: string[]): Promise<MemoryEffectivenessEvent[]>;
|
|
165
|
+
/**
|
|
166
|
+
* Get feedback stats for a set of memory IDs.
|
|
167
|
+
* Returns a map of memoryId -> feedback stats.
|
|
168
|
+
* Only considers feedback within the last 30 days.
|
|
169
|
+
*/
|
|
170
|
+
getMemoryFeedbackStatsMap(memoryIds: string[], scopes: string[]): Promise<Map<string, MemoryFeedbackStats>>;
|
|
171
|
+
private readByScopesIncludingMerged;
|
|
172
|
+
private readByScopes;
|
|
173
|
+
private ensureIndexes;
|
|
174
|
+
/**
|
|
175
|
+
* Returns true if the error message indicates a LanceDB retryable commit conflict,
|
|
176
|
+
* meaning another concurrent process may have already created the same index.
|
|
177
|
+
*/
|
|
178
|
+
private isCommitConflict;
|
|
179
|
+
/**
|
|
180
|
+
* Create vector index with exponential backoff retry and existence check.
|
|
181
|
+
* Handles concurrent-process commit conflicts by re-verifying index existence
|
|
182
|
+
* after each conflict error, and adds jitter to avoid thundering-herd re-collision.
|
|
183
|
+
*/
|
|
184
|
+
private createVectorIndexWithRetry;
|
|
185
|
+
/**
|
|
186
|
+
* Create FTS index with exponential backoff retry and existence check.
|
|
187
|
+
* Handles concurrent-process commit conflicts by re-verifying index existence
|
|
188
|
+
* after each conflict error, and adds jitter to avoid thundering-herd re-collision.
|
|
189
|
+
*/
|
|
190
|
+
private createFtsIndexWithRetry;
|
|
191
|
+
private ensureMemoriesTableCompatibility;
|
|
192
|
+
private ensureEventTableCompatibility;
|
|
193
|
+
}
|
|
194
|
+
export {};
|