om-memory-system 5.10.1 → 6.1.0-next.237
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 +1 -1
- package/dist/adapters/opencode/auto-capture-host.d.ts +2 -2
- package/dist/adapters/opencode/auto-capture-host.js +5 -15
- package/dist/adapters/opencode/auto-capture-summary.js +9 -6
- package/dist/adapters/opencode/backfill-models.js +1 -1
- package/dist/adapters/opencode/backfill-startup.js +5 -4
- package/dist/adapters/opencode/conversation.d.ts +5 -1
- package/dist/adapters/opencode/conversation.js +23 -23
- package/dist/adapters/opencode/import-command.d.ts +0 -12
- package/dist/adapters/opencode/import-command.js +1 -17
- package/dist/adapters/opencode/internal-capture-sessions.d.ts +0 -3
- package/dist/adapters/opencode/internal-capture-sessions.js +0 -26
- package/dist/adapters/opencode/memory-tool.d.ts +3 -4
- package/dist/adapters/opencode/memory-tool.js +8 -50
- package/dist/adapters/opencode/opencode-host.d.ts +27 -0
- package/dist/adapters/opencode/opencode-host.js +30 -0
- package/dist/adapters/opencode/opencode-import-models.d.ts +2 -2
- package/dist/adapters/opencode/opencode-import-models.js +8 -10
- package/dist/adapters/opencode/opencode-provider.d.ts +23 -62
- package/dist/adapters/opencode/opencode-provider.js +75 -378
- package/dist/adapters/opencode/package-skills.d.ts +1 -6
- package/dist/adapters/opencode/package-skills.js +2 -17
- package/dist/adapters/opencode/profile-learning.d.ts +1 -2
- package/dist/adapters/opencode/profile-learning.js +15 -19
- package/dist/adapters/opencode/profile-llm-client.d.ts +3 -2
- package/dist/adapters/opencode/profile-llm-client.js +8 -17
- package/dist/adapters/opencode/profile-model.d.ts +2 -18
- package/dist/adapters/opencode/profile-model.js +18 -69
- package/dist/adapters/opencode/prompt-model.d.ts +9 -0
- package/dist/adapters/opencode/prompt-model.js +21 -0
- package/dist/adapters/opencode/skills-tool.d.ts +3 -3
- package/dist/adapters/opencode/skills-tool.js +4 -30
- package/dist/adapters/opencode/toast.d.ts +11 -0
- package/dist/adapters/opencode/toast.js +11 -0
- package/dist/adapters/opencode/user-prompt.d.ts +2 -2
- package/dist/adapters/opencode/user-prompt.js +4 -5
- package/dist/config-template.d.ts +1 -1
- package/dist/config-template.js +2 -6
- package/dist/config.d.ts +0 -9
- package/dist/config.js +0 -9
- package/dist/core/retrieval.d.ts +0 -21
- package/dist/core/retrieval.js +0 -29
- package/dist/importer/handled-lookup.d.ts +17 -0
- package/dist/importer/handled-lookup.js +13 -0
- package/dist/importer/importer.js +3 -3
- package/dist/importer/ledger.d.ts +9 -0
- package/dist/importer/ledger.js +21 -0
- package/dist/importer/opencode-reader.d.ts +1 -1
- package/dist/importer/opencode-reader.js +88 -34
- package/dist/importer/opencode-v2-units.d.ts +16 -0
- package/dist/importer/opencode-v2-units.js +93 -0
- package/dist/importer/settings-models.d.ts +11 -6
- package/dist/importer/settings-models.js +15 -11
- package/dist/plugin.d.ts +0 -3
- package/dist/plugin.js +1 -7
- package/dist/services/global-config-writer.js +2 -3
- package/dist/services/settings-snapshot.js +6 -6
- package/dist/services/turso/vector-search.js +4 -2
- package/dist/shared/api/schemas.d.ts +1 -1
- package/dist/utils/memory-limits.d.ts +0 -1
- package/dist/utils/memory-limits.js +0 -1
- package/dist/v2/adapter.d.ts +16 -84
- package/dist/v2/adapter.js +17 -88
- package/dist/v2/memory-bridge.js +1 -1
- package/dist/v2/plugin.js +27 -16
- package/dist/v2/session-events.d.ts +30 -0
- package/dist/v2/session-events.js +130 -0
- package/dist/v2/startup.d.ts +14 -0
- package/dist/v2/startup.js +210 -0
- package/dist/v2/tools.d.ts +106 -0
- package/dist/v2/tools.js +89 -0
- package/dist/web/assets/index-DBSeQOs6.js +171 -0
- package/dist/web/index.html +1 -1
- package/package.json +2 -14
- package/dist/adapters/opencode/in-process-client.d.ts +0 -2
- package/dist/adapters/opencode/in-process-client.js +0 -16
- package/dist/adapters/opencode/opencode-diagnostics.d.ts +0 -7
- package/dist/adapters/opencode/opencode-diagnostics.js +0 -37
- package/dist/adapters/opencode/opencode-host-config.d.ts +0 -13
- package/dist/adapters/opencode/opencode-host-config.js +0 -53
- package/dist/adapters/opencode/opencode-sdk-client.d.ts +0 -6
- package/dist/adapters/opencode/opencode-sdk-client.js +0 -38
- package/dist/index.d.ts +0 -28
- package/dist/index.js +0 -620
- package/dist/v2/legacy-client.d.ts +0 -15
- package/dist/v2/legacy-client.js +0 -275
- package/dist/web/assets/index-DQgI670D.js +0 -171
package/dist/v2/adapter.d.ts
CHANGED
|
@@ -1,90 +1,22 @@
|
|
|
1
1
|
import type { Context } from "@opencode/plugin/promise/plugin";
|
|
2
|
+
import { type SessionEvent } from "./session-events.js";
|
|
3
|
+
import { type OpencodeTools } from "./tools.js";
|
|
2
4
|
import type { V2MemoryBridge } from "./memory-bridge.js";
|
|
3
|
-
export
|
|
4
|
-
readonly type: "object";
|
|
5
|
-
readonly properties: {
|
|
6
|
-
readonly mode: {
|
|
7
|
-
readonly type: "string";
|
|
8
|
-
readonly enum: readonly ["add", "memorise", "memorize", "recall", "search", "profile", "list", "forget", "help", "migrate", "list-shards", "export", "import", "space"];
|
|
9
|
-
};
|
|
10
|
-
readonly content: {
|
|
11
|
-
readonly type: "string";
|
|
12
|
-
};
|
|
13
|
-
readonly query: {
|
|
14
|
-
readonly type: "string";
|
|
15
|
-
};
|
|
16
|
-
readonly tags: {
|
|
17
|
-
readonly type: "string";
|
|
18
|
-
};
|
|
19
|
-
readonly type: {
|
|
20
|
-
readonly type: "string";
|
|
21
|
-
};
|
|
22
|
-
readonly topic: {
|
|
23
|
-
readonly type: "string";
|
|
24
|
-
};
|
|
25
|
-
readonly done: {
|
|
26
|
-
readonly type: "string";
|
|
27
|
-
};
|
|
28
|
-
readonly doing: {
|
|
29
|
-
readonly type: "string";
|
|
30
|
-
};
|
|
31
|
-
readonly next: {
|
|
32
|
-
readonly type: "string";
|
|
33
|
-
};
|
|
34
|
-
readonly memoryId: {
|
|
35
|
-
readonly type: "string";
|
|
36
|
-
};
|
|
37
|
-
readonly limit: {
|
|
38
|
-
readonly type: "number";
|
|
39
|
-
};
|
|
40
|
-
readonly scope: {
|
|
41
|
-
readonly type: "string";
|
|
42
|
-
readonly enum: readonly ["project", "all-projects"];
|
|
43
|
-
};
|
|
44
|
-
readonly fromPath: {
|
|
45
|
-
readonly type: "string";
|
|
46
|
-
};
|
|
47
|
-
readonly fromHash: {
|
|
48
|
-
readonly type: "string";
|
|
49
|
-
};
|
|
50
|
-
readonly outputPath: {
|
|
51
|
-
readonly type: "string";
|
|
52
|
-
};
|
|
53
|
-
readonly inputPath: {
|
|
54
|
-
readonly type: "string";
|
|
55
|
-
};
|
|
56
|
-
readonly dryRun: {
|
|
57
|
-
readonly type: "boolean";
|
|
58
|
-
};
|
|
59
|
-
readonly allowLinkedSource: {
|
|
60
|
-
readonly type: "boolean";
|
|
61
|
-
};
|
|
62
|
-
readonly spaceAction: {
|
|
63
|
-
readonly type: "string";
|
|
64
|
-
};
|
|
65
|
-
readonly spaceName: {
|
|
66
|
-
readonly type: "string";
|
|
67
|
-
};
|
|
68
|
-
readonly spaceTo: {
|
|
69
|
-
readonly type: "string";
|
|
70
|
-
};
|
|
71
|
-
readonly spaceSince: {
|
|
72
|
-
readonly type: "string";
|
|
73
|
-
};
|
|
74
|
-
readonly spaceUntil: {
|
|
75
|
-
readonly type: "string";
|
|
76
|
-
};
|
|
77
|
-
readonly spaceProject: {
|
|
78
|
-
readonly type: "string";
|
|
79
|
-
};
|
|
80
|
-
readonly spaceIn: {
|
|
81
|
-
readonly type: "string";
|
|
82
|
-
};
|
|
83
|
-
};
|
|
84
|
-
readonly additionalProperties: false;
|
|
85
|
-
};
|
|
5
|
+
export { memoryInput } from "./tools.js";
|
|
86
6
|
/** Per-session state is bounded so long-running servers cannot grow it without limit. */
|
|
87
7
|
export declare const MAX_TRACKED_SESSIONS = 256;
|
|
88
8
|
/** Session ids remembered as already seen by this process, for the first-prompt rule. */
|
|
89
9
|
export declare const MAX_SEEN_SESSIONS = 500;
|
|
90
|
-
|
|
10
|
+
/** The OpenCode work the adapter wires into the V2 context. */
|
|
11
|
+
export type V2AdapterDeps = {
|
|
12
|
+
readonly tools: OpencodeTools;
|
|
13
|
+
/** Store a model request's model on the recorded prompt row. */
|
|
14
|
+
readonly recordPromptModel?: (messageID: string, model: {
|
|
15
|
+
readonly providerID: string;
|
|
16
|
+
readonly id: string;
|
|
17
|
+
}) => Promise<void>;
|
|
18
|
+
/** Session events of this plugin's directory, compaction excluded. */
|
|
19
|
+
readonly onEvent?: (event: SessionEvent) => Promise<void>;
|
|
20
|
+
readonly dispose?: () => Promise<void>;
|
|
21
|
+
};
|
|
22
|
+
export declare function registerV2Adapter(ctx: Context, deps: V2AdapterDeps, memory: V2MemoryBridge): Promise<() => Promise<void>>;
|
package/dist/v2/adapter.js
CHANGED
|
@@ -1,67 +1,19 @@
|
|
|
1
1
|
import { OPENCODE_IMPORT_COMMAND, OPENCODE_IMPORT_DESCRIPTION, runOpencodeImportCommand, } from "../adapters/opencode/import-command.js";
|
|
2
2
|
import { addPackageSkill } from "../adapters/opencode/package-skills.js";
|
|
3
|
-
import { SKILLS_TOOL_INPUT_SCHEMA } from "../core/skills-tool.js";
|
|
4
3
|
import { log } from "../services/logger.js";
|
|
5
4
|
import { utf8ByteLength } from "../utils/context-limit.js";
|
|
6
|
-
import { eventBelongsToLocation,
|
|
5
|
+
import { eventBelongsToLocation, toSessionEvent } from "./session-events.js";
|
|
6
|
+
import { registerOpencodeTools } from "./tools.js";
|
|
7
7
|
import { createRecallReporter } from "./recall-reporter.js";
|
|
8
8
|
import { createSessionParents } from "./session-parent.js";
|
|
9
|
-
export
|
|
10
|
-
type: "object",
|
|
11
|
-
properties: {
|
|
12
|
-
mode: {
|
|
13
|
-
type: "string",
|
|
14
|
-
enum: [
|
|
15
|
-
"add",
|
|
16
|
-
"memorise",
|
|
17
|
-
"memorize",
|
|
18
|
-
"recall",
|
|
19
|
-
"search",
|
|
20
|
-
"profile",
|
|
21
|
-
"list",
|
|
22
|
-
"forget",
|
|
23
|
-
"help",
|
|
24
|
-
"migrate",
|
|
25
|
-
"list-shards",
|
|
26
|
-
"export",
|
|
27
|
-
"import",
|
|
28
|
-
"space",
|
|
29
|
-
],
|
|
30
|
-
},
|
|
31
|
-
content: { type: "string" },
|
|
32
|
-
query: { type: "string" },
|
|
33
|
-
tags: { type: "string" },
|
|
34
|
-
type: { type: "string" },
|
|
35
|
-
topic: { type: "string" },
|
|
36
|
-
done: { type: "string" },
|
|
37
|
-
doing: { type: "string" },
|
|
38
|
-
next: { type: "string" },
|
|
39
|
-
memoryId: { type: "string" },
|
|
40
|
-
limit: { type: "number" },
|
|
41
|
-
scope: { type: "string", enum: ["project", "all-projects"] },
|
|
42
|
-
fromPath: { type: "string" },
|
|
43
|
-
fromHash: { type: "string" },
|
|
44
|
-
outputPath: { type: "string" },
|
|
45
|
-
inputPath: { type: "string" },
|
|
46
|
-
dryRun: { type: "boolean" },
|
|
47
|
-
allowLinkedSource: { type: "boolean" },
|
|
48
|
-
spaceAction: { type: "string" },
|
|
49
|
-
spaceName: { type: "string" },
|
|
50
|
-
spaceTo: { type: "string" },
|
|
51
|
-
spaceSince: { type: "string" },
|
|
52
|
-
spaceUntil: { type: "string" },
|
|
53
|
-
spaceProject: { type: "string" },
|
|
54
|
-
spaceIn: { type: "string" },
|
|
55
|
-
},
|
|
56
|
-
additionalProperties: false,
|
|
57
|
-
};
|
|
9
|
+
export { memoryInput } from "./tools.js";
|
|
58
10
|
/** Per-session state is bounded so long-running servers cannot grow it without limit. */
|
|
59
11
|
export const MAX_TRACKED_SESSIONS = 256;
|
|
60
12
|
/** Session ids remembered as already seen by this process, for the first-prompt rule. */
|
|
61
13
|
export const MAX_SEEN_SESSIONS = 500;
|
|
62
14
|
/** Unadmitted prompts kept per session before the oldest is dropped. */
|
|
63
15
|
const MAX_PENDING_PROMPTS = 16;
|
|
64
|
-
/** Compaction is restored
|
|
16
|
+
/** Compaction is restored through the `compaction` hook, never from the event stream. */
|
|
65
17
|
const COMPACTION_EVENT_TYPES = new Set(["session.compacted", "session.compaction.ended"]);
|
|
66
18
|
const NO_SECTIONS = {
|
|
67
19
|
promptSection: null,
|
|
@@ -91,7 +43,7 @@ function deletedSessionID(event) {
|
|
|
91
43
|
const props = event.properties ?? {};
|
|
92
44
|
return props.sessionID ?? props.info?.id ?? props.session?.id;
|
|
93
45
|
}
|
|
94
|
-
export async function registerV2Adapter(ctx,
|
|
46
|
+
export async function registerV2Adapter(ctx, deps, memory) {
|
|
95
47
|
const retrievals = new Map();
|
|
96
48
|
const restored = new Map();
|
|
97
49
|
// Sessions this process has seen a prompt or compaction for. The first prompt of a session not
|
|
@@ -184,31 +136,10 @@ export async function registerV2Adapter(ctx, legacy, memory) {
|
|
|
184
136
|
if (!subagent)
|
|
185
137
|
await loadRestored(sessionID, memory.retrievalTimeoutMs);
|
|
186
138
|
};
|
|
187
|
-
|
|
188
|
-
//
|
|
189
|
-
const legacyTool = (name, input) => ({
|
|
190
|
-
name,
|
|
191
|
-
description: legacy.tool[name].description,
|
|
192
|
-
input: input,
|
|
193
|
-
options: { codemode: false },
|
|
194
|
-
execute: async (args, toolContext) => legacyToolResult(await legacy.tool[name].execute(args, {
|
|
195
|
-
sessionID: toolContext.sessionID,
|
|
196
|
-
messageID: toolContext.messageID,
|
|
197
|
-
agent: toolContext.agent,
|
|
198
|
-
directory: ctx.location.directory,
|
|
199
|
-
worktree: ctx.location.project.directory,
|
|
200
|
-
abort: new AbortController().signal,
|
|
201
|
-
metadata() { },
|
|
202
|
-
async ask() { },
|
|
203
|
-
})),
|
|
204
|
-
});
|
|
205
|
-
await ctx.tool.transform((editor) => {
|
|
206
|
-
editor.add(legacyTool("memory", memoryInput));
|
|
207
|
-
editor.add(legacyTool("skills", SKILLS_TOOL_INPUT_SCHEMA));
|
|
208
|
-
});
|
|
209
|
-
// The omms-memory skill ships in the package; V1 loads it through the config hook.
|
|
139
|
+
await registerOpencodeTools(ctx, deps.tools);
|
|
140
|
+
// The omms-memory and omms-remember skills ship in the package.
|
|
210
141
|
await ctx.skill?.transform?.((editor) => addPackageSkill(editor));
|
|
211
|
-
// Same command as
|
|
142
|
+
// Same command as Pi. V2 runs it natively, so no model turn relays the report.
|
|
212
143
|
await ctx.command?.transform?.((editor) => editor.add({
|
|
213
144
|
name: OPENCODE_IMPORT_COMMAND,
|
|
214
145
|
description: OPENCODE_IMPORT_DESCRIPTION,
|
|
@@ -284,7 +215,7 @@ export async function registerV2Adapter(ctx, legacy, memory) {
|
|
|
284
215
|
const sessionID = event.sessionID;
|
|
285
216
|
const retrieval = retrievals.get(sessionID);
|
|
286
217
|
const budgetBytes = retrieval?.budgetBytes ?? memory.snapshotRequestBudget();
|
|
287
|
-
// Before
|
|
218
|
+
// Before the model is stored on the recorded prompt row, below.
|
|
288
219
|
await recordAdmittedPrompts(sessionID, event.messages);
|
|
289
220
|
await decideFirstRequest(sessionID, event.messages, retrieval);
|
|
290
221
|
// The retrieval sections and the restored section share one request budget: the
|
|
@@ -312,12 +243,10 @@ export async function registerV2Adapter(ctx, legacy, memory) {
|
|
|
312
243
|
recall.record(sessionID, restoredEntry, "restore", null, section);
|
|
313
244
|
}
|
|
314
245
|
}
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
});
|
|
320
|
-
}
|
|
246
|
+
await deps.recordPromptModel?.(messageIDs.get(sessionID) ?? sessionID, {
|
|
247
|
+
providerID: event.model.providerID,
|
|
248
|
+
id: event.model.id,
|
|
249
|
+
});
|
|
321
250
|
});
|
|
322
251
|
await ctx.session.hook("compaction", async (event) => {
|
|
323
252
|
memory.snapshotRequestBudget();
|
|
@@ -332,14 +261,14 @@ export async function registerV2Adapter(ctx, legacy, memory) {
|
|
|
332
261
|
const watcher = (async () => {
|
|
333
262
|
try {
|
|
334
263
|
for await (const raw of ctx.event.subscribe({ signal: controller.signal })) {
|
|
335
|
-
const event =
|
|
264
|
+
const event = toSessionEvent(raw);
|
|
336
265
|
const deleted = deletedSessionID(event);
|
|
337
266
|
if (deleted)
|
|
338
267
|
forgetSession(deleted);
|
|
339
|
-
if (!
|
|
268
|
+
if (!deps.onEvent || COMPACTION_EVENT_TYPES.has(event.type))
|
|
340
269
|
continue;
|
|
341
270
|
if (await eventBelongsToLocation(ctx, raw)) {
|
|
342
|
-
await
|
|
271
|
+
await deps.onEvent(event);
|
|
343
272
|
}
|
|
344
273
|
}
|
|
345
274
|
}
|
|
@@ -360,6 +289,6 @@ export async function registerV2Adapter(ctx, legacy, memory) {
|
|
|
360
289
|
firstPending.clear();
|
|
361
290
|
parents.clear();
|
|
362
291
|
recall.clear();
|
|
363
|
-
await
|
|
292
|
+
await deps.dispose?.();
|
|
364
293
|
};
|
|
365
294
|
}
|
package/dist/v2/memory-bridge.js
CHANGED
|
@@ -17,7 +17,7 @@ export function createV2MemoryBridge(directory) {
|
|
|
17
17
|
return CONFIG.visibleRecall !== false;
|
|
18
18
|
},
|
|
19
19
|
isSubagentMemoryEnabled: () => CONFIG.subagentMemory !== false,
|
|
20
|
-
isInternalPrompt,
|
|
20
|
+
isInternalPrompt: (_sessionID, text) => isInternalPrompt(text),
|
|
21
21
|
async recordPrompt(sessionID, messageID, text) {
|
|
22
22
|
await recordUserPrompt(sessionID, messageID, directory, text);
|
|
23
23
|
},
|
package/dist/v2/plugin.js
CHANGED
|
@@ -1,9 +1,14 @@
|
|
|
1
1
|
import { fileURLToPath } from "node:url";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
2
|
+
import { setOpencodeHost } from "../adapters/opencode/opencode-host.js";
|
|
3
|
+
import { CONFIG } from "../config.js";
|
|
4
|
+
import { recordOpencodePromptModel } from "../adapters/opencode/prompt-model.js";
|
|
5
|
+
import { performUserProfileLearning } from "../adapters/opencode/profile-learning.js";
|
|
6
|
+
import { getLanguageName } from "../services/language-detector.js";
|
|
4
7
|
import { registerV2Adapter } from "./adapter.js";
|
|
5
8
|
import { createV2MemoryBridge } from "./memory-bridge.js";
|
|
6
|
-
import {
|
|
9
|
+
import { createOpencodeSessionEvents } from "./session-events.js";
|
|
10
|
+
import { startOpencodeRuntime } from "./startup.js";
|
|
11
|
+
import { createOpencodeTools } from "./tools.js";
|
|
7
12
|
/**
|
|
8
13
|
* Remove old OMMS copies from the OpenCode cache. It runs in the background and
|
|
9
14
|
* is not awaited, so a slow or failing clean-up never delays or breaks setup.
|
|
@@ -62,19 +67,25 @@ function startServiceSelfUpdate() {
|
|
|
62
67
|
const OmmsPluginV2 = {
|
|
63
68
|
id: "omms",
|
|
64
69
|
async setup(ctx) {
|
|
65
|
-
const
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
70
|
+
const directory = ctx.location.directory;
|
|
71
|
+
// Capture, profile learning, imports and Settings reach OpenCode through the context.
|
|
72
|
+
setOpencodeHost(ctx);
|
|
73
|
+
// The runtime's shutdown drops pending idle work, so it needs the handler created after it.
|
|
74
|
+
const holder = {};
|
|
75
|
+
const runtime = await startOpencodeRuntime(ctx, () => holder.events?.dispose());
|
|
76
|
+
const events = createOpencodeSessionEvents({
|
|
77
|
+
session: ctx.session,
|
|
78
|
+
directory,
|
|
79
|
+
autoCaptureHost: runtime.autoCaptureHost,
|
|
80
|
+
learnProfile: () => performUserProfileLearning(directory),
|
|
81
|
+
});
|
|
82
|
+
holder.events = events;
|
|
83
|
+
const adapter = await registerV2Adapter(ctx, {
|
|
84
|
+
tools: createOpencodeTools({ directory, tags: runtime.tags }, getLanguageName(CONFIG.autoCaptureLanguage || "en")),
|
|
85
|
+
recordPromptModel: recordOpencodePromptModel,
|
|
86
|
+
onEvent: (event) => events.handle(event),
|
|
87
|
+
dispose: () => runtime.dispose(),
|
|
88
|
+
}, createV2MemoryBridge(directory));
|
|
78
89
|
startCacheCleanup();
|
|
79
90
|
startServiceSelfUpdate();
|
|
80
91
|
return adapter;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { Context } from "@opencode/plugin/promise/plugin";
|
|
2
|
+
import type { AutoCaptureHost } from "../core/host.js";
|
|
3
|
+
/** Capture waits this long after a session goes idle, so a quick follow-up prompt wins. */
|
|
4
|
+
export declare const IDLE_CAPTURE_DELAY_MS = 10000;
|
|
5
|
+
export type SessionEvent = {
|
|
6
|
+
readonly type: string;
|
|
7
|
+
readonly properties: any;
|
|
8
|
+
};
|
|
9
|
+
/** Map a raw V2 event onto the names the capture path reads. */
|
|
10
|
+
export declare function toSessionEvent(raw: any): SessionEvent;
|
|
11
|
+
/** True when a raw event names this plugin's directory, directly or through its session. */
|
|
12
|
+
export declare function eventBelongsToLocation(ctx: Context, raw: any): Promise<boolean>;
|
|
13
|
+
/**
|
|
14
|
+
* True for a session that OMMS created for its own model calls. Current versions generate
|
|
15
|
+
* without a session; older versions left sessions titled `omms capture`.
|
|
16
|
+
*/
|
|
17
|
+
export declare function isInternalOpencodeSession(session: Pick<Context["session"], "get">, sessionID: string): Promise<boolean>;
|
|
18
|
+
export type SessionEventDeps = {
|
|
19
|
+
readonly session: Pick<Context["session"], "get">;
|
|
20
|
+
readonly directory: string;
|
|
21
|
+
readonly autoCaptureHost: AutoCaptureHost;
|
|
22
|
+
/** Profile learning for this plugin's directory; runs after capture. */
|
|
23
|
+
readonly learnProfile: () => Promise<void>;
|
|
24
|
+
};
|
|
25
|
+
/** Start capture, skill-turn recording, profile learning and the retry drain from session events. */
|
|
26
|
+
export declare function createOpencodeSessionEvents(deps: SessionEventDeps): {
|
|
27
|
+
handle(event: SessionEvent): Promise<void>;
|
|
28
|
+
/** Drop pending idle work; the plugin is unloading. */
|
|
29
|
+
dispose(): void;
|
|
30
|
+
};
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
import { resolve } from "node:path";
|
|
2
|
+
import { CONFIG, isConfigured } from "../config.js";
|
|
3
|
+
import { isInternalCaptureSessionTitle } from "../adapters/opencode/internal-capture-sessions.js";
|
|
4
|
+
import { log } from "../services/logger.js";
|
|
5
|
+
/** Capture waits this long after a session goes idle, so a quick follow-up prompt wins. */
|
|
6
|
+
export const IDLE_CAPTURE_DELAY_MS = 10_000;
|
|
7
|
+
/** Map a raw V2 event onto the names the capture path reads. */
|
|
8
|
+
export function toSessionEvent(raw) {
|
|
9
|
+
const envelope = raw?.payload ?? raw;
|
|
10
|
+
const source = envelope?.type === "sync" && envelope.syncEvent ? envelope.syncEvent : envelope;
|
|
11
|
+
const rawType = typeof source?.type === "string" ? source.type.replace(/\.1$/, "") : source?.type;
|
|
12
|
+
const data = source?.data ?? {};
|
|
13
|
+
// OpenCode 2.0.14 ends a turn with `session.execution.succeeded` and emits no
|
|
14
|
+
// `session.idle`; some builds report idleness through `session.status`. Both
|
|
15
|
+
// mean the session is idle. Subscribed events carry their payload in `data`;
|
|
16
|
+
// bus-style ones in `properties`.
|
|
17
|
+
const payload = source?.data ?? source?.properties ?? {};
|
|
18
|
+
if (rawType === "session.execution.succeeded" ||
|
|
19
|
+
(rawType === "session.status" && payload?.status?.type === "idle")) {
|
|
20
|
+
return { type: "session.idle", properties: { sessionID: payload.sessionID } };
|
|
21
|
+
}
|
|
22
|
+
const type = rawType === "session.compaction.ended" ? "session.compacted" : rawType;
|
|
23
|
+
if (source && typeof source === "object" && "properties" in source) {
|
|
24
|
+
return { type, properties: source.properties };
|
|
25
|
+
}
|
|
26
|
+
if (type === "session.created" || type === "session.updated") {
|
|
27
|
+
return { type, properties: { info: data.session ?? data.info ?? data } };
|
|
28
|
+
}
|
|
29
|
+
return { type, properties: data };
|
|
30
|
+
}
|
|
31
|
+
/** True when a raw event names this plugin's directory, directly or through its session. */
|
|
32
|
+
export async function eventBelongsToLocation(ctx, raw) {
|
|
33
|
+
const directory = raw?.location?.directory ??
|
|
34
|
+
raw?.directory ??
|
|
35
|
+
raw?.payload?.location?.directory ??
|
|
36
|
+
raw?.payload?.directory ??
|
|
37
|
+
raw?.data?.info?.directory;
|
|
38
|
+
if (typeof directory === "string") {
|
|
39
|
+
return resolve(directory) === resolve(ctx.location.directory);
|
|
40
|
+
}
|
|
41
|
+
const data = raw?.data ?? raw?.payload?.data ?? raw?.properties;
|
|
42
|
+
const sessionID = data?.sessionID ?? data?.session?.id ?? data?.info?.id;
|
|
43
|
+
if (!sessionID)
|
|
44
|
+
return false;
|
|
45
|
+
try {
|
|
46
|
+
const session = await ctx.session.get({ sessionID });
|
|
47
|
+
const sessionDirectory = session?.location?.directory ?? session?.directory ?? session?.data?.directory;
|
|
48
|
+
return (typeof sessionDirectory === "string" &&
|
|
49
|
+
resolve(sessionDirectory) === resolve(ctx.location.directory));
|
|
50
|
+
}
|
|
51
|
+
catch {
|
|
52
|
+
return false;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* True for a session that OMMS created for its own model calls. Current versions generate
|
|
57
|
+
* without a session; older versions left sessions titled `omms capture`.
|
|
58
|
+
*/
|
|
59
|
+
export async function isInternalOpencodeSession(session, sessionID) {
|
|
60
|
+
try {
|
|
61
|
+
const info = await session.get({ sessionID });
|
|
62
|
+
return isInternalCaptureSessionTitle(info?.title);
|
|
63
|
+
}
|
|
64
|
+
catch (error) {
|
|
65
|
+
log("internal capture session check failed", { sessionID, error: String(error) }, "error");
|
|
66
|
+
return false;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
/** Start capture, skill-turn recording, profile learning and the retry drain from session events. */
|
|
70
|
+
export function createOpencodeSessionEvents(deps) {
|
|
71
|
+
let idleTimeout = null;
|
|
72
|
+
const onCreated = async (event) => {
|
|
73
|
+
if (!isConfigured() || !CONFIG.autoCaptureEnabled)
|
|
74
|
+
return;
|
|
75
|
+
const sessionID = event.properties?.info?.id ?? event.properties?.sessionID;
|
|
76
|
+
// OMMS's own structured-output sessions must not start a retry pass.
|
|
77
|
+
if (sessionID && (await isInternalOpencodeSession(deps.session, sessionID)))
|
|
78
|
+
return;
|
|
79
|
+
const { startCaptureRetryDrain } = await import("../services/capture-retry-drain.js");
|
|
80
|
+
startCaptureRetryDrain("opencode");
|
|
81
|
+
};
|
|
82
|
+
const onIdle = async (event) => {
|
|
83
|
+
// Skill learning records turns even when memory capture is off (ADR-036).
|
|
84
|
+
if (!isConfigured() || !(CONFIG.autoCaptureEnabled || CONFIG.skillLearning))
|
|
85
|
+
return;
|
|
86
|
+
const sessionID = event.properties?.sessionID;
|
|
87
|
+
if (!sessionID)
|
|
88
|
+
return;
|
|
89
|
+
// Internal sessions must not re-trigger capture or learning: that would loop
|
|
90
|
+
// idle, model call, idle without end.
|
|
91
|
+
if (await isInternalOpencodeSession(deps.session, sessionID)) {
|
|
92
|
+
log("Skipping idle processing for internal capture session", { sessionID });
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
if (idleTimeout)
|
|
96
|
+
clearTimeout(idleTimeout);
|
|
97
|
+
idleTimeout = setTimeout(async () => {
|
|
98
|
+
try {
|
|
99
|
+
const { performAutoCapture } = await import("../services/auto-capture.js");
|
|
100
|
+
await performAutoCapture(deps.autoCaptureHost, sessionID, deps.directory);
|
|
101
|
+
if (!CONFIG.autoCaptureEnabled)
|
|
102
|
+
return; // Skill turns only; the memory work stays off.
|
|
103
|
+
await deps.learnProfile();
|
|
104
|
+
const { cleanupService } = await import("../services/cleanup-service.js");
|
|
105
|
+
if (await cleanupService.shouldRunCleanup())
|
|
106
|
+
await cleanupService.runCleanup();
|
|
107
|
+
}
|
|
108
|
+
catch (error) {
|
|
109
|
+
log("Idle processing error", { error: String(error) }, "error");
|
|
110
|
+
}
|
|
111
|
+
finally {
|
|
112
|
+
idleTimeout = null;
|
|
113
|
+
}
|
|
114
|
+
}, IDLE_CAPTURE_DELAY_MS);
|
|
115
|
+
};
|
|
116
|
+
return {
|
|
117
|
+
async handle(event) {
|
|
118
|
+
if (event.type === "session.created")
|
|
119
|
+
await onCreated(event);
|
|
120
|
+
else if (event.type === "session.idle")
|
|
121
|
+
await onIdle(event);
|
|
122
|
+
},
|
|
123
|
+
/** Drop pending idle work; the plugin is unloading. */
|
|
124
|
+
dispose() {
|
|
125
|
+
if (idleTimeout)
|
|
126
|
+
clearTimeout(idleTimeout);
|
|
127
|
+
idleTimeout = null;
|
|
128
|
+
},
|
|
129
|
+
};
|
|
130
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { Context } from "@opencode/plugin/promise/plugin";
|
|
2
|
+
/**
|
|
3
|
+
* Start OMMS for an OpenCode V2 plugin: config, traces, runtime record, warm-up, models,
|
|
4
|
+
* backfill, web app and shutdown handlers. Returns the dispose function for plugin unload.
|
|
5
|
+
*/
|
|
6
|
+
export declare function startOpencodeRuntime(ctx: Context, onCleanup?: () => void): Promise<{
|
|
7
|
+
directory: string & import("effect/Brand").Brand<"AbsolutePath">;
|
|
8
|
+
tags: {
|
|
9
|
+
user: import("../services/tags.js").TagInfo;
|
|
10
|
+
project: import("../services/tags.js").TagInfo;
|
|
11
|
+
};
|
|
12
|
+
autoCaptureHost: import("../core/host.js").AutoCaptureHost;
|
|
13
|
+
dispose(): Promise<void>;
|
|
14
|
+
}>;
|