feat: auto-register plugin-compaction-init slash command

Adds a custom OpenCode command that scaffolds the compaction memory
file with ## Keep and ## Discard sections of classification rules.
The configured memoryFile path is substituted into both the command
description and the prompt template, and any arguments passed after
the command name are appended as user instructions.
This commit is contained in:
2026-08-11 12:48:11 +05:30
parent edb5bb47f4
commit e8c76ea922
4 changed files with 165 additions and 1 deletions
+50
View File
@@ -17,6 +17,38 @@ const defaultCompletionMarker =
"opencode-plugin-compaction-prompt: Custom compaction done.";
const skippedCompactionMarker =
"opencode-plugin-compaction-prompt: No custom compaction applied.";
const initCommandName = "plugin-compaction-init";
/**
* Builds the prompt the auto-registered `/plugin-compaction-init` slash
* command sends to the model. `$ARGUMENTS$` is left unsubstituted so
* OpenCode substitutes it at invocation time.
*
* @param memoryFile Literal path to the memory file, inserted verbatim.
* @returns The full command-body template.
*/
export function buildInitCommandTemplate(memoryFile: string): string {
return `You are creating the file \`${memoryFile}\` (relative to the current project root). It is a meta-classification of which messages to preserve and which to discard during session compaction, not a summary of details.
Follow this format:
\`\`\`
Keep all details related to the keep topics below, and discard everything related to the discard topics below.
## Keep
## Discard
\`\`\`
\`## Keep\` contains one bullet per active in-progress topic. Each bullet is a **classification rule** describing how to recognize messages that discuss that topic, including its requirements, design decisions, dependency information, and ongoing discussions needed to continue the work.
\`## Discard\` contains one bullet per older or already-finished topic. Each bullet is a **classification rule** describing how to recognize messages to drop — features/tasks already shipped, abandoned, or otherwise not relevant to the next session, including any debug loops or repeated fix attempts that have already concluded. Add a final catch-all bullet:
- Any other older discussions not mentioned above.
$ARGUMENTS$
`;
}
function asString(value: unknown): string | undefined {
if (typeof value !== "string") {
@@ -106,6 +138,24 @@ export const CompactionPromptPlugin: Plugin = async (
};
return {
config: async (cfg): Promise<void> => {
if (cfg.command?.[initCommandName]) {
await context.client.app.log({
body: {
level: "warn",
message: `Skipping registration of "${initCommandName}": already defined in config.`,
service: "opencode-plugin-compaction-prompt",
},
});
return;
}
cfg.command ??= {};
cfg.command[initCommandName] = {
description: `Create ${memoryFile} [compaction file]`,
template: buildInitCommandTemplate(memoryFile),
};
},
"experimental.session.compacting": async (
_input,
output,