mirror of
https://github.com/claude-code-best/claude-code.git
synced 2026-06-18 14:25:51 +00:00
更新大量 tsx 原始文件; 已经迁移 login panel; 部分 (#121)
* style(B1-1): 格式化 ink/buddy/cli/context/screens/tasks/services/keybindings/state (43 files) 纯格式化:移除分号、React Compiler import、import 多行展开。 修复了 Box.tsx 和 ScrollBox.tsx 中无效的 global.d.ts import。 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * style(B1-2): 格式化 commands (79 files) 纯格式化:移除分号、React Compiler import、import 多行展开。 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * style(B1-3): 格式化 components/messages,permissions,mcp,sandbox,shell (104 files) 纯格式化:移除分号、React Compiler import、import 多行展开。 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * style(B1-4): 格式化 components/PromptInput,FeedbackSurvey,tasks,agents,skills,design-system,wizard (73 files) 纯格式化:移除分号、React Compiler import、import 多行展开。 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * style(B1-5): 格式化 components其余 + hooks + tools (232 files) 纯格式化:移除分号、React Compiler import、import 多行展开。 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * style(B1-6): 格式化 main/entrypoints/utils/moreright (21 files) 纯格式化:移除分号、React Compiler import、import 多行展开。 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * docs: 更新 README,新增 Run.ps1/TODO.md,删除 V6.md - README.md: 大幅重写,更详细版本历史和配置示例 - Run.ps1: 新增 Windows 启动脚本 - TODO.md: 新增包完成清单 - V6.md: 删除(架构重构规划已不适用) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: 修复以前的问题 * fix: 修复 login 面板的问题 --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,13 +1,13 @@
|
||||
import React, { useRef } from 'react';
|
||||
import stripAnsi from 'strip-ansi';
|
||||
import { Messages } from '../components/Messages.js';
|
||||
import { KeybindingProvider } from '../keybindings/KeybindingContext.js';
|
||||
import { loadKeybindingsSyncWithWarnings } from '../keybindings/loadUserBindings.js';
|
||||
import type { KeybindingContextName } from '../keybindings/types.js';
|
||||
import { AppStateProvider } from '../state/AppState.js';
|
||||
import type { Tools } from '../Tool.js';
|
||||
import type { Message } from '../types/message.js';
|
||||
import { renderToAnsiString } from './staticRender.js';
|
||||
import React, { useRef } from 'react'
|
||||
import stripAnsi from 'strip-ansi'
|
||||
import { Messages } from '../components/Messages.js'
|
||||
import { KeybindingProvider } from '../keybindings/KeybindingContext.js'
|
||||
import { loadKeybindingsSyncWithWarnings } from '../keybindings/loadUserBindings.js'
|
||||
import type { KeybindingContextName } from '../keybindings/types.js'
|
||||
import { AppStateProvider } from '../state/AppState.js'
|
||||
import type { Tools } from '../Tool.js'
|
||||
import type { Message } from '../types/message.js'
|
||||
import { renderToAnsiString } from './staticRender.js'
|
||||
|
||||
/**
|
||||
* Minimal keybinding provider for static/headless renders.
|
||||
@@ -15,19 +15,29 @@ import { renderToAnsiString } from './staticRender.js';
|
||||
* and would hang in headless renders with no stdin).
|
||||
*/
|
||||
function StaticKeybindingProvider({
|
||||
children
|
||||
children,
|
||||
}: {
|
||||
children: React.ReactNode;
|
||||
children: React.ReactNode
|
||||
}): React.ReactNode {
|
||||
const {
|
||||
bindings
|
||||
} = loadKeybindingsSyncWithWarnings();
|
||||
const pendingChordRef = useRef(null);
|
||||
const handlerRegistryRef = useRef(new Map());
|
||||
const activeContexts = useRef(new Set<KeybindingContextName>()).current;
|
||||
return <KeybindingProvider bindings={bindings} pendingChordRef={pendingChordRef} pendingChord={null} setPendingChord={() => {}} activeContexts={activeContexts} registerActiveContext={() => {}} unregisterActiveContext={() => {}} handlerRegistryRef={handlerRegistryRef}>
|
||||
const { bindings } = loadKeybindingsSyncWithWarnings()
|
||||
const pendingChordRef = useRef(null)
|
||||
const handlerRegistryRef = useRef(new Map())
|
||||
const activeContexts = useRef(new Set<KeybindingContextName>()).current
|
||||
|
||||
return (
|
||||
<KeybindingProvider
|
||||
bindings={bindings}
|
||||
pendingChordRef={pendingChordRef}
|
||||
pendingChord={null}
|
||||
setPendingChord={() => {}}
|
||||
activeContexts={activeContexts}
|
||||
registerActiveContext={() => {}}
|
||||
unregisterActiveContext={() => {}}
|
||||
handlerRegistryRef={handlerRegistryRef}
|
||||
>
|
||||
{children}
|
||||
</KeybindingProvider>;
|
||||
</KeybindingProvider>
|
||||
)
|
||||
}
|
||||
|
||||
// Upper-bound how many NormalizedMessages a Message can produce.
|
||||
@@ -35,9 +45,9 @@ function StaticKeybindingProvider({
|
||||
// NormalizedMessages — 1:1 with block count. String content = 1 block.
|
||||
// AttachmentMessage etc. have no .message and normalize to ≤1.
|
||||
function normalizedUpperBound(m: Message): number {
|
||||
if (!('message' in m)) return 1;
|
||||
const c = m.message.content;
|
||||
return Array.isArray(c) ? c.length : 1;
|
||||
if (!('message' in m)) return 1
|
||||
const c = m.message.content
|
||||
return Array.isArray(c) ? c.length : 1
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -52,35 +62,59 @@ function normalizedUpperBound(m: Message): number {
|
||||
* the full normalized array so tool_use↔tool_result resolves regardless of
|
||||
* which chunk each landed in.
|
||||
*/
|
||||
export async function streamRenderedMessages(messages: Message[], tools: Tools, sink: (ansiChunk: string) => void | Promise<void>, {
|
||||
columns,
|
||||
verbose = false,
|
||||
chunkSize = 40,
|
||||
onProgress
|
||||
}: {
|
||||
columns?: number;
|
||||
verbose?: boolean;
|
||||
chunkSize?: number;
|
||||
onProgress?: (rendered: number) => void;
|
||||
} = {}): Promise<void> {
|
||||
const renderChunk = (range: readonly [number, number]) => renderToAnsiString(<AppStateProvider>
|
||||
export async function streamRenderedMessages(
|
||||
messages: Message[],
|
||||
tools: Tools,
|
||||
sink: (ansiChunk: string) => void | Promise<void>,
|
||||
{
|
||||
columns,
|
||||
verbose = false,
|
||||
chunkSize = 40,
|
||||
onProgress,
|
||||
}: {
|
||||
columns?: number
|
||||
verbose?: boolean
|
||||
chunkSize?: number
|
||||
onProgress?: (rendered: number) => void
|
||||
} = {},
|
||||
): Promise<void> {
|
||||
const renderChunk = (range: readonly [number, number]) =>
|
||||
renderToAnsiString(
|
||||
<AppStateProvider>
|
||||
<StaticKeybindingProvider>
|
||||
<Messages messages={messages} tools={tools} commands={[]} verbose={verbose} toolJSX={null} toolUseConfirmQueue={[]} inProgressToolUseIDs={new Set()} isMessageSelectorVisible={false} conversationId="export" screen="prompt" streamingToolUses={[]} showAllInTranscript={true} isLoading={false} renderRange={range} />
|
||||
<Messages
|
||||
messages={messages}
|
||||
tools={tools}
|
||||
commands={[]}
|
||||
verbose={verbose}
|
||||
toolJSX={null}
|
||||
toolUseConfirmQueue={[]}
|
||||
inProgressToolUseIDs={new Set()}
|
||||
isMessageSelectorVisible={false}
|
||||
conversationId="export"
|
||||
screen="prompt"
|
||||
streamingToolUses={[]}
|
||||
showAllInTranscript={true}
|
||||
isLoading={false}
|
||||
renderRange={range}
|
||||
/>
|
||||
</StaticKeybindingProvider>
|
||||
</AppStateProvider>, columns);
|
||||
</AppStateProvider>,
|
||||
columns,
|
||||
)
|
||||
|
||||
// renderRange indexes into the post-collapse array whose length we can't
|
||||
// see from here — normalize splits each Message into one NormalizedMessage
|
||||
// per content block (unbounded per message), collapse merges some back.
|
||||
// Ceiling is the exact normalize output count + chunkSize so the loop
|
||||
// always reaches the empty slice where break fires (collapse only shrinks).
|
||||
let ceiling = chunkSize;
|
||||
for (const m of messages) ceiling += normalizedUpperBound(m);
|
||||
let ceiling = chunkSize
|
||||
for (const m of messages) ceiling += normalizedUpperBound(m)
|
||||
for (let offset = 0; offset < ceiling; offset += chunkSize) {
|
||||
const ansi = await renderChunk([offset, offset + chunkSize]);
|
||||
if (stripAnsi(ansi).trim() === '') break;
|
||||
await sink(ansi);
|
||||
onProgress?.(offset + chunkSize);
|
||||
const ansi = await renderChunk([offset, offset + chunkSize])
|
||||
if (stripAnsi(ansi).trim() === '') break
|
||||
await sink(ansi)
|
||||
onProgress?.(offset + chunkSize)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -88,10 +122,17 @@ export async function streamRenderedMessages(messages: Message[], tools: Tools,
|
||||
* Renders messages to a plain text string suitable for export.
|
||||
* Uses the same React rendering logic as the interactive UI.
|
||||
*/
|
||||
export async function renderMessagesToPlainText(messages: Message[], tools: Tools = [], columns?: number): Promise<string> {
|
||||
const parts: string[] = [];
|
||||
await streamRenderedMessages(messages, tools, chunk => void parts.push(stripAnsi(chunk)), {
|
||||
columns
|
||||
});
|
||||
return parts.join('');
|
||||
export async function renderMessagesToPlainText(
|
||||
messages: Message[],
|
||||
tools: Tools = [],
|
||||
columns?: number,
|
||||
): Promise<string> {
|
||||
const parts: string[] = []
|
||||
await streamRenderedMessages(
|
||||
messages,
|
||||
tools,
|
||||
chunk => void parts.push(stripAnsi(chunk)),
|
||||
{ columns },
|
||||
)
|
||||
return parts.join('')
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user