opencode-mem 2.16.0 → 2.17.1
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/dist/index.d.ts.map +1 -1
- package/dist/index.js +13 -4
- package/dist/services/ai/providers/openai-chat-completion.d.ts.map +1 -1
- package/dist/services/ai/providers/openai-chat-completion.js +37 -2
- package/dist/services/auto-capture.d.ts.map +1 -1
- package/dist/services/auto-capture.js +32 -1
- package/dist/services/client.d.ts.map +1 -1
- package/dist/services/client.js +7 -1
- package/dist/services/embedding.js +2 -2
- package/dist/services/user-prompt/user-prompt-manager.d.ts +10 -0
- package/dist/services/user-prompt/user-prompt-manager.d.ts.map +1 -1
- package/dist/services/user-prompt/user-prompt-manager.js +14 -0
- package/dist/services/web-server.d.ts.map +1 -1
- package/dist/services/web-server.js +12 -2
- package/package.json +2 -2
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAe,MAAM,qBAAqB,CAAC;AAmB/D,eAAO,MAAM,iBAAiB,EAAE,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAe,MAAM,qBAAqB,CAAC;AAmB/D,eAAO,MAAM,iBAAiB,EAAE,MAkiB/B,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -114,12 +114,15 @@ export const OpenCodeMemPlugin = async (ctx) => {
|
|
|
114
114
|
}
|
|
115
115
|
});
|
|
116
116
|
}
|
|
117
|
+
const cleanupPlugin = async () => {
|
|
118
|
+
if (webServer)
|
|
119
|
+
await webServer.stop();
|
|
120
|
+
if (memoryClient)
|
|
121
|
+
memoryClient.close();
|
|
122
|
+
};
|
|
117
123
|
const shutdownHandler = async () => {
|
|
118
124
|
try {
|
|
119
|
-
|
|
120
|
-
await webServer.stop();
|
|
121
|
-
}
|
|
122
|
-
memoryClient.close();
|
|
125
|
+
await cleanupPlugin();
|
|
123
126
|
process.exit(0);
|
|
124
127
|
}
|
|
125
128
|
catch (error) {
|
|
@@ -129,6 +132,12 @@ export const OpenCodeMemPlugin = async (ctx) => {
|
|
|
129
132
|
};
|
|
130
133
|
process.on("SIGINT", shutdownHandler);
|
|
131
134
|
process.on("SIGTERM", shutdownHandler);
|
|
135
|
+
process.on("exit", () => {
|
|
136
|
+
if (webServer)
|
|
137
|
+
webServer.stop().catch(() => { });
|
|
138
|
+
if (memoryClient)
|
|
139
|
+
memoryClient.close();
|
|
140
|
+
});
|
|
132
141
|
return {
|
|
133
142
|
"chat.message": async (input, output) => {
|
|
134
143
|
if (!isConfigured() || !CONFIG.chatMessage.enabled)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"openai-chat-completion.d.ts","sourceRoot":"","sources":["../../../../src/services/ai/providers/openai-chat-completion.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,cAAc,EACd,KAAK,cAAc,EACnB,KAAK,cAAc,EAEpB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,kCAAkC,CAAC;AACzE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,6BAA6B,CAAC;AAC7D,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;
|
|
1
|
+
{"version":3,"file":"openai-chat-completion.d.ts","sourceRoot":"","sources":["../../../../src/services/ai/providers/openai-chat-completion.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,cAAc,EACd,KAAK,cAAc,EACnB,KAAK,cAAc,EAEpB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,kCAAkC,CAAC;AACzE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,6BAA6B,CAAC;AAC7D,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AA+ElE,qBAAa,4BAA6B,SAAQ,cAAc;IAC9D,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAmB;gBAExC,MAAM,EAAE,cAAc,EAAE,gBAAgB,EAAE,gBAAgB;IAKtE,eAAe,IAAI,MAAM;IAIzB,eAAe,IAAI,OAAO;IAI1B,OAAO,CAAC,eAAe;IAqBvB,SAAS,CAAC,iCAAiC,CAAC,QAAQ,EAAE,SAAS,EAAE,GAAG,SAAS,EAAE;IAwCzE,eAAe,CACnB,YAAY,EAAE,MAAM,EACpB,UAAU,EAAE,MAAM,EAClB,UAAU,EAAE,kBAAkB,EAC9B,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,cAAc,CAAC;CAkT3B"}
|
|
@@ -25,6 +25,23 @@ function hasNonEmptyChoices(data) {
|
|
|
25
25
|
return false;
|
|
26
26
|
return true;
|
|
27
27
|
}
|
|
28
|
+
function extractFirstJSON(raw) {
|
|
29
|
+
let depth = 0;
|
|
30
|
+
let start = -1;
|
|
31
|
+
for (let i = 0; i < raw.length; i++) {
|
|
32
|
+
if (raw[i] === "{" || raw[i] === "[") {
|
|
33
|
+
if (depth === 0)
|
|
34
|
+
start = i;
|
|
35
|
+
depth++;
|
|
36
|
+
}
|
|
37
|
+
else if (raw[i] === "}" || raw[i] === "]") {
|
|
38
|
+
depth--;
|
|
39
|
+
if (depth === 0)
|
|
40
|
+
return raw.slice(start, i + 1);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
return null;
|
|
44
|
+
}
|
|
28
45
|
export class OpenAIChatCompletionProvider extends BaseAIProvider {
|
|
29
46
|
aiSessionManager;
|
|
30
47
|
constructor(config, aiSessionManager) {
|
|
@@ -133,6 +150,7 @@ export class OpenAIChatCompletionProvider extends BaseAIProvider {
|
|
|
133
150
|
let iterations = 0;
|
|
134
151
|
const maxIterations = this.config.maxIterations ?? 5;
|
|
135
152
|
const iterationTimeout = this.config.iterationTimeout ?? 30000;
|
|
153
|
+
let lastErrorMessage = "";
|
|
136
154
|
while (iterations < maxIterations) {
|
|
137
155
|
iterations++;
|
|
138
156
|
const controller = new AbortController();
|
|
@@ -245,7 +263,21 @@ export class OpenAIChatCompletionProvider extends BaseAIProvider {
|
|
|
245
263
|
const toolCallId = toolCall.id;
|
|
246
264
|
if (toolCall.function.name === toolSchema.function.name) {
|
|
247
265
|
try {
|
|
248
|
-
const parsed =
|
|
266
|
+
const parsed = (() => {
|
|
267
|
+
const raw = toolCall.function.arguments;
|
|
268
|
+
if (typeof raw !== "string") {
|
|
269
|
+
return JSON.parse(JSON.stringify(raw));
|
|
270
|
+
}
|
|
271
|
+
try {
|
|
272
|
+
return JSON.parse(raw);
|
|
273
|
+
}
|
|
274
|
+
catch (e1) {
|
|
275
|
+
const fixed = extractFirstJSON(raw);
|
|
276
|
+
if (fixed)
|
|
277
|
+
return JSON.parse(fixed);
|
|
278
|
+
throw e1;
|
|
279
|
+
}
|
|
280
|
+
})();
|
|
249
281
|
const result = UserProfileValidator.validate(parsed);
|
|
250
282
|
if (!result.valid) {
|
|
251
283
|
throw new Error(result.errors.join(", "));
|
|
@@ -270,6 +302,7 @@ export class OpenAIChatCompletionProvider extends BaseAIProvider {
|
|
|
270
302
|
rawArguments: toolCall.function.arguments.slice(0, 500),
|
|
271
303
|
});
|
|
272
304
|
const errorMessage = `Validation failed: ${String(validationError)}`;
|
|
305
|
+
lastErrorMessage = errorMessage;
|
|
273
306
|
this.addToolResponse(session.id, messages, toolCallId, JSON.stringify({ success: false, error: errorMessage }));
|
|
274
307
|
return {
|
|
275
308
|
success: false,
|
|
@@ -284,7 +317,9 @@ export class OpenAIChatCompletionProvider extends BaseAIProvider {
|
|
|
284
317
|
}
|
|
285
318
|
}
|
|
286
319
|
const retrySequence = this.aiSessionManager.getLastSequence(session.id) + 1;
|
|
287
|
-
const retryPrompt =
|
|
320
|
+
const retryPrompt = lastErrorMessage
|
|
321
|
+
? `Your previous attempt failed. Error: ${lastErrorMessage}. Please fix the JSON in your tool call arguments and try again. Output ONLY valid JSON, no extra text outside the JSON structure.`
|
|
322
|
+
: "Please use the tool to extract and save the data as instructed.";
|
|
288
323
|
this.aiSessionManager.addMessage({
|
|
289
324
|
aiSessionId: session.id,
|
|
290
325
|
sequence: retrySequence,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auto-capture.d.ts","sourceRoot":"","sources":["../../src/services/auto-capture.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAgBvD,wBAAsB,kBAAkB,CACtC,GAAG,EAAE,WAAW,EAChB,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,IAAI,CAAC,
|
|
1
|
+
{"version":3,"file":"auto-capture.d.ts","sourceRoot":"","sources":["../../src/services/auto-capture.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAgBvD,wBAAsB,kBAAkB,CACtC,GAAG,EAAE,WAAW,EAChB,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,IAAI,CAAC,CA+Hf"}
|
|
@@ -9,6 +9,13 @@ export async function performAutoCapture(ctx, sessionID, directory) {
|
|
|
9
9
|
if (isCaptureRunning)
|
|
10
10
|
return;
|
|
11
11
|
isCaptureRunning = true;
|
|
12
|
+
// Tracks the prompt currently held in the captured=2 in-progress state.
|
|
13
|
+
// Any code path between claimPrompt() and a terminal action (markAsCaptured
|
|
14
|
+
// or deletePrompt) MUST leave this set so the finally block can release the
|
|
15
|
+
// lock. Without this, transient failures (no AI response yet, missing
|
|
16
|
+
// client, LLM error, plugin restart) leave the row stuck at captured=2 and
|
|
17
|
+
// block all future captures of that prompt.
|
|
18
|
+
let claimedPromptId = null;
|
|
12
19
|
try {
|
|
13
20
|
const prompt = userPromptManager.getLastUncapturedPrompt(sessionID);
|
|
14
21
|
if (!prompt) {
|
|
@@ -17,6 +24,7 @@ export async function performAutoCapture(ctx, sessionID, directory) {
|
|
|
17
24
|
if (!userPromptManager.claimPrompt(prompt.id)) {
|
|
18
25
|
return;
|
|
19
26
|
}
|
|
27
|
+
claimedPromptId = prompt.id;
|
|
20
28
|
if (!ctx.client) {
|
|
21
29
|
throw new Error("Client not available");
|
|
22
30
|
}
|
|
@@ -45,9 +53,18 @@ export async function performAutoCapture(ctx, sessionID, directory) {
|
|
|
45
53
|
const summaryResult = await generateSummary(context, sessionID, prompt.content);
|
|
46
54
|
if (!summaryResult || summaryResult.type === "skip") {
|
|
47
55
|
userPromptManager.deletePrompt(prompt.id);
|
|
56
|
+
claimedPromptId = null;
|
|
48
57
|
return;
|
|
49
58
|
}
|
|
50
|
-
|
|
59
|
+
// Append a "Tags: ..." footer to the summary before persisting. Tags are
|
|
60
|
+
// already embedded separately into tagsVector, but the contentVector never
|
|
61
|
+
// sees them. Inlining them here lets the 0.6-weight content channel also
|
|
62
|
+
// contribute when a query mentions a tag keyword, making recall noticeably
|
|
63
|
+
// less brittle for precise lookups (e.g. searching for a single API name).
|
|
64
|
+
const summaryWithTags = summaryResult.tags && summaryResult.tags.length > 0
|
|
65
|
+
? `${summaryResult.summary}\n\nTags: ${summaryResult.tags.join(", ")}`
|
|
66
|
+
: summaryResult.summary;
|
|
67
|
+
const result = await memoryClient.addMemory(summaryWithTags, tags.project.tag, {
|
|
51
68
|
source: "auto-capture",
|
|
52
69
|
type: summaryResult.type,
|
|
53
70
|
tags: summaryResult.tags,
|
|
@@ -64,6 +81,7 @@ export async function performAutoCapture(ctx, sessionID, directory) {
|
|
|
64
81
|
if (result.success) {
|
|
65
82
|
userPromptManager.linkMemoryToPrompt(prompt.id, result.id);
|
|
66
83
|
userPromptManager.markAsCaptured(prompt.id);
|
|
84
|
+
claimedPromptId = null;
|
|
67
85
|
if (CONFIG.showAutoCaptureToasts) {
|
|
68
86
|
await ctx.client?.tui
|
|
69
87
|
.showToast({
|
|
@@ -79,6 +97,19 @@ export async function performAutoCapture(ctx, sessionID, directory) {
|
|
|
79
97
|
}
|
|
80
98
|
}
|
|
81
99
|
finally {
|
|
100
|
+
// Release any in-progress claim that did not reach a terminal state.
|
|
101
|
+
// This covers both early returns (no AI response yet, missing client,
|
|
102
|
+
// empty content) and exceptions (LLM failure, network error). Without
|
|
103
|
+
// releasing here, the prompt would remain locked at captured=2 with no
|
|
104
|
+
// automatic recovery path until the next plugin restart.
|
|
105
|
+
if (claimedPromptId !== null) {
|
|
106
|
+
try {
|
|
107
|
+
userPromptManager.releaseClaim(claimedPromptId);
|
|
108
|
+
}
|
|
109
|
+
catch (releaseErr) {
|
|
110
|
+
log(`Failed to release captured=2 claim for prompt ${claimedPromptId}: ${releaseErr instanceof Error ? releaseErr.message : String(releaseErr)}`);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
82
113
|
isCaptureRunning = false;
|
|
83
114
|
}
|
|
84
115
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/services/client.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAGpD,MAAM,MAAM,WAAW,GAAG,SAAS,GAAG,cAAc,CAAC;AAyDrD,qBAAa,iBAAiB;IAC5B,OAAO,CAAC,WAAW,CAA8B;IACjD,OAAO,CAAC,aAAa,CAAkB;;YAIzB,UAAU;IAiBlB,MAAM,CAAC,gBAAgB,CAAC,EAAE,CAAC,QAAQ,EAAE,GAAG,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;IAKjE,OAAO,IAAI,OAAO,CAAC,OAAO,CAAC;IAIjC,SAAS,IAAI;QACX,WAAW,EAAE,OAAO,CAAC;QACrB,WAAW,EAAE,OAAO,CAAC;QACrB,KAAK,EAAE,OAAO,CAAC;KAChB;IAQD,KAAK,IAAI,IAAI;IAIP,cAAc,CAAC,KAAK,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,EAAE,KAAK,GAAE,WAAuB;;;;;;;;;;;;;IA6BlF,SAAS,CACb,OAAO,EAAE,MAAM,EACf,YAAY,EAAE,MAAM,EACpB,QAAQ,CAAC,EAAE;QACT,IAAI,CAAC,EAAE,UAAU,CAAC;QAClB,MAAM,CAAC,EAAE,QAAQ,GAAG,cAAc,GAAG,QAAQ,GAAG,KAAK,CAAC;QACtD,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;QAChB,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,gBAAgB,CAAC,EAAE,MAAM,CAAC;QAC1B,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,UAAU,CAAC,EAAE,MAAM,CAAC;QACpB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;KACxB;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/services/client.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAGpD,MAAM,MAAM,WAAW,GAAG,SAAS,GAAG,cAAc,CAAC;AAyDrD,qBAAa,iBAAiB;IAC5B,OAAO,CAAC,WAAW,CAA8B;IACjD,OAAO,CAAC,aAAa,CAAkB;;YAIzB,UAAU;IAiBlB,MAAM,CAAC,gBAAgB,CAAC,EAAE,CAAC,QAAQ,EAAE,GAAG,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;IAKjE,OAAO,IAAI,OAAO,CAAC,OAAO,CAAC;IAIjC,SAAS,IAAI;QACX,WAAW,EAAE,OAAO,CAAC;QACrB,WAAW,EAAE,OAAO,CAAC;QACrB,KAAK,EAAE,OAAO,CAAC;KAChB;IAQD,KAAK,IAAI,IAAI;IAIP,cAAc,CAAC,KAAK,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,EAAE,KAAK,GAAE,WAAuB;;;;;;;;;;;;;IA6BlF,SAAS,CACb,OAAO,EAAE,MAAM,EACf,YAAY,EAAE,MAAM,EACpB,QAAQ,CAAC,EAAE;QACT,IAAI,CAAC,EAAE,UAAU,CAAC;QAClB,MAAM,CAAC,EAAE,QAAQ,GAAG,cAAc,GAAG,QAAQ,GAAG,KAAK,CAAC;QACtD,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;QAChB,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,gBAAgB,CAAC,EAAE,MAAM,CAAC;QAC1B,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,UAAU,CAAC,EAAE,MAAM,CAAC;QACpB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;KACxB;;;;;;;;;IA+GG,YAAY,CAAC,QAAQ,EAAE,MAAM;;;;;;;IA2B7B,YAAY,CAAC,YAAY,EAAE,MAAM,EAAE,KAAK,SAAK,EAAE,KAAK,GAAE,WAAuB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IA2D7E,yBAAyB,CAAC,SAAS,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,EAAE,KAAK,GAAE,MAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;CA4C5F;AAED,eAAO,MAAM,YAAY,mBAA0B,CAAC"}
|
package/dist/services/client.js
CHANGED
|
@@ -111,7 +111,13 @@ export class LocalMemoryClient {
|
|
|
111
111
|
const vector = await embeddingService.embedWithTimeout(content);
|
|
112
112
|
let tagsVector = undefined;
|
|
113
113
|
if (tags.length > 0) {
|
|
114
|
-
|
|
114
|
+
// Wrap tags in a natural-language template before embedding. Bare comma
|
|
115
|
+
// lists like "react, auth, bug-fix" sit outside the multilingual-e5
|
|
116
|
+
// training distribution, so the resulting tagsVector drifts toward
|
|
117
|
+
// unrelated chatter and weakens the 0.4-weight tag boost in
|
|
118
|
+
// VectorSearch#searchInShard. The "Topics: ..." prefix is a sentence
|
|
119
|
+
// form e5 was trained on and yields a more discriminative vector.
|
|
120
|
+
tagsVector = await embeddingService.embedWithTimeout(`Topics: ${tags.join(", ")}`);
|
|
115
121
|
}
|
|
116
122
|
const { scope, hash } = extractScopeFromContainerTag(containerTag);
|
|
117
123
|
const shard = shardManager.getWriteShard(scope, hash);
|
|
@@ -7,9 +7,9 @@ const MAX_CACHE_SIZE = 100;
|
|
|
7
7
|
let _transformers = null;
|
|
8
8
|
function getTransformersPackageSpecifier() {
|
|
9
9
|
// Keep this non-literal so OpenCode/Bun plugin-loader bundling does not eagerly
|
|
10
|
-
// traverse @
|
|
10
|
+
// traverse @huggingface/transformers internals during plugin startup. The package
|
|
11
11
|
// is only needed for the local embedding backend, and should stay lazy.
|
|
12
|
-
return ["@
|
|
12
|
+
return ["@huggingface", "transformers"].join("/");
|
|
13
13
|
}
|
|
14
14
|
async function ensureTransformersLoaded() {
|
|
15
15
|
if (_transformers !== null)
|
|
@@ -19,6 +19,16 @@ export declare class UserPromptManager {
|
|
|
19
19
|
deletePrompt(promptId: string): void;
|
|
20
20
|
markAsCaptured(promptId: string): void;
|
|
21
21
|
claimPrompt(promptId: string): boolean;
|
|
22
|
+
/**
|
|
23
|
+
* Release a previously claimed prompt back to the pending state so it can
|
|
24
|
+
* be retried by a future capture cycle. Used when capture aborts before
|
|
25
|
+
* either successfully writing a memory or explicitly skipping the prompt
|
|
26
|
+
* (e.g. transient network error, missing AI response, plugin restart).
|
|
27
|
+
*
|
|
28
|
+
* Only rows still marked as in-progress (captured = 2) are touched, so
|
|
29
|
+
* concurrent callers that already finished the capture cannot be reverted.
|
|
30
|
+
*/
|
|
31
|
+
releaseClaim(promptId: string): boolean;
|
|
22
32
|
countUncapturedPrompts(): number;
|
|
23
33
|
getUncapturedPrompts(limit: number): UserPrompt[];
|
|
24
34
|
markMultipleAsCaptured(promptIds: string[]): void;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"user-prompt-manager.d.ts","sourceRoot":"","sources":["../../../src/services/user-prompt/user-prompt-manager.ts"],"names":[],"mappings":"AAUA,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,OAAO,CAAC;IAClB,oBAAoB,EAAE,OAAO,CAAC;IAC9B,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;CAC/B;AAED,qBAAa,iBAAiB;IAC5B,OAAO,CAAC,EAAE,CAAe;IACzB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;;IAQhC,OAAO,CAAC,YAAY;IAiCpB,UAAU,CAAC,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM;IAa9F,uBAAuB,CAAC,SAAS,EAAE,MAAM,GAAG,UAAU,GAAG,IAAI;IAc7D,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI;IAKpC,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI;IAKtC,WAAW,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO;IAQtC,sBAAsB,IAAI,MAAM;IAMhC,oBAAoB,CAAC,KAAK,EAAE,MAAM,GAAG,UAAU,EAAE;IAYjD,sBAAsB,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,IAAI;IAUjD,8BAA8B,IAAI,MAAM;IAQxC,yBAAyB,CAAC,KAAK,EAAE,MAAM,GAAG,UAAU,EAAE;IAYtD,0BAA0B,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI;IAKlD,kCAAkC,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,IAAI;IAU7D,gBAAgB,CAAC,UAAU,EAAE,MAAM,GAAG;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,eAAe,EAAE,MAAM,EAAE,CAAA;KAAE;IAiBpF,kBAAkB,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI;IAK5D,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG,UAAU,GAAG,IAAI;IAOlD,kBAAkB,CAAC,WAAW,CAAC,EAAE,MAAM,GAAG,UAAU,EAAE;IAgBtD,aAAa,CAAC,KAAK,EAAE,MAAM,EAAE,WAAW,CAAC,EAAE,MAAM,EAAE,KAAK,GAAE,MAAW,GAAG,UAAU,EAAE;IAiBpF,eAAe,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,UAAU,EAAE;IAQ5C,OAAO,CAAC,WAAW;CAapB;AAED,eAAO,MAAM,iBAAiB,mBAA0B,CAAC"}
|
|
1
|
+
{"version":3,"file":"user-prompt-manager.d.ts","sourceRoot":"","sources":["../../../src/services/user-prompt/user-prompt-manager.ts"],"names":[],"mappings":"AAUA,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,OAAO,CAAC;IAClB,oBAAoB,EAAE,OAAO,CAAC;IAC9B,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;CAC/B;AAED,qBAAa,iBAAiB;IAC5B,OAAO,CAAC,EAAE,CAAe;IACzB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;;IAQhC,OAAO,CAAC,YAAY;IAiCpB,UAAU,CAAC,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM;IAa9F,uBAAuB,CAAC,SAAS,EAAE,MAAM,GAAG,UAAU,GAAG,IAAI;IAc7D,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI;IAKpC,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI;IAKtC,WAAW,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO;IAQtC;;;;;;;;OAQG;IACH,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO;IAQvC,sBAAsB,IAAI,MAAM;IAMhC,oBAAoB,CAAC,KAAK,EAAE,MAAM,GAAG,UAAU,EAAE;IAYjD,sBAAsB,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,IAAI;IAUjD,8BAA8B,IAAI,MAAM;IAQxC,yBAAyB,CAAC,KAAK,EAAE,MAAM,GAAG,UAAU,EAAE;IAYtD,0BAA0B,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI;IAKlD,kCAAkC,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,IAAI;IAU7D,gBAAgB,CAAC,UAAU,EAAE,MAAM,GAAG;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,eAAe,EAAE,MAAM,EAAE,CAAA;KAAE;IAiBpF,kBAAkB,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI;IAK5D,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG,UAAU,GAAG,IAAI;IAOlD,kBAAkB,CAAC,WAAW,CAAC,EAAE,MAAM,GAAG,UAAU,EAAE;IAgBtD,aAAa,CAAC,KAAK,EAAE,MAAM,EAAE,WAAW,CAAC,EAAE,MAAM,EAAE,KAAK,GAAE,MAAW,GAAG,UAAU,EAAE;IAiBpF,eAAe,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,UAAU,EAAE;IAQ5C,OAAO,CAAC,WAAW;CAapB;AAED,eAAO,MAAM,iBAAiB,mBAA0B,CAAC"}
|
|
@@ -69,6 +69,20 @@ export class UserPromptManager {
|
|
|
69
69
|
const result = stmt.run(promptId);
|
|
70
70
|
return result.changes > 0;
|
|
71
71
|
}
|
|
72
|
+
/**
|
|
73
|
+
* Release a previously claimed prompt back to the pending state so it can
|
|
74
|
+
* be retried by a future capture cycle. Used when capture aborts before
|
|
75
|
+
* either successfully writing a memory or explicitly skipping the prompt
|
|
76
|
+
* (e.g. transient network error, missing AI response, plugin restart).
|
|
77
|
+
*
|
|
78
|
+
* Only rows still marked as in-progress (captured = 2) are touched, so
|
|
79
|
+
* concurrent callers that already finished the capture cannot be reverted.
|
|
80
|
+
*/
|
|
81
|
+
releaseClaim(promptId) {
|
|
82
|
+
const stmt = this.db.prepare(`UPDATE user_prompts SET captured = 0 WHERE id = ? AND captured = 2`);
|
|
83
|
+
const result = stmt.run(promptId);
|
|
84
|
+
return result.changes > 0;
|
|
85
|
+
}
|
|
72
86
|
countUncapturedPrompts() {
|
|
73
87
|
const stmt = this.db.prepare(`SELECT COUNT(*) as count FROM user_prompts WHERE captured = 0`);
|
|
74
88
|
const row = stmt.get();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"web-server.d.ts","sourceRoot":"","sources":["../../src/services/web-server.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"web-server.d.ts","sourceRoot":"","sources":["../../src/services/web-server.ts"],"names":[],"mappings":"AAqIA,UAAU,eAAe;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,OAAO,CAAC;CAClB;AAED,qBAAa,SAAS;IACpB,OAAO,CAAC,MAAM,CAAqC;IACnD,OAAO,CAAC,MAAM,CAAkB;IAChC,OAAO,CAAC,OAAO,CAAkB;IACjC,OAAO,CAAC,YAAY,CAA8B;IAClD,OAAO,CAAC,mBAAmB,CAA+B;IAC1D,OAAO,CAAC,kBAAkB,CAAsC;gBAEpD,MAAM,EAAE,eAAe;IAInC,qBAAqB,CAAC,QAAQ,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI;IAIpD,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;YASd,MAAM;IAgCpB,OAAO,CAAC,oBAAoB;IAe5B,OAAO,CAAC,mBAAmB;YAOb,eAAe;IA+BvB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAY3B,SAAS,IAAI,OAAO;IAIpB,aAAa,IAAI,OAAO;IAIxB,MAAM,IAAI,MAAM;IAIV,oBAAoB,IAAI,OAAO,CAAC,OAAO,CAAC;YAchC,aAAa;IAuN3B,OAAO,CAAC,eAAe;IA4BvB,OAAO,CAAC,YAAY;CAWrB;AAED,wBAAsB,cAAc,CAAC,MAAM,EAAE,eAAe,GAAG,OAAO,CAAC,SAAS,CAAC,CAIhF"}
|
|
@@ -35,6 +35,7 @@ function serveFetch(opts) {
|
|
|
35
35
|
const webRes = await opts.fetch(webReq);
|
|
36
36
|
res.statusCode = webRes.status;
|
|
37
37
|
webRes.headers.forEach((value, name) => res.setHeader(name, value));
|
|
38
|
+
res.setHeader("Connection", "close");
|
|
38
39
|
if (webRes.body) {
|
|
39
40
|
Readable.fromWeb(webRes.body).pipe(res);
|
|
40
41
|
}
|
|
@@ -58,11 +59,20 @@ function serveFetch(opts) {
|
|
|
58
59
|
listenError = err;
|
|
59
60
|
}
|
|
60
61
|
});
|
|
61
|
-
server.listen(opts.port, opts.hostname);
|
|
62
|
+
server.listen({ port: opts.port, host: opts.hostname, reuseAddr: true });
|
|
63
|
+
server.unref();
|
|
64
|
+
server.timeout = 30000;
|
|
65
|
+
server.keepAliveTimeout = 10000;
|
|
66
|
+
server.headersTimeout = 11000;
|
|
62
67
|
if (listenError) {
|
|
63
68
|
throw listenError;
|
|
64
69
|
}
|
|
65
|
-
return {
|
|
70
|
+
return {
|
|
71
|
+
stop: () => {
|
|
72
|
+
server.closeAllConnections();
|
|
73
|
+
server.close();
|
|
74
|
+
},
|
|
75
|
+
};
|
|
66
76
|
}
|
|
67
77
|
const __filename = fileURLToPath(import.meta.url);
|
|
68
78
|
const __dirname = dirname(__filename);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "opencode-mem",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.17.1",
|
|
4
4
|
"description": "OpenCode plugin that gives coding agents persistent memory using local vector database",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/plugin.js",
|
|
@@ -53,7 +53,7 @@
|
|
|
53
53
|
"iso-639-3": "^3.0.1",
|
|
54
54
|
"usearch": "^2.21.4",
|
|
55
55
|
"zod": "^4.3.6",
|
|
56
|
-
"@
|
|
56
|
+
"@huggingface/transformers": "^4.2.0"
|
|
57
57
|
},
|
|
58
58
|
"devDependencies": {
|
|
59
59
|
"@types/bun": "^1.3.8",
|