chore: v2.8.12 — clone queue and progress, session defaults, chat agents, drops as @ mentions
Whole tree from parallel sessions, plus the version bump: - Clone: a queue with live progress (Add workspace and extra folders), clones run under nice/ionice so the machine stays responsive. - Settings → AI tools → Session defaults: a new session's default permission mode / bypass per account. - Chat lists the background subagents that have not reported back yet. - A file pasted or dropped into a claude pane goes in as an @ mention. - Changes panel: say why amend/undo is refused on a pushed commit. - openapi.yaml regenerated (Artifacts, Host, resumeById).
This commit is contained in:
+43
-2
@@ -19,6 +19,26 @@ const PROTECTED_BRANCHES = new Set(["main", "master"]);
|
||||
/** Most status lines `statusCounts` reports by name; the counts stay exact. */
|
||||
const STATUS_FILE_CAP = 20;
|
||||
|
||||
/**
|
||||
* `nice`/`ionice` before a heavy git (a clone) so the dashboard and the panes
|
||||
* beside it keep their share of the machine; children (index-pack, sudo's
|
||||
* git) inherit both. Empty where neither exists (Windows).
|
||||
*/
|
||||
let lowPriorityPrefix = null;
|
||||
function lowPriority() {
|
||||
if (lowPriorityPrefix) return lowPriorityPrefix;
|
||||
const find = (name) =>
|
||||
["/usr/bin", "/bin"].map((d) => path.join(d, name)).find((f) => fs.existsSync(f));
|
||||
const nice = process.platform === "win32" ? null : find("nice");
|
||||
const ionice = process.platform === "linux" ? find("ionice") : null;
|
||||
lowPriorityPrefix = [
|
||||
...(nice ? [nice, "-n", "10"] : []),
|
||||
// best-effort class, lowest level: never the idle class, which can wait forever
|
||||
...(ionice ? [ionice, "-c", "2", "-n", "7"] : []),
|
||||
];
|
||||
return lowPriorityPrefix;
|
||||
}
|
||||
|
||||
/**
|
||||
* Promisified git wrapper. On failure, throws an Error with err.git = { args, code, stderr }.
|
||||
* Treats zero exit code as success even if stderr has hints.
|
||||
@@ -42,6 +62,10 @@ async function git(
|
||||
encoding = "utf8",
|
||||
// stdin (a patch for `apply -`): never a file the dashboard writes.
|
||||
input = null,
|
||||
// true: run under nice/ionice (a clone — see lowPriority above).
|
||||
background = false,
|
||||
// Called with each stderr chunk as it arrives (a clone's --progress).
|
||||
onStderr = null,
|
||||
} = {}
|
||||
) {
|
||||
// Build a clean environment: copy process.env but scrub git hook variables
|
||||
@@ -88,6 +112,12 @@ async function git(
|
||||
if (literal) pass.GIT_LITERAL_PATHSPECS = "1";
|
||||
[cmd, argv] = require("./run-as").sudoArgv(member, "git", args, pass);
|
||||
}
|
||||
const gitCmd = cmd;
|
||||
if (background && lowPriority().length) {
|
||||
const [first, ...rest] = lowPriority();
|
||||
argv = [...rest, cmd, ...argv];
|
||||
cmd = first;
|
||||
}
|
||||
|
||||
try {
|
||||
const run =
|
||||
@@ -100,7 +130,7 @@ async function git(
|
||||
);
|
||||
child.stdin.end(input);
|
||||
});
|
||||
const result = await run(cmd, argv, {
|
||||
const pending = run(cmd, argv, {
|
||||
cwd,
|
||||
env,
|
||||
// A read with its own size cap passes a bigger buffer and treats an
|
||||
@@ -113,12 +143,23 @@ async function git(
|
||||
timeout,
|
||||
encoding,
|
||||
});
|
||||
// promisify(execFile) hands back its child; the stdin runner has none.
|
||||
if (onStderr && pending.child?.stderr) {
|
||||
pending.child.stderr.on("data", (d) => {
|
||||
try {
|
||||
onStderr(String(d));
|
||||
} catch {
|
||||
/* a progress reader never fails the git call */
|
||||
}
|
||||
});
|
||||
}
|
||||
const result = await pending;
|
||||
return { stdout: result.stdout, stderr: result.stderr };
|
||||
} catch (err) {
|
||||
// ENOENT from execFile is ambiguous: a missing binary OR a missing cwd.
|
||||
// With the folder present it is git itself that is absent — say so, with
|
||||
// the fix, rather than `git status failed` (like ETMUXMISSING for tmux).
|
||||
if (err.code === "ENOENT" && cmd === "git" && fs.existsSync(cwd)) {
|
||||
if (err.code === "ENOENT" && gitCmd === "git" && fs.existsSync(cwd)) {
|
||||
const error = new Error(
|
||||
"git is not installed (or not on the dashboard's PATH), and every git action needs it. " +
|
||||
"Install it (sudo apt install git / brew install git / https://git-scm.com/download/win), " +
|
||||
|
||||
Reference in New Issue
Block a user