From 6c8822b1d6a57e138bb5602c7a03df9c7e22a8f9 Mon Sep 17 00:00:00 2001 From: Daniel Smolsky Date: Wed, 1 Apr 2026 19:11:23 -0400 Subject: [PATCH 1/3] message mode prompt update --- lib/prompts/compress-message.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/prompts/compress-message.ts b/lib/prompts/compress-message.ts index 9c41a122..d0964d36 100644 --- a/lib/prompts/compress-message.ts +++ b/lib/prompts/compress-message.ts @@ -39,4 +39,5 @@ During general cleanup, compress all medium and high-priority messages that are Optimize for reducing context footprint, not for grouping messages by topic. Do not compress away still-active instructions, unresolved questions, or constraints that are likely to matter soon. Prioritize the earliest messages in the context as they will be the least relevant to the active task. +General cleanup should be done periodically between other normal compression tool passes, not as the primary form of compression. ` From ffefe4fad8b8c62f2eb0292044c71e7d1adb3e15 Mon Sep 17 00:00:00 2001 From: Daniel Smolsky Date: Fri, 3 Apr 2026 15:24:45 -0400 Subject: [PATCH 2/3] fix: align plugin exports and remove unused dependency --- index.ts | 9 +++++++-- package-lock.json | 32 +------------------------------- package.json | 13 +++++++++++-- 3 files changed, 19 insertions(+), 35 deletions(-) diff --git a/index.ts b/index.ts index e69357e6..a7f073f0 100644 --- a/index.ts +++ b/index.ts @@ -19,7 +19,9 @@ import { } from "./lib/hooks" import { configureClientAuth, isSecureMode } from "./lib/auth" -const plugin: Plugin = (async (ctx) => { +const id = "opencode-dynamic-context-pruning" + +const server: Plugin = (async (ctx) => { const config = getConfig(ctx) if (!config.enabled) { @@ -133,4 +135,7 @@ const plugin: Plugin = (async (ctx) => { } }) satisfies Plugin -export default plugin +export default { + id, + server, +} diff --git a/package-lock.json b/package-lock.json index 84453442..557e38a3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,7 +11,6 @@ "dependencies": { "@anthropic-ai/tokenizer": "^0.0.4", "@opencode-ai/sdk": "^1.3.2", - "fuzzball": "^2.2.3", "jsonc-parser": "^3.3.1", "zod": "^4.3.6" }, @@ -23,7 +22,7 @@ "typescript": "^6.0.2" }, "peerDependencies": { - "@opencode-ai/plugin": ">=0.13.7" + "@opencode-ai/plugin": ">=1.2.0" } }, "node_modules/@anthropic-ai/tokenizer": { @@ -587,17 +586,6 @@ "node": "^8.16.0 || ^10.6.0 || >=11.0.0" } }, - "node_modules/fuzzball": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/fuzzball/-/fuzzball-2.2.3.tgz", - "integrity": "sha512-sQDb3kjI7auA4YyE1YgEW85MTparcSgRgcCweUK06Cn0niY5lN+uhFiRUZKN4MQVGGiHxlbrYCA4nL1QjOXBLQ==", - "license": "MIT", - "dependencies": { - "heap": ">=0.2.0", - "lodash": "^4.17.21", - "setimmediate": "^1.0.5" - } - }, "node_modules/get-tsconfig": { "version": "4.13.0", "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.13.0.tgz", @@ -611,24 +599,12 @@ "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" } }, - "node_modules/heap": { - "version": "0.2.7", - "resolved": "https://registry.npmjs.org/heap/-/heap-0.2.7.tgz", - "integrity": "sha512-2bsegYkkHO+h/9MGbn6KWcE45cHZgPANo5LXF7EvWdT0yT2EguSVO1nDgU5c8+ZOPwp2vMNa7YFsJhVcDR9Sdg==", - "license": "MIT" - }, "node_modules/jsonc-parser": { "version": "3.3.1", "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.3.1.tgz", "integrity": "sha512-HUgH65KyejrUFPvHFPbqOY0rsFip3Bo5wb4ngvdi1EpCYWUQDC5V+Y7mZws+DLkr4M//zQJoanu1SP+87Dv1oQ==", "license": "MIT" }, - "node_modules/lodash": { - "version": "4.17.23", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.23.tgz", - "integrity": "sha512-LgVTMpQtIopCi79SJeDiP0TfWi5CNEc/L/aRdTh3yIvmZXTnheWpKjSZhnvMl8iXbC1tFg9gdHHDMLoV7CnG+w==", - "license": "MIT" - }, "node_modules/prettier": { "version": "3.8.1", "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.8.1.tgz", @@ -655,12 +631,6 @@ "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" } }, - "node_modules/setimmediate": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", - "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==", - "license": "MIT" - }, "node_modules/tiktoken": { "version": "1.0.22", "resolved": "https://registry.npmjs.org/tiktoken/-/tiktoken-1.0.22.tgz", diff --git a/package.json b/package.json index e8b4bea0..ce4ced00 100644 --- a/package.json +++ b/package.json @@ -6,6 +6,16 @@ "description": "OpenCode plugin that optimizes token usage by pruning obsolete tool outputs from conversation context", "main": "./dist/index.js", "types": "./dist/index.d.ts", + "exports": { + ".": { + "types": "./dist/index.d.ts", + "import": "./dist/index.js" + }, + "./server": { + "types": "./dist/index.d.ts", + "import": "./dist/index.js" + } + }, "scripts": { "clean": "rm -rf dist", "build": "npm run clean && tsc", @@ -39,12 +49,11 @@ "author": "tarquinen", "license": "AGPL-3.0-or-later", "peerDependencies": { - "@opencode-ai/plugin": ">=0.13.7" + "@opencode-ai/plugin": ">=1.2.0" }, "dependencies": { "@anthropic-ai/tokenizer": "^0.0.4", "@opencode-ai/sdk": "^1.3.2", - "fuzzball": "^2.2.3", "jsonc-parser": "^3.3.1", "zod": "^4.3.6" }, From d28afa73ebe09fbaa5d91ad71d21ae1cb9a1ccba Mon Sep 17 00:00:00 2001 From: Daniel Smolsky Date: Fri, 3 Apr 2026 15:24:45 -0400 Subject: [PATCH 3/3] fix: harden runtime imports for package loading --- lib/config.ts | 4 ++-- lib/token-utils.ts | 6 ++++-- scripts/verify-package.mjs | 12 ++++++++++++ 3 files changed, 18 insertions(+), 4 deletions(-) diff --git a/lib/config.ts b/lib/config.ts index bd19f768..1eb81df1 100644 --- a/lib/config.ts +++ b/lib/config.ts @@ -1,7 +1,7 @@ import { readFileSync, writeFileSync, existsSync, mkdirSync, statSync } from "fs" import { join, dirname } from "path" import { homedir } from "os" -import * as jsoncParser from "jsonc-parser" +import { parse } from "jsonc-parser/lib/esm/main.js" import type { PluginInput } from "@opencode-ai/plugin" type Permission = "ask" | "allow" | "deny" @@ -773,7 +773,7 @@ function loadConfigFile(configPath: string): ConfigLoadResult { } try { - const parsed = jsoncParser.parse(fileContent, undefined, { allowTrailingComma: true }) + const parsed = parse(fileContent, undefined, { allowTrailingComma: true }) if (parsed === undefined || parsed === null) { return { data: null, parseError: "Config file is empty or invalid" } } diff --git a/lib/token-utils.ts b/lib/token-utils.ts index 6d514a64..ac1c09df 100644 --- a/lib/token-utils.ts +++ b/lib/token-utils.ts @@ -1,7 +1,9 @@ import { SessionState, WithParts } from "./state" import { AssistantMessage, UserMessage } from "@opencode-ai/sdk/v2" import { Logger } from "./logger" -import * as anthropicTokenizer from "@anthropic-ai/tokenizer" +import * as _anthropicTokenizer from "@anthropic-ai/tokenizer" +const anthropicCountTokens = (_anthropicTokenizer.countTokens ?? + (_anthropicTokenizer as any).default?.countTokens) as typeof _anthropicTokenizer.countTokens import { getLastUserMessage } from "./messages/query" export function getCurrentTokenUsage(state: SessionState, messages: WithParts[]): number { @@ -67,7 +69,7 @@ export function getCurrentParams( export function countTokens(text: string): number { if (!text) return 0 try { - return anthropicTokenizer.countTokens(text) + return anthropicCountTokens(text) } catch { return Math.round(text.length / 4) } diff --git a/scripts/verify-package.mjs b/scripts/verify-package.mjs index e2547494..a1f5802c 100644 --- a/scripts/verify-package.mjs +++ b/scripts/verify-package.mjs @@ -66,6 +66,14 @@ function assertPackageJsonShape() { fail(`package.json main must remain ./dist/index.js, found ${pkg.main ?? ""}`) } + if (pkg.exports?.["."]?.import !== "./dist/index.js") { + fail("expected package.json exports['.'].import to be './dist/index.js'") + } + + if (pkg.exports?.["./server"]?.import !== "./dist/index.js") { + fail("expected package.json exports['./server'].import to be './dist/index.js'") + } + const files = Array.isArray(pkg.files) ? pkg.files : [] for (const entry of ["dist/", "README.md", "LICENSE"]) { if (!files.includes(entry)) { @@ -177,6 +185,10 @@ function validateRuntimeImportGraph() { continue } + if (entry.specifier === "jsonc-parser/lib/esm/main.js") { + continue + } + const packageName = getPackageName(entry.specifier) if (builtinNames.has(packageName)) continue