дзеркало
https://github.com/l0ng-ai/openidea.git
синхронізовано 2026-11-09 03:05:40 +02:00
116 рядки
3.6 KiB
TypeScript
116 рядки
3.6 KiB
TypeScript
import type { AgentTask } from "@/bindings";
|
|
import type { Action } from "@/platform/actions";
|
|
import { tx } from "@/platform/i18n";
|
|
import type { MenuItem } from "@/ui";
|
|
import { showError, confirmChecked } from "@/workbench/messages";
|
|
import { isBusy } from "./model";
|
|
import { archiveTask, deleteTask, openTask, useAgents } from "./store";
|
|
|
|
const canArchive = (task: AgentTask) => !isBusy(task.status) && task.status !== "archived";
|
|
|
|
function resolveTasks(arg: unknown): AgentTask[] {
|
|
if (!Array.isArray(arg)) return [];
|
|
return [...new Set(arg)].flatMap((id: unknown) => {
|
|
const task = typeof id === "string" ? useAgents.getState().tasks.get(id) : undefined;
|
|
return task ? [task] : [];
|
|
});
|
|
}
|
|
|
|
async function runTasks(tasks: AgentTask[], run: (task: AgentTask) => Promise<unknown>, title: string) {
|
|
const errors: string[] = [];
|
|
for (const task of tasks) {
|
|
try {
|
|
await run(task);
|
|
} catch (error) {
|
|
errors.push(`${task.title}: ${error instanceof Error ? error.message : String(error)}`);
|
|
}
|
|
}
|
|
if (errors.length) await showError(title, errors.join("\n"));
|
|
}
|
|
|
|
async function confirmDelete(tasks: AgentTask[]) {
|
|
if (!tasks.length) return;
|
|
const task = tasks[0]!;
|
|
const multiple = tasks.length > 1;
|
|
const worktree = tasks.some((t) => t.isolation === "worktree");
|
|
const r = await confirmChecked({
|
|
title: multiple ? "Delete Agent Tasks" : "Delete Agent Task",
|
|
message: multiple
|
|
? tx`Delete ${tasks.length} agent tasks? Their branches and files outside worktrees are kept.`
|
|
: worktree
|
|
? tx`Delete “${task.title}”? Its branch ${task.branch ?? ""} is kept.`
|
|
: tx`Delete “${task.title}”? Files it changed are kept.`,
|
|
ok: "Delete",
|
|
icon: "warning",
|
|
checkbox: worktree
|
|
? multiple
|
|
? "Also remove their worktree folders"
|
|
: "Also remove its worktree folder"
|
|
: undefined,
|
|
checked: worktree,
|
|
});
|
|
if (r)
|
|
await runTasks(
|
|
tasks,
|
|
(t) => deleteTask(t.id, t.isolation === "worktree" && r.checked),
|
|
tx("Cannot delete agent tasks"),
|
|
);
|
|
}
|
|
|
|
export const taskActions: Action[] = [
|
|
{
|
|
id: "agents.openTask",
|
|
title: "Open Agent Task",
|
|
category: "Agents",
|
|
hidden: true,
|
|
run: ({ arg }) => {
|
|
if (typeof arg === "string") openTask(arg);
|
|
},
|
|
},
|
|
{
|
|
id: "agents.archiveTasks",
|
|
title: "Archive Agent Tasks",
|
|
category: "Agents",
|
|
hidden: true,
|
|
run: ({ arg }) =>
|
|
runTasks(resolveTasks(arg).filter(canArchive), (task) => archiveTask(task.id), tx("Cannot archive agent tasks")),
|
|
},
|
|
{
|
|
id: "agents.deleteTasks",
|
|
title: "Delete Agent Tasks",
|
|
category: "Agents",
|
|
hidden: true,
|
|
run: ({ arg }) => confirmDelete(resolveTasks(arg)),
|
|
},
|
|
];
|
|
|
|
export function taskMenu(tasks: AgentTask[]): MenuItem[] {
|
|
if (!tasks.length) return [];
|
|
const ids = tasks.map((task) => task.id);
|
|
const task = tasks[0]!;
|
|
const multiple = tasks.length > 1;
|
|
const archivable = tasks.filter(canArchive).length;
|
|
return [
|
|
...(!multiple
|
|
? ([
|
|
{ kind: "action", action: "agents.openTask", label: "Open", arg: task.id },
|
|
{ kind: "action", action: "terminal.openAt", label: "Open in Terminal", icon: "terminal", arg: task.cwd },
|
|
{ kind: "separator" },
|
|
] satisfies MenuItem[])
|
|
: []),
|
|
{
|
|
kind: "action",
|
|
action: "agents.archiveTasks",
|
|
label: multiple ? tx`Archive (${archivable})` : "Archive",
|
|
arg: ids,
|
|
disabled: !archivable,
|
|
},
|
|
{
|
|
kind: "action",
|
|
action: "agents.deleteTasks",
|
|
label: multiple ? tx`Delete (${tasks.length})…` : "Delete…",
|
|
arg: ids,
|
|
},
|
|
];
|
|
}
|