chore: v2.8.13 — Artifacts reinstall/edit/installs, agent steps in chat, pick a local file to attach, Windows paths as links
- Chat: an Agent step shows its task, status and tool calls and opens its conversation in place; Windows paths (E:\…, C:/…) in replies open as files - Prompt: attach a file on this computer by path (native picker), clearer too-large messages - Artifacts: edit title/description and a skill's files (new snapshot), Reinstall, install history, Hub-only rows, skills installed into ~/.claude/skills and ~/.agents/skills - Files: batch upload of small files in one extract - AI Tools: npm install falls back to --prefix ~/.local when the global prefix is not writable
This commit is contained in:
@@ -2,7 +2,8 @@
|
||||
* @file The one-at-a-time install/update runner behind Settings → AI Tools.
|
||||
* Every command comes from a catalog file (never a request) and runs as an
|
||||
* argv with stdin closed and the login shell's PATH first: `npm install -g
|
||||
* <pkg>@latest`, a tool's own updater, or a vendor script the server
|
||||
* <pkg>@latest` (with `--prefix ~/.local` when npm's global prefix is not the
|
||||
* account's to write — a system-wide Node), a tool's own updater, or a vendor script the server
|
||||
* downloads (https, same site as the tool's homepage, ≤ 1 MB) and runs with
|
||||
* `bash <file>`. The job lives in memory — a child of the server, so it dies
|
||||
* with it — and it reports its end only AFTER the PATH is re-read and the tool
|
||||
@@ -27,7 +28,8 @@ let jobTimeoutMs = 10 * 60 * 1000;
|
||||
const SCRIPT_MAX = 1024 * 1024;
|
||||
const EACCES_HINT =
|
||||
"\n[agenthub] npm could not write its global directory (EACCES): this Node is installed " +
|
||||
"system-wide. Use a user-level Node (nvm, fnm) or install the tool by hand.\n";
|
||||
"system-wide and ~/.local is not writable either. Use a user-level Node (nvm, fnm) or install " +
|
||||
"the tool by hand.\n";
|
||||
|
||||
const EXIT_GRACE_MS = 500; // after 'exit', how long to wait for the pipes to close
|
||||
const KILL_GRACE_MS = 5000; // SIGTERM → SIGKILL
|
||||
@@ -44,10 +46,11 @@ function makeErr(code, message) {
|
||||
return err;
|
||||
}
|
||||
|
||||
const npmArgv = (pkg) => {
|
||||
/** `prefix`: the `--prefix` args (none for npm's own global prefix). */
|
||||
const npmArgv = (pkg, prefix = []) => {
|
||||
const npm = versions.npmBin();
|
||||
if (!npm) throw makeErr("ENONPM", "npm was not found on the login shell's PATH");
|
||||
return [npm, "install", "-g", `${pkg}@latest`];
|
||||
return [npm, "install", "-g", ...prefix, `${pkg}@latest`];
|
||||
};
|
||||
|
||||
/** The steps one action on one tool would run — `{argv}` or `{script: url}`. */
|
||||
@@ -59,20 +62,22 @@ async function stepsFor(id, action) {
|
||||
if (!tool.install) throw makeErr("ENOINSTALL", `${tool.label} has no install command`);
|
||||
if (d.installed) throw makeErr("EINSTALLED", `${tool.label} is already installed`);
|
||||
return tool.install.kind === "npm"
|
||||
? [{ argv: npmArgv(tool.install.package) }]
|
||||
? [{ argv: npmArgv(tool.install.package, await versions.installPrefixArgs()) }]
|
||||
: [{ script: tool.install.url }];
|
||||
}
|
||||
if (!tool.update) throw makeErr("ENOUPDATE", `${tool.label} has no update command`);
|
||||
if (!d.installed) throw makeErr("ENOTINSTALLED", `${tool.label} is not installed`);
|
||||
if (tool.update.kind === "self") return [{ argv: [d.path, ...tool.update.args] }];
|
||||
if (tool.update.kind === "script") return [{ script: tool.install.url }];
|
||||
if (!(await versions.npmManaged(id))) {
|
||||
const by = await versions.managedBy(id);
|
||||
if (!by) {
|
||||
throw makeErr(
|
||||
"ENOTNPM",
|
||||
`${tool.label} was installed outside npm; update it the way it was installed`
|
||||
);
|
||||
}
|
||||
return [{ argv: npmArgv(tool.install.package) }];
|
||||
const prefix = by === "user" ? ["--prefix", versions.userPrefix()] : [];
|
||||
return [{ argv: npmArgv(tool.install.package, prefix) }];
|
||||
}
|
||||
|
||||
function append(j, text) {
|
||||
|
||||
Reference in New Issue
Block a user