|
1 | 1 | import type { Plugin, PluginInput } from "@opencode-ai/plugin"; |
2 | | -import type { Part } from "@opencode-ai/sdk"; |
| 2 | +import type { Part, Permission } from "@opencode-ai/sdk"; |
3 | 3 | import { tool } from "@opencode-ai/plugin"; |
4 | 4 |
|
5 | 5 | import { AGENT_ENTITY_CONTEXT } from "./services/entity-context.js"; |
6 | 6 | import { supermemoryClient } from "./services/client.js"; |
7 | 7 | import { formatContextForPrompt } from "./services/context.js"; |
| 8 | +import { createCaptureHook } from "./services/capture.js"; |
| 9 | +import { buildRecallDirective } from "./services/recall.js"; |
8 | 10 | import { getTags } from "./services/tags.js"; |
9 | 11 | import { stripPrivateContent, isFullyPrivate } from "./services/privacy.js"; |
10 | 12 | import { createCompactionHook, type CompactionContext } from "./services/compaction.js"; |
@@ -43,6 +45,24 @@ function combineContextParts(parts: Array<string | null | undefined>): string { |
43 | 45 | return parts.map((part) => part?.trim()).filter(Boolean).join("\n\n"); |
44 | 46 | } |
45 | 47 |
|
| 48 | +function isSupermemoryRecallSearch(input: Permission): boolean { |
| 49 | + const type = String((input as { type?: unknown }).type ?? ""); |
| 50 | + const title = String((input as { title?: unknown }).title ?? "").toLowerCase(); |
| 51 | + const metadata = |
| 52 | + ((input as { metadata?: Record<string, unknown> }).metadata ?? {}) as Record<string, unknown>; |
| 53 | + |
| 54 | + const toolName = String(metadata.tool ?? metadata.toolName ?? type); |
| 55 | + const isSupermemory = |
| 56 | + type === "supermemory" || toolName === "supermemory" || title.includes("supermemory"); |
| 57 | + if (!isSupermemory) return false; |
| 58 | + |
| 59 | + const args = (metadata.args ?? metadata.input ?? metadata.arguments ?? metadata) as Record< |
| 60 | + string, |
| 61 | + unknown |
| 62 | + >; |
| 63 | + return String(args.mode ?? "") === "search"; |
| 64 | +} |
| 65 | + |
46 | 66 | export const SupermemoryPlugin: Plugin = async (ctx: PluginInput) => { |
47 | 67 | const { directory } = ctx; |
48 | 68 | const tags = getTags(directory); |
@@ -86,6 +106,9 @@ export const SupermemoryPlugin: Plugin = async (ctx: PluginInput) => { |
86 | 106 | getModelLimit, |
87 | 107 | }) |
88 | 108 | : null; |
| 109 | + const captureHook = isConfigured() && ctx.client |
| 110 | + ? createCaptureHook(ctx, tags) |
| 111 | + : null; |
89 | 112 |
|
90 | 113 | return { |
91 | 114 | "chat.message": async (input, output) => { |
@@ -129,6 +152,16 @@ export const SupermemoryPlugin: Plugin = async (ctx: PluginInput) => { |
129 | 152 | output.parts.push(nudgePart); |
130 | 153 | } |
131 | 154 |
|
| 155 | + const recallPart: Part = { |
| 156 | + id: `prt_supermemory-recall-${Date.now()}`, |
| 157 | + sessionID: input.sessionID, |
| 158 | + messageID: output.message.id, |
| 159 | + type: "text", |
| 160 | + text: buildRecallDirective(), |
| 161 | + synthetic: true, |
| 162 | + }; |
| 163 | + output.parts.push(recallPart); |
| 164 | + |
132 | 165 | const isFirstMessage = !injectedSessions.has(input.sessionID); |
133 | 166 |
|
134 | 167 | if (isFirstMessage) { |
@@ -525,10 +558,25 @@ export const SupermemoryPlugin: Plugin = async (ctx: PluginInput) => { |
525 | 558 | }), |
526 | 559 | }, |
527 | 560 |
|
| 561 | + "permission.ask": async (input, output) => { |
| 562 | + if (!isConfigured()) return; |
| 563 | + try { |
| 564 | + if (isSupermemoryRecallSearch(input)) { |
| 565 | + output.status = "allow"; |
| 566 | + log("permission.ask: auto-allowing supermemory recall search"); |
| 567 | + } |
| 568 | + } catch (error) { |
| 569 | + log("permission.ask: ERROR", { error: String(error) }); |
| 570 | + } |
| 571 | + }, |
| 572 | + |
528 | 573 | event: async (input: { event: { type: string; properties?: unknown } }) => { |
529 | 574 | if (compactionHook) { |
530 | 575 | await compactionHook.event(input); |
531 | 576 | } |
| 577 | + if (captureHook) { |
| 578 | + await captureHook.event(input); |
| 579 | + } |
532 | 580 | }, |
533 | 581 | }; |
534 | 582 | }; |
|
0 commit comments