fix: preserve inherited workspace delete copy (#3864)
This commit is contained in:
@@ -9,12 +9,14 @@ import { Button } from "@kandev/ui/button";
|
||||
import { Badge } from "@kandev/ui/badge";
|
||||
import { Tooltip, TooltipContent, TooltipTrigger } from "@kandev/ui/tooltip";
|
||||
import { formatTimeDistance, useDateLocale } from "@/lib/i18n/date-locale";
|
||||
import { cleanupSharesParentWorkspace } from "@/components/task/task-cleanup-summary";
|
||||
import { TaskDeleteConfirmDialog } from "@/components/task/task-delete-confirm-dialog";
|
||||
import { TaskArchiveConfirmation } from "@/components/task/task-archive-confirmation";
|
||||
import { linkToTask } from "@/lib/links";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { t } from "@/lib/i18n";
|
||||
import { useResponsiveBreakpoint } from "@/hooks/use-responsive-breakpoint";
|
||||
import { workspaceModeFromMetadata } from "@/lib/kanban/map-task";
|
||||
|
||||
type TaskWithResolution = Task & {
|
||||
workflowName?: string;
|
||||
@@ -132,6 +134,9 @@ function ActionsCell({ row, ctx }: { row: Row<TaskWithResolution>; ctx: ActionsC
|
||||
taskTitle={task.title}
|
||||
taskId={task.id}
|
||||
executorType={task.primary_executor_type}
|
||||
sharesParentWorkspace={cleanupSharesParentWorkspace(
|
||||
workspaceModeFromMetadata(task.metadata),
|
||||
)}
|
||||
isDeleting={isDeleting}
|
||||
onConfirm={({ cascade, discardWorktreeChanges }) =>
|
||||
ctx.onDelete(task.id, { cascade, discardWorktreeChanges })
|
||||
|
||||
@@ -6,6 +6,7 @@ import { Button } from "@kandev/ui/button";
|
||||
import { Tooltip, TooltipContent, TooltipTrigger } from "@kandev/ui/tooltip";
|
||||
import { IconArchive, IconArchiveOff, IconLoader, IconTrash } from "@tabler/icons-react";
|
||||
import { TaskArchiveConfirmation } from "@/components/task/task-archive-confirmation";
|
||||
import { cleanupSharesParentWorkspace } from "@/components/task/task-cleanup-summary";
|
||||
import { TaskDeleteConfirmDialog } from "@/components/task/task-delete-confirm-dialog";
|
||||
import { primaryTaskRepository, type Repository, type Task, type Workflow } from "@/lib/types/http";
|
||||
import { formatTaskStateLabel } from "@/lib/ui/state-labels";
|
||||
@@ -20,6 +21,7 @@ import { useTranslation } from "react-i18next";
|
||||
import { t } from "@/lib/i18n";
|
||||
import { useResponsiveBreakpoint } from "@/hooks/use-responsive-breakpoint";
|
||||
import type { TaskListFacetValue } from "@/lib/plugins/types";
|
||||
import { workspaceModeFromMetadata } from "@/lib/kanban/map-task";
|
||||
|
||||
export type TasksListViewProps = {
|
||||
total: number;
|
||||
@@ -548,6 +550,7 @@ function TaskRowActions({
|
||||
) => Promise<void>;
|
||||
}) {
|
||||
const { t } = useTranslation();
|
||||
const workspaceMode = workspaceModeFromMetadata(task.metadata);
|
||||
const archiveAnchorRef = useRef<HTMLButtonElement>(null);
|
||||
const { isFinePointer } = useResponsiveBreakpoint();
|
||||
return (
|
||||
@@ -601,6 +604,7 @@ function TaskRowActions({
|
||||
taskId={task.id}
|
||||
isInFlight={isTaskInFlight(task.foreground_activity)}
|
||||
executorType={task.primary_executor_type}
|
||||
sharesParentWorkspace={cleanupSharesParentWorkspace(workspaceMode)}
|
||||
isDeleting={isDeleting}
|
||||
onConfirm={({ cascade, discardWorktreeChanges }) =>
|
||||
onDelete(task.id, { cascade, discardWorktreeChanges })
|
||||
|
||||
@@ -6,6 +6,7 @@ import {
|
||||
useKanbanCardMoveTargets,
|
||||
} from "@/components/kanban-card-menu-items";
|
||||
import { useTaskPluginLinkActions } from "@/components/task/task-session-sidebar-link-actions";
|
||||
import { cleanupSharesParentWorkspace } from "@/components/task/task-cleanup-summary";
|
||||
import { TaskDeleteConfirmDialog } from "@/components/task/task-delete-confirm-dialog";
|
||||
import {
|
||||
TaskExternalLinkDialog,
|
||||
@@ -269,6 +270,7 @@ export function KanbanCardDialogs({
|
||||
taskTitle={task.title}
|
||||
taskId={task.id}
|
||||
executorType={task.primaryExecutorType}
|
||||
sharesParentWorkspace={cleanupSharesParentWorkspace(task.workspaceMode)}
|
||||
isDeleting={isDeleting}
|
||||
onConfirm={(opts) => onDelete?.(task, opts)}
|
||||
/>
|
||||
|
||||
@@ -4,6 +4,7 @@ import { useRef, type RefObject } from "react";
|
||||
import { useActiveWorkspaceRepositories } from "@/components/kanban-card-repositories";
|
||||
import { TaskArchiveConfirmation } from "@/components/task/task-archive-confirmation";
|
||||
import { TaskCreateDialog } from "@/components/task-create-dialog";
|
||||
import { cleanupSharesParentWorkspace } from "@/components/task/task-cleanup-summary";
|
||||
import { TaskDeleteConfirmDialog } from "@/components/task/task-delete-confirm-dialog";
|
||||
import { TaskDetachConfirmationSurface } from "@/components/task/task-detach-confirm-dialog";
|
||||
import { TaskExternalLinkDialog } from "@/components/task/task-external-link-dialog";
|
||||
@@ -122,6 +123,20 @@ function useLastResolvedBoardRow(
|
||||
return ref.current.boardRow;
|
||||
}
|
||||
|
||||
function buildConfirmationTarget(
|
||||
taskId: string,
|
||||
taskTitle: string,
|
||||
triggerRef: RefObject<HTMLElement | null>,
|
||||
) {
|
||||
return {
|
||||
taskId,
|
||||
taskTitle,
|
||||
anchorRef: triggerRef,
|
||||
focusReturnRef: triggerRef,
|
||||
restoreFocusOnConfirm: true,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Mounts every dialog a task actions menu entry can open. Hosted per surface
|
||||
* so a dialog outlives the menu that opened it.
|
||||
@@ -140,13 +155,7 @@ export function TaskActionsMenuDialogs({
|
||||
const editBoardRow = useLastResolvedBoardRow(taskId, boardRow);
|
||||
if (!taskId) return null;
|
||||
const linkDialogTask = buildLinkDialogTask(taskId, taskTitle, boardRow);
|
||||
const confirmationTarget = {
|
||||
taskId,
|
||||
taskTitle,
|
||||
anchorRef: menu.triggerRef,
|
||||
focusReturnRef: menu.triggerRef,
|
||||
restoreFocusOnConfirm: true,
|
||||
};
|
||||
const confirmationTarget = buildConfirmationTarget(taskId, taskTitle, menu.triggerRef);
|
||||
|
||||
return (
|
||||
<>
|
||||
@@ -175,6 +184,7 @@ export function TaskActionsMenuDialogs({
|
||||
taskTitle={taskTitle}
|
||||
taskId={taskId}
|
||||
executorType={boardRow?.primaryExecutorType ?? subjectExecutorType}
|
||||
sharesParentWorkspace={cleanupSharesParentWorkspace(boardRow?.workspaceMode)}
|
||||
isDeleting={isDeleting}
|
||||
onConfirm={(opts) => menu.onConfirmDelete(opts)}
|
||||
focusReturnRef={menu.triggerRef}
|
||||
|
||||
@@ -25,6 +25,15 @@ describe("getCleanupSummary (single task)", () => {
|
||||
expect(notes.join(" ")).toMatch(/not affected/i);
|
||||
});
|
||||
|
||||
it("preserves the parent workspace for inherited-parent tasks", () => {
|
||||
expect(getCleanupSummary("worktree", { sharesParentWorkspace: true })).toEqual({
|
||||
effects: [AGENT_STOP_EFFECT],
|
||||
notes: [
|
||||
"This task shares its parent's workspace. The parent task's worktree, branch, and files are not touched.",
|
||||
],
|
||||
});
|
||||
});
|
||||
|
||||
it("describes local_docker container removal", () => {
|
||||
const { effects, notes } = getCleanupSummary("local_docker");
|
||||
expect(effects[0]).toMatch(/Docker container/i);
|
||||
|
||||
@@ -1,11 +1,22 @@
|
||||
// Executor types match models.ExecutorType in apps/backend/internal/task/models/models.go.
|
||||
import { t } from "@/lib/i18n";
|
||||
import type { WorkspaceMode } from "@/lib/kanban/map-task";
|
||||
|
||||
export type CleanupSummary = {
|
||||
effects: string[];
|
||||
notes: string[];
|
||||
};
|
||||
|
||||
export type CleanupSummaryOptions = {
|
||||
sharesParentWorkspace?: boolean;
|
||||
};
|
||||
|
||||
export function cleanupSharesParentWorkspace(
|
||||
workspaceMode: WorkspaceMode | null | undefined,
|
||||
): boolean | undefined {
|
||||
return workspaceMode == null ? undefined : workspaceMode === "inherit_parent";
|
||||
}
|
||||
|
||||
// mock_remote is test-only and intentionally falls through to the generic effect.
|
||||
type KnownExecutor =
|
||||
| "local"
|
||||
@@ -45,6 +56,7 @@ const SINGLE_COPIES: Record<KnownExecutor, CleanupCopy> = {
|
||||
};
|
||||
|
||||
const GENERIC_EFFECT_KEY = "task:cleanupAgentSessionsStopped";
|
||||
const INHERITED_PARENT_WORKSPACE_NOTE_KEY = "task:cleanupInheritedParentWorkspaceNote";
|
||||
|
||||
function normalize(executorType: string | null | undefined): KnownExecutor | null {
|
||||
if (!executorType) return null;
|
||||
@@ -65,7 +77,16 @@ function resolveCopy(copy: CleanupCopy, options?: { count: number }): CleanupSum
|
||||
}
|
||||
|
||||
/** Single-task variant. */
|
||||
export function getCleanupSummary(executorType: string | null | undefined): CleanupSummary {
|
||||
export function getCleanupSummary(
|
||||
executorType: string | null | undefined,
|
||||
options?: CleanupSummaryOptions,
|
||||
): CleanupSummary {
|
||||
if (options?.sharesParentWorkspace) {
|
||||
return {
|
||||
effects: [t(GENERIC_EFFECT_KEY)],
|
||||
notes: [t(INHERITED_PARENT_WORKSPACE_NOTE_KEY)],
|
||||
};
|
||||
}
|
||||
const known = normalize(executorType);
|
||||
return known
|
||||
? resolveCopy(SINGLE_COPIES[known])
|
||||
|
||||
@@ -14,7 +14,11 @@ vi.mock("@/lib/api", () => ({
|
||||
import { TaskDeleteConfirmDialog } from "./task-delete-confirm-dialog";
|
||||
import { expectCompactWarning } from "./task-confirm-dialog.test-helpers";
|
||||
|
||||
type SeedTask = { id: string; foregroundActivity?: "generating" | "background" | null };
|
||||
type SeedTask = {
|
||||
id: string;
|
||||
foregroundActivity?: "generating" | "background" | null;
|
||||
workspaceMode?: "inherit_parent" | "new_workspace" | "shared_group";
|
||||
};
|
||||
|
||||
// The dialog reads live foreground_activity from the store via useTaskInFlight,
|
||||
// so every render needs a StateProvider. `tasks` seeds the active kanban tasks
|
||||
@@ -33,6 +37,7 @@ function renderDialog(ui: ReactNode, tasks: SeedTask[] = []) {
|
||||
title: t.id,
|
||||
position: 0,
|
||||
foregroundActivity: t.foregroundActivity ?? undefined,
|
||||
workspaceMode: t.workspaceMode,
|
||||
})),
|
||||
},
|
||||
}}
|
||||
@@ -444,6 +449,72 @@ describe("TaskDeleteConfirmDialog executor cleanup copy", () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe("TaskDeleteConfirmDialog inherited-parent workspace copy", () => {
|
||||
it("describes inherited-parent workspace preservation from explicit context", () => {
|
||||
mockGetSubtaskCount.mockResolvedValue({ count: 0 });
|
||||
renderDialog(
|
||||
<TaskDeleteConfirmDialog
|
||||
open
|
||||
onOpenChange={() => {}}
|
||||
taskTitle="Child task"
|
||||
taskId={TASK_ID}
|
||||
executorType="worktree"
|
||||
sharesParentWorkspace
|
||||
onConfirm={() => {}}
|
||||
/>,
|
||||
);
|
||||
|
||||
expect(screen.getByTestId("task-cleanup-effects").querySelectorAll("li")).toHaveLength(1);
|
||||
expect(
|
||||
screen.getByText(
|
||||
/This task shares its parent's workspace\. The parent task's worktree, branch, and files are not touched\./i,
|
||||
),
|
||||
).toBeTruthy();
|
||||
expect(screen.queryByText(/worktree and its branch will be deleted/i)).toBeNull();
|
||||
});
|
||||
|
||||
it("resolves inherited-parent workspace preservation from the task store", () => {
|
||||
mockGetSubtaskCount.mockResolvedValue({ count: 0 });
|
||||
renderDialog(
|
||||
<TaskDeleteConfirmDialog
|
||||
open
|
||||
onOpenChange={() => {}}
|
||||
taskTitle="Child task"
|
||||
taskId={TASK_ID}
|
||||
executorType="worktree"
|
||||
onConfirm={() => {}}
|
||||
/>,
|
||||
[{ id: TASK_ID, workspaceMode: "inherit_parent" }],
|
||||
);
|
||||
|
||||
expect(
|
||||
screen.getByText(
|
||||
/This task shares its parent's workspace\. The parent task's worktree, branch, and files are not touched\./i,
|
||||
),
|
||||
).toBeTruthy();
|
||||
expect(screen.queryByText(/worktree and its branch will be deleted/i)).toBeNull();
|
||||
});
|
||||
|
||||
it("prefers the live task-store mode over stale caller context", () => {
|
||||
mockGetSubtaskCount.mockResolvedValue({ count: 0 });
|
||||
renderDialog(
|
||||
<TaskDeleteConfirmDialog
|
||||
open
|
||||
onOpenChange={() => {}}
|
||||
taskTitle="Child task"
|
||||
taskId={TASK_ID}
|
||||
executorType="worktree"
|
||||
sharesParentWorkspace
|
||||
onConfirm={() => {}}
|
||||
/>,
|
||||
[{ id: TASK_ID, workspaceMode: "new_workspace" }],
|
||||
);
|
||||
|
||||
expect(screen.getByText(/worktree and its branch will be deleted/i)).toBeTruthy();
|
||||
expect(screen.queryByText(/shares its parent's workspace/i)).toBeNull();
|
||||
});
|
||||
});
|
||||
|
||||
describe("TaskDeleteConfirmDialog still-working guard", () => {
|
||||
it("keeps the shared in-flight warning visually subordinate", () => {
|
||||
mockGetSubtaskCount.mockResolvedValue({ count: 0 });
|
||||
|
||||
@@ -23,6 +23,8 @@ import { useTaskInFlight } from "@/hooks/use-task-in-flight";
|
||||
import { getCleanupSummary, getBulkCleanupSummary } from "./task-cleanup-summary";
|
||||
import { TaskCleanupConsequences } from "./task-cleanup-consequences";
|
||||
import { StillWorkingWarning } from "./task-still-working-warning";
|
||||
import { useAppStore } from "@/components/state-provider";
|
||||
import { findTaskInSnapshots } from "@/lib/kanban/find-task";
|
||||
import {
|
||||
TASK_CONFIRM_ACTION_CLASS,
|
||||
TASK_CONFIRM_BODY_CLASS,
|
||||
@@ -34,6 +36,14 @@ import {
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { createFocusReturnHandler } from "@/lib/dialog-focus-return";
|
||||
|
||||
function useStoreSharesParentWorkspace(taskId: string | undefined, isBulkOperation?: boolean) {
|
||||
return useAppStore((state) => {
|
||||
if (isBulkOperation || !taskId) return undefined;
|
||||
const task = findTaskInSnapshots(taskId, state.kanbanMulti.snapshots, state.kanban.tasks);
|
||||
return task ? task.workspaceMode === "inherit_parent" : undefined;
|
||||
});
|
||||
}
|
||||
|
||||
type TaskDeleteConfirmDialogProps = {
|
||||
open: boolean;
|
||||
onOpenChange: (open: boolean) => void;
|
||||
@@ -48,6 +58,8 @@ type TaskDeleteConfirmDialogProps = {
|
||||
executorType?: string | null;
|
||||
/** Executor types of the tasks being deleted (bulk). */
|
||||
executorTypes?: Array<string | null | undefined>;
|
||||
/** Whether the single task borrows its workspace from its parent. */
|
||||
sharesParentWorkspace?: boolean;
|
||||
onConfirm: (opts: { cascade: boolean; discardWorktreeChanges: boolean }) => void;
|
||||
confirmTestId?: string;
|
||||
/** Overrides default focus restoration when the original trigger may disappear. */
|
||||
@@ -284,6 +296,7 @@ export function TaskDeleteConfirmDialog({
|
||||
isInFlight,
|
||||
executorType,
|
||||
executorTypes,
|
||||
sharesParentWorkspace,
|
||||
onConfirm,
|
||||
confirmTestId,
|
||||
onCloseAutoFocus,
|
||||
@@ -297,9 +310,12 @@ export function TaskDeleteConfirmDialog({
|
||||
const description = isBulkOperation
|
||||
? t("task:deleteTasksConfirm", { count: safeCount })
|
||||
: t("task:deleteTaskConfirm", { taskTitle });
|
||||
const storeSharesParentWorkspace = useStoreSharesParentWorkspace(taskId, isBulkOperation);
|
||||
const cleanup = isBulkOperation
|
||||
? getBulkCleanupSummary(executorTypes ?? [])
|
||||
: getCleanupSummary(executorType);
|
||||
: getCleanupSummary(executorType, {
|
||||
sharesParentWorkspace: storeSharesParentWorkspace ?? sharesParentWorkspace,
|
||||
});
|
||||
|
||||
const {
|
||||
cascade,
|
||||
|
||||
@@ -19,6 +19,7 @@ import type { TaskPriority } from "@/lib/types/http";
|
||||
import { TaskManagementMenu, type TaskManagementMenuProps } from "./task-management-menu";
|
||||
import { TaskManagementDrawer, TaskManagementSheet } from "./task-management-drawer";
|
||||
import { TaskArchiveConfirmation } from "./task-archive-confirmation";
|
||||
import { cleanupSharesParentWorkspace } from "./task-cleanup-summary";
|
||||
import { TaskDeleteConfirmDialog } from "./task-delete-confirm-dialog";
|
||||
import { useSidebarLinkActions } from "./task-session-sidebar-link-actions";
|
||||
import { useSidebarTaskLinking } from "./task-session-sidebar-task-linking";
|
||||
@@ -215,6 +216,7 @@ function ManagementConfirmations({
|
||||
taskId={task.id}
|
||||
taskTitle={task.title}
|
||||
executorType={task.remoteExecutorType}
|
||||
sharesParentWorkspace={cleanupSharesParentWorkspace(task.workspaceMode)}
|
||||
isDeleting={mutations.disabled}
|
||||
onCloseAutoFocus={onCloseAutoFocus}
|
||||
confirmTestId="thread-delete-confirm"
|
||||
|
||||
@@ -3,7 +3,10 @@ import { createAppStore } from "@/lib/state/store";
|
||||
import { resolveTaskMenuTarget } from "./task-menu-target";
|
||||
|
||||
const identity = { taskId: "A", workspaceId: "workspace" };
|
||||
function fixture(loss?: string) {
|
||||
function fixture(
|
||||
loss?: string,
|
||||
workspaceMode?: "inherit_parent" | "new_workspace" | "shared_group",
|
||||
) {
|
||||
const store = createAppStore();
|
||||
store.setState((state) => ({
|
||||
workspaces: { ...state.workspaces, activeId: loss === "workspace" ? "elsewhere" : "workspace" },
|
||||
@@ -32,6 +35,7 @@ function fixture(loss?: string) {
|
||||
priority: "high",
|
||||
isArchived: loss === "archived",
|
||||
primaryExecutorType: "worktree",
|
||||
workspaceMode,
|
||||
},
|
||||
],
|
||||
},
|
||||
@@ -61,4 +65,9 @@ describe("task menu eligibility", () => {
|
||||
expect(resolveTaskMenuTarget(state, identity)).toBeNull();
|
||||
},
|
||||
);
|
||||
|
||||
it("carries the task workspace mode into the management target", () => {
|
||||
const state = fixture(undefined, "inherit_parent").getState();
|
||||
expect(resolveTaskMenuTarget(state, identity)?.workspaceMode).toBe("inherit_parent");
|
||||
});
|
||||
});
|
||||
|
||||
@@ -32,5 +32,6 @@ export function resolveTaskMenuTarget(
|
||||
remoteExecutorType: task.primaryExecutorType ?? undefined,
|
||||
primarySessionId: task.primarySessionId,
|
||||
parentTaskId: task.parentTaskId ?? undefined,
|
||||
workspaceMode: task.workspaceMode,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -2237,6 +2237,7 @@
|
||||
"cleanupSingleSprites": "The Sprites cloud sandbox for this task will be destroyed. Any uncommitted work inside it will be lost.",
|
||||
"cleanupSingleSsh": "The task directory on the remote host will be removed.",
|
||||
"cleanupSingleSshNote": "Best-effort removal may not complete. Your local repo is not touched.",
|
||||
"cleanupInheritedParentWorkspaceNote": "This task shares its parent's workspace. The parent task's worktree, branch, and files are not touched.",
|
||||
"cleanupSingleWorktree": "The task's git worktree and its branch will be deleted.",
|
||||
"cleanupSingleWorktreeNote": "Your main repo and other branches are not affected.",
|
||||
"enhancedPromptCopiedToClipboard": "Enhanced prompt copied to clipboard.",
|
||||
|
||||
@@ -2237,6 +2237,7 @@
|
||||
"cleanupSingleSprites": "このタスクの Sprites クラウドサンドボックスは破棄されます。中の未コミット作業は失われます。",
|
||||
"cleanupSingleSsh": "リモートホスト上のタスクディレクトリが削除されます。",
|
||||
"cleanupSingleSshNote": "ベストエフォート削除なので、完了しない場合があります。ローカルリポジトリには触れません。",
|
||||
"cleanupInheritedParentWorkspaceNote": "このタスクは親タスクのワークスペースを共有します。親タスクの worktree、ブランチ、ファイルには触れません。",
|
||||
"cleanupSingleWorktree": "タスクの git worktree とそのブランチが削除されます。",
|
||||
"cleanupSingleWorktreeNote": "メインリポジトリと他のブランチには影響しません。",
|
||||
"enhancedPromptCopiedToClipboard": "拡張プロンプトをクリップボードにコピーしました。",
|
||||
|
||||
@@ -2237,6 +2237,7 @@
|
||||
"cleanupSingleSprites": "Ţĥē Śƥŕĩţēś ćĺōũď śàńďƀōx ƒōŕ ţĥĩś ţàśķ ŵĩĺĺ ƀē ďēśţŕōŷēď. Àńŷ ũńćōḿḿĩţţēď ŵōŕķ ĩńśĩďē ĩţ ŵĩĺĺ ƀē ĺōśţ.",
|
||||
"cleanupSingleSsh": "Ţĥē ţàśķ ďĩŕēćţōŕŷ ōń ţĥē ŕēḿōţē ĥōśţ ŵĩĺĺ ƀē ŕēḿōvēď.",
|
||||
"cleanupSingleSshNote": "Ɓēśţ-ēƒƒōŕţ ŕēḿōvàĺ ḿàŷ ńōţ ćōḿƥĺēţē. Ŷōũŕ ĺōćàĺ ŕēƥō ĩś ńōţ ţōũćĥēď.",
|
||||
"cleanupInheritedParentWorkspaceNote": "Ţĥĩś ţàśķ śĥàŕēś ĩţś ƥàŕēńţ'ś ŵōŕķśƥàćē. Ţĥē ƥàŕēńţ ţàśķ'ś ŵōŕķţŕēē, ƀŕàńćĥ, àńď ƒĩĺēś àŕē ńōţ ţōũćĥēď.",
|
||||
"cleanupSingleWorktree": "Ţĥē ţàśķ'ś ĝĩţ ŵōŕķţŕēē àńď ĩţś ƀŕàńćĥ ŵĩĺĺ ƀē ďēĺēţēď.",
|
||||
"cleanupSingleWorktreeNote": "Ŷōũŕ ḿàĩń ŕēƥō àńď ōţĥēŕ ƀŕàńćĥēś àŕē ńōţ àƒƒēćţēď.",
|
||||
"enhancedPromptCopiedToClipboard": "Ēńĥàńćēď ƥŕōḿƥţ ćōƥĩēď ţō ćĺĩƥƀōàŕď.",
|
||||
|
||||
@@ -2101,6 +2101,7 @@
|
||||
"cleanupSingleSprites": "A sandbox na cloud Sprites desta tarefa será destruída. Todo o trabalho não commitado lá dentro será perdido.",
|
||||
"cleanupSingleSsh": "O diretório da tarefa no anfitrião remoto será removido.",
|
||||
"cleanupSingleSshNote": "A remoção é uma tentativa e pode não ser concluída. O seu repositório local não é tocado.",
|
||||
"cleanupInheritedParentWorkspaceNote": "Esta tarefa partilha o espaço de trabalho da tarefa principal. O worktree, o ramo e os ficheiros da tarefa principal não serão tocados.",
|
||||
"cleanupSingleWorktree": "O worktree git da tarefa e o seu ramo serão eliminados.",
|
||||
"cleanupSingleWorktreeNote": "O seu repositório principal e os outros ramos não são afetados.",
|
||||
"composerPlaceholderBusy": "Colocar instruções na fila para o agente...",
|
||||
|
||||
@@ -2101,6 +2101,7 @@
|
||||
"cleanupSingleSprites": "该任务的 Sprites 云沙箱将被销毁。其中所有未提交的工作都会丢失。",
|
||||
"cleanupSingleSsh": "远程主机上的任务目录将被移除。",
|
||||
"cleanupSingleSshNote": "尽力移除,可能无法完成。你的本地仓库不会被改动。",
|
||||
"cleanupInheritedParentWorkspaceNote": "此任务与父任务共享工作区。父任务的 worktree、分支和文件不会受到影响。",
|
||||
"cleanupSingleWorktree": "该任务的 git worktree 及其分支将被删除。",
|
||||
"cleanupSingleWorktreeNote": "你的主仓库和其他分支不受影响。",
|
||||
"composerPlaceholderBusy": "为智能体排队指令…",
|
||||
|
||||
@@ -2101,6 +2101,7 @@
|
||||
"cleanupSingleSprites": "該任務的 Sprites 雲沙箱將被銷燬。其中所有未提交的工作都會丟失。",
|
||||
"cleanupSingleSsh": "遠端主機上的任務目錄將被移除。",
|
||||
"cleanupSingleSshNote": "盡力移除,可能無法完成。你的本地儲存庫不會被改動。",
|
||||
"cleanupInheritedParentWorkspaceNote": "此任務與父任務共享工作區。父任務的 worktree、分支和檔案不會受到影響。",
|
||||
"cleanupSingleWorktree": "該任務的 git worktree 及其分支將被刪除。",
|
||||
"cleanupSingleWorktreeNote": "你的主儲存庫和其他分支不受影響。",
|
||||
"composerPlaceholderBusy": "為代理程式排隊指令…",
|
||||
|
||||
@@ -2101,6 +2101,7 @@
|
||||
"cleanupSingleSprites": "該任務的 Sprites 雲沙箱將被銷燬。其中所有未提交的工作都會丟失。",
|
||||
"cleanupSingleSsh": "遠端主機上的任務目錄將被移除。",
|
||||
"cleanupSingleSshNote": "盡力移除,可能無法完成。你的本地儲存庫不會被改動。",
|
||||
"cleanupInheritedParentWorkspaceNote": "此任務與父任務共享工作區。父任務的 worktree、分支和檔案不會受到影響。",
|
||||
"cleanupSingleWorktree": "該任務的 git worktree 及其分支將被刪除。",
|
||||
"cleanupSingleWorktreeNote": "你的主儲存庫和其他分支不受影響。",
|
||||
"composerPlaceholderBusy": "為代理程式排隊指令…",
|
||||
|
||||
Reference in New Issue
Block a user