Skip to content

feat(skills): edit text assets in place - #15

Merged
squarezw merged 1 commit into
mainfrom
feat/edit-asset-inline
Aug 11, 2026
Merged

feat(skills): edit text assets in place#15
squarezw merged 1 commit into
mainfrom
feat/edit-asset-inline

Conversation

@squarezw

Copy link
Copy Markdown
Owner

Changing one character in a script meant downloading the file, editing it and
re-uploading. That is how a BASE_URL with a missing character sat inside a
published skill for a while. The preview dialog now has an edit mode.

No backend change. PUT /skills/{id}/assets/{path} was already an upsert of
the whole file, so "edit" is a different entry point rather than a different
operation. The full body still goes over the wire on save; that gap between what
the user does and what is transmitted is fine and does not justify a second,
incremental endpoint.

Two hard limits, both about silently corrupting a file

Extracted into lib/assetEditGuard so they are testable rather than buried in
JSX — they are data-safety decisions, not presentation details.

  • Truncated content cannot be saved. The preview keeps only the first 200k
    characters. Saving that erases the rest of the file — and the PUT succeeds, and
    the UI says "saved", and nothing anywhere reports a problem. You would find out
    the next time you opened the file. The editor is withheld, with a line saying
    why.
  • Images and Office files cannot be edited as text. The bytes are already
    ruined by the time they have been read as a string.

Mutation-verified three ways: removing the truncation guard, the binary guard, or
the permission check each turns the suite red.

kind is echoed back verbatim

Typed as string rather than narrowed to SkillAssetKind. PUT is an upsert, so
a wrong kind silently reclassifies a script as a reference — it stops being
executed and nothing errors. Narrowing would force a future backend kind to be
mapped onto some known value, which is exactly that failure.

Edit mode also states that saving writes to the draft and that a published skill
drops back to draft pending review. Without that line the natural assumption is
that the change is already live.

The dialog collapsed, and two fixes for it were wrong

DialogContent's base classes contain grid. twMerge does not treat grid
and flex as conflicting — they belong to the display and flex-direction
groups — so both survive into the DOM. In the compiled CSS, .grid is defined
after .flex at equal specificity, so display: grid wins and the entire flex
chain (flex-1, min-h-0, flex-col) was dead code.

That is why two rounds of tuning flex properties changed nothing on screen. The
first attempt blamed flex-basis: 0 collapsing inside an auto-height container —
wrong layer entirely. The second found the real cause but reached for !flex,
which turned out never to be generated.

Layout is now inline styles. They beat any class, so there is no arguing with
class order, and no dependency on whether an important-prefixed utility compiles.

Not verified

The rendered dialog was not measured. The asset panel needs a logged-in session,
which is not automatable from here. The layout diagnosis is evidence-based — the
positions of .grid and .flex were read out of the compiled CSS — but the
final appearance was confirmed by the repo owner in a browser, not by me.

258 passed. tsc unchanged at 112 non-TS5097 errors.

🤖 Generated with Claude Code

Changing one character in a script meant downloading the file, editing it, and
re-uploading — which is how a wrong BASE_URL sat in a published skill for a
while. The preview dialog now has an edit mode.

No backend change. `PUT /skills/{id}/assets/{path}` was already an upsert of the
whole file, so "edit" is a different entry point rather than a different
operation. The whole body still goes over the wire on save; that mismatch
between what the user does and what is transmitted is fine and does not justify
a second, incremental endpoint.

## Two hard limits, both about silently corrupting a file

Extracted into `lib/assetEditGuard` so they are testable rather than buried in
JSX:

- **Truncated content cannot be saved.** The preview keeps only the first 200k
  characters. Saving that would erase the rest of the file, and the PUT would
  succeed, and the UI would say "saved" — nothing anywhere reports a problem.
  The editor is withheld in that case, with a line saying why.
- **Images and Office files cannot be edited as text.** The bytes are already
  ruined by the time they have been read as a string.

Mutation-verified three ways: dropping the truncation guard, the binary guard,
or the permission check each turns the suite red.

`kind` is echoed back exactly as the server sent it, typed as `string` rather
than narrowed to `SkillAssetKind`. PUT is an upsert, so a wrong `kind` silently
reclassifies a script as a reference — it stops being executed, and nothing
errors. Narrowing would force a future backend kind to be mapped onto some known
value, which is precisely that failure.

Editing shows that saving writes to the draft, and that a published skill drops
back to draft and needs review again. Without it the natural assumption is that
the change is live.

## The dialog collapsed, and the first two fixes were wrong

`DialogContent`'s base classes contain `grid`. `twMerge` does not treat `grid`
and `flex` as conflicting — they belong to the `display` and `flex-direction`
groups — so both survive into the DOM, and in the compiled CSS `.grid` is
defined after `.flex` at equal specificity. `display: grid` wins, and the entire
flex chain (`flex-1`, `min-h-0`, `flex-col`) was dead code.

That is why two rounds of adjusting flex properties changed nothing. The first
attempt blamed `flex-basis: 0` collapsing inside an auto-height container. The
second found the real cause but reached for `!flex`, which turned out never to
compile.

Layout is now expressed with inline styles: they beat any class, so there is no
arguing with class order or with whether an important-prefixed utility got
generated.

258 passed. `tsc` unchanged at 112 non-TS5097 errors.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@squarezw
squarezw merged commit 4f9419c into main Aug 11, 2026
1 check passed
@squarezw
squarezw deleted the feat/edit-asset-inline branch August 11, 2026 09:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant