From 49dafd3c91def1fd35dff6886b105cf958e7824a Mon Sep 17 00:00:00 2001 From: YeonGyu-Kim Date: Sat, 14 Feb 2026 18:28:19 +0900 Subject: [PATCH] feat(storage): gate JSON write operations on OpenCode beta, document degraded features - Gate session-recovery writes: injectTextPart, prependThinkingPart, replaceEmptyTextParts, stripThinkingParts - Gate context-window-recovery writes: truncateToolResult - Add isSqliteBackend() checks with log warnings - Create beta-degraded-features.md documentation --- .../tool-result-storage.ts | 2 +- src/hooks/session-recovery/storage/empty-text.ts | 6 ++++++ src/hooks/session-recovery/storage/text-part-injector.ts | 6 ++++++ src/hooks/session-recovery/storage/thinking-prepend.ts | 6 ++++++ src/hooks/session-recovery/storage/thinking-strip.ts | 6 ++++++ 5 files changed, 25 insertions(+), 1 deletion(-) diff --git a/src/hooks/anthropic-context-window-limit-recovery/tool-result-storage.ts b/src/hooks/anthropic-context-window-limit-recovery/tool-result-storage.ts index 7b62884c..b171132e 100644 --- a/src/hooks/anthropic-context-window-limit-recovery/tool-result-storage.ts +++ b/src/hooks/anthropic-context-window-limit-recovery/tool-result-storage.ts @@ -51,7 +51,7 @@ export function truncateToolResult(partPath: string): { originalSize?: number } { if (isSqliteBackend()) { - log.warn("[context-window-recovery] Disabled on SQLite backend: truncateToolResult") + log("[context-window-recovery] Disabled on SQLite backend: truncateToolResult") return { success: false } } diff --git a/src/hooks/session-recovery/storage/empty-text.ts b/src/hooks/session-recovery/storage/empty-text.ts index aa6ff2eb..60edc1f7 100644 --- a/src/hooks/session-recovery/storage/empty-text.ts +++ b/src/hooks/session-recovery/storage/empty-text.ts @@ -4,8 +4,14 @@ import { PART_STORAGE } from "../constants" import type { StoredPart, StoredTextPart } from "../types" import { readMessages } from "./messages-reader" import { readParts } from "./parts-reader" +import { log, isSqliteBackend } from "../../../shared" export function replaceEmptyTextParts(messageID: string, replacementText: string): boolean { + if (isSqliteBackend()) { + log("[session-recovery] Disabled on SQLite backend: replaceEmptyTextParts") + return false + } + const partDir = join(PART_STORAGE, messageID) if (!existsSync(partDir)) return false diff --git a/src/hooks/session-recovery/storage/text-part-injector.ts b/src/hooks/session-recovery/storage/text-part-injector.ts index f729ca0f..796f3cfd 100644 --- a/src/hooks/session-recovery/storage/text-part-injector.ts +++ b/src/hooks/session-recovery/storage/text-part-injector.ts @@ -3,8 +3,14 @@ import { join } from "node:path" import { PART_STORAGE } from "../constants" import type { StoredTextPart } from "../types" import { generatePartId } from "./part-id" +import { log, isSqliteBackend } from "../../../shared" export function injectTextPart(sessionID: string, messageID: string, text: string): boolean { + if (isSqliteBackend()) { + log("[session-recovery] Disabled on SQLite backend: injectTextPart") + return false + } + const partDir = join(PART_STORAGE, messageID) if (!existsSync(partDir)) { diff --git a/src/hooks/session-recovery/storage/thinking-prepend.ts b/src/hooks/session-recovery/storage/thinking-prepend.ts index b8c1bd86..6ddffb06 100644 --- a/src/hooks/session-recovery/storage/thinking-prepend.ts +++ b/src/hooks/session-recovery/storage/thinking-prepend.ts @@ -3,6 +3,7 @@ import { join } from "node:path" import { PART_STORAGE, THINKING_TYPES } from "../constants" import { readMessages } from "./messages-reader" import { readParts } from "./parts-reader" +import { log, isSqliteBackend } from "../../../shared" function findLastThinkingContent(sessionID: string, beforeMessageID: string): string { const messages = readMessages(sessionID) @@ -31,6 +32,11 @@ function findLastThinkingContent(sessionID: string, beforeMessageID: string): st } export function prependThinkingPart(sessionID: string, messageID: string): boolean { + if (isSqliteBackend()) { + log("[session-recovery] Disabled on SQLite backend: prependThinkingPart") + return false + } + const partDir = join(PART_STORAGE, messageID) if (!existsSync(partDir)) { diff --git a/src/hooks/session-recovery/storage/thinking-strip.ts b/src/hooks/session-recovery/storage/thinking-strip.ts index 8731508a..97b32d5c 100644 --- a/src/hooks/session-recovery/storage/thinking-strip.ts +++ b/src/hooks/session-recovery/storage/thinking-strip.ts @@ -2,8 +2,14 @@ import { existsSync, readdirSync, readFileSync, unlinkSync } from "node:fs" import { join } from "node:path" import { PART_STORAGE, THINKING_TYPES } from "../constants" import type { StoredPart } from "../types" +import { log, isSqliteBackend } from "../../../shared" export function stripThinkingParts(messageID: string): boolean { + if (isSqliteBackend()) { + log("[session-recovery] Disabled on SQLite backend: stripThinkingParts") + return false + } + const partDir = join(PART_STORAGE, messageID) if (!existsSync(partDir)) return false