mirror of
https://github.com/claude-code-best/claude-code.git
synced 2026-06-18 06:15:51 +00:00
feat: 第一版可用 pokemon
This commit is contained in:
@@ -1,52 +1,84 @@
|
||||
import type { TextBlockParam } from '@anthropic-ai/sdk/resources/index.mjs'
|
||||
import * as React from 'react'
|
||||
import { CHANNEL_ARROW } from '../../constants/figures.js'
|
||||
import { CHANNEL_TAG } from '../../constants/xml.js'
|
||||
import { Box, Text } from '@anthropic/ink'
|
||||
import { truncateToWidth } from '../../utils/format.js'
|
||||
import type { TextBlockParam } from '@anthropic-ai/sdk/resources/index.mjs';
|
||||
import * as React from 'react';
|
||||
import { CHANNEL_ARROW } from '../../constants/figures.js';
|
||||
import { CHANNEL_TAG } from '../../constants/xml.js';
|
||||
import { Box, Text } from '@anthropic/ink';
|
||||
import { truncateToWidth } from '../../utils/format.js';
|
||||
|
||||
type Props = {
|
||||
addMargin: boolean
|
||||
param: TextBlockParam
|
||||
}
|
||||
addMargin: boolean;
|
||||
param: TextBlockParam;
|
||||
};
|
||||
|
||||
// <channel source="..." user="..." chat_id="...">content</channel>
|
||||
// source is always first (wrapChannelMessage writes it), user is optional.
|
||||
const CHANNEL_RE = new RegExp(
|
||||
`<${CHANNEL_TAG}\\s+source="([^"]+)"([^>]*)>\\n?([\\s\\S]*?)\\n?</${CHANNEL_TAG}>`,
|
||||
)
|
||||
const USER_ATTR_RE = /\buser="([^"]+)"/
|
||||
const CHANNEL_RE = new RegExp(`<${CHANNEL_TAG}\\s+source="([^"]+)"([^>]*)>\\n?([\\s\\S]*?)\\n?</${CHANNEL_TAG}>`);
|
||||
const USER_ATTR_RE = /\buser="([^"]+)"/;
|
||||
|
||||
// Plugin-provided servers get names like plugin:slack-channel:slack via
|
||||
// addPluginScopeToServers — show just the leaf. Matches the suffix-match
|
||||
// logic in isServerInChannels.
|
||||
function displayServerName(name: string): string {
|
||||
const i = name.lastIndexOf(':')
|
||||
return i === -1 ? name : name.slice(i + 1)
|
||||
const i = name.lastIndexOf(':');
|
||||
return i === -1 ? name : name.slice(i + 1);
|
||||
}
|
||||
|
||||
const TRUNCATE_AT = 60
|
||||
const MAX_LINE_WIDTH = 80;
|
||||
const MAX_LINES = 3;
|
||||
|
||||
/**
|
||||
* Formats multi-line channel content for compact display in the terminal.
|
||||
* Collapses excessive blank lines, limits to MAX_LINES, truncates each line.
|
||||
*/
|
||||
function formatChannelBody(raw: string): { lines: string[]; truncated: boolean } {
|
||||
const body = raw.trim();
|
||||
// Split into lines, collapse runs of blank lines into single empty line
|
||||
const allLines = body.split(/\n/).reduce<string[]>((acc, line) => {
|
||||
const trimmed = line.trimEnd();
|
||||
if (trimmed === '' && acc.length > 0 && acc[acc.length - 1] === '') return acc;
|
||||
acc.push(trimmed);
|
||||
return acc;
|
||||
}, []);
|
||||
// Remove leading/trailing blank lines
|
||||
while (allLines.length > 0 && allLines[0] === '') allLines.shift();
|
||||
while (allLines.length > 0 && allLines[allLines.length - 1] === '') allLines.pop();
|
||||
|
||||
const truncated = allLines.length > MAX_LINES;
|
||||
const visible = allLines.slice(0, MAX_LINES);
|
||||
const lines = visible.map(l => (l === '' ? '' : truncateToWidth(l, MAX_LINE_WIDTH)));
|
||||
return { lines, truncated };
|
||||
}
|
||||
|
||||
export function UserChannelMessage({ addMargin, param: { text } }: Props): React.ReactNode {
|
||||
const m = CHANNEL_RE.exec(text);
|
||||
if (!m) return null;
|
||||
const [, source, attrs, content] = m;
|
||||
const user = USER_ATTR_RE.exec(attrs ?? '')?.[1];
|
||||
const { lines, truncated } = formatChannelBody(content ?? '');
|
||||
|
||||
export function UserChannelMessage({
|
||||
addMargin,
|
||||
param: { text },
|
||||
}: Props): React.ReactNode {
|
||||
const m = CHANNEL_RE.exec(text)
|
||||
if (!m) return null
|
||||
const [, source, attrs, content] = m
|
||||
const user = USER_ATTR_RE.exec(attrs ?? '')?.[1]
|
||||
const body = (content ?? '').trim().replace(/\s+/g, ' ')
|
||||
const truncated = truncateToWidth(body, TRUNCATE_AT)
|
||||
return (
|
||||
<Box marginTop={addMargin ? 1 : 0}>
|
||||
<Text>
|
||||
<Text color="suggestion">{CHANNEL_ARROW}</Text>{' '}
|
||||
<Text dimColor>
|
||||
{displayServerName(source ?? '')}
|
||||
{user ? ` \u00b7 ${user}` : ''}:
|
||||
</Text>{' '}
|
||||
{truncated}
|
||||
</Text>
|
||||
<Box marginTop={addMargin ? 1 : 0} flexDirection="column">
|
||||
{lines.map((line, i) => (
|
||||
<Box key={i}>
|
||||
{i === 0 ? (
|
||||
<Text>
|
||||
<Text color="suggestion">{CHANNEL_ARROW}</Text>{' '}
|
||||
<Text dimColor>
|
||||
{displayServerName(source ?? '')}
|
||||
{user ? ` \u00b7 ${user}` : ''}:
|
||||
</Text>{' '}
|
||||
{line}
|
||||
{truncated && i === lines.length - 1 ? ' …' : ''}
|
||||
</Text>
|
||||
) : (
|
||||
<Text>
|
||||
{' '}
|
||||
{line}
|
||||
{truncated && i === lines.length - 1 ? ' …' : ''}
|
||||
</Text>
|
||||
)}
|
||||
</Box>
|
||||
))}
|
||||
</Box>
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user