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:
2026-10-20 16:44:55 +07:00
parent 49f87c4da3
commit 0547488f13
59 changed files with 4285 additions and 690 deletions
+52
View File
@@ -181,6 +181,58 @@ describe("stepsFor", () => {
});
});
describe("a system-wide npm prefix", () => {
const ro = path.join(root, "ro-prefix");
const user = path.join(root, "user-local");
const asRoot = process.getuid?.() === 0;
before(() => {
for (const d of [path.join(ro, "lib", "node_modules"), path.join(ro, "bin")]) {
fs.mkdirSync(d, { recursive: true });
fs.chmodSync(d, 0o555);
}
versions.__setUserPrefix(user);
});
after(() => {
versions.__setUserPrefix(undefined);
for (const d of [path.join(ro, "lib", "node_modules"), path.join(ro, "bin")]) {
fs.chmodSync(d, 0o755);
}
});
it("installs into the account's ~/.local when npm's global prefix is not writable", async (t) => {
if (asRoot) return t.skip("root writes anywhere");
versions.__setExec(async (_f, args) => {
if (args[0] === "prefix") return { stdout: `${ro}\n` };
throw new Error("unexpected");
});
assert.deepEqual(await jobs.stepsFor("fresh", "install"), [
{
argv: [path.join(shellBin, "npm"), "install", "-g", "--prefix", user, "fresh-pkg@latest"],
},
]);
});
it("updates a tool under ~/.local/lib/node_modules with the same --prefix", async () => {
const pkg = path.join(user, "lib", "node_modules", "fresh-pkg", "cli.js");
exe(pkg);
fs.mkdirSync(path.join(user, "bin"), { recursive: true });
fs.symlinkSync(pkg, path.join(serverBin, "fresh"));
aiTools.refresh();
try {
assert.equal(await versions.managedBy("fresh"), "user");
assert.deepEqual(await jobs.stepsFor("fresh", "update"), [
{
argv: [path.join(shellBin, "npm"), "install", "-g", "--prefix", user, "fresh-pkg@latest"],
},
]);
} finally {
fs.rmSync(path.join(serverBin, "fresh"));
aiTools.refresh();
}
});
});
describe("versions", () => {
it("marks npm-managed by realpath and badges a newer version", async () => {
const v = await versions.versions({ fresh: true });