mirror of
https://github.com/siteboon/claudecodeui.git
synced 2026-06-10 15:55:53 +08:00
Merge branch 'main' into fix/editor-toolbar-offscreen-796
This commit is contained in:
@@ -1,7 +1,8 @@
|
|||||||
import fs from 'fs';
|
import fs from 'fs';
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
import os from 'os';
|
import os from 'os';
|
||||||
import { spawn } from 'child_process';
|
|
||||||
|
import { spawn } from 'cross-spawn';
|
||||||
|
|
||||||
const PLUGINS_DIR = path.join(os.homedir(), '.claude-code-ui', 'plugins');
|
const PLUGINS_DIR = path.join(os.homedir(), '.claude-code-ui', 'plugins');
|
||||||
const PLUGINS_CONFIG_PATH = path.join(os.homedir(), '.claude-code-ui', 'plugins.json');
|
const PLUGINS_CONFIG_PATH = path.join(os.homedir(), '.claude-code-ui', 'plugins.json');
|
||||||
|
|||||||
@@ -383,12 +383,47 @@ export function useChatSessionState({
|
|||||||
setIsUserScrolledUp(false);
|
setIsUserScrolledUp(false);
|
||||||
}, [selectedProject?.projectId, selectedSession?.id]);
|
}, [selectedProject?.projectId, selectedSession?.id]);
|
||||||
|
|
||||||
// Initial scroll to bottom
|
// Initial scroll to bottom — robust to lazy content reflow.
|
||||||
|
// The previous implementation fired one scrollToBottom() at +200ms and
|
||||||
|
// cleared the pending flag. When markdown blocks, code highlighting, or
|
||||||
|
// images finished rendering after that window, scrollHeight grew but
|
||||||
|
// nothing re-anchored the viewport, leaving the chat tab visually
|
||||||
|
// "scrolled way up" with the latest assistant message off-screen.
|
||||||
|
//
|
||||||
|
// This version re-scrolls every animation frame while scrollHeight is
|
||||||
|
// still growing, capped at ~1s (60 frames) or 3 consecutive stable
|
||||||
|
// frames. Cancels cleanly on session change via the pending flag.
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!pendingInitialScrollRef.current || !scrollContainerRef.current || isLoadingSessionMessages) return;
|
if (!pendingInitialScrollRef.current || !scrollContainerRef.current || isLoadingSessionMessages) return;
|
||||||
if (chatMessages.length === 0) { pendingInitialScrollRef.current = false; return; }
|
if (chatMessages.length === 0) { pendingInitialScrollRef.current = false; return; }
|
||||||
pendingInitialScrollRef.current = false;
|
if (searchScrollActiveRef.current) { pendingInitialScrollRef.current = false; return; }
|
||||||
if (!searchScrollActiveRef.current) setTimeout(() => scrollToBottom(), 200);
|
|
||||||
|
const container = scrollContainerRef.current;
|
||||||
|
let frame = 0;
|
||||||
|
let lastHeight = 0;
|
||||||
|
let stableCount = 0;
|
||||||
|
let rafId = 0;
|
||||||
|
|
||||||
|
const tick = () => {
|
||||||
|
if (!pendingInitialScrollRef.current || !scrollContainerRef.current) return;
|
||||||
|
container.scrollTop = container.scrollHeight;
|
||||||
|
if (container.scrollHeight === lastHeight) {
|
||||||
|
stableCount++;
|
||||||
|
} else {
|
||||||
|
stableCount = 0;
|
||||||
|
lastHeight = container.scrollHeight;
|
||||||
|
}
|
||||||
|
frame++;
|
||||||
|
if (stableCount < 3 && frame < 60) {
|
||||||
|
rafId = requestAnimationFrame(tick);
|
||||||
|
} else {
|
||||||
|
pendingInitialScrollRef.current = false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
rafId = requestAnimationFrame(tick);
|
||||||
|
return () => {
|
||||||
|
if (rafId) cancelAnimationFrame(rafId);
|
||||||
|
};
|
||||||
}, [chatMessages.length, isLoadingSessionMessages, scrollToBottom]);
|
}, [chatMessages.length, isLoadingSessionMessages, scrollToBottom]);
|
||||||
|
|
||||||
// Main session loading effect — store-based
|
// Main session loading effect — store-based
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ const STARTER_PLUGIN_URL = 'https://github.com/cloudcli-ai/cloudcli-plugin-start
|
|||||||
const TERMINAL_PLUGIN_URL = 'https://github.com/cloudcli-ai/cloudcli-plugin-terminal';
|
const TERMINAL_PLUGIN_URL = 'https://github.com/cloudcli-ai/cloudcli-plugin-terminal';
|
||||||
const SCHEDULED_PROMPT_PLUGIN_URL = 'https://github.com/grostim/cloudcli-cron';
|
const SCHEDULED_PROMPT_PLUGIN_URL = 'https://github.com/grostim/cloudcli-cron';
|
||||||
const CLAUDE_WATCH_PLUGIN_URL = 'https://github.com/satsuki19980613/cloudcli-claude-watch';
|
const CLAUDE_WATCH_PLUGIN_URL = 'https://github.com/satsuki19980613/cloudcli-claude-watch';
|
||||||
|
const PRISM_CLOUDCLI_PLUGIN_URL = 'https://github.com/jakeefr/cloudcli-plugin-prism';
|
||||||
|
|
||||||
type PluginRecommendation = {
|
type PluginRecommendation = {
|
||||||
id: string;
|
id: string;
|
||||||
@@ -72,6 +73,14 @@ const UNOFFICIAL_PLUGIN_RECOMMENDATIONS: PluginRecommendation[] = [
|
|||||||
icon: Clock,
|
icon: Clock,
|
||||||
source: 'unofficial',
|
source: 'unofficial',
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
id: 'prism',
|
||||||
|
translationKey: 'prismCloudCLI',
|
||||||
|
repoUrl: PRISM_CLOUDCLI_PLUGIN_URL,
|
||||||
|
installedNames: ['prism'],
|
||||||
|
icon: Activity,
|
||||||
|
source: 'unofficial'
|
||||||
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
function repoSlug(repoUrl: string) {
|
function repoSlug(repoUrl: string) {
|
||||||
|
|||||||
@@ -502,6 +502,12 @@
|
|||||||
"description": "Watch long-running Claude Code sessions for hangs and expose process controls.",
|
"description": "Watch long-running Claude Code sessions for hangs and expose process controls.",
|
||||||
"install": "Install"
|
"install": "Install"
|
||||||
},
|
},
|
||||||
|
"prismCloudCLI": {
|
||||||
|
"name": "PRISM CloudCLI",
|
||||||
|
"badge": "unofficial",
|
||||||
|
"description": "Session intelligence for Claude Code, inside CloudCLI. See why your sessions are burning tokens without leaving the browser.",
|
||||||
|
"install": "Install"
|
||||||
|
},
|
||||||
"morePlugins": "More",
|
"morePlugins": "More",
|
||||||
"enable": "Enable",
|
"enable": "Enable",
|
||||||
"disable": "Disable",
|
"disable": "Disable",
|
||||||
|
|||||||
Reference in New Issue
Block a user