@nanocollective/nanocoder
Version:
A local-first CLI coding agent that brings the power of agentic coding tools like Claude Code and Gemini CLI to local models or controlled APIs like OpenRouter
148 lines • 7.23 kB
JavaScript
import React from 'react';
import { ErrorMessage, InfoMessage, SuccessMessage, } from '../../../components/message-box.js';
import { DELAY_COMMAND_COMPLETE_MS } from '../../../constants.js';
import { createTokenizer } from '../../../tokenization/index.js';
import { setAutoCompactEnabled, setAutoCompactThreshold, } from '../../../utils/auto-compact.js';
import { compressionBackup } from '../../../utils/compression-backup.js';
import { compressMessages } from '../../../utils/message-compression.js';
import { processPromptTemplate } from '../../../utils/prompt-processor.js';
/**
* Handles /compact command. Returns true if handled.
*/
export async function handleCompactCommand(commandParts, options) {
const { onAddToChatQueue, onCommandComplete, getNextComponentKey, messages, setMessages, provider, model, } = options;
if (commandParts[0] !== 'compact') {
return false;
}
const args = commandParts.slice(1);
let mode = 'default';
let preview = false;
for (let i = 0; i < args.length; i++) {
const arg = args[i];
if (arg === '--aggressive') {
mode = 'aggressive';
}
else if (arg === '--conservative') {
mode = 'conservative';
}
else if (arg === '--preview') {
preview = true;
}
else if (arg === '--default') {
mode = 'default';
}
else if (arg === '--restore') {
const restored = compressionBackup.restore();
if (restored) {
setMessages(restored);
onAddToChatQueue(React.createElement(SuccessMessage, {
key: `compact-restore-${getNextComponentKey()}`,
message: `Restored ${restored.length} messages from backup.`,
hideBox: true,
}));
compressionBackup.clearBackup();
}
else {
onAddToChatQueue(React.createElement(ErrorMessage, {
key: `compact-restore-error-${getNextComponentKey()}`,
message: 'No backup available to restore.',
hideBox: true,
}));
}
setTimeout(() => onCommandComplete?.(), DELAY_COMMAND_COMPLETE_MS);
return true;
}
else if (arg === '--auto-on') {
setAutoCompactEnabled(true);
onAddToChatQueue(React.createElement(SuccessMessage, {
key: `compact-auto-on-${getNextComponentKey()}`,
message: 'Auto-compact enabled for this session.',
hideBox: true,
}));
setTimeout(() => onCommandComplete?.(), DELAY_COMMAND_COMPLETE_MS);
return true;
}
else if (arg === '--auto-off') {
setAutoCompactEnabled(false);
onAddToChatQueue(React.createElement(SuccessMessage, {
key: `compact-auto-off-${getNextComponentKey()}`,
message: 'Auto-compact disabled for this session.',
hideBox: true,
}));
setTimeout(() => onCommandComplete?.(), DELAY_COMMAND_COMPLETE_MS);
return true;
}
else if (arg === '--threshold' && i + 1 < args.length) {
const thresholdValue = Number.parseFloat(args[i + 1]);
if (Number.isNaN(thresholdValue) ||
thresholdValue < 50 ||
thresholdValue > 95) {
onAddToChatQueue(React.createElement(ErrorMessage, {
key: `compact-threshold-error-${getNextComponentKey()}`,
message: 'Threshold must be a number between 50 and 95.',
hideBox: true,
}));
setTimeout(() => onCommandComplete?.(), DELAY_COMMAND_COMPLETE_MS);
return true;
}
setAutoCompactThreshold(Math.round(thresholdValue));
onAddToChatQueue(React.createElement(SuccessMessage, {
key: `compact-threshold-${getNextComponentKey()}`,
message: `Auto-compact threshold set to ${Math.round(thresholdValue)}% for this session.`,
hideBox: true,
}));
setTimeout(() => onCommandComplete?.(), DELAY_COMMAND_COMPLETE_MS);
return true;
}
}
try {
if (messages.length === 0) {
onAddToChatQueue(React.createElement(InfoMessage, {
key: `compact-info-${getNextComponentKey()}`,
message: 'No messages to compact.',
hideBox: true,
}));
onCommandComplete?.();
return true;
}
const tokenizer = createTokenizer(provider, model);
const systemPrompt = processPromptTemplate();
const systemMessage = { role: 'system', content: systemPrompt };
const allMessages = [systemMessage, ...messages];
const result = compressMessages(allMessages, tokenizer, { mode });
if (tokenizer.free) {
tokenizer.free();
}
if (preview) {
const message = `Preview: Context would be compacted: ${result.originalTokenCount.toLocaleString()} tokens → ${result.compressedTokenCount.toLocaleString()} tokens (${Math.round(result.reductionPercentage)}% reduction)\n\nPreserved:\n• ${result.preservedInfo.keyDecisions} key decisions\n• ${result.preservedInfo.fileModifications} file modifications\n• ${result.preservedInfo.toolResults} tool results\n• ${result.preservedInfo.recentMessages} recent messages at full detail`;
onAddToChatQueue(React.createElement(InfoMessage, {
key: `compact-preview-${getNextComponentKey()}`,
message,
hideBox: false,
}));
}
else {
compressionBackup.storeBackup(messages);
const compressedUserMessages = result.compressedMessages.filter(msg => msg.role !== 'system');
setMessages(compressedUserMessages);
const message = `Context Compacted: ${result.originalTokenCount.toLocaleString()} tokens → ${result.compressedTokenCount.toLocaleString()} tokens (${Math.round(result.reductionPercentage)}% reduction)\n\nPreserved:\n• ${result.preservedInfo.keyDecisions} key decisions\n• ${result.preservedInfo.fileModifications} file modifications\n• ${result.preservedInfo.toolResults} tool results\n• ${result.preservedInfo.recentMessages} recent messages at full detail`;
onAddToChatQueue(React.createElement(SuccessMessage, {
key: `compact-success-${getNextComponentKey()}`,
message,
hideBox: false,
}));
}
setTimeout(() => onCommandComplete?.(), DELAY_COMMAND_COMPLETE_MS);
return true;
}
catch (error) {
onAddToChatQueue(React.createElement(ErrorMessage, {
key: `compact-error-${getNextComponentKey()}`,
message: `Failed to compact messages: ${error instanceof Error ? error.message : 'Unknown error'}`,
hideBox: true,
}));
onCommandComplete?.();
return true;
}
}
//# sourceMappingURL=compact-handler.js.map