@mingxy/cerebro 1.11.9 โ†’ 1.11.10

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mingxy/cerebro",
3
- "version": "1.11.9",
3
+ "version": "1.11.10",
4
4
  "description": "Cerebro persistent memory plugin for OpenCode โ€” auto-recall, auto-capture, 9 memory tools with clustering",
5
5
  "type": "module",
6
6
  "main": "src/index.ts",
package/src/hooks.ts CHANGED
@@ -653,6 +653,109 @@ export function compactingHook(client: CerebroClient, containerTags: string[], t
653
653
  };
654
654
  }
655
655
 
656
+ export function autocontinueHook(
657
+ client: CerebroClient,
658
+ containerTags: string[],
659
+ tui: any,
660
+ ingestMode: "smart" | "raw" = "smart",
661
+ isAutoStoreEnabled?: (sessionId: string | undefined) => boolean,
662
+ getMainSessionId?: () => string | undefined,
663
+ sdkClient?: any,
664
+ config: Partial<OmemPluginConfig> = {},
665
+ agentId?: string,
666
+ ) {
667
+ const effectiveAgentId = agentId || process.env.OMEM_AGENT_ID || "opencode";
668
+ return async (
669
+ input: {
670
+ sessionID: string;
671
+ agent: string;
672
+ model: Model;
673
+ message: UserMessage;
674
+ overflow: boolean;
675
+ },
676
+ _output: { enabled: boolean },
677
+ ) => {
678
+ try {
679
+ const policy = resolveAgentPolicy(effectiveAgentId, config);
680
+ if (policy !== "readwrite") {
681
+ logInfo("autocontinueHook blocked by policy", { agentId: effectiveAgentId, policy });
682
+ return;
683
+ }
684
+
685
+ if (isAutoStoreEnabled && !isAutoStoreEnabled(input.sessionID)) {
686
+ logInfo("autocontinueHook skipped: auto-store disabled", { sessionId: input.sessionID });
687
+ return;
688
+ }
689
+
690
+ const effectiveSessionId = getMainSessionId?.() || input.sessionID;
691
+
692
+ if (!sdkClient) {
693
+ logInfo("autocontinueHook skipped: no sdkClient", { sessionId: input.sessionID });
694
+ return;
695
+ }
696
+
697
+ let summaryText: string | undefined;
698
+ try {
699
+ const response = await sdkClient.session.messages({ path: { id: input.sessionID } });
700
+ if (response?.data) {
701
+ const targetMsg = response.data.find(
702
+ (msg: any) => msg.info?.id === input.message.id,
703
+ );
704
+ if (targetMsg?.parts) {
705
+ const textParts = (targetMsg.parts as any[])
706
+ .filter((p: any) => p.type === "text" && p.text)
707
+ .map((p: any) => p.text);
708
+ summaryText = textParts.join("\n").trim();
709
+ }
710
+ }
711
+ } catch (e) {
712
+ logErr("autocontinueHook failed to fetch message parts", { error: String(e) });
713
+ }
714
+
715
+ if (!summaryText) {
716
+ logInfo("autocontinueHook skipped: no summary text found", { sessionId: input.sessionID, messageId: input.message.id });
717
+ return;
718
+ }
719
+
720
+ let projectName: string | undefined;
721
+ try {
722
+ const sessionInfo = await sdkClient.session.get({ path: { id: input.sessionID } });
723
+ projectName = sessionInfo?.data?.directory
724
+ ? await detectProjectName(sessionInfo.data.directory)
725
+ : undefined;
726
+ } catch (e) {
727
+ logErr("autocontinueHook detectProjectName failed", { error: String(e) });
728
+ }
729
+
730
+ const messages = [{ role: "user" as const, content: summaryText }];
731
+ logInfo("autocontinueHook storing compact summary", {
732
+ summaryLen: summaryText.length,
733
+ sessionId: effectiveSessionId,
734
+ agentId: effectiveAgentId,
735
+ overflow: input.overflow,
736
+ projectName,
737
+ });
738
+
739
+ const result = await client.ingestMessages(messages, {
740
+ mode: ingestMode,
741
+ tags: [...containerTags, "auto-capture", "compact-summary"],
742
+ sessionId: effectiveSessionId,
743
+ projectName: projectName,
744
+ agentId: effectiveAgentId,
745
+ });
746
+
747
+ logInfo("autocontinueHook store result", { result: result === null ? "null(blocked)" : "ok" });
748
+ if (result === null) {
749
+ showToast(tui, "๐Ÿ”ด Compact Summary Failed", "Storage blocked ยท check server status", "error");
750
+ } else {
751
+ showToast(tui, "๐Ÿ“ฆ Compact Summary Stored", "Session summary archived to memory", "success");
752
+ }
753
+ } catch (e) {
754
+ logErr("autocontinueHook failed", { error: String(e) });
755
+ }
756
+ };
757
+ }
758
+
656
759
  const processedMessageIds = new Set<string>();
657
760
  const pluginStartTime = Date.now();
658
761
 
package/src/index.ts CHANGED
@@ -4,7 +4,7 @@ import { join, dirname } from "node:path";
4
4
  import { tmpdir } from "node:os";
5
5
  import { fileURLToPath } from "node:url";
6
6
  import { CerebroClient } from "./client.js";
7
- import { autoRecallHook, compactingHook, keywordDetectionHook, sessionIdleHook } from "./hooks.js";
7
+ import { autoRecallHook, autocontinueHook, compactingHook, keywordDetectionHook, sessionIdleHook } from "./hooks.js";
8
8
  import { getUserTag, getProjectTag } from "./tags.js";
9
9
  import { buildTools } from "./tools.js";
10
10
  import { logInfo, logDebug, logError } from "./logger.js";
@@ -140,6 +140,7 @@ const OmemPlugin: Plugin = async (input) => {
140
140
  },
141
141
  "chat.message": keywordDetectionHook(cerebroClient, containerTags, config.ingest.autoCaptureThreshold, tui, config.ingest.ingestMode, config, agentId),
142
142
  "experimental.session.compacting": compactingHook(cerebroClient, containerTags, tui, config.ingest.ingestMode, isAutoStoreEnabled, () => mainSessionId, client, config, agentId),
143
+ "experimental.compaction.autocontinue": autocontinueHook(cerebroClient, containerTags, tui, config.ingest.ingestMode, isAutoStoreEnabled, () => mainSessionId, client, config, agentId),
143
144
  tool: buildTools(cerebroClient, containerTags, { agentId, getSessionId: () => mainSessionId, getAgentName: () => cachedAgentName || agentId }),
144
145
  event: sessionIdleHook(cerebroClient, containerTags, tui, client, config.ingest.ingestMode, config.ingest.autoCaptureThreshold, () => mainSessionId, isAutoStoreEnabled, agentId, config, (name: string) => { cachedAgentName = name; }),
145
146
  "shell.env": async (_input: any, output: any) => {