目录 / drawer | publish ai artifacts
MCP
鉴权未知
未评级
已上架
drawer | publish ai artifacts
该来源不提供完整文件导出(国内平台多为平台内托管),仅存元数据与原链
接入信息
- 传输形态
- http
- 鉴权方式
- 鉴权未知
- 端点
https://drawer--munxch.run.tools
鉴权方式未标注,请核对官方文档后再接入——不要直接使用以下片段
{
"mcpServers": {
"drawer | publish ai artifacts": {
"url": "https://drawer--munxch.run.tools"
}
}
}
能力清单
| 工具 | 说明 |
|---|---|
| create_artifact | Creates a NEW artifact (HTML, markdown, or multi-file site) and returns its stable URL. Default visibility is 'private' — only the signed-in owner can see it. Pass `visibility` explicitly (private / unlisted / public) only when the user has explicitly said so: phrases like 'save', 'keep', 'put in my drawer' mean private; 'shareable link', 'share with the team' mean unlisted; 'publish', 'make public', 'ship it' mean public. If in doubt, default private — the user can call publish_artifact later. visibility='public' triggers a confirmation round-trip; the first call returns a private artifact + confirmation prompt instead of going public immediately. See also: after creating, use `update_artifact` for full rewrites or `patch_artifact` for surgical edits. Use `publish_artifact` to change visibility. |
| update_artifact | Push a NEW VERSION to an existing artifact. The URL and artifact_id stay the same — only the content changes. The previous version remains accessible at /a/<artifact_id>/v/<old_version_id>. CANNOT change visibility or password — to flip access, call publish_artifact(id, visibility). Passing visibility/password fields here returns a 400 with a hint. Drift is checked automatically based on what this principal has read. If the artifact changed since your last read, you'll get a `version_drift` error — re-read and retry, or pass `force: true` to overwrite (deprecated alias: `acknowledge_drift: true`). If you never read the artifact in the current key's history (e.g. you got the id out-of-band), the write proceeds without a drift check. For atomic edits against a known version, pass `expected_version_id` — the call will fail with 409 stale_artifact if the artifact has moved past that version. The response's `drift_warnings` array flags suspected drift even when you didn't pin a version (e.g. when the artifact was last touched via the dashboard or a different API key). See also: for smaller, targeted edits to the same artifact, prefer `patch_artifact` — it's cheaper and the version history reads better. Call `get_artifact` first if you're not sure of the current content. |
| patch_artifact | Apply surgical find/replace edits to an existing artifact without resending the full content. Massively faster + cheaper than update_artifact for small changes (e.g., a CSS tweak in a 17KB file goes from 17KB to ~200 bytes). Each edit needs exact-match 'old' text that's unique in the file — include enough surrounding context to disambiguate. Edits apply in order; if any edit fails (text not found, not unique), the whole patch fails atomically with no partial state. For multi-file artifacts, specify the file path per edit. Multi-file edits land atomically: a single call may carry patches for several files in the artifact's `files` map, and the resulting version_id covers the whole set — partial application is not possible (either every edit applies, or the call fails and the artifact stays on its previous version). Same semantics as Claude Code's Edit tool. CANNOT change visibility or password — call publish_artifact for that. Drift is checked automatically based on what this principal has read. If the artifact changed since your last read, you'll get a `version_drift` error — re-read and retry, or pass `force: true` to overwrite (deprecated alias: `acknowledge_drift: true`). If you never read the artifact under this key, the write proceeds. For atomic edits against a known version, pass `expected_version_id` — the call will fail with 409 stale_artifact if the artifact has moved past that version. The response's `drift_warnings` array flags suspected drift even when you didn't pin a version. No-op short-circuit: if every edit's `old` matches but the resulting content is byte-identical to the input (e.g. replacing a string with itself, or a retry after the change already landed), the call succeeds without creating a new version. Response includes `no_op: true` and `version_id` equal to the existing current version — handy for retry-prone agents that don't want to pollute version history. See also: prefer `grep_artifact` or `read_artifact_file` over `get_artifact` to confirm anchor text before patching — much cheaper. For full rewrites, use `update_artifact`. |
| regex_replace_artifact | Surgical regex-based replace for small textual edits — CSS class renames, hex value swaps, version bumps, identifier renames. Operates on ONE file at a time (the `path` field; defaults to the artifact's entry file). The agent sends a regex + replacement instead of a literal `old`/`new` pair, which is dramatically cheaper for repeated-pattern edits: renaming `.btn-primary` → `.btn-action` across 20 occurrences sends ~50 bytes instead of 20 copies of the surrounding context. When NOT to use: prefer `patch_artifact` when the edit is a literal block of code with no repeated pattern (its `old`/`new` semantics are clearer for one-off changes). Use `update_artifact` for full-file rewrites. Use `patch_artifact` when you need multiple unrelated edits in one call — `regex_replace_artifact` is single-file, single-pattern. Replacement string uses JavaScript `String.prototype.replace` semantics: `$1`, `$2`, … for capture groups, `$&` for the full match, `$$` for a literal `$`. Named groups via `$<name>` also work. Safety default: `replace_all` defaults to FALSE — a single-match operation by default. If the pattern matches more than one location, the call fails with `pattern_multiple_matches` (including line numbers of every match) rather than silently overwriting them all. Set `replace_all: true` to opt into multi-replace. Flags: pass `flags` as any subset of `imsu` (ignore-case / multiline ^$ / dotall / unicode). `g` is NOT accepted — use `replace_all` instead. `y` (sticky) is rejected because it doesn't compose with file-wide replace. Dry-run: pass `preview: true` to see what WOULD change without writing. Returns the match list with ±3 lines of context and the byte delta, but no new version is created and the principal's seen-version is not advanced. No-op short-circuit: if the pattern matches but the replacement produces byte-identical content (e.g. `div` → `div`), the call succeeds without creating a new version. Response includes `no_op: true` and `version_id` equal to the existing current version — handy for retry-prone agents that don't want to pollute version history. Drift detection identical to `patch_artifact`: implicit per-principal check; `force: true` (deprecated alias: `acknowledge_drift: true`); `expected_version_id` to pin. See also: `patch_artifact` for literal find/replace, `grep_artifact` to locate the pattern's targets before calling, `read_artifact_file` to inspect surrounding context. |
| publish_artifact | Changes the visibility of an EXISTING artifact. Use 'private' to make it owner-only; 'unlisted' for a shareable URL that isn't on the profile; 'public' for an indexable, profile-listed artifact. Does NOT create artifacts (call create_artifact for that). Does NOT update content (call update_artifact / patch_artifact for that). Switching to public requires a confirmation round-trip: first call without confirmed=true returns a prompt; re-call with confirmed=true to proceed. private/unlisted are recoverable and flip immediately. See also: to make an artifact private again, use `unpublish_artifact`. For per-email sharing while keeping the artifact private, see the grants API. |
| unpublish_artifact | Makes an EXISTING artifact private again — only the owner can view it. Use this when the user says 'unpublish', 'take it down', 'make it private', 'hide this', or 'remove it from my profile'. Does NOT delete the artifact (use delete_artifact for that). Does NOT update content. Equivalent to publish_artifact(id, 'private') but distinct so 'unpublish' never gets routed to delete_artifact by mistake. Flips immediately (no confirm round-trip needed). See also: equivalent to `publish_artifact(id, 'private')`. Use `delete_artifact` to permanently remove an artifact instead of just hiding it. |
| favorite_artifact | Star (favorite) an existing artifact. Surfaces it in the owner's dashboard sidebar 'Favorites' quick-view. Use when the user says 'star this', 'pin this', 'favorite this', or 'add to favorites'. Pair with unfavorite_artifact. Idempotent — starring an already-starred artifact is a no-op. See also: use `unfavorite_artifact` to remove the star. Filter to starred artifacts with `list_artifacts({favorited: true})`. |
| unfavorite_artifact | Remove the star (favorite) from an artifact. Use when the user says 'unstar', 'unpin', 'remove favorite', or 'unfavorite'. Does NOT change visibility or delete anything. Idempotent. See also: `favorite_artifact` (the inverse). Favorites are independent of visibility — use `publish_artifact` / `unpublish_artifact` to change who can view. |
| list_artifacts | List all artifacts owned by the calling API key with view counts, titles, URLs, tag sets, favorite state, and update timestamps. Use when the user asks 'what have I published?', before suggesting an update to a recent artifact, or to find an artifact_id by title. Pass favorited=true to filter to starred artifacts only. See also: use `get_artifact` to read the contents of a specific artifact. Use `list_connections` for connections (formerly workspace secrets) and `list_tags` for tags. |
| list_tags | List the calling user's tags with artifact counts. Tags are per-user; new users are seeded with docs/tools/sites. You usually don't need to call this before publishing — passing a `tags` array on publish_artifact/update_artifact auto-creates unknown tags. See also: tags are auto-created when you pass an unknown tag to `create_artifact` or `update_artifact`. Filter artifact lists by tag with `list_artifacts({tag: '...'})`. |
| get_artifact | Returns an artifact's metadata + version history. **For reading file contents, prefer `read_artifact_file` (one file)** or `grep_artifact` (search across files) — they're much cheaper in context than pulling the whole bundle. Only use `get_artifact` with default args when you need ALL file contents at once (rare). Pass `include_content: false` (recommended default) for metadata + version list. Pass `version_id` to inspect a historical version. Reading with content marks this version as 'seen' by your principal for implicit drift detection on subsequent patches. Metadata-only calls (`include_content: false`) do NOT mark seen — you didn't actually look at the bytes. See also: `read_artifact_file` to read ONE file, `grep_artifact` to search without pulling bodies, `patch_artifact` to edit. Use `list_artifacts` to discover artifact IDs by title or tag. |
| read_artifact_file | Read ONE file (or a line window of one file) from an artifact. Use AFTER `grep_artifact` has located the right path + line range — the common cheap navigation pattern is `grep_artifact` → pick a hit → `read_artifact_file` with `offset` + `limit` around that hit, NOT the whole file. For a multi-file artifact, reading a single 200-line window beats `get_artifact`'s full-bundle pull by orders of magnitude. Line slicing matches Claude Code's `Read` tool: pass `offset` (0-indexed) and `limit` to read a window. Binary files (images, fonts) return an error pointing at the viewer URL — fetch the URL directly to inspect the bytes. Reading also marks this version as 'seen' by your principal for implicit drift detection on subsequent patches. See also: `grep_artifact` is almost always the right FIRST call when you need to navigate or debug — start there, not here. `patch_artifact` to edit once you've found the right anchor. |
| grep_artifact | PRIMARY navigation tool for any non-trivial artifact work. Reach for grep FIRST whenever you need to locate anything in an artifact — debugging a broken section, finding where a class/function/string lives, confirming an `old` string before patch_artifact, answering a question about the artifact's structure. It's a fraction of the bytes of `get_artifact` and `read_artifact_file`, and you almost always need to know `where` before you need to know `what`. Common usages: - 'where does this CSS class get defined?' → grep for the class name - 'what file is the bug in?' → grep for the broken string - 'does this artifact have any X?' → grep for X (or a regex variant) - 'confirm `old` exists before I patch' → grep the exact substring - 'find the right anchor for my patch' → grep nearby, then patch with surrounding context Returns {path, line, column, snippet} hits. Pattern is a JavaScript regex (same flavor as `String.prototype.match`); plain substrings work too. Anchor with `^`/`$` for full-line matches. `case_sensitive: true` only when you mean it — default is case-insensitive. Pass `files` to scope the search. Max 200 matches per call; `truncated: true` indicates the cap was hit. Searches the CURRENT version only in v1 — call `read_artifact_file` with `version_id` for historical reads. ⚠️ SIDE EFFECT — drift cursor advances: calling grep_artifact marks the current artifact version as 'seen' by your session. Subsequent patch_artifact / update_artifact / regex_replace_artifact calls are validated against this version (the implicit drift check passes only if the artifact hasn't moved since). This is usually what you want — a successful grep counts as having read enough of the artifact to mutate it next, no extra read_artifact_file required — but if you intend a pure read with no follow-up mutation, be aware your cursor will move. read_artifact_file and content-returning get_artifact also advance the cursor; only `get_artifact({include_content: false})` is fully non-advancing. See also: `read_artifact_file` to expand a specific hit into context (also cursor-advancing). `patch_artifact` to edit once you've located the right anchor. Use `get_artifact` ONLY when you actually need every file (rare). |
| rename_slug | Rename (or claim) the custom slug on an EXISTING artifact. After this call, the artifact lives at `<handle>.drawer.so/<slug>`. The artifact's ID URL keeps working forever, and any previous slug 301-redirects to the new canonical URL. Use when the user says 'rename the URL to /docs', 'put my resume at /resume', 'change the link to /...'. To CLEAR a slug entirely (revert to ID-only URL) and prune the redirect history, call `update_artifact(artifact_id, slug: "")` with an empty string. The slug name is per-user (your own subdomain), so cross-user collisions are impossible. Reclaim semantics — if the slug you're claiming was previously held by a DIFFERENT artifact (that was renamed away from it), the new claim wins and the old redirect is broken. Matches GitHub repo-rename behavior. See also: `update_artifact({slug: "..."})` does the same thing as part of a content update; this tool is the dedicated single-purpose verb. Pass `slug: ""` to `update_artifact` to clear the slug. |
| revert_artifact | Promote a previous version back to current. Creates a NEW version with the old content (so history is preserved — nothing is lost). Use when a recent update or patch was wrong and the user wants to undo it. If to_version_id is omitted, reverts to the version immediately before current ('undo my last change'). Drift is checked automatically based on what this principal has read. If the artifact changed since your last read, you'll get a `version_drift` error — re-read and retry, or pass `force: true` to overwrite (deprecated alias: `acknowledge_drift: true`). See also: use `diff_artifact` first to see what would change. Use `get_artifact` to see the current state. |
| diff_artifact | Compute a unified diff between two versions of an artifact. Returns per-file added/removed/modified status with standard unified-diff text. Use when the user asks 'what changed between v3 and v4?' or before reverting to confirm what's about to be undone. See also: use `revert_artifact` to promote a previous version back to current. Use `get_artifact` for full content. |
| delete_artifact | Permanently delete an artifact and all its versions. This is destructive and not reversible. Always confirm with the user before calling — never delete on your own initiative. See also: to soft-hide an artifact without losing it, use `unpublish_artifact` (sets visibility to private). To revert to an earlier version, use `revert_artifact`. |
| debug_artifact | Diagnostic snapshot for an artifact you own: file list, recent activity, OG card status, last render result, plan quota, and a re-run of the publish-time static checks (unresolved assets, mixed content, missing title). Use this when an artifact appears broken — blank page, no preview card, image not loading — before asking the user what they see. One call returns everything you need to self-diagnose. Owner-only; calls for artifacts you don't own return a `not_found` error (existence is intentionally not leaked). See also: use `get_artifact` for the artifact's actual content; this returns diagnostic metadata only. |
| list_connections | Lists the external service connections (Airtable, Notion, OpenAI, Stripe, etc.) the user has configured. Each connection has a name, allowed hosts, a header template for auth, and the underlying credential value (never returned via MCP). Use these names with `drawer.fetch(name, url, opts)` in HTML artifacts to make authenticated API calls without exposing keys in the browser. Connections are managed in the user's dashboard (Dashboard → Connections); agents cannot create, modify, or delete them. See also: returns the connections the user has configured. To fetch live data through a connection, use `request_data` with the connection's name. |
| request_data | Asks the user to fetch real data from one of their authorized APIs (via a stored connection). Use when you need to see actual schema, response shapes, or API behavior to build a correct artifact. You CANNOT call APIs directly — this tool creates a pending request that the user opens in their browser, reviews, fires, and sends back to you. Returns immediately with a URL the user must open. Then call `wait_for_data(request_id)` to receive the response. Best for read operations (GET). For mutations (POST/PUT/PATCH/DELETE), the user will see a confirmation dialog before the request fires. If the named connection doesn't exist, returns an error with the list of available connection names. Call `list_connections` first if you're unsure. See also: after this returns, call `wait_for_data` with the request_id to receive the response. If you're unsure which connection to name, call `list_connections` first. |
| wait_for_data | Polls for a pending data request to be fulfilled by the user. Blocks server-side for up to 25 seconds (well inside CF Workers' 30s response budget). Returns one of: - {status: 'fulfilled', response: {status, headers, body, ms_elapsed}} — user submitted, here's the data - {status: 'pending', poll_again: true} — user hasn't acted yet; call this tool again immediately to keep waiting - {status: 'expired'} — request timed out (15 min); ask the user to retry - {status: 'cancelled'} — user cancelled the request When you get 'pending', re-call this tool immediately — that's the polling pattern. Don't wait between calls; the tool already blocks. See also: created by `request_data`. If this returns `{status: 'pending', poll_again: true}`, call it again — the user hasn't acted yet. Returns `{status: 'fulfilled'}` when the user has sent the response. |
| request_upload | Get a URL the user can open in their browser to drop a file (image, PDF, HTML, markdown, or zipped multi-file site) and turn it into a Drawer artifact. Use this when the user wants to share a binary or local file you can't generate as text — e.g., 'host this PDF', 'share this screenshot', 'upload my slides'. Returns a URL to the upload page. The user signs in via their normal Drawer session, drops the file, and gets a shareable artifact URL back. The URL goes to a normal dashboard page; no special tokens or expiry. See also: for programmatic creates, prefer `create_artifact` with `files: {...}`. To add a file to an EXISTING artifact (a new version), use `request_upload_to_artifact` (user-supplied bytes) or `add_files_to_artifact` (bytes you already have in context). |
| request_upload_to_artifact | Every successful upload through this tool creates a NEW VERSION of an EXISTING artifact — the artifact id and URL stay the same; only the file map advances. Use this when the user (not you) is going to supply the bytes: 'add this PDF to my deck', 'attach the screenshot to the artifact I made earlier'. Returns a one-time URL the user opens in their browser; they sign in via their normal Drawer session, drop the file, and the file lands as a new version on the target artifact. The pending row expires after 15 minutes (same TTL as `request_data`). When to choose: pick THIS tool when the user has the file (a local PDF, a screenshot on their desktop). Pick `add_files_to_artifact` when YOU already have the bytes in context (e.g. you generated the file or it's part of the conversation). Pick `request_upload` (no suffix) when you want a NEW artifact, not a version bump on an existing one. Path collisions: this tool only mints the URL; the resulting upload always REPLACES whatever path the file lands at (same semantics as the dashboard upload page). If you need finer control (error-on-collision), use `add_files_to_artifact` instead. Owner-only: the caller's principal must own the target artifact. Calls for an artifact you don't own return 404 (existence is intentionally not leaked). Drift: if another principal advances the artifact between this call and the user's drop, the upload still applies — the user's physical hand on the file is treated as the final word. The `force` param exists on `add_files_to_artifact` for the inline path. Allowlist matches the dashboard upload page: HTML, markdown, txt, SVG, PNG, JPEG, WebP, GIF, PDF. CSS/JS belong in multi-file site authoring via `update_artifact`. See also: `add_files_to_artifact` (inline sibling — you supply bytes); `request_upload` (creates a NEW artifact); `update_artifact` for full rewrites; `patch_artifact` for surgical edits. |
| await_upload | Block until the user finishes uploading. Pair with `request_upload_to_artifact` to close the agent's deterministic loop — the agent mints an upload URL, hands it to the user, and calls this tool to learn when (and what) landed without polling `debug_artifact` in a loop. Long-polls server-side for up to `timeout_seconds` (default 60, max 300). Returns one of: - `{status: 'completed', new_version_id, files_landed, full_file_list}` — user finished; here's what landed - `{status: 'pending', expires_at, request_id}` — timed out before completion. Re-call to keep waiting, or relay the URL to the user if you suspect they haven't started - `{status: 'expired'}` — the 15-minute upload window elapsed. Mint a fresh URL with `request_upload_to_artifact` and retry Returns immediately if the upload has already completed (idempotent). Owner-only — `request_id` must belong to the calling user. See also: `request_upload_to_artifact` (mints the upload URL this tool blocks on). |
| add_files_to_artifact | Every successful call to this tool creates a NEW VERSION of an EXISTING artifact, merging the supplied files into its file map. Use this when YOU already have the bytes in context — you generated an HTML report and want to bundle a chart image alongside it, or the conversation already contains the file as a base64 data URI. The artifact id and URL stay the same; only the version advances. When to choose: pick THIS tool when you have the bytes. Pick `request_upload_to_artifact` when the USER has the bytes (a file on their desktop). Pick `create_artifact` with `files:{...}` when you want a NEW artifact, not a version bump on an existing one. Path collisions (`mode`): default `mode:"error"` returns a 409 path_collision listing the colliding paths AND the artifact's existing file list, so you can decide whether to rename your incoming paths or re-issue with `mode:"overwrite"`. `mode:"overwrite"` replaces colliding files; the response separates `added_paths` from `overwritten_paths` for audit. Single → multi-file promotion: if the target artifact is a single file (e.g. one PDF at `index.pdf`) and you add a second file, the original file keeps its current path; new files land at their given paths. The artifact's `entry_file` is preserved — we don't silently rename. If you want different routing, follow up with `update_artifact`. Owner-only: the caller's principal must own the target artifact. Calls for an artifact you don't own return 404 (existence is intentionally not leaked). Allowlist matches the dashboard upload page: HTML, markdown, txt, SVG, PNG, JPEG, WebP, GIF, PDF. CSS/JS belong in multi-file site authoring via `update_artifact`. Per-file inline limit ~500 KB — for larger files, call `request_upload_to_artifact` to hand the user a one-time upload URL. Drift: implicit per-principal drift check applies (same as patch_artifact / update_artifact). If the artifact has moved past your last-seen version, you'll get a `version_drift` error — pass `force: true` to merge (deprecated alias: `acknowledge_drift: true`), or re-read and retry. See also: `request_upload_to_artifact` (back-channel sibling — user supplies bytes); `create_artifact` for new artifacts; `update_artifact` for full rewrites. |
| rename_file_in_artifact | Creates a new version of the artifact. Targets an EXISTING artifact. Don't use for new artifact creation. Moves a single file from `from` to `to`, atomically — one version bump, the file's bytes are preserved verbatim and only its path changes. When to use: an agent uploaded `chart.png` and the user wants it called `figure-1.png`; a previous turn dropped a file at a placeholder path and you want to slot it into the right name. Reach for THIS over `update_artifact` (which would force you to re-send every other file's bytes) or `patch_artifact` (which edits content, not paths). entry_file handling: if `from` is the artifact's entry_file, the new version's entry_file is updated to `to` automatically — the artifact keeps rendering and the response carries `entry_file_updated: true` so you know it changed. Other files' contents are untouched. No overwrite mode: rename-onto-existing is rejected. Renaming onto a path that already exists is almost always a bug (it would silently destroy the target file's contents), so this tool refuses; the agent must delete the target first via `delete_file_from_artifact` or pick a different name. Error codes you can recover from: - `file_not_found` (404): `from` doesn't exist in the artifact. The response includes `path` and `file_list` so you can pick the right one without a fallback `get_artifact` round-trip. - `path_collision` (409): `to` already exists. The response includes `path` (the colliding target) and `file_list`. Either delete the target first with `delete_file_from_artifact`, or pick a different `to`. Paths: `to` must pass the same validation as `add_files_to_artifact` — relative path only, no `..`, no backslash, no scheme, ≤256 chars. Owner-only: calls for an artifact you don't own return not_found (existence is intentionally not leaked). Drift: implicit per-principal drift check applies (same as `patch_artifact` / `add_files_to_artifact`). If the artifact moved past your last-seen version, you'll get `version_drift` — pass `force: true` to rename (deprecated alias: `acknowledge_drift: true`), or re-read and retry. See also: `add_files_to_artifact`, `request_upload_to_artifact`, `update_artifact`, `patch_artifact`, `debug_artifact`. |
| delete_file_from_artifact | Creates a new version of the artifact. Targets an EXISTING artifact. Don't use for new artifact creation. Removes a single file from the artifact's file map, atomically — one version bump, every other file's bytes are preserved verbatim. Old versions remain readable (the historical version still has the file in its R2 snapshot), so the deletion only affects the artifact's current version — earlier versions still surface the file via `read_artifact_file` and `revert_artifact`. When to use: drop a stale asset the agent added in a previous turn; remove a file the user no longer wants in the bundle. Reach for THIS over `update_artifact` (which would force you to re-send every remaining file's bytes) when you just want one file gone. entry_file handling: refuses to delete the artifact's entry_file. Deleting the file the viewer renders would silently break the artifact, so the tool returns `cannot_delete_entry_file` and points you at `rename_file_in_artifact` (move entry to a different file first) or `update_artifact` (change entry_file). Empty-artifact guard: refuses to delete the last remaining file. An artifact must have at least one file; the response carries `would_leave_artifact_empty` and points you at adding a file first (`add_files_to_artifact`) or deleting the artifact entirely (`delete_artifact`). Error codes you can recover from: - `file_not_found` (404): `path` isn't in the artifact. The response includes `path` and `file_list` so you can pick the right one without a fallback `get_artifact` round-trip. - `cannot_delete_entry_file` (400): the file you targeted is the entry_file. Hint: rename entry to a different file first via `rename_file_in_artifact`, or change entry_file via `update_artifact`. - `would_leave_artifact_empty` (400): deleting this file would leave the artifact with zero files. Hint: add another file first via `add_files_to_artifact`, or delete the whole artifact via `delete_artifact`. Owner-only: calls for an artifact you don't own return not_found (existence is intentionally not leaked). Drift: implicit per-principal drift check applies (same as `patch_artifact` / `add_files_to_artifact`). If the artifact moved past your last-seen version, you'll get `version_drift` — pass `force: true` to delete (deprecated alias: `acknowledge_drift: true`), or re-read and retry. See also: `add_files_to_artifact`, `request_upload_to_artifact`, `update_artifact`, `patch_artifact`, `debug_artifact`. |
| get_comments | List comments on an artifact. Returns the comment thread with author, version_id (the artifact version each comment was posted against), agent/human attribution, resolved state, plus the v0.11 anchoring fields needed to act on review feedback. Use when the user asks 'what comments are on this?', 'did anyone reply?', or before posting a follow-up so you can see the thread. Each comment in the response carries: - `anchor`: parsed object when pinned. Discriminated by `anchor.type`: - `text-range`: `{ v:1, type:'text-range', exact, prefix, suffix, selector_hint? }` (W3C text-quote pin). - `element`: `{ v:1, type:'element', selector, label, text_excerpt }` (pinned to a structural element via CSS selector — use `anchor.selector` to locate it in the source). `null` for a whole-artifact (sidebar) comment. Already deserialized — no JSON.parse needed. - `anchored_text`: convenience flat field. text-range = `anchor.exact`; element = `anchor.text_excerpt || anchor.label`; `null` when unanchored. Read this first. - `parent_comment_id` + `parent_body`: on replies, the parent's body is inlined (truncated to 200 chars) so you have thread context without a follow-up call. Both null on top-level comments. - `version_drift`: true when the comment was posted on an older version than current. Acting on an anchored comment: read `anchored_text` to see the snippet the reviewer pinned to, then call `grep_artifact` (or `read_artifact_file` if you already know the file) to locate that exact text in the source, then apply the fix. Replies should be read alongside their `parent_body` so you understand the thread. Respects artifact visibility: the calling user must be able to see the artifact (owner, grantee on a private artifact, or visitor on unlisted/public — plus the password unlock cookie when one is set). Returns 404 when the artifact doesn't exist, when the caller can't see it (no existence leak), or when the comments feature is disabled for the calling account. See also: `post_comment` to add a comment; `set_comment_settings` to toggle whether the artifact accepts comments. |
| post_comment | Post a new comment on an artifact. The comment is auto-flagged `via: 'agent'` and rendered with an `[AI]` badge on the viewer. Plain text only in v1 — links are auto-detected; markdown is not parsed. Comment is anchored to the artifact's current version so the viewer can label it 'Posted on v3' once the artifact moves forward. Pass `anchor` to pin the comment. Two anchor shapes: - `text-range` (W3C text-quote): `exact` + `prefix`/`suffix` context + optional `selector_hint`. For prose feedback on specific words/sentences. - `element` (structural): `selector` + `label` + `text_excerpt`. For feedback on a block-level element (a paragraph, card, chart, etc.). The selector wins on re-anchor — if the author rewrites the paragraph's text, the comment stays on the same paragraph. Anchored comments render as inline pins on the viewer; unanchored comments stay in the side panel. Pass `parent_comment_id` to reply to an existing comment (one level deep — replies cannot themselves be replied to). Drift discipline: posting on a stale version (you last read v3, current is v5) returns a `version_drift` error with the new current id. Re-read the artifact (or call grep / read_artifact_file on the changed sections), then either retry or pass `force: true` to post against the new current without re-reading (the deprecated alias `acknowledge_drift: true` still works). The target artifact must have comments enabled. If the user hasn't turned them on for the artifact, the call returns a `comments_disabled` error — call `set_comment_settings(artifact_id, enabled: true)` to enable, or relay the error to the user. See also: `get_comments` to read the existing thread first; `set_comment_settings` to enable comments on an artifact the user owns. |
| set_comment_settings | Enable or disable comments on an artifact you own. Comments default to OFF on every artifact — call this with `enabled: true` to turn them on when the user asks 'let people comment on this', 'turn comments on', 'open this for feedback'. Creator-only — calls against an artifact you don't own return `not_found` (existence is not leaked). Disabling comments hides the viewer's side panel and rejects new posts with `comments_disabled`; existing comments are NOT deleted and re-enabling restores the thread untouched. See also: `post_comment` to add a comment once enabled; `get_comments` to read the existing thread. |
| duplicate_artifact | Duplicate an existing artifact into a NEW artifact owned by the calling user. Use this when the user asks 'start from this template', 'fork this', 'make my own copy', or 'use this as a starting point'. The copy carries the source's current-version files (byte-exact) + title + display settings; version history, comments, password, and per-artifact toggles (comments_enabled, duplicate_enabled, visibility) are NOT inherited — the new artifact starts as private with all toggles off, regardless of the source. Safety: Connections, API keys, and secrets are NEVER copied. The duplicate starts with an empty connection allowlist; any runtime integrations need to be wired by the new owner. Gating: - Source must be discoverable to the caller. Private artifacts can only be duplicated by their owner ('save as new' pattern); unlisted/public artifacts can be duplicated by anyone, but ONLY when the source owner has flipped `duplicate_enabled: true` on it. - Password-protected artifacts are refused outright in v1 (returns `forbidden`). - Source-not-found and not-allowed (non-owner against a private source) both collapse to `not_found` so existence is never leaked. - Quota: counts as a new artifact for the caller; over-quota returns `payment_required`. The new artifact carries a `duplicated_from` pointer back to the source — the viewer renders 'Duplicated from @<handle>/<id>' on every duplicate so attribution is preserved. See also: `set_duplicate_settings` is reserved; for v1 the duplicate toggle on an artifact you own flips via the dashboard or the `PUT /api/artifacts/:id/duplicate-settings` REST endpoint. |
纠错与举报(发现条目失效、署名有误或涉及侵权?)
提交举报 / 纠错
侵权举报经核验成立后,我们会即时下线该条目并删除已存的内容副本。