feat(skills): read-only built-in skills; fix(chat): allow CSV attachments - #11
Merged
Conversation
Needs ragent-service (`SkillResponse.is_managed`). Built-in skills are maintained in the backend repo and sync in with each release, so nobody can edit them — **including super admins**. That rule sits first in `canEditSkill`: its answer is the same for everyone, and letting a super admin through wouldn't be granting power, it would be handing them work that the next sync silently overwrites. ## What changes visually - List: a 「平台维护」badge next to the display name (hover explains it), and the row's actions collapse to 查看 - Detail: the title reads 查看 Skill, not 编辑 Skill — calling it "edit" when nothing on the page can be edited is a lie - Detail: save / publish / submit-review are **removed**, not disabled — a row of greyed-out buttons invites repeated clicking on something that will never work. In their place, one sentence saying why, so the missing buttons don't read as a broken page - The four content fields are disabled; the assets panel follows `canEditSkill` `is_managed` missing (older backend) is treated as a normal skill — a field that hasn't shipped yet must not lock down every skill. ## Verified in the browser Against a backend carrying the new field: zero write buttons on a built-in skill, all four content fields disabled, and the two remaining editable inputs are the dependency picker's search boxes. Two display bugs found and fixed there — the badge squeezed the display name into one character per line, and the stale title. 232 tests (+3), including the one pinning "super admin cannot edit either" — the rule most likely to get loosened later by someone who knows super admins pass everywhere else. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…e list CSV was rejected in chat even though the backend has supported it all along (file_processing_service.supported_extensions has a .csv handler, and upload-confirm already labels it). Two front-end gates blocked it, and they were two separately-maintained lists — the accept attribute on the file input and a MIME allowlist in useFileAttachments. Both had drifted and both were missing .csv, so adding the extension to just one of them would have produced a file you can pick but cannot upload. Merged them into lib/chatAttachments.ts and derived accept from the extension list, so they cannot diverge again. Validation is now extension-first with MIME as fallback. file.type comes from the OS type registry and differs per machine for CSV: text/csv on macOS, application/vnd.ms-excel on Windows with Excel installed, sometimes empty. A MIME-only check would have made this work on one machine and fail on a colleague's with no visible reason. The .ai special case existed for exactly this reason and is now the general rule. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Read-only built-in skills, and CSV attachments in chat
Two independent changes, both small and both front-end only.
1. Read-only state for built-in skills
The backend gains
is_managed— skills that ship with the platform and syncfrom the repo on each release. Users cannot edit or delete them.
The UI says why rather than making buttons vanish. A missing button reads as
a permission problem, and a user will go ask an admin for access that nobody
has. So the list shows a 「平台维护」 badge and a 查看 button, and the editor
drops its write actions instead of disabling them — a disabled button still
invites clicking.
canEditSkillchecksis_managedfirst, ahead of the super-admin branch.Super admins cannot edit these either: the constraint is not about privilege
level, it is that any edit gets silently overwritten by the next sync.
Falls back safely if the backend is older —
is_managedundefined means theskill is treated as ordinary.
2. CSV attachments in chat
CSV was rejected in chat although the backend has supported it all along
(
file_processing_service.supported_extensionshas a.csvhandler, andupload-confirmalready labels the type). Nothing on the server side blockedit; the presign endpoint does not check types at all.
Two front-end gates did, and they were two separately-maintained lists:
the
acceptattribute on the file input, and a MIME allowlist inuseFileAttachments. Both had drifted and both were missing.csv. Addingthe extension to only one of them produces a file you can pick but cannot
upload — so they are now merged into
lib/chatAttachments.ts, withacceptderived from the extension list. They cannot diverge again, and a test asserts
it.
Validation is now extension-first with MIME as fallback.
file.typecomesfrom the OS type registry and differs per machine for CSV:
text/csvonmacOS,
application/vnd.ms-excelon Windows with Excel installed, sometimesan empty string. A MIME-only check would work on one machine and fail on a
colleague's with nothing in the error to explain why. The
.aispecial caseexisted for exactly this reason; it is now the general rule rather than a
per-type patch.
MIME is kept as a fallback for files with no extension — pasted screenshots.
The list is aligned with the backend's supported extensions: anything that
uploads can be read by
extract_document_text.Tests
244 passed (was 229).
tscreports 135 errors against a baseline of 134; theextra one is
TS5097on the new test file, the same error the repo's other 18test files already produce (tests run under
--experimental-strip-types, whichrequires the
.tssuffix thattscrejects).Mutation-verified: dropping
.csvfrom the list turns 4 red; reverting toMIME-only turns 6 red; changing
endsWithtoincludes(which would letnote.csv.exethrough as a CSV) turns 1 red.Note on pairing
The read-only half pairs with the backend PR that adds
is_managed. Mergingthis first is harmless — the badge simply does not appear until the backend
ships. The CSV half is independent of both.
🤖 Generated with Claude Code