@rvboris/opencode-mempalace 0.3.0 → 0.5.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/README.md +94 -25
- package/README.ru.md +94 -25
- package/dist/bridge/mempalace_adapter.py +26 -0
- package/dist/plugin/hooks/event.js +17 -6
- package/dist/plugin/lib/adapter.d.ts +21 -0
- package/dist/plugin/lib/adapter.js +180 -56
- package/dist/plugin/lib/autosave.d.ts +1 -0
- package/dist/plugin/lib/autosave.js +23 -0
- package/dist/plugin/lib/constants.d.ts +6 -0
- package/dist/plugin/lib/constants.js +10 -0
- package/dist/plugin/lib/context.d.ts +0 -1
- package/dist/plugin/lib/context.js +2 -15
- package/dist/plugin/lib/derive.d.ts +2 -0
- package/dist/plugin/lib/derive.js +21 -0
- package/dist/plugin/lib/status.d.ts +14 -3
- package/dist/plugin/lib/status.js +72 -27
- package/dist/plugin/lib/types.d.ts +51 -3
- package/dist/plugin/lib/types.js +2 -2
- package/dist/plugin/tools/mempalace-memory.d.ts +30 -1
- package/dist/plugin/tools/mempalace-memory.js +99 -3
- package/dist/plugin/tools/mempalace-status.js +1 -1
- package/dist/plugin/tui/hud.js +1 -1
- package/package.json +3 -3
|
@@ -7,10 +7,18 @@ export type MemoryScope = (typeof MEMORY_SCOPES)[number];
|
|
|
7
7
|
export declare const USER_MEMORY_ROOMS: readonly ["preferences", "workflow", "communication"];
|
|
8
8
|
export declare const PROJECT_MEMORY_ROOMS: readonly ["architecture", "workflow", "decisions", "bugs", "setup"];
|
|
9
9
|
export type KnownMemoryRoom = (typeof USER_MEMORY_ROOMS)[number] | (typeof PROJECT_MEMORY_ROOMS)[number];
|
|
10
|
-
export declare const TOOL_MEMORY_MODES: readonly ["save", "search", "kg_add", "diary_write"];
|
|
10
|
+
export declare const TOOL_MEMORY_MODES: readonly ["save", "search", "kg_add", "diary_write", "delete", "delete_by_source", "kg_query", "diary_read", "checkpoint"];
|
|
11
11
|
export type ToolMemoryMode = (typeof TOOL_MEMORY_MODES)[number];
|
|
12
|
-
export declare const ADAPTER_MODES: readonly ["save", "search", "kg_add", "diary_write", "mine_messages"];
|
|
12
|
+
export declare const ADAPTER_MODES: readonly ["save", "search", "kg_add", "diary_write", "mine_messages", "delete", "delete_by_source", "kg_query", "diary_read", "checkpoint"];
|
|
13
13
|
export type AdapterMode = (typeof ADAPTER_MODES)[number];
|
|
14
|
+
export type RetrievalVerdict = "none" | "cited" | "improved" | "saved-time" | "unknown";
|
|
15
|
+
export type RetrievalJudgeCounters = {
|
|
16
|
+
none: number;
|
|
17
|
+
cited: number;
|
|
18
|
+
improved: number;
|
|
19
|
+
savedTime: number;
|
|
20
|
+
unknown: number;
|
|
21
|
+
};
|
|
14
22
|
export declare const SESSION_EVENT_TYPES: readonly ["session.idle", "session.compacted", "session.deleted", "session.error", "session.updated", "message.updated"];
|
|
15
23
|
export type SessionEventType = (typeof SESSION_EVENT_TYPES)[number];
|
|
16
24
|
export type AppLogLevel = "info" | "warn" | "error";
|
|
@@ -49,6 +57,7 @@ export type SearchAdapterRequest = {
|
|
|
49
57
|
wing: string;
|
|
50
58
|
room?: string;
|
|
51
59
|
limit?: number;
|
|
60
|
+
source_file?: string;
|
|
52
61
|
};
|
|
53
62
|
export type KgAddAdapterRequest = {
|
|
54
63
|
mode: "kg_add";
|
|
@@ -70,8 +79,47 @@ export type MineMessagesAdapterRequest = {
|
|
|
70
79
|
wing: string;
|
|
71
80
|
extract_mode: string;
|
|
72
81
|
agent: string;
|
|
82
|
+
palace_path?: string;
|
|
83
|
+
};
|
|
84
|
+
export type DeleteAdapterRequest = {
|
|
85
|
+
mode: "delete";
|
|
86
|
+
drawer_id: string;
|
|
87
|
+
};
|
|
88
|
+
export type DeleteBySourceAdapterRequest = {
|
|
89
|
+
mode: "delete_by_source";
|
|
90
|
+
source_file: string;
|
|
91
|
+
dry_run: boolean;
|
|
92
|
+
};
|
|
93
|
+
export type KgQueryAdapterRequest = {
|
|
94
|
+
mode: "kg_query";
|
|
95
|
+
entity: string;
|
|
96
|
+
as_of?: string;
|
|
97
|
+
direction?: string;
|
|
98
|
+
};
|
|
99
|
+
export type DiaryReadAdapterRequest = {
|
|
100
|
+
mode: "diary_read";
|
|
101
|
+
agent_name?: string;
|
|
102
|
+
last_n?: number;
|
|
103
|
+
wing?: string;
|
|
104
|
+
};
|
|
105
|
+
export type CheckpointItem = {
|
|
106
|
+
wing: string;
|
|
107
|
+
room: string;
|
|
108
|
+
content: string;
|
|
109
|
+
};
|
|
110
|
+
export type CheckpointDiary = {
|
|
111
|
+
agent_name?: string;
|
|
112
|
+
entry: string;
|
|
113
|
+
topic?: string;
|
|
114
|
+
wing?: string;
|
|
115
|
+
};
|
|
116
|
+
export type CheckpointAdapterRequest = {
|
|
117
|
+
mode: "checkpoint";
|
|
118
|
+
items: CheckpointItem[];
|
|
119
|
+
diary?: CheckpointDiary;
|
|
120
|
+
dedup_threshold?: number;
|
|
73
121
|
};
|
|
74
|
-
export type AdapterRequest = SaveAdapterRequest | SearchAdapterRequest | KgAddAdapterRequest | DiaryWriteAdapterRequest | MineMessagesAdapterRequest;
|
|
122
|
+
export type AdapterRequest = SaveAdapterRequest | SearchAdapterRequest | KgAddAdapterRequest | DiaryWriteAdapterRequest | MineMessagesAdapterRequest | DeleteAdapterRequest | DeleteBySourceAdapterRequest | KgQueryAdapterRequest | DiaryReadAdapterRequest | CheckpointAdapterRequest;
|
|
75
123
|
export type AdapterResponse = {
|
|
76
124
|
success?: boolean;
|
|
77
125
|
error?: string;
|
package/dist/plugin/lib/types.js
CHANGED
|
@@ -3,8 +3,8 @@ export { DEFAULT_ROOM, DEFAULT_TOPIC, DEFAULT_AGENT_NAME, DEFAULT_EXTRACT_MODE,
|
|
|
3
3
|
export const MEMORY_SCOPES = ["user", "project"];
|
|
4
4
|
export const USER_MEMORY_ROOMS = ["preferences", "workflow", "communication"];
|
|
5
5
|
export const PROJECT_MEMORY_ROOMS = ["architecture", "workflow", "decisions", "bugs", "setup"];
|
|
6
|
-
export const TOOL_MEMORY_MODES = ["save", "search", "kg_add", "diary_write"];
|
|
7
|
-
export const ADAPTER_MODES = ["save", "search", "kg_add", "diary_write", "mine_messages"];
|
|
6
|
+
export const TOOL_MEMORY_MODES = ["save", "search", "kg_add", "diary_write", "delete", "delete_by_source", "kg_query", "diary_read", "checkpoint"];
|
|
7
|
+
export const ADAPTER_MODES = ["save", "search", "kg_add", "diary_write", "mine_messages", "delete", "delete_by_source", "kg_query", "diary_read", "checkpoint"];
|
|
8
8
|
export const SESSION_EVENT_TYPES = [
|
|
9
9
|
"session.idle",
|
|
10
10
|
"session.compacted",
|
|
@@ -7,6 +7,11 @@ export declare const mempalaceMemoryTool: (ctx: ToolContext) => {
|
|
|
7
7
|
search: "search";
|
|
8
8
|
kg_add: "kg_add";
|
|
9
9
|
diary_write: "diary_write";
|
|
10
|
+
delete: "delete";
|
|
11
|
+
delete_by_source: "delete_by_source";
|
|
12
|
+
kg_query: "kg_query";
|
|
13
|
+
diary_read: "diary_read";
|
|
14
|
+
checkpoint: "checkpoint";
|
|
10
15
|
}>;
|
|
11
16
|
scope: import("zod").ZodDefault<import("zod").ZodOptional<import("zod").ZodEnum<{
|
|
12
17
|
user: "user";
|
|
@@ -21,18 +26,42 @@ export declare const mempalaceMemoryTool: (ctx: ToolContext) => {
|
|
|
21
26
|
topic: import("zod").ZodDefault<import("zod").ZodOptional<import("zod").ZodString>>;
|
|
22
27
|
agent_name: import("zod").ZodDefault<import("zod").ZodOptional<import("zod").ZodString>>;
|
|
23
28
|
limit: import("zod").ZodDefault<import("zod").ZodOptional<import("zod").ZodNumber>>;
|
|
29
|
+
source_file: import("zod").ZodOptional<import("zod").ZodString>;
|
|
30
|
+
drawer_id: import("zod").ZodOptional<import("zod").ZodString>;
|
|
31
|
+
entity: import("zod").ZodOptional<import("zod").ZodString>;
|
|
32
|
+
as_of: import("zod").ZodOptional<import("zod").ZodString>;
|
|
33
|
+
direction: import("zod").ZodDefault<import("zod").ZodOptional<import("zod").ZodEnum<{
|
|
34
|
+
outgoing: "outgoing";
|
|
35
|
+
incoming: "incoming";
|
|
36
|
+
both: "both";
|
|
37
|
+
}>>>;
|
|
38
|
+
dry_run: import("zod").ZodDefault<import("zod").ZodOptional<import("zod").ZodBoolean>>;
|
|
39
|
+
last_n: import("zod").ZodDefault<import("zod").ZodOptional<import("zod").ZodNumber>>;
|
|
40
|
+
items: import("zod").ZodOptional<import("zod").ZodString>;
|
|
41
|
+
diary: import("zod").ZodOptional<import("zod").ZodString>;
|
|
42
|
+
dedup_threshold: import("zod").ZodDefault<import("zod").ZodOptional<import("zod").ZodNumber>>;
|
|
24
43
|
};
|
|
25
44
|
execute(args: {
|
|
26
|
-
mode: "save" | "search" | "kg_add" | "diary_write";
|
|
45
|
+
mode: "save" | "search" | "kg_add" | "diary_write" | "delete" | "delete_by_source" | "kg_query" | "diary_read" | "checkpoint";
|
|
27
46
|
scope: "user" | "project";
|
|
28
47
|
room: string;
|
|
29
48
|
topic: string;
|
|
30
49
|
agent_name: string;
|
|
31
50
|
limit: number;
|
|
51
|
+
direction: "outgoing" | "incoming" | "both";
|
|
52
|
+
dry_run: boolean;
|
|
53
|
+
last_n: number;
|
|
54
|
+
dedup_threshold: number;
|
|
32
55
|
content?: string | undefined;
|
|
33
56
|
query?: string | undefined;
|
|
34
57
|
subject?: string | undefined;
|
|
35
58
|
predicate?: string | undefined;
|
|
36
59
|
object?: string | undefined;
|
|
60
|
+
source_file?: string | undefined;
|
|
61
|
+
drawer_id?: string | undefined;
|
|
62
|
+
entity?: string | undefined;
|
|
63
|
+
as_of?: string | undefined;
|
|
64
|
+
items?: string | undefined;
|
|
65
|
+
diary?: string | undefined;
|
|
37
66
|
}, context: import("@opencode-ai/plugin").ToolContext): Promise<string>;
|
|
38
67
|
};
|
|
@@ -2,11 +2,12 @@ import { tool } from "@opencode-ai/plugin";
|
|
|
2
2
|
import { executeAdapter } from "../lib/adapter";
|
|
3
3
|
import { loadConfig } from "../lib/config";
|
|
4
4
|
import { sanitizeText } from "../lib/derive";
|
|
5
|
-
import { DATE_ISO_SLICE, DEFAULT_AGENT_NAME, DEFAULT_LIMIT, DEFAULT_ROOM, DEFAULT_TOPIC, ERROR_MESSAGES, TOOL_DESCRIPTIONS } from "../lib/constants";
|
|
5
|
+
import { DATE_ISO_SLICE, DEFAULT_AGENT_NAME, DEFAULT_LIMIT, DEFAULT_ROOM, DEFAULT_TOPIC, ERROR_MESSAGES, LOG_MESSAGES, TOOL_DESCRIPTIONS } from "../lib/constants";
|
|
6
6
|
import { getProjectName } from "../lib/opencode";
|
|
7
7
|
import { isFullyPrivate, redactSecrets } from "../lib/privacy";
|
|
8
8
|
import { getProjectScope, getUserScope } from "../lib/scope";
|
|
9
|
-
import { recordMemoryWrite, recordRetrievalSearch } from "../lib/status";
|
|
9
|
+
import { recordMemoryWrite, recordRetrievalSearch, summarizeSearchResult } from "../lib/status";
|
|
10
|
+
import { writeLog } from "../lib/log";
|
|
10
11
|
import { MEMORY_SCOPES, TOOL_MEMORY_MODES } from "../lib/types";
|
|
11
12
|
const getProjectWing = (projectName, prefix) => {
|
|
12
13
|
return getProjectScope(projectName, prefix).wing;
|
|
@@ -34,6 +35,16 @@ export const mempalaceMemoryTool = (ctx) => tool({
|
|
|
34
35
|
topic: tool.schema.string().optional().default(DEFAULT_TOPIC),
|
|
35
36
|
agent_name: tool.schema.string().optional().default(DEFAULT_AGENT_NAME),
|
|
36
37
|
limit: tool.schema.number().optional().default(DEFAULT_LIMIT),
|
|
38
|
+
source_file: tool.schema.string().optional(),
|
|
39
|
+
drawer_id: tool.schema.string().optional(),
|
|
40
|
+
entity: tool.schema.string().optional(),
|
|
41
|
+
as_of: tool.schema.string().optional(),
|
|
42
|
+
direction: tool.schema.enum(["outgoing", "incoming", "both"]).optional().default("both"),
|
|
43
|
+
dry_run: tool.schema.boolean().optional().default(true),
|
|
44
|
+
last_n: tool.schema.number().optional().default(10),
|
|
45
|
+
items: tool.schema.string().optional(),
|
|
46
|
+
diary: tool.schema.string().optional(),
|
|
47
|
+
dedup_threshold: tool.schema.number().optional().default(0.9),
|
|
37
48
|
},
|
|
38
49
|
async execute(args, executionContext) {
|
|
39
50
|
const config = await loadConfig();
|
|
@@ -76,7 +87,9 @@ export const mempalaceMemoryTool = (ctx) => tool({
|
|
|
76
87
|
wing,
|
|
77
88
|
room: normalizeValue(args.room, false),
|
|
78
89
|
limit: args.limit,
|
|
90
|
+
source_file: args.source_file,
|
|
79
91
|
});
|
|
92
|
+
const summary = summarizeSearchResult(result);
|
|
80
93
|
if (result?.success !== false) {
|
|
81
94
|
await recordRetrievalSearch({
|
|
82
95
|
sessionId: executionContext.sessionID,
|
|
@@ -85,8 +98,22 @@ export const mempalaceMemoryTool = (ctx) => tool({
|
|
|
85
98
|
query,
|
|
86
99
|
result,
|
|
87
100
|
});
|
|
101
|
+
await writeLog("INFO", LOG_MESSAGES.retrievalSearchCompleted, {
|
|
102
|
+
sessionId: executionContext.sessionID,
|
|
103
|
+
scope,
|
|
104
|
+
room: args.room,
|
|
105
|
+
query: query.slice(0, 200),
|
|
106
|
+
resultCount: summary.resultCount ?? 0,
|
|
107
|
+
previews: summary.previews,
|
|
108
|
+
});
|
|
88
109
|
}
|
|
89
|
-
|
|
110
|
+
const retrievalNote = summary.resultCount
|
|
111
|
+
? `Found ${summary.resultCount} relevant ${summary.resultCount === 1 ? "memory" : "memories"}:\n${summary.previews.map((p, i) => `${i + 1}. ${p}`).join("\n")}`
|
|
112
|
+
: "No relevant memories found.";
|
|
113
|
+
const enriched = typeof result === "object" && result !== null
|
|
114
|
+
? { ...result, _retrieval_summary: retrievalNote }
|
|
115
|
+
: result;
|
|
116
|
+
return JSON.stringify(enriched);
|
|
90
117
|
}
|
|
91
118
|
if (args.mode === "kg_add") {
|
|
92
119
|
if (!args.subject || !args.predicate || !args.object) {
|
|
@@ -113,6 +140,75 @@ export const mempalaceMemoryTool = (ctx) => tool({
|
|
|
113
140
|
}
|
|
114
141
|
return JSON.stringify(result);
|
|
115
142
|
}
|
|
143
|
+
if (args.mode === "delete") {
|
|
144
|
+
if (!args.drawer_id)
|
|
145
|
+
return JSON.stringify({ success: false, error: "drawer_id is required" });
|
|
146
|
+
const result = await executeAdapter(ctx.$, {
|
|
147
|
+
mode: "delete",
|
|
148
|
+
drawer_id: args.drawer_id,
|
|
149
|
+
});
|
|
150
|
+
return JSON.stringify(result);
|
|
151
|
+
}
|
|
152
|
+
if (args.mode === "delete_by_source") {
|
|
153
|
+
if (!args.source_file)
|
|
154
|
+
return JSON.stringify({ success: false, error: "source_file is required" });
|
|
155
|
+
const result = await executeAdapter(ctx.$, {
|
|
156
|
+
mode: "delete_by_source",
|
|
157
|
+
source_file: args.source_file,
|
|
158
|
+
dry_run: args.dry_run ?? true,
|
|
159
|
+
});
|
|
160
|
+
return JSON.stringify(result);
|
|
161
|
+
}
|
|
162
|
+
if (args.mode === "kg_query") {
|
|
163
|
+
if (!args.entity)
|
|
164
|
+
return JSON.stringify({ success: false, error: "entity is required" });
|
|
165
|
+
const result = await executeAdapter(ctx.$, {
|
|
166
|
+
mode: "kg_query",
|
|
167
|
+
entity: args.entity,
|
|
168
|
+
as_of: args.as_of,
|
|
169
|
+
direction: args.direction ?? "both",
|
|
170
|
+
});
|
|
171
|
+
return JSON.stringify(result);
|
|
172
|
+
}
|
|
173
|
+
if (args.mode === "diary_read") {
|
|
174
|
+
const result = await executeAdapter(ctx.$, {
|
|
175
|
+
mode: "diary_read",
|
|
176
|
+
agent_name: args.agent_name ?? DEFAULT_AGENT_NAME,
|
|
177
|
+
last_n: args.last_n ?? 10,
|
|
178
|
+
wing: scope === "user" ? getUserWing(config.userWingPrefix) : wing,
|
|
179
|
+
});
|
|
180
|
+
return JSON.stringify(result);
|
|
181
|
+
}
|
|
182
|
+
if (args.mode === "checkpoint") {
|
|
183
|
+
if (!args.items)
|
|
184
|
+
return JSON.stringify({ success: false, error: "items (JSON array) is required" });
|
|
185
|
+
let parsedItems;
|
|
186
|
+
let parsedDiary;
|
|
187
|
+
try {
|
|
188
|
+
parsedItems = JSON.parse(args.items);
|
|
189
|
+
if (args.diary)
|
|
190
|
+
parsedDiary = JSON.parse(args.diary);
|
|
191
|
+
}
|
|
192
|
+
catch {
|
|
193
|
+
return JSON.stringify({ success: false, error: "items/diary must be valid JSON" });
|
|
194
|
+
}
|
|
195
|
+
const result = await executeAdapter(ctx.$, {
|
|
196
|
+
mode: "checkpoint",
|
|
197
|
+
items: parsedItems,
|
|
198
|
+
diary: parsedDiary,
|
|
199
|
+
dedup_threshold: args.dedup_threshold ?? 0.9,
|
|
200
|
+
});
|
|
201
|
+
if (result?.success !== false) {
|
|
202
|
+
await recordMemoryWrite({
|
|
203
|
+
sessionId: executionContext.sessionID,
|
|
204
|
+
mode: "save",
|
|
205
|
+
scope,
|
|
206
|
+
preview: `checkpoint: ${parsedItems.length} items`,
|
|
207
|
+
});
|
|
208
|
+
}
|
|
209
|
+
return JSON.stringify(result);
|
|
210
|
+
}
|
|
211
|
+
// Default: diary_write (fallthrough for mode === "diary_write")
|
|
116
212
|
const result = await executeAdapter(ctx.$, {
|
|
117
213
|
mode: "diary_write",
|
|
118
214
|
agent_name: normalizeValue(args.agent_name, false) ?? DEFAULT_AGENT_NAME,
|
|
@@ -4,7 +4,7 @@ import { formatStatusSummary, readStatusState } from "../lib/status";
|
|
|
4
4
|
export const mempalaceStatusTool = () => tool({
|
|
5
5
|
description: TOOL_DESCRIPTIONS.mempalaceStatus,
|
|
6
6
|
args: {
|
|
7
|
-
verbose: tool.schema.boolean().optional().default(
|
|
7
|
+
verbose: tool.schema.boolean().optional().default(true),
|
|
8
8
|
compact: tool.schema.boolean().optional().default(false),
|
|
9
9
|
},
|
|
10
10
|
async execute(args, executionContext) {
|
package/dist/plugin/tui/hud.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rvboris/opencode-mempalace",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"description": "OpenCode plugin for hidden MemPalace retrieval and autosave via a local Python adapter.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/plugin/index.js",
|
|
@@ -57,8 +57,8 @@
|
|
|
57
57
|
"lint": "biome lint plugin tests scripts package.json tsconfig.json example-opencode.json biome.json",
|
|
58
58
|
"lint:ci": "biome lint plugin tests scripts package.json tsconfig.json example-opencode.json biome.json",
|
|
59
59
|
"prepublishOnly": "npm run build",
|
|
60
|
-
"test": "bun test",
|
|
61
|
-
"test:coverage": "bun test --coverage --coverage-reporter=text --coverage-reporter=lcov",
|
|
60
|
+
"test": "bun test --parallel",
|
|
61
|
+
"test:coverage": "bun test --parallel --coverage --coverage-reporter=text --coverage-reporter=lcov",
|
|
62
62
|
"typecheck": "tsc -p tsconfig.json --noEmit"
|
|
63
63
|
},
|
|
64
64
|
"publishConfig": {
|