mirror of
https://github.com/lobehub/lobehub
synced 2026-04-21 17:47:27 +00:00
* ♻️ refactor: unify tool content formatting with ComputerRuntime and shared UI components Introduce `@lobechat/tool-runtime` with `ComputerRuntime` abstract class to ensure consistent content formatting (via `formatCommandResult`, `formatFileContent`, etc.) across local-system, cloud-sandbox, and skills packages. Create `@lobechat/shared-tool-ui` to share Render and Inspector components, eliminating duplicated UI code across tool packages. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * 🐛 fix: address review issues — state mapping for renders and IPC param denormalization - Add legacy state field mappings in local-system executor (listResults, fileContent, searchResults) for backward compatibility with existing render components - Add denormalizeParams in LocalSystemExecutionRuntime to map ComputerRuntime params back to IPC-expected field names (file_path, items, shell_id, etc.) - Fix i18n type casting for dynamic translation keys in shared-tool-ui inspectors Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * ♻️ refactor: inject render capabilities via context, unify state shape for cross-package render reuse - Add ToolRenderContext with injectable capabilities (openFile, openFolder, isLoading, displayRelativePath) to shared-tool-ui - Update local-system render components (ReadLocalFile, ListFiles, SearchFiles, MoveLocalFiles, FileItem) to use context instead of direct Electron imports - Enrich ReadFileState with render-compatible fields (filename, fileType, charCount, loc, totalCharCount) - Cloud-sandbox now fully reuses local-system renders — renders degrade gracefully when capabilities are not provided (no open file buttons in sandbox) - Remove executor-level state mapping hacks Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * 🐛 fix: fix sandbox render bugs — SearchFiles, GrepContent, MoveFiles, GlobFiles - SearchFiles: ensure results is always an array (not object passthrough) - GrepContent: update formatGrepResults to support object matches `{path, content, lineNumber}` alongside string matches - MoveFiles: render now handles both IPC format (items/oldPath/newPath) and ComputerRuntime format (operations/source/destination) - GlobFiles: fallback totalCount to files.length when API returns 0 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * 🐛 fix: unify SearchLocalFiles inspector with shared factory SearchLocalFiles inspector now supports all keyword field variants (keyword, keywords, query) and reads from unified state (results/totalCount). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * 🐛 fix: handle missing path in grep matches to avoid undefined display Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * 🐛 fix: improve render field compatibility for sandbox - EditLocalFile render: support both file_path (IPC) and path (sandbox) args - SearchFiles render: support keyword/keywords/query arg variants - FileItem: derive name from path when not provided Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * 🐛 fix: add missing cloud-sandbox i18n key for noResults Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
88 lines
2.9 KiB
TypeScript
88 lines
2.9 KiB
TypeScript
'use client';
|
|
|
|
import type { RunCommandState } from '@lobechat/tool-runtime';
|
|
import type { BuiltinInspectorProps } from '@lobechat/types';
|
|
import { createStaticStyles, cssVar, cx } from 'antd-style';
|
|
import { Check, X } from 'lucide-react';
|
|
import { memo } from 'react';
|
|
import { useTranslation } from 'react-i18next';
|
|
|
|
import { highlightTextStyles, inspectorTextStyles, shinyTextStyles } from '../../styles';
|
|
|
|
const styles = createStaticStyles(({ css }) => ({
|
|
statusIcon: css`
|
|
margin-block-end: -2px;
|
|
margin-inline-start: 4px;
|
|
`,
|
|
}));
|
|
|
|
interface RunCommandArgs {
|
|
background?: boolean;
|
|
command: string;
|
|
description?: string;
|
|
timeout?: number;
|
|
}
|
|
|
|
export interface RunCommandInspectorProps extends BuiltinInspectorProps<
|
|
RunCommandArgs,
|
|
RunCommandState
|
|
> {
|
|
/** i18n key for the API name label, e.g. 'builtins.lobe-local-system.apiName.runCommand' */
|
|
translationKey: string;
|
|
}
|
|
|
|
export const RunCommandInspector = memo<RunCommandInspectorProps>(
|
|
({ args, partialArgs, isArgumentsStreaming, pluginState, isLoading, translationKey }) => {
|
|
const { t } = useTranslation('plugin');
|
|
|
|
const description = args?.description || partialArgs?.description || args?.command || '';
|
|
|
|
if (isArgumentsStreaming) {
|
|
if (!description)
|
|
return (
|
|
<div className={cx(inspectorTextStyles.root, shinyTextStyles.shinyText)}>
|
|
<span>{t(translationKey as any)}</span>
|
|
</div>
|
|
);
|
|
|
|
return (
|
|
<div className={cx(inspectorTextStyles.root, shinyTextStyles.shinyText)}>
|
|
<span>{t(translationKey as any)}: </span>
|
|
<span className={highlightTextStyles.primary}>{description}</span>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
const isSuccess = pluginState?.success || pluginState?.exitCode === 0;
|
|
|
|
return (
|
|
<div className={cx(inspectorTextStyles.root, isLoading && shinyTextStyles.shinyText)}>
|
|
<span style={{ marginInlineStart: 2 }}>
|
|
<span>{t(translationKey as any)}: </span>
|
|
{description && <span className={highlightTextStyles.primary}>{description}</span>}
|
|
{isLoading ? null : pluginState?.success !== undefined ? (
|
|
isSuccess ? (
|
|
<Check className={styles.statusIcon} color={cssVar.colorSuccess} size={14} />
|
|
) : (
|
|
<X className={styles.statusIcon} color={cssVar.colorError} size={14} />
|
|
)
|
|
) : null}
|
|
</span>
|
|
</div>
|
|
);
|
|
},
|
|
);
|
|
|
|
RunCommandInspector.displayName = 'RunCommandInspector';
|
|
|
|
/**
|
|
* Factory to create a RunCommandInspector with a bound translation key.
|
|
* Use this in each package's inspector registry to avoid wrapper components.
|
|
*/
|
|
export const createRunCommandInspector = (translationKey: string) => {
|
|
const Inspector = memo<BuiltinInspectorProps<RunCommandArgs, RunCommandState>>((props) => (
|
|
<RunCommandInspector {...props} translationKey={translationKey} />
|
|
));
|
|
Inspector.displayName = 'RunCommandInspector';
|
|
return Inspector;
|
|
};
|