diff --git a/CHANGELOG.md b/CHANGELOG.md index 7de3b145..039c9fe2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -24,6 +24,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Extend the `thinkingVerbs` patch to cover past-tense verbs e.g. "Baked" (#454) - @bl-ue - Only apply the `thinkingBlockStyling` patch in CC version under 2.1.26 (#455) - @bl-ue - Fix `subagentModels` patch to not error when nothing was changed (#456) - @bl-ue +- Enable the builtin `/remember` skill (#457) - @bl-ue - AGENTS.md support for Claude Code (#459) - @bl-ue ## [v3.4.0](https://github.com/Piebald-AI/tweakcc/releases/tag/v3.4.0) - 2026-01-18 diff --git a/README.md b/README.md index 86ed6ab1..bd0cab1a 100644 --- a/README.md +++ b/README.md @@ -107,6 +107,8 @@ $ pnpm dlx tweakcc - Suppression of `1→ ` prefixes from `Read` output - Suppress `/rate-limit-options` from being injected - Swarm mode + - Session memory + - `/remember` skill - [Toolsets](#toolsets) - User message display customization - Token indicator display diff --git a/src/defaultSettings.ts b/src/defaultSettings.ts index 77567d23..a92f1d75 100644 --- a/src/defaultSettings.ts +++ b/src/defaultSettings.ts @@ -697,7 +697,7 @@ export const DEFAULT_SETTINGS: Settings = { hideCtrlGToEdit: false, hideStartupClawd: false, increaseFileReadLimit: false, - suppressLineNumbers: true, + suppressLineNumbers: false, suppressRateLimitOptions: false, mcpConnectionNonBlocking: true, mcpServerBatchSize: null, @@ -706,6 +706,7 @@ export const DEFAULT_SETTINGS: Settings = { tableFormat: 'default', enableSwarmMode: true, enableSessionMemory: true, + enableRememberSkill: false, tokenCountRounding: null, }, toolsets: [], diff --git a/src/patches/index.ts b/src/patches/index.ts index 7cebd847..7481c2c3 100644 --- a/src/patches/index.ts +++ b/src/patches/index.ts @@ -60,6 +60,7 @@ import { writeSuppressLineNumbers } from './suppressLineNumbers'; import { writeSuppressRateLimitOptions } from './suppressRateLimitOptions'; import { writeSwarmMode } from './swarmMode'; import { writeSessionMemory } from './sessionMemory'; +import { writeRememberSkill } from './rememberSkill'; import { writeThinkingBlockStyling } from './thinkingBlockStyling'; import { writeMcpNonBlocking, writeMcpBatchSize } from './mcpStartup'; import { writeStatuslineUpdateThrottle } from './statuslineUpdateThrottle'; @@ -310,6 +311,13 @@ const PATCH_DEFINITIONS = [ description: 'Round displayed token counts to the nearest multiple of chosen value', }, + { + id: 'remember-skill', + name: 'Remember skill', + group: PatchGroup.MISC_CONFIGURABLE, + description: + 'Register the built-in "/remember" skill to review session memories and update CLAUDE.local.md', + }, { id: 'agents-md', name: 'AGENTS.md (and others)', @@ -713,6 +721,10 @@ export const applyCustomization = async ( writeTokenCountRounding(c, config.settings.misc!.tokenCountRounding!), condition: !!config.settings.misc?.tokenCountRounding, }, + 'remember-skill': { + fn: c => writeRememberSkill(c), + condition: !!config.settings.misc?.enableRememberSkill, + }, 'agents-md': { fn: c => writeAgentsMd(c, config.settings.claudeMdAltNames!), condition: !!( diff --git a/src/patches/rememberSkill.ts b/src/patches/rememberSkill.ts new file mode 100644 index 00000000..3f02e491 --- /dev/null +++ b/src/patches/rememberSkill.ts @@ -0,0 +1,83 @@ +// Please see the note about writing patches in ./index + +import { showDiff } from './index'; + +/** + * Registers the builtin "/remember" skill that allows users to review session memories + * and update CLAUDE.local.md with learnings from past sessions. + * + * Pattern 1 - Find skill registration function: + * ``` + * {SKILL_REG_FN({name:"claude-in-chrome"... + * ``` + * + * Pattern 2 - Find injection point: + * ```diff + * function SESSION_MEM_LOADER(...){...}function XX(){ + * + SKILL_REG_FN({name:"remember",...}); + * return + * }var SKILL_DATA_VAR=`# Remember Skill... + * ``` + */ + +const findSkillRegistrationFn = (file: string): string | null => { + const pattern = /\{([$\w]+)\(\{name:"claude-in-chrome"/; + const match = file.match(pattern); + if (!match) { + console.error( + 'patch: rememberSkill: failed to find skill registration function' + ); + return null; + } + return match[1]; +}; + +export const writeRememberSkill = (oldFile: string): string | null => { + // Find the skill registration function name + const skillRegistrationFn = findSkillRegistrationFn(oldFile); + if (!skillRegistrationFn) { + return null; + } + + // Find the injection point pattern + const pattern = + /(function ([$\w]+)\(.{0,500}\}function [$\w]+\(\)\{)return(\}var ([$\w]+)=`# Remember Skill)/; + const match = oldFile.match(pattern); + + if (!match || match.index === undefined) { + console.error( + 'patch: rememberSkill: failed to find injection point pattern' + ); + return null; + } + + const [fullMatch, pre, sessionMemLoaderFn, post, skillDataVar] = match; + + // Build the insertion code + const insertCode = ` +${skillRegistrationFn}({ + name: "remember", + description: "Review session memories and update CLAUDE.local.md with learnings", + whenToUse: "When the user wants to save learnings from past sessions", + userInvocable: true, + isEnabled: () => true, + async getPromptForCommand(A) { + let content = ${skillDataVar}; + let sessionMemFiles = ${sessionMemLoaderFn}(null); + content += "\\n\\n## Session Memory Files to Review\\n\\n" + (sessionMemFiles.length ? sessionMemFiles.join("\\n") : "None found"); + if (A) content += "\\n\\n## User Arguments\\n\\n" + A; + return [{ type: "text", text: content }]; + }, +}); +`; + + const replacement = pre + insertCode + 'return' + post; + const startIndex = match.index; + const endIndex = startIndex + fullMatch.length; + + const newFile = + oldFile.slice(0, startIndex) + replacement + oldFile.slice(endIndex); + + showDiff(oldFile, newFile, replacement, startIndex, endIndex); + return newFile; +}; diff --git a/src/types.ts b/src/types.ts index b979a6af..634fed31 100644 --- a/src/types.ts +++ b/src/types.ts @@ -124,6 +124,7 @@ export interface MiscConfig { tableFormat: TableFormat; enableSwarmMode: boolean; enableSessionMemory: boolean; + enableRememberSkill: boolean; tokenCountRounding: number | null; } diff --git a/src/ui/components/MiscView.tsx b/src/ui/components/MiscView.tsx index f5db6304..f6526a61 100644 --- a/src/ui/components/MiscView.tsx +++ b/src/ui/components/MiscView.tsx @@ -71,6 +71,7 @@ export function MiscView({ onSubmit }: MiscViewProps) { tableFormat: 'default' as TableFormat, enableSwarmMode: true, enableSessionMemory: true, + enableRememberSkill: false, tokenCountRounding: null as number | null, }; @@ -451,6 +452,20 @@ export function MiscView({ onSubmit }: MiscViewProps) { }); }, }, + { + id: 'enableRememberSkill', + title: 'Enable remember skill', + description: + 'Register a "remember" skill to review session memories and update CLAUDE.local.md with learnings from past sessions.', + getValue: () => settings.misc?.enableRememberSkill ?? false, + toggle: () => { + updateSettings(settings => { + ensureMisc(); + settings.misc!.enableRememberSkill = + !settings.misc!.enableRememberSkill; + }); + }, + }, { id: 'tokenCountRounding', title: 'Token count rounding',