Files
stack/packages/mosaic/src/tui/commands/local/history.ts
Jarvis c6fc090c98
All checks were successful
ci/woodpecker/push/ci Pipeline was successful
ci/woodpecker/pr/ci Pipeline was successful
feat(mosaic): merge @mosaic/cli into @mosaic/mosaic
@mosaic/mosaic is now the single package providing both:
- 'mosaic' binary (CLI: yolo, coord, prdy, tui, gateway, etc.)
- 'mosaic-wizard' binary (installation wizard)

Changes:
- Move packages/cli/src/* into packages/mosaic/src/
- Convert dynamic @mosaic/mosaic imports to static relative imports
- Add CLI deps (ink, react, socket.io-client, @mosaic/config) to mosaic
- Add jsx: react-jsx to mosaic's tsconfig
- Exclude packages/cli from workspace (pnpm-workspace.yaml)
- Update install.sh to install @mosaic/mosaic instead of @mosaic/cli
- Bump version to 0.0.17

This eliminates the circular dependency between @mosaic/cli and
@mosaic/mosaic that was blocking the build graph.
2026-04-04 20:07:27 -05:00

54 lines
1.7 KiB
TypeScript

import type { ConversationMessage } from '../../gateway-api.js';
const CONTEXT_WINDOW = 200_000;
const CHARS_PER_TOKEN = 4;
function estimateTokens(messages: ConversationMessage[]): number {
const totalChars = messages.reduce((sum, m) => sum + (m.content?.length ?? 0), 0);
return Math.round(totalChars / CHARS_PER_TOKEN);
}
export interface HistoryContext {
conversationId: string | undefined;
conversationTitle?: string | null;
gatewayUrl: string;
sessionCookie: string | undefined;
fetchMessages: (
gatewayUrl: string,
sessionCookie: string,
conversationId: string,
) => Promise<ConversationMessage[]>;
}
export async function executeHistory(ctx: HistoryContext): Promise<string> {
const { conversationId, conversationTitle, gatewayUrl, sessionCookie, fetchMessages } = ctx;
if (!conversationId) {
return 'No active conversation.';
}
if (!sessionCookie) {
return 'Not authenticated — cannot fetch conversation messages.';
}
const messages = await fetchMessages(gatewayUrl, sessionCookie, conversationId);
const userMessages = messages.filter((m) => m.role === 'user').length;
const assistantMessages = messages.filter((m) => m.role === 'assistant').length;
const totalMessages = messages.length;
const estimatedTokens = estimateTokens(messages);
const contextPercent = Math.round((estimatedTokens / CONTEXT_WINDOW) * 100);
const label = conversationTitle ?? conversationId;
const lines = [
`Conversation: ${label}`,
`Messages: ${totalMessages} (${userMessages} user, ${assistantMessages} assistant)`,
`Estimated tokens: ~${estimatedTokens.toLocaleString()}`,
`Context usage: ~${contextPercent}% of ${(CONTEXT_WINDOW / 1000).toFixed(0)}K`,
];
return lines.join('\n');
}