mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-07-20 15:33:54 +00:00
fix(kanban): make scratch cleanup explicit in dashboard (#63123)
This commit is contained in:
parent
837077dfae
commit
f67aae3230
3 changed files with 84 additions and 14 deletions
41
plugins/kanban/dashboard/dist/index.js
vendored
41
plugins/kanban/dashboard/dist/index.js
vendored
|
|
@ -1072,6 +1072,7 @@
|
|||
error ? h("div", { className: "text-xs text-destructive px-2" }, error) : null,
|
||||
h(BoardColumns, {
|
||||
board: filteredBoard,
|
||||
boardMeta: boardList.find(function (item) { return item.slug === board; }) || null,
|
||||
laneByProfile,
|
||||
selectedIds,
|
||||
failedIds,
|
||||
|
|
@ -2384,6 +2385,7 @@
|
|||
return h(Column, {
|
||||
key: col.name,
|
||||
column: col,
|
||||
boardMeta: props.boardMeta,
|
||||
laneByProfile: props.laneByProfile,
|
||||
selectedIds: props.selectedIds,
|
||||
failedIds: props.failedIds,
|
||||
|
|
@ -2504,6 +2506,8 @@
|
|||
showCreate ? h(InlineCreate, {
|
||||
columnName: props.column.name,
|
||||
allTasks: props.allTasks,
|
||||
defaultWorkspaceKind: (props.boardMeta && props.boardMeta.default_workspace_kind) || "scratch",
|
||||
defaultWorkspacePath: (props.boardMeta && props.boardMeta.default_workdir) || "",
|
||||
onSubmit: function (body) {
|
||||
props.onCreate(body).then(function () { setShowCreate(false); });
|
||||
},
|
||||
|
|
@ -2745,12 +2749,13 @@
|
|||
const [priority, setPriority] = useState(0);
|
||||
const [parent, setParent] = useState("");
|
||||
const [skills, setSkills] = useState("");
|
||||
// Workspace controls. `scratch` (default) ignores path; `worktree` optionally
|
||||
// takes a path (dispatcher derives one from the assignee profile otherwise);
|
||||
// `dir` requires a path. Backend enforces the rule — we only hide/show the
|
||||
// input here to save vertical space in the common `scratch` case.
|
||||
const [workspaceKind, setWorkspaceKind] = useState("scratch");
|
||||
const [workspacePath, setWorkspacePath] = useState("");
|
||||
// A board with a configured workdir defaults to a persistent workspace:
|
||||
// worktree for git repositories, dir for ordinary directories. Boards
|
||||
// without one keep scratch for disposable research and ops tasks.
|
||||
const defaultWorkspaceKind = props.defaultWorkspaceKind || "scratch";
|
||||
const defaultWorkspacePath = props.defaultWorkspacePath || "";
|
||||
const [workspaceKind, setWorkspaceKind] = useState(defaultWorkspaceKind);
|
||||
const [workspacePath, setWorkspacePath] = useState(defaultWorkspacePath);
|
||||
// Goal-mode: when on, the dispatched worker runs the Ralph-style /goal
|
||||
// loop — a judge re-checks the card after each turn and the worker keeps
|
||||
// going in the same session until done, or the turn budget runs out
|
||||
|
|
@ -2793,15 +2798,15 @@
|
|||
}
|
||||
props.onSubmit(body);
|
||||
setTitle(""); setAssignee(""); setPriority(0); setParent(""); setSkills("");
|
||||
setWorkspaceKind("scratch"); setWorkspacePath("");
|
||||
setWorkspaceKind(defaultWorkspaceKind); setWorkspacePath(defaultWorkspacePath);
|
||||
setGoalMode(false); setGoalMaxTurns("");
|
||||
};
|
||||
|
||||
const showPathInput = workspaceKind !== "scratch";
|
||||
const pathPlaceholder = workspaceKind === "dir"
|
||||
? tx(t, "workspacePathDir", "workspace path (required, e.g. ~/projects/my-app)")
|
||||
? tx(t, "workspacePathDir", "workspace path (required without a board workdir)")
|
||||
: tx(t, "workspacePathOptional",
|
||||
"workspace path (optional, derived from assignee if blank)");
|
||||
"repository path (optional when the board has a workdir)");
|
||||
|
||||
return h("div", { className: "hermes-kanban-inline-create" },
|
||||
h("textarea", {
|
||||
|
|
@ -2877,12 +2882,15 @@
|
|||
h("div", { className: "flex gap-2" },
|
||||
h(Select, Object.assign({
|
||||
value: workspaceKind,
|
||||
title: "scratch: isolated temp dir (default). worktree: git worktree on the assignee profile. dir: exact path (required below).",
|
||||
className: "h-7 text-xs w-28",
|
||||
title: "Choose whether task files are temporary or preserved after completion.",
|
||||
className: "h-7 text-xs flex-1",
|
||||
}, selectChangeHandler(setWorkspaceKind)),
|
||||
h(SelectOption, { value: "scratch" }, "scratch"),
|
||||
h(SelectOption, { value: "worktree" }, "worktree"),
|
||||
h(SelectOption, { value: "dir" }, "dir"),
|
||||
h(SelectOption, { value: "scratch" },
|
||||
tx(t, "workspaceScratch", "Temporary — deleted on completion")),
|
||||
h(SelectOption, { value: "worktree" },
|
||||
tx(t, "workspaceWorktree", "Git worktree — preserved")),
|
||||
h(SelectOption, { value: "dir" },
|
||||
tx(t, "workspaceDir", "Directory — preserved")),
|
||||
),
|
||||
showPathInput ? h(Input, {
|
||||
value: workspacePath,
|
||||
|
|
@ -2891,6 +2899,11 @@
|
|||
className: "h-7 text-xs flex-1",
|
||||
}) : null,
|
||||
),
|
||||
workspaceKind === "scratch" ? h("div", {
|
||||
className: "text-xs text-destructive",
|
||||
role: "alert",
|
||||
}, tx(t, "workspaceScratchWarning",
|
||||
"This workspace and any files left in it are deleted when the task completes.")) : null,
|
||||
h(Select, Object.assign({
|
||||
value: parent,
|
||||
className: "h-7 text-xs",
|
||||
|
|
|
|||
|
|
@ -2010,6 +2010,17 @@ def _board_counts(slug: str) -> dict[str, int]:
|
|||
return {}
|
||||
|
||||
|
||||
def _default_workspace_kind(board: dict[str, Any]) -> str:
|
||||
"""Recommend a non-destructive task workspace from board metadata."""
|
||||
workdir = str(board.get("default_workdir") or "").strip()
|
||||
if not workdir:
|
||||
return "scratch"
|
||||
try:
|
||||
return "worktree" if kanban_db._git_toplevel(Path(workdir)) else "dir"
|
||||
except (OSError, ValueError):
|
||||
return "dir"
|
||||
|
||||
|
||||
@router.get("/boards")
|
||||
def list_boards(include_archived: bool = Query(False)):
|
||||
"""Return every board on disk with task counts and the active slug."""
|
||||
|
|
@ -2019,6 +2030,7 @@ def list_boards(include_archived: bool = Query(False)):
|
|||
b["is_current"] = (b["slug"] == current)
|
||||
b["counts"] = _board_counts(b["slug"])
|
||||
b["total"] = sum(b["counts"].values())
|
||||
b["default_workspace_kind"] = _default_workspace_kind(b)
|
||||
return {"boards": boards, "current": current}
|
||||
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue