放开部分文件读/写限制

This commit is contained in:
xintaofei
2026-03-19 21:33:07 +08:00
parent 0209de17eb
commit f6fd3da401
6 changed files with 55 additions and 71 deletions

View File

@@ -777,10 +777,9 @@ export function FileWorkspacePanel() {
const renderedContent = activeFileTab?.content ?? "" const renderedContent = activeFileTab?.content ?? ""
const isFileTab = activeFileTab?.kind === "file" const isFileTab = activeFileTab?.kind === "file"
const fileReadonly = isFileTab ? Boolean(activeFileTab.readonly) : true const fileReadonly = isFileTab ? Boolean(activeFileTab.readonly) : true
const fileTruncated = isFileTab ? Boolean(activeFileTab.truncated) : false
const fileSaveState = isFileTab ? (activeFileTab.saveState ?? "idle") : "idle" const fileSaveState = isFileTab ? (activeFileTab.saveState ?? "idle") : "idle"
const fileIsDirty = isFileTab ? Boolean(activeFileTab.isDirty) : false const fileIsDirty = isFileTab ? Boolean(activeFileTab.isDirty) : false
const canEdit = isFileTab && !fileReadonly && !fileTruncated const canEdit = isFileTab && !fileReadonly
const autoSaveTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null) const autoSaveTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null)
const autoSaveGuardRef = useRef({ const autoSaveGuardRef = useRef({
canEdit: false, canEdit: false,

View File

@@ -2302,7 +2302,9 @@ export function FileTreeTab() {
<DialogContent <DialogContent
onOpenAutoFocus={(e) => { onOpenAutoFocus={(e) => {
e.preventDefault() e.preventDefault()
const input = (e.currentTarget as HTMLElement | null)?.querySelector("input") const input = (
e.currentTarget as HTMLElement | null
)?.querySelector("input")
if (input) requestAnimationFrame(() => input.focus()) if (input) requestAnimationFrame(() => input.focus())
}} }}
> >
@@ -2369,7 +2371,9 @@ export function FileTreeTab() {
<DialogContent <DialogContent
onOpenAutoFocus={(e) => { onOpenAutoFocus={(e) => {
e.preventDefault() e.preventDefault()
const input = (e.currentTarget as HTMLElement | null)?.querySelector("input") const input = (
e.currentTarget as HTMLElement | null
)?.querySelector("input")
if (input) requestAnimationFrame(() => input.focus()) if (input) requestAnimationFrame(() => input.focus())
}} }}
> >

View File

@@ -2040,10 +2040,7 @@ function hasComparableVersion(
} }
function buildVersionCheck(agent: AcpAgentInfo): UiCheckItem | null { function buildVersionCheck(agent: AcpAgentInfo): UiCheckItem | null {
if ( if (agent.distribution_type !== "binary" && agent.distribution_type !== "npx")
agent.distribution_type !== "binary" &&
agent.distribution_type !== "npx"
)
return null return null
const remoteVersion = agent.registry_version ?? "unknown" const remoteVersion = agent.registry_version ?? "unknown"
@@ -2390,46 +2387,51 @@ export function AcpAgentSettings() {
const runPreflight = useCallback( const runPreflight = useCallback(
async (agentType: AgentType, forceRefresh?: boolean) => { async (agentType: AgentType, forceRefresh?: boolean) => {
setChecking((prev) => ({ ...prev, [agentType]: true })) setChecking((prev) => ({ ...prev, [agentType]: true }))
try { try {
const [resultState, versionState] = await Promise.allSettled([ const [resultState, versionState] = await Promise.allSettled([
acpPreflight(agentType, forceRefresh), acpPreflight(agentType, forceRefresh),
acpDetectAgentLocalVersion(agentType), acpDetectAgentLocalVersion(agentType),
]) ])
if (versionState.status === "fulfilled") { if (versionState.status === "fulfilled") {
setAgents((prev) => { setAgents((prev) => {
if (versionState.value === null) return prev if (versionState.value === null) return prev
let changed = false let changed = false
const next = prev.map((agent) => { const next = prev.map((agent) => {
if (agent.agent_type !== agentType) return agent if (agent.agent_type !== agentType) return agent
if (agent.installed_version === versionState.value) return agent if (agent.installed_version === versionState.value) return agent
changed = true changed = true
return { ...agent, installed_version: versionState.value } return { ...agent, installed_version: versionState.value }
})
return changed ? next : prev
}) })
return changed ? next : prev }
})
}
if (resultState.status === "fulfilled") { if (resultState.status === "fulfilled") {
setCheckState((prev) => ({ setCheckState((prev) => ({
...prev, ...prev,
[agentType]: { result: resultState.value }, [agentType]: { result: resultState.value },
})) }))
} else { } else {
const message = const message =
resultState.reason instanceof Error resultState.reason instanceof Error
? resultState.reason.message ? resultState.reason.message
: String(resultState.reason) : String(resultState.reason)
setCheckState((prev) => ({
...prev,
[agentType]: { error: message },
}))
}
} catch (err) {
const message = err instanceof Error ? err.message : String(err)
setCheckState((prev) => ({ ...prev, [agentType]: { error: message } })) setCheckState((prev) => ({ ...prev, [agentType]: { error: message } }))
} finally {
setChecking((prev) => ({ ...prev, [agentType]: false }))
} }
} catch (err) { },
const message = err instanceof Error ? err.message : String(err) []
setCheckState((prev) => ({ ...prev, [agentType]: { error: message } })) )
} finally {
setChecking((prev) => ({ ...prev, [agentType]: false }))
}
}, [])
const runAllPreflight = useCallback( const runAllPreflight = useCallback(
async (agentTypes: AgentType[]) => { async (agentTypes: AgentType[]) => {
@@ -2790,10 +2792,7 @@ export function AcpAgentSettings() {
await runNpxAction(agent, "upgrade") await runNpxAction(agent, "upgrade")
return return
} }
if ( if (action.kind === "uninstall_binary" || action.kind === "uninstall_npx") {
action.kind === "uninstall_binary" ||
action.kind === "uninstall_npx"
) {
setUninstallConfirmAgent(agent) setUninstallConfirmAgent(agent)
return return
} }

View File

@@ -54,7 +54,6 @@ export interface FileWorkspaceTab {
etag?: string | null etag?: string | null
mtimeMs?: number | null mtimeMs?: number | null
readonly?: boolean readonly?: boolean
truncated?: boolean
lineEnding?: LineEnding lineEnding?: LineEnding
saveState?: FileSaveState saveState?: FileSaveState
saveError?: string | null saveError?: string | null
@@ -150,7 +149,6 @@ function loadingTab(
etag: null, etag: null,
mtimeMs: null, mtimeMs: null,
readonly: kind !== "file", readonly: kind !== "file",
truncated: false,
lineEnding: "none", lineEnding: "none",
saveState: "idle", saveState: "idle",
saveError: null, saveError: null,
@@ -390,7 +388,6 @@ export function WorkspaceProvider({ children }: WorkspaceProviderProps) {
etag: result.etag, etag: result.etag,
mtimeMs: result.mtime_ms, mtimeMs: result.mtime_ms,
readonly: result.readonly, readonly: result.readonly,
truncated: result.truncated,
lineEnding: result.line_ending, lineEnding: result.line_ending,
saveState: "idle", saveState: "idle",
saveError: null, saveError: null,
@@ -512,7 +509,6 @@ export function WorkspaceProvider({ children }: WorkspaceProviderProps) {
gitShowFile(folderPath, path).catch(() => ""), gitShowFile(folderPath, path).catch(() => ""),
readFilePreview(folderPath, path).catch(() => ({ readFilePreview(folderPath, path).catch(() => ({
content: "", content: "",
truncated: false,
path: "", path: "",
})), })),
]), ]),
@@ -564,7 +560,6 @@ export function WorkspaceProvider({ children }: WorkspaceProviderProps) {
gitShowFile(folderPath, path, targetBranch).catch(() => ""), gitShowFile(folderPath, path, targetBranch).catch(() => ""),
readFilePreview(folderPath, path).catch(() => ({ readFilePreview(folderPath, path).catch(() => ({
content: "", content: "",
truncated: false,
path: "", path: "",
})), })),
]), ]),
@@ -715,7 +710,7 @@ export function WorkspaceProvider({ children }: WorkspaceProviderProps) {
setFileTabs((prev) => setFileTabs((prev) =>
prev.map((tab) => { prev.map((tab) => {
if (tab.id !== activeFileTabId || tab.kind !== "file") return tab if (tab.id !== activeFileTabId || tab.kind !== "file") return tab
if (tab.loading || tab.readonly || tab.truncated) return tab if (tab.loading || tab.readonly) return tab
if (tab.content === content) return tab if (tab.content === content) return tab
const savedContent = tab.savedContent ?? "" const savedContent = tab.savedContent ?? ""
@@ -739,7 +734,7 @@ export function WorkspaceProvider({ children }: WorkspaceProviderProps) {
(candidate) => candidate.id === tabId (candidate) => candidate.id === tabId
) )
if (!tab || tab.kind !== "file") return false if (!tab || tab.kind !== "file") return false
if (tab.loading || tab.readonly || tab.truncated) return false if (tab.loading || tab.readonly) return false
if (!tab.path) return false if (!tab.path) return false
if (!tab.isDirty) return true if (!tab.isDirty) return true
@@ -868,7 +863,6 @@ export function WorkspaceProvider({ children }: WorkspaceProviderProps) {
etag: result.etag, etag: result.etag,
mtimeMs: result.mtime_ms, mtimeMs: result.mtime_ms,
readonly: result.readonly, readonly: result.readonly,
truncated: result.truncated,
lineEnding: result.line_ending, lineEnding: result.line_ending,
saveState: "idle", saveState: "idle",
saveError: null, saveError: null,

View File

@@ -900,26 +900,16 @@ export async function readFileBase64(
export async function readFilePreview( export async function readFilePreview(
rootPath: string, rootPath: string,
path: string, path: string
maxBytes?: number
): Promise<FilePreviewContent> { ): Promise<FilePreviewContent> {
return invoke("read_file_preview", { return invoke("read_file_preview", { rootPath, path })
rootPath,
path,
maxBytes: maxBytes ?? null,
})
} }
export async function readFileForEdit( export async function readFileForEdit(
rootPath: string, rootPath: string,
path: string, path: string
maxBytes?: number
): Promise<FileEditContent> { ): Promise<FileEditContent> {
return invoke("read_file_for_edit", { return invoke("read_file_for_edit", { rootPath, path })
rootPath,
path,
maxBytes: maxBytes ?? null,
})
} }
export async function saveFileContent( export async function saveFileContent(

View File

@@ -677,7 +677,6 @@ export type FileTreeNode =
export interface FilePreviewContent { export interface FilePreviewContent {
path: string path: string
content: string content: string
truncated: boolean
} }
export interface FileEditContent { export interface FileEditContent {
@@ -686,7 +685,6 @@ export interface FileEditContent {
etag: string etag: string
mtime_ms: number | null mtime_ms: number | null
readonly: boolean readonly: boolean
truncated: boolean
line_ending: "lf" | "crlf" | "mixed" | "none" line_ending: "lf" | "crlf" | "mixed" | "none"
} }