Repository navigation
feat: publish an image or a video with stele attach - #9
Conversation
The server has stored attachments since it learned to, and its skill document already tells agents to run this command — so until now the live contract named a command that did not parse. That is the same failure `--ttl` had, in the other direction: last time the document was stale, this time the client was. The request is a `publish` with a binary content type, because on the server an attachment is a page whose body is bytes. What earns it a command of its own is the answer, not the request. An attachment has two URLs — the bytes under `/static/`, and a viewer page about the file — and mixing them up fails silently, because an `<img>` pointed at the viewer renders nothing and both answer 200. So stdout is the bytes, which is the value `src=$(stele attach chart.png)` captures and the one a page-writing agent needs; the viewer goes to stderr under the deadline, for the human who wants to send someone a link. `--json` names both and calls neither of them `url`. That key means "the viewer" on every other command, so whichever meaning it took here would be wrong half the time and wrong silently — a caller reaching for `.url` would get a working URL of the wrong kind. Absent, they get nothing, which is a failure they can see. An unrecognised extension is refused before the upload rather than guessed at. `publish` may fall through to `text/html` because that is what it is for; the same shrug on a JPEG spends the upload and comes back as a 415 naming a type nobody chose. `--filename` defaults to the file's own basename and is omitted rather than refused when that name is one the server would reject — the caller never typed it, and the server's fallback is a working download where a 400 about an unpassed parameter is not. An explicit `--filename` travels untouched. Exit 6 and its two messages widen to cover an attachment. The status is the same and the code stays one, because the caller's next move has the same shape either way; what differs is the advice, and 413 now carries both halves rather than telling someone with an oversized video to drop their inline images. 0.4.0, in this commit: the server version-gates on the User-Agent, and a capability its skill references should be a version an operator can require. Co-Authored-By: Claude Opus 5 <[email protected]>
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Free Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
Note 🎁 Summarized by CodeRabbit FreeYour organization is on the Free plan. CodeRabbit will generate a high-level summary and a walkthrough for each pull request. For a comprehensive line-by-line review, please upgrade your subscription to CodeRabbit Pro by visiting https://app.coderabbit.ai/settings/billing. Comment |
The server has stored attachments since it learned to, and its skill document — the one
stele skillproxies live — already tells agents to runstele attach. Until now that command did not parse, so the live contract named a tool that did not exist. It is the same failure--ttlhad, in the other direction: last time the document was stale, this time the client was.The request is a
publishwith a binary content type, because on the server an attachment is a page whose body is bytes. What earns it a command of its own is the answer, not the request. An attachment has two URLs — the bytes under/static/, and a viewer page about the file — and mixing them up fails silently, because an<img>pointed at the viewer renders nothing and both answer 200. So stdout is the bytes, which is the valuesrc=$(stele attach chart.png)captures and the one a page-writing agent needs; the viewer goes to stderr under the deadline, for the human who wants to send someone a link.--jsonnames both and calls neither of themurl. That key means "the viewer" on every other command, so whichever meaning it took here would be wrong half the time and wrong silently — a caller reaching for.urlwould get a working URL of the wrong kind. Absent, they get nothing, which is a failure they can see.An unrecognised extension is refused before the upload rather than guessed at.
publishmay fall through totext/htmlbecause that is what it is for; the same shrug on a JPEG spends the upload and comes back as a 415 naming a type nobody chose.--filenamedefaults to the file's own basename and is omitted rather than refused when that name is one the server would reject — the caller never typed it, and the server's fallback is a working download where a 400 about an unpassed parameter is not. An explicit--filenametravels untouched, because there the caller has an opinion and the server is the one that gets to answer it.Exit 6 and its two messages widen to cover an attachment. The status is the same and the code stays one, because the caller's next move has the same shape either way; what differs is the advice, and 413 now carries both halves rather than telling someone with an oversized video to drop their inline images.
Version goes to 0.4.0 in this commit. The server version-gates on the User-Agent, and a capability its skill document references should be a version an operator can require.
Checks
swift test— 168 tests in 18 suites, all passing.swift build -c releaseclean, no warnings.The executable has no test target, so the command itself was verified by driving the built binary against a stand-in server that records what it was sent. Confirmed on the wire:
POST /pageswithContent-Type: image/png,?filename=derived from the basename, PNG magic bytes intact,?slug=/?ttl=/?filename=all travelling together, an explicit--content-typeoverriding inference, andpublishstill sendingtext/htmlwith no filename. Confirmed in the output: stdout is one line and it is the/static/URL, stderr carries the deadline and the viewer,--jsonemitsbytes/viewer/slug/expiresand nothing on stderr, and an unknown extension exits 1 before any request is built.Against the real deployment
stele attachcurrently exits 6 —stele.olympus.lanpredates the attachment support and answersAllowed: text/css, text/html, text/markdown, text/plain. The error path is therefore verified end to end against a real server; the success path is not, and cannot be until that deployment is updated.scripts/integration-smoke.shgains section 4c, which covers the whole of it — byte-identical fetch-back, both URLs and their content types, theContent-Dispositionfilename, the refusal, andstele deletereaching an attachment. It has not been run, for the same reason.🤖 Generated with Claude Code