mirror of
https://github.com/paperclipai/paperclip.git
synced 2026-10-19 10:36:26 +02:00
Serialize native workspace finalization, validate streamed archives within bounded limits, and quietly recover unsafe exports from saved results. Preserve exact allocations for exhausted transient failures and provide export-only retry without rerunning the provider. Consolidates #14314, #14315, #14329, and #14334 while preserving the already-merged finalization label changes. Co-Authored-By: Paperclip <noreply@paperclip.ing>
27 lines
1.3 KiB
TypeScript
27 lines
1.3 KiB
TypeScript
/** Closed, path-free classifications persisted by adapter settlement. */
|
|
export const WORKSPACE_RESTORE_FAILURE_CODES = [
|
|
"restore_permission_denied",
|
|
"restore_lock_timeout",
|
|
"restore_unsafe_archive",
|
|
"restore_failed",
|
|
] as const;
|
|
|
|
/** These failures preserve an accepted native result for board-owned export repair. */
|
|
export function isNativeWorkspaceExportRepairCause(value: unknown): boolean {
|
|
return value === "native_workspace_sync_out_retry_exhausted";
|
|
}
|
|
|
|
export function hasWorkspaceRestoreFailure(result: Record<string, unknown> | null | undefined): boolean {
|
|
return WORKSPACE_RESTORE_FAILURE_CODES.some((code) => result?.workspaceRestoreFailure === code);
|
|
}
|
|
|
|
/** Display only ordinary repository paths, never targets, host paths or temp IDs. */
|
|
export function safeWorkspaceRestorePath(value: unknown): string | null {
|
|
if (typeof value !== "string" || value.length > 180) return null;
|
|
const relative = value.replace(/^\.\//, "");
|
|
if (!relative || !/^[a-zA-Z0-9_.\/-]+$/.test(relative) || relative.startsWith("/")) return null;
|
|
if (relative.split("/").some((part) => !part || part === "." || part === "..")) return null;
|
|
if (/(?:[a-f0-9]{8}-[a-f0-9-]{27,}|[a-zA-Z0-9_-]{32,}|(?:^|\/)(?:tmp|temp|paperclip-clone)[^/]*)(?:\/|$)/i.test(relative)) return null;
|
|
return relative;
|
|
}
|