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
+54 -2
View File
@@ -149,6 +149,58 @@ const OPS = [
status: 201,
},
],
[
"post",
"/upload-check",
"Before a batch: the names already taken, and whether a batch can go there",
{
note: "`taken`: which of `paths` (relative to `dir`) exist; `batch: false` = send the files one by one (a member's folder whose `write-as` predates `extract`).",
body: json({ dir: { type: "string", default: "" }, paths: pathsArr }, ["paths"]),
ok: {
description: "`{taken, batch}`",
content: {
"application/json": {
schema: {
type: "object",
properties: { taken: pathsArr, batch: { type: "boolean" } },
},
},
},
},
},
],
[
"post",
"/upload-batch",
"Upload many small files in one request (≤ 5,000 files, 16 MB each, 256 MB in all)",
{
note: "Body: a 4-byte big-endian length, that many bytes of JSON `{files: [{path, size, mtime?}]}` (paths relative to `dir`), then each file's bytes in that order. Planned whole before the first write — a taken name under `conflict=fail` is ONE 409 naming them all; a member's batch is one `write-as extract` (409 EUPGRADE until `agenthub server install-system` is re-run). 400 EBADBODY for a malformed or short body.",
parameters: [
{ name: "dir", in: "query", schema: { type: "string", default: "" } },
{ name: "conflict", in: "query", schema: conflict },
],
body: {
required: true,
content: { "application/octet-stream": { schema: { type: "string", format: "binary" } } },
},
status: 201,
ok: {
description: "`{saved, skipped, paths}`",
content: {
"application/json": {
schema: {
type: "object",
properties: {
saved: { type: "integer" },
skipped: { type: "integer" },
paths: pathsArr,
},
},
},
},
},
},
],
[
"get",
"/zip",
@@ -180,8 +232,8 @@ function operations(prefix, idParam, opPrefix, note) {
out[key][method] = {
tags: ["Files"],
summary,
description: `${note} ${errorCodes}`,
operationId: `${opPrefix}${sub.replace(/\/(\w)/g, (_, c) => c.toUpperCase())}`,
description: `${note} ${x.note ? `${x.note} ` : ""}${errorCodes}`,
operationId: `${opPrefix}${sub.replace(/[/-](\w)/g, (_, c) => c.toUpperCase())}`,
parameters: [idParam, ...(x.parameters || [])],
...(x.body ? { requestBody: x.body } : {}),
responses: { [x.status || 200]: x.ok || { description: "Done." } },