@rvboris/opencode-mempalace 0.2.1 → 0.4.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 +137 -96
- package/README.ru.md +136 -95
- package/dist/bridge/mempalace_adapter.py +5 -1
- package/dist/plugin/hooks/event.js +37 -3
- package/dist/plugin/hooks/system.js +2 -0
- package/dist/plugin/index.js +2 -0
- package/dist/plugin/lib/constants.d.ts +5 -0
- package/dist/plugin/lib/constants.js +5 -0
- package/dist/plugin/lib/context.js +1 -1
- package/dist/plugin/lib/status.d.ts +105 -0
- package/dist/plugin/lib/status.js +537 -0
- package/dist/plugin/lib/types.d.ts +2 -2
- package/dist/plugin/lib/types.js +2 -2
- package/dist/plugin/tools/mempalace-memory.js +54 -3
- package/dist/plugin/tools/mempalace-status.d.ts +11 -0
- package/dist/plugin/tools/mempalace-status.js +18 -0
- package/dist/plugin/tui/hud.d.ts +3 -0
- package/dist/plugin/tui/hud.js +54 -0
- package/dist/plugin/tui/index.d.ts +6 -0
- package/dist/plugin/tui/index.js +9 -0
- package/package.json +14 -1
|
@@ -0,0 +1,537 @@
|
|
|
1
|
+
import fs from "node:fs/promises";
|
|
2
|
+
import os from "node:os";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import { ENV_KEYS, STATUS_FILE_NAME } from "./constants";
|
|
5
|
+
const MAX_SESSION_IDS = 50;
|
|
6
|
+
const MAX_PREVIEWS = 3;
|
|
7
|
+
const MAX_PREVIEW_LENGTH = 140;
|
|
8
|
+
const DEFAULT_SESSION_COUNTERS = () => ({
|
|
9
|
+
retrievalSearches: 0,
|
|
10
|
+
retrievalHits: 0,
|
|
11
|
+
autosavesCompleted: 0,
|
|
12
|
+
autosavesSkipped: 0,
|
|
13
|
+
autosavesFailed: 0,
|
|
14
|
+
manualWrites: 0,
|
|
15
|
+
});
|
|
16
|
+
const DEFAULT_SESSION_STATE = () => ({
|
|
17
|
+
updatedAt: new Date(0).toISOString(),
|
|
18
|
+
counters: DEFAULT_SESSION_COUNTERS(),
|
|
19
|
+
});
|
|
20
|
+
const DEFAULT_STATE = () => ({
|
|
21
|
+
version: 2,
|
|
22
|
+
updatedAt: new Date(0).toISOString(),
|
|
23
|
+
counters: {
|
|
24
|
+
retrievalPrompts: 0,
|
|
25
|
+
retrievalSearches: 0,
|
|
26
|
+
retrievalHits: 0,
|
|
27
|
+
autosavesCompleted: 0,
|
|
28
|
+
autosavesSkipped: 0,
|
|
29
|
+
autosavesFailed: 0,
|
|
30
|
+
manualWrites: 0,
|
|
31
|
+
},
|
|
32
|
+
helpedSessionIds: [],
|
|
33
|
+
sessions: {},
|
|
34
|
+
});
|
|
35
|
+
let writeQueue = Promise.resolve();
|
|
36
|
+
const getStatusFilePath = () => {
|
|
37
|
+
return process.env[ENV_KEYS.statusFile] || path.join(os.homedir(), ".mempalace", STATUS_FILE_NAME);
|
|
38
|
+
};
|
|
39
|
+
const isRecord = (value) => {
|
|
40
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
41
|
+
};
|
|
42
|
+
const normalizeString = (value) => {
|
|
43
|
+
if (typeof value !== "string")
|
|
44
|
+
return undefined;
|
|
45
|
+
const normalized = value.replace(/\s+/g, " ").trim();
|
|
46
|
+
return normalized || undefined;
|
|
47
|
+
};
|
|
48
|
+
const previewText = (value) => {
|
|
49
|
+
if (!value)
|
|
50
|
+
return "";
|
|
51
|
+
const normalized = value.replace(/\s+/g, " ").trim();
|
|
52
|
+
if (normalized.length <= MAX_PREVIEW_LENGTH)
|
|
53
|
+
return normalized;
|
|
54
|
+
return `${normalized.slice(0, MAX_PREVIEW_LENGTH - 3)}...`;
|
|
55
|
+
};
|
|
56
|
+
const readStringArray = (value) => {
|
|
57
|
+
if (!Array.isArray(value))
|
|
58
|
+
return [];
|
|
59
|
+
return value.map((item) => normalizeString(item)).filter((item) => Boolean(item));
|
|
60
|
+
};
|
|
61
|
+
const readCounters = (value) => {
|
|
62
|
+
const input = isRecord(value) ? value : {};
|
|
63
|
+
const readCount = (key) => {
|
|
64
|
+
const item = input[key];
|
|
65
|
+
return typeof item === "number" && Number.isFinite(item) && item >= 0 ? Math.floor(item) : 0;
|
|
66
|
+
};
|
|
67
|
+
return {
|
|
68
|
+
retrievalPrompts: readCount("retrievalPrompts"),
|
|
69
|
+
retrievalSearches: readCount("retrievalSearches"),
|
|
70
|
+
retrievalHits: readCount("retrievalHits"),
|
|
71
|
+
autosavesCompleted: readCount("autosavesCompleted"),
|
|
72
|
+
autosavesSkipped: readCount("autosavesSkipped"),
|
|
73
|
+
autosavesFailed: readCount("autosavesFailed"),
|
|
74
|
+
manualWrites: readCount("manualWrites"),
|
|
75
|
+
};
|
|
76
|
+
};
|
|
77
|
+
const readSessionCounters = (value) => {
|
|
78
|
+
const input = isRecord(value) ? value : {};
|
|
79
|
+
const readCount = (key) => {
|
|
80
|
+
const item = input[key];
|
|
81
|
+
return typeof item === "number" && Number.isFinite(item) && item >= 0 ? Math.floor(item) : 0;
|
|
82
|
+
};
|
|
83
|
+
return {
|
|
84
|
+
retrievalSearches: readCount("retrievalSearches"),
|
|
85
|
+
retrievalHits: readCount("retrievalHits"),
|
|
86
|
+
autosavesCompleted: readCount("autosavesCompleted"),
|
|
87
|
+
autosavesSkipped: readCount("autosavesSkipped"),
|
|
88
|
+
autosavesFailed: readCount("autosavesFailed"),
|
|
89
|
+
manualWrites: readCount("manualWrites"),
|
|
90
|
+
};
|
|
91
|
+
};
|
|
92
|
+
const readRetrievalPrompt = (value) => {
|
|
93
|
+
if (!isRecord(value))
|
|
94
|
+
return undefined;
|
|
95
|
+
const timestamp = normalizeString(value.timestamp);
|
|
96
|
+
const queryPreview = normalizeString(value.queryPreview);
|
|
97
|
+
if (!timestamp || !queryPreview)
|
|
98
|
+
return undefined;
|
|
99
|
+
return {
|
|
100
|
+
sessionId: normalizeString(value.sessionId),
|
|
101
|
+
timestamp,
|
|
102
|
+
queryPreview,
|
|
103
|
+
};
|
|
104
|
+
};
|
|
105
|
+
const readRetrieval = (value) => {
|
|
106
|
+
if (!isRecord(value))
|
|
107
|
+
return undefined;
|
|
108
|
+
const timestamp = normalizeString(value.timestamp);
|
|
109
|
+
const scope = value.scope === "user" || value.scope === "project" ? value.scope : undefined;
|
|
110
|
+
const queryPreview = normalizeString(value.queryPreview);
|
|
111
|
+
if (!timestamp || !scope || !queryPreview)
|
|
112
|
+
return undefined;
|
|
113
|
+
const count = typeof value.resultCount === "number" && Number.isFinite(value.resultCount) && value.resultCount >= 0
|
|
114
|
+
? Math.floor(value.resultCount)
|
|
115
|
+
: undefined;
|
|
116
|
+
return {
|
|
117
|
+
sessionId: normalizeString(value.sessionId),
|
|
118
|
+
timestamp,
|
|
119
|
+
scope,
|
|
120
|
+
room: normalizeString(value.room),
|
|
121
|
+
queryPreview,
|
|
122
|
+
resultCount: count,
|
|
123
|
+
previews: readStringArray(value.previews).slice(0, MAX_PREVIEWS),
|
|
124
|
+
};
|
|
125
|
+
};
|
|
126
|
+
const readAutosave = (value) => {
|
|
127
|
+
if (!isRecord(value))
|
|
128
|
+
return undefined;
|
|
129
|
+
const timestamp = normalizeString(value.timestamp);
|
|
130
|
+
const sessionId = normalizeString(value.sessionId);
|
|
131
|
+
const reason = normalizeString(value.reason);
|
|
132
|
+
const outcome = value.outcome === "saved" || value.outcome === "skipped" || value.outcome === "failed"
|
|
133
|
+
? value.outcome
|
|
134
|
+
: undefined;
|
|
135
|
+
if (!timestamp || !sessionId || !reason || !outcome)
|
|
136
|
+
return undefined;
|
|
137
|
+
return {
|
|
138
|
+
sessionId,
|
|
139
|
+
timestamp,
|
|
140
|
+
outcome,
|
|
141
|
+
reason,
|
|
142
|
+
wing: normalizeString(value.wing),
|
|
143
|
+
sourcePreview: normalizeString(value.sourcePreview),
|
|
144
|
+
};
|
|
145
|
+
};
|
|
146
|
+
const readWrite = (value) => {
|
|
147
|
+
if (!isRecord(value))
|
|
148
|
+
return undefined;
|
|
149
|
+
const timestamp = normalizeString(value.timestamp);
|
|
150
|
+
const preview = normalizeString(value.preview);
|
|
151
|
+
const mode = value.mode === "save" || value.mode === "kg_add" || value.mode === "diary_write" ? value.mode : undefined;
|
|
152
|
+
if (!timestamp || !preview || !mode)
|
|
153
|
+
return undefined;
|
|
154
|
+
return {
|
|
155
|
+
timestamp,
|
|
156
|
+
mode,
|
|
157
|
+
scope: value.scope === "user" || value.scope === "project" ? value.scope : undefined,
|
|
158
|
+
room: normalizeString(value.room),
|
|
159
|
+
preview,
|
|
160
|
+
};
|
|
161
|
+
};
|
|
162
|
+
const readSessionState = (value) => {
|
|
163
|
+
if (!isRecord(value))
|
|
164
|
+
return undefined;
|
|
165
|
+
return {
|
|
166
|
+
updatedAt: normalizeString(value.updatedAt) || new Date(0).toISOString(),
|
|
167
|
+
counters: readSessionCounters(value.counters),
|
|
168
|
+
lastRetrievalPrompt: readRetrievalPrompt(value.lastRetrievalPrompt),
|
|
169
|
+
lastRetrieval: readRetrieval(value.lastRetrieval),
|
|
170
|
+
lastAutosave: readAutosave(value.lastAutosave),
|
|
171
|
+
lastWrite: readWrite(value.lastWrite),
|
|
172
|
+
};
|
|
173
|
+
};
|
|
174
|
+
const readSessions = (value) => {
|
|
175
|
+
if (!isRecord(value))
|
|
176
|
+
return {};
|
|
177
|
+
const sessions = Object.entries(value)
|
|
178
|
+
.map(([sessionId, sessionState]) => {
|
|
179
|
+
const normalizedSessionId = normalizeString(sessionId);
|
|
180
|
+
const parsed = readSessionState(sessionState);
|
|
181
|
+
if (!normalizedSessionId || !parsed)
|
|
182
|
+
return undefined;
|
|
183
|
+
return [normalizedSessionId, parsed];
|
|
184
|
+
})
|
|
185
|
+
.filter((entry) => Boolean(entry))
|
|
186
|
+
.sort((a, b) => a[1].updatedAt.localeCompare(b[1].updatedAt))
|
|
187
|
+
.slice(-MAX_SESSION_IDS);
|
|
188
|
+
return Object.fromEntries(sessions);
|
|
189
|
+
};
|
|
190
|
+
const parseState = (value) => {
|
|
191
|
+
if (!isRecord(value))
|
|
192
|
+
return DEFAULT_STATE();
|
|
193
|
+
return {
|
|
194
|
+
version: 2,
|
|
195
|
+
updatedAt: normalizeString(value.updatedAt) || new Date(0).toISOString(),
|
|
196
|
+
counters: readCounters(value.counters),
|
|
197
|
+
helpedSessionIds: readStringArray(value.helpedSessionIds).slice(-MAX_SESSION_IDS),
|
|
198
|
+
sessions: readSessions(value.sessions),
|
|
199
|
+
lastRetrievalPrompt: readRetrievalPrompt(value.lastRetrievalPrompt),
|
|
200
|
+
lastRetrieval: readRetrieval(value.lastRetrieval),
|
|
201
|
+
lastAutosave: readAutosave(value.lastAutosave),
|
|
202
|
+
lastWrite: readWrite(value.lastWrite),
|
|
203
|
+
};
|
|
204
|
+
};
|
|
205
|
+
const loadState = async () => {
|
|
206
|
+
try {
|
|
207
|
+
const raw = await fs.readFile(getStatusFilePath(), "utf8");
|
|
208
|
+
return parseState(JSON.parse(raw));
|
|
209
|
+
}
|
|
210
|
+
catch {
|
|
211
|
+
return DEFAULT_STATE();
|
|
212
|
+
}
|
|
213
|
+
};
|
|
214
|
+
const persistState = async (state) => {
|
|
215
|
+
const filePath = getStatusFilePath();
|
|
216
|
+
await fs.mkdir(path.dirname(filePath), { recursive: true });
|
|
217
|
+
await fs.writeFile(filePath, `${JSON.stringify(state, null, 2)}\n`, "utf8");
|
|
218
|
+
};
|
|
219
|
+
const updateState = async (updater) => {
|
|
220
|
+
writeQueue = writeQueue.then(async () => {
|
|
221
|
+
const state = await loadState();
|
|
222
|
+
updater(state);
|
|
223
|
+
state.updatedAt = new Date().toISOString();
|
|
224
|
+
await persistState(state);
|
|
225
|
+
}).catch(() => { });
|
|
226
|
+
await writeQueue;
|
|
227
|
+
};
|
|
228
|
+
const addHelpedSession = (state, sessionId) => {
|
|
229
|
+
if (!sessionId || state.helpedSessionIds.includes(sessionId))
|
|
230
|
+
return;
|
|
231
|
+
state.helpedSessionIds.push(sessionId);
|
|
232
|
+
if (state.helpedSessionIds.length > MAX_SESSION_IDS) {
|
|
233
|
+
state.helpedSessionIds.splice(0, state.helpedSessionIds.length - MAX_SESSION_IDS);
|
|
234
|
+
}
|
|
235
|
+
};
|
|
236
|
+
const updateSessionState = (state, sessionId, updater) => {
|
|
237
|
+
if (!sessionId)
|
|
238
|
+
return;
|
|
239
|
+
const sessionState = state.sessions[sessionId] ?? DEFAULT_SESSION_STATE();
|
|
240
|
+
updater(sessionState);
|
|
241
|
+
sessionState.updatedAt = new Date().toISOString();
|
|
242
|
+
state.sessions[sessionId] = sessionState;
|
|
243
|
+
const entries = Object.entries(state.sessions);
|
|
244
|
+
if (entries.length <= MAX_SESSION_IDS)
|
|
245
|
+
return;
|
|
246
|
+
entries.sort((a, b) => a[1].updatedAt.localeCompare(b[1].updatedAt));
|
|
247
|
+
state.sessions = Object.fromEntries(entries.slice(-MAX_SESSION_IDS));
|
|
248
|
+
};
|
|
249
|
+
const collectCandidateTexts = (value, bucket) => {
|
|
250
|
+
if (bucket.length >= MAX_PREVIEWS)
|
|
251
|
+
return;
|
|
252
|
+
if (typeof value === "string") {
|
|
253
|
+
const preview = previewText(value);
|
|
254
|
+
if (preview)
|
|
255
|
+
bucket.push(preview);
|
|
256
|
+
return;
|
|
257
|
+
}
|
|
258
|
+
if (!isRecord(value))
|
|
259
|
+
return;
|
|
260
|
+
for (const key of ["content", "text", "entry", "summary", "memory", "drawer", "object"]) {
|
|
261
|
+
const preview = previewText(normalizeString(value[key]));
|
|
262
|
+
if (preview) {
|
|
263
|
+
bucket.push(preview);
|
|
264
|
+
return;
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
};
|
|
268
|
+
const extractResultArray = (result) => {
|
|
269
|
+
for (const key of ["results", "items", "matches", "entries", "drawers", "data"]) {
|
|
270
|
+
const value = result[key];
|
|
271
|
+
if (Array.isArray(value))
|
|
272
|
+
return value;
|
|
273
|
+
}
|
|
274
|
+
return undefined;
|
|
275
|
+
};
|
|
276
|
+
export const summarizeSearchResult = (result) => {
|
|
277
|
+
const array = extractResultArray(result);
|
|
278
|
+
const previews = [];
|
|
279
|
+
if (array) {
|
|
280
|
+
for (const item of array) {
|
|
281
|
+
collectCandidateTexts(item, previews);
|
|
282
|
+
if (previews.length >= MAX_PREVIEWS)
|
|
283
|
+
break;
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
return {
|
|
287
|
+
resultCount: array?.length,
|
|
288
|
+
previews,
|
|
289
|
+
};
|
|
290
|
+
};
|
|
291
|
+
export const recordRetrievalPrompt = async (input) => {
|
|
292
|
+
await updateState((state) => {
|
|
293
|
+
state.counters.retrievalPrompts += 1;
|
|
294
|
+
state.lastRetrievalPrompt = {
|
|
295
|
+
sessionId: input.sessionId,
|
|
296
|
+
timestamp: new Date().toISOString(),
|
|
297
|
+
queryPreview: previewText(input.queryPreview),
|
|
298
|
+
};
|
|
299
|
+
updateSessionState(state, input.sessionId, (sessionState) => {
|
|
300
|
+
sessionState.lastRetrievalPrompt = state.lastRetrievalPrompt;
|
|
301
|
+
});
|
|
302
|
+
});
|
|
303
|
+
};
|
|
304
|
+
export const recordRetrievalSearch = async (input) => {
|
|
305
|
+
const summary = summarizeSearchResult(input.result);
|
|
306
|
+
await updateState((state) => {
|
|
307
|
+
state.counters.retrievalSearches += 1;
|
|
308
|
+
if ((summary.resultCount ?? 0) > 0) {
|
|
309
|
+
state.counters.retrievalHits += 1;
|
|
310
|
+
addHelpedSession(state, input.sessionId);
|
|
311
|
+
}
|
|
312
|
+
state.lastRetrieval = {
|
|
313
|
+
sessionId: input.sessionId,
|
|
314
|
+
timestamp: new Date().toISOString(),
|
|
315
|
+
scope: input.scope,
|
|
316
|
+
room: input.room,
|
|
317
|
+
queryPreview: previewText(input.query),
|
|
318
|
+
resultCount: summary.resultCount,
|
|
319
|
+
previews: summary.previews,
|
|
320
|
+
};
|
|
321
|
+
updateSessionState(state, input.sessionId, (sessionState) => {
|
|
322
|
+
sessionState.counters.retrievalSearches += 1;
|
|
323
|
+
if ((summary.resultCount ?? 0) > 0) {
|
|
324
|
+
sessionState.counters.retrievalHits += 1;
|
|
325
|
+
}
|
|
326
|
+
sessionState.lastRetrieval = state.lastRetrieval;
|
|
327
|
+
});
|
|
328
|
+
});
|
|
329
|
+
};
|
|
330
|
+
export const recordMemoryWrite = async (input) => {
|
|
331
|
+
await updateState((state) => {
|
|
332
|
+
state.counters.manualWrites += 1;
|
|
333
|
+
state.lastWrite = {
|
|
334
|
+
timestamp: new Date().toISOString(),
|
|
335
|
+
mode: input.mode,
|
|
336
|
+
scope: input.scope,
|
|
337
|
+
room: input.room,
|
|
338
|
+
preview: previewText(input.preview),
|
|
339
|
+
};
|
|
340
|
+
updateSessionState(state, input.sessionId, (sessionState) => {
|
|
341
|
+
sessionState.counters.manualWrites += 1;
|
|
342
|
+
sessionState.lastWrite = state.lastWrite;
|
|
343
|
+
});
|
|
344
|
+
});
|
|
345
|
+
};
|
|
346
|
+
export const recordAutosave = async (input) => {
|
|
347
|
+
await updateState((state) => {
|
|
348
|
+
if (input.outcome === "saved")
|
|
349
|
+
state.counters.autosavesCompleted += 1;
|
|
350
|
+
if (input.outcome === "skipped")
|
|
351
|
+
state.counters.autosavesSkipped += 1;
|
|
352
|
+
if (input.outcome === "failed")
|
|
353
|
+
state.counters.autosavesFailed += 1;
|
|
354
|
+
state.lastAutosave = {
|
|
355
|
+
sessionId: input.sessionId,
|
|
356
|
+
timestamp: new Date().toISOString(),
|
|
357
|
+
outcome: input.outcome,
|
|
358
|
+
reason: input.reason,
|
|
359
|
+
wing: input.wing,
|
|
360
|
+
sourcePreview: previewText(input.sourcePreview),
|
|
361
|
+
};
|
|
362
|
+
updateSessionState(state, input.sessionId, (sessionState) => {
|
|
363
|
+
if (input.outcome === "saved")
|
|
364
|
+
sessionState.counters.autosavesCompleted += 1;
|
|
365
|
+
if (input.outcome === "skipped")
|
|
366
|
+
sessionState.counters.autosavesSkipped += 1;
|
|
367
|
+
if (input.outcome === "failed")
|
|
368
|
+
sessionState.counters.autosavesFailed += 1;
|
|
369
|
+
sessionState.lastAutosave = state.lastAutosave;
|
|
370
|
+
});
|
|
371
|
+
});
|
|
372
|
+
};
|
|
373
|
+
export const readStatusState = async () => {
|
|
374
|
+
await writeQueue;
|
|
375
|
+
return loadState();
|
|
376
|
+
};
|
|
377
|
+
export const resetStatusState = async () => {
|
|
378
|
+
writeQueue = Promise.resolve();
|
|
379
|
+
try {
|
|
380
|
+
await fs.unlink(getStatusFilePath());
|
|
381
|
+
}
|
|
382
|
+
catch {
|
|
383
|
+
// ignore missing file in tests
|
|
384
|
+
}
|
|
385
|
+
};
|
|
386
|
+
const isCurrentSession = (expectedSessionId, actualSessionId) => {
|
|
387
|
+
return Boolean(expectedSessionId && actualSessionId && expectedSessionId === actualSessionId);
|
|
388
|
+
};
|
|
389
|
+
export const formatSessionHud = (state, sessionId) => {
|
|
390
|
+
const sessionState = state.sessions[sessionId];
|
|
391
|
+
if (!sessionState)
|
|
392
|
+
return "MEM no activity yet";
|
|
393
|
+
const parts = [
|
|
394
|
+
`hits ${sessionState.counters.retrievalHits}`,
|
|
395
|
+
`saved ${sessionState.counters.autosavesCompleted}`,
|
|
396
|
+
`failed ${sessionState.counters.autosavesFailed}`,
|
|
397
|
+
];
|
|
398
|
+
if (sessionState.counters.autosavesSkipped > 0) {
|
|
399
|
+
parts.push(`skipped ${sessionState.counters.autosavesSkipped}`);
|
|
400
|
+
}
|
|
401
|
+
if (sessionState.counters.manualWrites > 0) {
|
|
402
|
+
parts.push(`writes ${sessionState.counters.manualWrites}`);
|
|
403
|
+
}
|
|
404
|
+
if (sessionState.lastAutosave?.outcome === "failed") {
|
|
405
|
+
return `MEM FAILED · ${parts.join(" · ")}`;
|
|
406
|
+
}
|
|
407
|
+
if (sessionState.lastAutosave?.outcome === "skipped") {
|
|
408
|
+
return `MEM SKIPPED · ${parts.join(" · ")}`;
|
|
409
|
+
}
|
|
410
|
+
return `MEM ${parts.join(" · ")}`;
|
|
411
|
+
};
|
|
412
|
+
const pushRetrievalLines = (lines, retrieval, verbose) => {
|
|
413
|
+
if ("scope" in retrieval) {
|
|
414
|
+
const count = retrieval.resultCount;
|
|
415
|
+
if (count && count > 0) {
|
|
416
|
+
lines.push(`- Memory lookup: found ${count} relevant ${count === 1 ? "memory" : "memories"}.`);
|
|
417
|
+
}
|
|
418
|
+
else if (count === 0) {
|
|
419
|
+
lines.push("- Memory lookup: no relevant memory found.");
|
|
420
|
+
}
|
|
421
|
+
else {
|
|
422
|
+
lines.push("- Memory lookup: search completed; result count unavailable.");
|
|
423
|
+
}
|
|
424
|
+
lines.push(`- Query: ${retrieval.queryPreview}`);
|
|
425
|
+
if (verbose && retrieval.previews.length) {
|
|
426
|
+
lines.push("- Relevant memories:");
|
|
427
|
+
for (const preview of retrieval.previews) {
|
|
428
|
+
lines.push(` - ${preview}`);
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
return;
|
|
432
|
+
}
|
|
433
|
+
lines.push("- Memory lookup: retrieval prompt was prepared but no visible search result is recorded yet.");
|
|
434
|
+
lines.push(`- Query: ${retrieval.queryPreview}`);
|
|
435
|
+
};
|
|
436
|
+
const pushAutosaveLines = (lines, autosave) => {
|
|
437
|
+
const outcome = autosave.outcome === "saved"
|
|
438
|
+
? "saved session context"
|
|
439
|
+
: autosave.outcome === "skipped"
|
|
440
|
+
? "skipped"
|
|
441
|
+
: "failed";
|
|
442
|
+
lines.push(`- Autosave: ${outcome} after ${autosave.reason}.`);
|
|
443
|
+
if (autosave.sourcePreview) {
|
|
444
|
+
lines.push(`- Source context: ${autosave.sourcePreview}`);
|
|
445
|
+
}
|
|
446
|
+
};
|
|
447
|
+
const compactRetrievalSummary = (retrieval) => {
|
|
448
|
+
if (!retrieval)
|
|
449
|
+
return "no memory lookup recorded";
|
|
450
|
+
if ("scope" in retrieval) {
|
|
451
|
+
const count = retrieval.resultCount;
|
|
452
|
+
if (count && count > 0)
|
|
453
|
+
return `${count} relevant ${count === 1 ? "memory" : "memories"} found`;
|
|
454
|
+
if (count === 0)
|
|
455
|
+
return "no relevant memory found";
|
|
456
|
+
return "memory lookup completed";
|
|
457
|
+
}
|
|
458
|
+
return "retrieval prompt prepared";
|
|
459
|
+
};
|
|
460
|
+
const compactAutosaveSummary = (autosave) => {
|
|
461
|
+
if (!autosave)
|
|
462
|
+
return "no autosave recorded";
|
|
463
|
+
if (autosave.outcome === "saved")
|
|
464
|
+
return `autosave saved after ${autosave.reason}`;
|
|
465
|
+
if (autosave.outcome === "skipped")
|
|
466
|
+
return `autosave skipped after ${autosave.reason}`;
|
|
467
|
+
return `autosave failed after ${autosave.reason}`;
|
|
468
|
+
};
|
|
469
|
+
export const formatStatusSummary = (state, sessionId, options = {}) => {
|
|
470
|
+
const verbose = options.verbose ?? false;
|
|
471
|
+
const compact = options.compact ?? false;
|
|
472
|
+
const lines = ["MemPalace status"];
|
|
473
|
+
if (!state.lastRetrieval && !state.lastAutosave && !state.lastWrite && !state.lastRetrievalPrompt) {
|
|
474
|
+
lines.push("- No visible retrieval or autosave activity recorded yet.");
|
|
475
|
+
return lines.join("\n");
|
|
476
|
+
}
|
|
477
|
+
const currentRetrieval = state.lastRetrieval && isCurrentSession(sessionId, state.lastRetrieval.sessionId)
|
|
478
|
+
? state.lastRetrieval
|
|
479
|
+
: !state.lastRetrieval && state.lastRetrievalPrompt && isCurrentSession(sessionId, state.lastRetrievalPrompt.sessionId)
|
|
480
|
+
? state.lastRetrievalPrompt
|
|
481
|
+
: undefined;
|
|
482
|
+
const lastRetrieval = state.lastRetrieval && !isCurrentSession(sessionId, state.lastRetrieval.sessionId)
|
|
483
|
+
? state.lastRetrieval
|
|
484
|
+
: !state.lastRetrieval && state.lastRetrievalPrompt && !isCurrentSession(sessionId, state.lastRetrievalPrompt.sessionId)
|
|
485
|
+
? state.lastRetrievalPrompt
|
|
486
|
+
: undefined;
|
|
487
|
+
const currentAutosave = state.lastAutosave && isCurrentSession(sessionId, state.lastAutosave.sessionId)
|
|
488
|
+
? state.lastAutosave
|
|
489
|
+
: undefined;
|
|
490
|
+
const lastAutosave = state.lastAutosave && !isCurrentSession(sessionId, state.lastAutosave.sessionId)
|
|
491
|
+
? state.lastAutosave
|
|
492
|
+
: undefined;
|
|
493
|
+
if (compact) {
|
|
494
|
+
lines.push(`- Current session: ${compactRetrievalSummary(currentRetrieval)}; ${compactAutosaveSummary(currentAutosave)}.`);
|
|
495
|
+
lines.push(`- Last activity: ${compactRetrievalSummary(lastRetrieval)}; ${compactAutosaveSummary(lastAutosave)}.`);
|
|
496
|
+
if (state.lastWrite) {
|
|
497
|
+
lines.push(`- Last write: ${state.lastWrite.mode} \`${state.lastWrite.preview}\`.`);
|
|
498
|
+
}
|
|
499
|
+
return lines.join("\n");
|
|
500
|
+
}
|
|
501
|
+
const currentLines = [];
|
|
502
|
+
const lastLines = [];
|
|
503
|
+
if (currentRetrieval)
|
|
504
|
+
pushRetrievalLines(currentLines, currentRetrieval, verbose);
|
|
505
|
+
if (lastRetrieval)
|
|
506
|
+
pushRetrievalLines(lastLines, lastRetrieval, verbose);
|
|
507
|
+
if (currentAutosave)
|
|
508
|
+
pushAutosaveLines(currentLines, currentAutosave);
|
|
509
|
+
if (lastAutosave)
|
|
510
|
+
pushAutosaveLines(lastLines, lastAutosave);
|
|
511
|
+
lines.push("Current session");
|
|
512
|
+
if (currentLines.length) {
|
|
513
|
+
lines.push(...currentLines);
|
|
514
|
+
}
|
|
515
|
+
else {
|
|
516
|
+
lines.push("- No retrieval or autosave recorded for this session yet.");
|
|
517
|
+
}
|
|
518
|
+
lines.push("Last activity");
|
|
519
|
+
if (lastLines.length) {
|
|
520
|
+
lines.push(...lastLines);
|
|
521
|
+
}
|
|
522
|
+
else {
|
|
523
|
+
lines.push("- No separate past retrieval or autosave activity recorded.");
|
|
524
|
+
}
|
|
525
|
+
if (state.lastWrite) {
|
|
526
|
+
lines.push(`- Last explicit memory write: ${state.lastWrite.mode} stored \`${state.lastWrite.preview}\`.`);
|
|
527
|
+
}
|
|
528
|
+
lines.push("- Totals:");
|
|
529
|
+
lines.push(` retrieval prompts: ${state.counters.retrievalPrompts}`);
|
|
530
|
+
lines.push(` retrieval searches: ${state.counters.retrievalSearches}`);
|
|
531
|
+
lines.push(` retrieval hits: ${state.counters.retrievalHits}`);
|
|
532
|
+
lines.push(` autosaves completed: ${state.counters.autosavesCompleted}`);
|
|
533
|
+
lines.push(` autosaves skipped: ${state.counters.autosavesSkipped}`);
|
|
534
|
+
lines.push(` autosaves failed: ${state.counters.autosavesFailed}`);
|
|
535
|
+
lines.push(` manual writes: ${state.counters.manualWrites}`);
|
|
536
|
+
return lines.join("\n");
|
|
537
|
+
};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { PluginInput } from "@opencode-ai/plugin";
|
|
2
2
|
import type { Event, Message, Part } from "@opencode-ai/sdk";
|
|
3
|
-
import { DEFAULT_ROOM, DEFAULT_TOPIC, DEFAULT_AGENT_NAME, DEFAULT_EXTRACT_MODE, DEFAULT_INJECTED_ITEMS, DEFAULT_RETRIEVAL_LIMIT, DEFAULT_LIMIT, DEFAULT_ADAPTER_TIMEOUT_MS, MAX_USER_MESSAGES_DIGEST, MAX_TRANSCRIPT_MESSAGES_DIGEST, DATE_ISO_SLICE, SERVICE_NAME, COMPACTION_CONTEXT_MESSAGE, ERROR_MESSAGES, DEFAULT_USER_WING_PREFIX, DEFAULT_PROJECT_WING_PREFIX, DEFAULT_KEYWORD_PATTERNS, CONFIG_PATH_SEGMENTS, ENV_KEYS, LOG_FILE_NAME, DIRECT_MEMPALACE_MUTATION_TOOLS, TOOL_DESCRIPTIONS, TOOL_ERROR_MESSAGES, LOG_MESSAGES, INSTRUCTION_TEXT } from "./constants";
|
|
4
|
-
export { DEFAULT_ROOM, DEFAULT_TOPIC, DEFAULT_AGENT_NAME, DEFAULT_EXTRACT_MODE, DEFAULT_INJECTED_ITEMS, DEFAULT_RETRIEVAL_LIMIT, DEFAULT_LIMIT, DEFAULT_ADAPTER_TIMEOUT_MS, DEFAULT_USER_WING_PREFIX, DEFAULT_PROJECT_WING_PREFIX, DEFAULT_KEYWORD_PATTERNS, CONFIG_PATH_SEGMENTS, ENV_KEYS, MAX_USER_MESSAGES_DIGEST, MAX_TRANSCRIPT_MESSAGES_DIGEST, DATE_ISO_SLICE, SERVICE_NAME, LOG_FILE_NAME, DIRECT_MEMPALACE_MUTATION_TOOLS, TOOL_DESCRIPTIONS, TOOL_ERROR_MESSAGES, LOG_MESSAGES, INSTRUCTION_TEXT, COMPACTION_CONTEXT_MESSAGE, ERROR_MESSAGES, };
|
|
3
|
+
import { DEFAULT_ROOM, DEFAULT_TOPIC, DEFAULT_AGENT_NAME, DEFAULT_EXTRACT_MODE, DEFAULT_INJECTED_ITEMS, DEFAULT_RETRIEVAL_LIMIT, DEFAULT_LIMIT, DEFAULT_ADAPTER_TIMEOUT_MS, MAX_USER_MESSAGES_DIGEST, MAX_TRANSCRIPT_MESSAGES_DIGEST, DATE_ISO_SLICE, SERVICE_NAME, COMPACTION_CONTEXT_MESSAGE, ERROR_MESSAGES, DEFAULT_USER_WING_PREFIX, DEFAULT_PROJECT_WING_PREFIX, DEFAULT_KEYWORD_PATTERNS, CONFIG_PATH_SEGMENTS, ENV_KEYS, LOG_FILE_NAME, STATUS_FILE_NAME, DIRECT_MEMPALACE_MUTATION_TOOLS, TOOL_DESCRIPTIONS, TOOL_ERROR_MESSAGES, LOG_MESSAGES, INSTRUCTION_TEXT } from "./constants";
|
|
4
|
+
export { DEFAULT_ROOM, DEFAULT_TOPIC, DEFAULT_AGENT_NAME, DEFAULT_EXTRACT_MODE, DEFAULT_INJECTED_ITEMS, DEFAULT_RETRIEVAL_LIMIT, DEFAULT_LIMIT, DEFAULT_ADAPTER_TIMEOUT_MS, DEFAULT_USER_WING_PREFIX, DEFAULT_PROJECT_WING_PREFIX, DEFAULT_KEYWORD_PATTERNS, CONFIG_PATH_SEGMENTS, ENV_KEYS, MAX_USER_MESSAGES_DIGEST, MAX_TRANSCRIPT_MESSAGES_DIGEST, DATE_ISO_SLICE, SERVICE_NAME, LOG_FILE_NAME, STATUS_FILE_NAME, DIRECT_MEMPALACE_MUTATION_TOOLS, TOOL_DESCRIPTIONS, TOOL_ERROR_MESSAGES, LOG_MESSAGES, INSTRUCTION_TEXT, COMPACTION_CONTEXT_MESSAGE, ERROR_MESSAGES, };
|
|
5
5
|
export declare const MEMORY_SCOPES: readonly ["user", "project"];
|
|
6
6
|
export type MemoryScope = (typeof MEMORY_SCOPES)[number];
|
|
7
7
|
export declare const USER_MEMORY_ROOMS: readonly ["preferences", "workflow", "communication"];
|
package/dist/plugin/lib/types.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { DEFAULT_ROOM, DEFAULT_TOPIC, DEFAULT_AGENT_NAME, DEFAULT_EXTRACT_MODE, DEFAULT_INJECTED_ITEMS, DEFAULT_RETRIEVAL_LIMIT, DEFAULT_LIMIT, DEFAULT_ADAPTER_TIMEOUT_MS, MAX_USER_MESSAGES_DIGEST, MAX_TRANSCRIPT_MESSAGES_DIGEST, DATE_ISO_SLICE, SERVICE_NAME, COMPACTION_CONTEXT_MESSAGE, ERROR_MESSAGES, DEFAULT_USER_WING_PREFIX, DEFAULT_PROJECT_WING_PREFIX, DEFAULT_KEYWORD_PATTERNS, CONFIG_PATH_SEGMENTS, ENV_KEYS, LOG_FILE_NAME, DIRECT_MEMPALACE_MUTATION_TOOLS, TOOL_DESCRIPTIONS, TOOL_ERROR_MESSAGES, LOG_MESSAGES, INSTRUCTION_TEXT, } from "./constants";
|
|
2
|
-
export { DEFAULT_ROOM, DEFAULT_TOPIC, DEFAULT_AGENT_NAME, DEFAULT_EXTRACT_MODE, DEFAULT_INJECTED_ITEMS, DEFAULT_RETRIEVAL_LIMIT, DEFAULT_LIMIT, DEFAULT_ADAPTER_TIMEOUT_MS, DEFAULT_USER_WING_PREFIX, DEFAULT_PROJECT_WING_PREFIX, DEFAULT_KEYWORD_PATTERNS, CONFIG_PATH_SEGMENTS, ENV_KEYS, MAX_USER_MESSAGES_DIGEST, MAX_TRANSCRIPT_MESSAGES_DIGEST, DATE_ISO_SLICE, SERVICE_NAME, LOG_FILE_NAME, DIRECT_MEMPALACE_MUTATION_TOOLS, TOOL_DESCRIPTIONS, TOOL_ERROR_MESSAGES, LOG_MESSAGES, INSTRUCTION_TEXT, COMPACTION_CONTEXT_MESSAGE, ERROR_MESSAGES, };
|
|
1
|
+
import { DEFAULT_ROOM, DEFAULT_TOPIC, DEFAULT_AGENT_NAME, DEFAULT_EXTRACT_MODE, DEFAULT_INJECTED_ITEMS, DEFAULT_RETRIEVAL_LIMIT, DEFAULT_LIMIT, DEFAULT_ADAPTER_TIMEOUT_MS, MAX_USER_MESSAGES_DIGEST, MAX_TRANSCRIPT_MESSAGES_DIGEST, DATE_ISO_SLICE, SERVICE_NAME, COMPACTION_CONTEXT_MESSAGE, ERROR_MESSAGES, DEFAULT_USER_WING_PREFIX, DEFAULT_PROJECT_WING_PREFIX, DEFAULT_KEYWORD_PATTERNS, CONFIG_PATH_SEGMENTS, ENV_KEYS, LOG_FILE_NAME, STATUS_FILE_NAME, DIRECT_MEMPALACE_MUTATION_TOOLS, TOOL_DESCRIPTIONS, TOOL_ERROR_MESSAGES, LOG_MESSAGES, INSTRUCTION_TEXT, } from "./constants";
|
|
2
|
+
export { DEFAULT_ROOM, DEFAULT_TOPIC, DEFAULT_AGENT_NAME, DEFAULT_EXTRACT_MODE, DEFAULT_INJECTED_ITEMS, DEFAULT_RETRIEVAL_LIMIT, DEFAULT_LIMIT, DEFAULT_ADAPTER_TIMEOUT_MS, DEFAULT_USER_WING_PREFIX, DEFAULT_PROJECT_WING_PREFIX, DEFAULT_KEYWORD_PATTERNS, CONFIG_PATH_SEGMENTS, ENV_KEYS, MAX_USER_MESSAGES_DIGEST, MAX_TRANSCRIPT_MESSAGES_DIGEST, DATE_ISO_SLICE, SERVICE_NAME, LOG_FILE_NAME, STATUS_FILE_NAME, DIRECT_MEMPALACE_MUTATION_TOOLS, TOOL_DESCRIPTIONS, TOOL_ERROR_MESSAGES, LOG_MESSAGES, INSTRUCTION_TEXT, COMPACTION_CONTEXT_MESSAGE, ERROR_MESSAGES, };
|
|
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"];
|
|
@@ -2,10 +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, summarizeSearchResult } from "../lib/status";
|
|
10
|
+
import { writeLog } from "../lib/log";
|
|
9
11
|
import { MEMORY_SCOPES, TOOL_MEMORY_MODES } from "../lib/types";
|
|
10
12
|
const getProjectWing = (projectName, prefix) => {
|
|
11
13
|
return getProjectScope(projectName, prefix).wing;
|
|
@@ -34,7 +36,7 @@ export const mempalaceMemoryTool = (ctx) => tool({
|
|
|
34
36
|
agent_name: tool.schema.string().optional().default(DEFAULT_AGENT_NAME),
|
|
35
37
|
limit: tool.schema.number().optional().default(DEFAULT_LIMIT),
|
|
36
38
|
},
|
|
37
|
-
async execute(args) {
|
|
39
|
+
async execute(args, executionContext) {
|
|
38
40
|
const config = await loadConfig();
|
|
39
41
|
const scope = args.scope ?? "project";
|
|
40
42
|
const wing = scope === "user"
|
|
@@ -54,6 +56,15 @@ export const mempalaceMemoryTool = (ctx) => tool({
|
|
|
54
56
|
content,
|
|
55
57
|
added_by: DEFAULT_AGENT_NAME,
|
|
56
58
|
});
|
|
59
|
+
if (result?.success !== false) {
|
|
60
|
+
await recordMemoryWrite({
|
|
61
|
+
sessionId: executionContext.sessionID,
|
|
62
|
+
mode: "save",
|
|
63
|
+
scope,
|
|
64
|
+
room: args.room,
|
|
65
|
+
preview: content,
|
|
66
|
+
});
|
|
67
|
+
}
|
|
57
68
|
return JSON.stringify(result);
|
|
58
69
|
}
|
|
59
70
|
if (args.mode === "search") {
|
|
@@ -67,7 +78,31 @@ export const mempalaceMemoryTool = (ctx) => tool({
|
|
|
67
78
|
room: normalizeValue(args.room, false),
|
|
68
79
|
limit: args.limit,
|
|
69
80
|
});
|
|
70
|
-
|
|
81
|
+
const summary = summarizeSearchResult(result);
|
|
82
|
+
if (result?.success !== false) {
|
|
83
|
+
await recordRetrievalSearch({
|
|
84
|
+
sessionId: executionContext.sessionID,
|
|
85
|
+
scope,
|
|
86
|
+
room: args.room,
|
|
87
|
+
query,
|
|
88
|
+
result,
|
|
89
|
+
});
|
|
90
|
+
await writeLog("INFO", LOG_MESSAGES.retrievalSearchCompleted, {
|
|
91
|
+
sessionId: executionContext.sessionID,
|
|
92
|
+
scope,
|
|
93
|
+
room: args.room,
|
|
94
|
+
query: query.slice(0, 200),
|
|
95
|
+
resultCount: summary.resultCount ?? 0,
|
|
96
|
+
previews: summary.previews,
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
const retrievalNote = summary.resultCount
|
|
100
|
+
? `Found ${summary.resultCount} relevant ${summary.resultCount === 1 ? "memory" : "memories"}:\n${summary.previews.map((p, i) => `${i + 1}. ${p}`).join("\n")}`
|
|
101
|
+
: "No relevant memories found.";
|
|
102
|
+
const enriched = typeof result === "object" && result !== null
|
|
103
|
+
? { ...result, _retrieval_summary: retrievalNote }
|
|
104
|
+
: result;
|
|
105
|
+
return JSON.stringify(enriched);
|
|
71
106
|
}
|
|
72
107
|
if (args.mode === "kg_add") {
|
|
73
108
|
if (!args.subject || !args.predicate || !args.object) {
|
|
@@ -84,6 +119,14 @@ export const mempalaceMemoryTool = (ctx) => tool({
|
|
|
84
119
|
valid_from: new Date().toISOString().slice(0, DATE_ISO_SLICE),
|
|
85
120
|
source_closet: "",
|
|
86
121
|
});
|
|
122
|
+
if (result?.success !== false) {
|
|
123
|
+
await recordMemoryWrite({
|
|
124
|
+
sessionId: executionContext.sessionID,
|
|
125
|
+
mode: "kg_add",
|
|
126
|
+
scope,
|
|
127
|
+
preview: `${subject} ${predicate} ${object}`,
|
|
128
|
+
});
|
|
129
|
+
}
|
|
87
130
|
return JSON.stringify(result);
|
|
88
131
|
}
|
|
89
132
|
const result = await executeAdapter(ctx.$, {
|
|
@@ -92,6 +135,14 @@ export const mempalaceMemoryTool = (ctx) => tool({
|
|
|
92
135
|
entry: normalizeValue(args.content || "", config.privacyRedactionEnabled) ?? "",
|
|
93
136
|
topic: normalizeValue(args.topic, false) ?? DEFAULT_TOPIC,
|
|
94
137
|
});
|
|
138
|
+
if (result?.success !== false) {
|
|
139
|
+
await recordMemoryWrite({
|
|
140
|
+
sessionId: executionContext.sessionID,
|
|
141
|
+
mode: "diary_write",
|
|
142
|
+
scope,
|
|
143
|
+
preview: normalizeValue(args.content || "", config.privacyRedactionEnabled) ?? "",
|
|
144
|
+
});
|
|
145
|
+
}
|
|
95
146
|
return JSON.stringify(result);
|
|
96
147
|
},
|
|
97
148
|
});
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export declare const mempalaceStatusTool: () => {
|
|
2
|
+
description: string;
|
|
3
|
+
args: {
|
|
4
|
+
verbose: import("zod").ZodDefault<import("zod").ZodOptional<import("zod").ZodBoolean>>;
|
|
5
|
+
compact: import("zod").ZodDefault<import("zod").ZodOptional<import("zod").ZodBoolean>>;
|
|
6
|
+
};
|
|
7
|
+
execute(args: {
|
|
8
|
+
verbose: boolean;
|
|
9
|
+
compact: boolean;
|
|
10
|
+
}, context: import("@opencode-ai/plugin").ToolContext): Promise<string>;
|
|
11
|
+
};
|