| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105 |
- import { logger } from 'ee-core/log';
- import {
- listAllArtifacts,
- listArtifacts,
- openArtifact,
- openArtifactRoot,
- readArtifactBase64,
- readArtifactText,
- revealArtifact,
- saveArtifactAs,
- } from '../service/codex/codexArtifactService';
- import { asMessage, fail, ok, type Rpc } from '../service/codex/types';
- /**
- * 产物(会话工作目录里的文件)读写控制器。
- *
- * 与 codexCtl 同为 ee-core 自动注册的 controller,通道前缀是 controller/codexArtifactCtl/。
- * 这里只做参数校验与异常包装,安全边界(root 白名单 + 路径穿越校验)在 service 里。
- */
- async function guard<T>(label: string, run: () => Promise<T>): Promise<Rpc<T>> {
- try {
- return ok(await run());
- } catch (error) {
- const message = asMessage(error);
- logger.error(`[codexArtifactCtl] ${label} failed:`, message);
- return fail(message);
- }
- }
- function requireString(value: unknown, label: string): string {
- if (typeof value !== 'string' || !value.trim()) throw new Error(`${label} 不能为空`);
- return value.trim();
- }
- function optionalNumber(value: unknown): number | undefined {
- return typeof value === 'number' && Number.isFinite(value) ? value : undefined;
- }
- class CodexArtifactCtl {
- async list(params?: { root?: string; dir?: string }): Promise<Rpc<unknown>> {
- return guard('list', async () =>
- listArtifacts(requireString(params?.root, 'root'), typeof params?.dir === 'string' ? params.dir : ''),
- );
- }
- /** 递归列出工作空间全部文件(「本会话产物」视图用) */
- async listAll(params?: { root?: string }): Promise<Rpc<unknown>> {
- return guard('listAll', async () => listAllArtifacts(requireString(params?.root, 'root')));
- }
- async readText(params?: { root?: string; path?: string; maxBytes?: number }): Promise<Rpc<unknown>> {
- return guard('readText', async () =>
- readArtifactText(
- requireString(params?.root, 'root'),
- requireString(params?.path, 'path'),
- optionalNumber(params?.maxBytes),
- ),
- );
- }
- async readBinary(params?: { root?: string; path?: string; maxBytes?: number }): Promise<Rpc<unknown>> {
- return guard('readBinary', async () =>
- readArtifactBase64(
- requireString(params?.root, 'root'),
- requireString(params?.path, 'path'),
- optionalNumber(params?.maxBytes),
- ),
- );
- }
- async saveAs(params?: { root?: string; path?: string; name?: string }): Promise<Rpc<unknown>> {
- return guard('saveAs', async () =>
- saveArtifactAs(
- requireString(params?.root, 'root'),
- requireString(params?.path, 'path'),
- typeof params?.name === 'string' ? params.name : undefined,
- ),
- );
- }
- async reveal(params?: { root?: string; path?: string }): Promise<Rpc<Record<string, never>>> {
- return guard('reveal', async () => {
- await revealArtifact(requireString(params?.root, 'root'), requireString(params?.path, 'path'));
- return {};
- });
- }
- async open(params?: { root?: string; path?: string }): Promise<Rpc<Record<string, never>>> {
- return guard('open', async () => {
- await openArtifact(requireString(params?.root, 'root'), requireString(params?.path, 'path'));
- return {};
- });
- }
- async openRoot(params?: { root?: string }): Promise<Rpc<Record<string, never>>> {
- return guard('openRoot', async () => {
- await openArtifactRoot(requireString(params?.root, 'root'));
- return {};
- });
- }
- }
- CodexArtifactCtl.toString = () => 'CodexArtifactCtl';
- export default CodexArtifactCtl;
|