Stop the desktop preview from autosaving files it cannot decode losslessly
Nobody has claimed this yet.
Assessment
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Newbie friendliness
- 54/100
- Issue type
- Bug
- Clarity
- Clearly specified
- Activity status
- Active
- Tech stack
- tauri, typescript
- Domain
- backend-api-design, desktop, testing
Research direction
Start with apps/kiki-gui/src/state/hostFileEditor.ts and its tests to trace how loading, autosave, blur, and visibility saves work; then read packages/klient/src/transports/http/rest.ts and packages/klient/test/http-rest.test.ts for preview decoding. Add the opt-in edit and lossless-read checks described in the issue, then verify the listed controller and transport cases. Done means unsafe or remote files cannot be edited, while eligible local UTF-8 files save only after edit mode begins and existing conflict behavior remains intact.
Written by the indexing model from the issue text.
Description
What version of Kiki is running?
Current kiki branch source; the behaviour is in the code, not tied to a release.
Which open platform/subscription were you using?
Not relevant; no model call is involved.
Which model were you using?
Not relevant.
What platform is your computer?
Kiki desktop app on any OS (the browser GUI cannot write files, so it is not affected).
What issue are you seeing?
In the desktop app, every text preview tab is a live editor that autosaves five seconds after the last keystroke, and also when the window loses focus or the page is hidden. The preview reads the file with a lossy UTF-8 decode and treats every file without an extension as text. So a GBK- or Latin-1-encoded text file, or an extension-less binary (for example an ELF executable), opens as garbled but writable text. One accidental keystroke, and five seconds later the file is written back as UTF-8 and the original bytes are gone. In an SSH space the same editor accepts typing and shows the unsaved dot, and then every save fails with an English message ("This is an SSH workspace. Use a remote server operation, not a local file or directory action.").
What steps can reproduce the bug?
- In the desktop app, open a preview of a text file saved in GBK (or any non-UTF-8 encoding), or of an extension-less binary such as a compiled executable.
- The content shows as garbled text; the editor is writable.
- Type one character and wait five seconds, or switch to another window.
- The file on disk is now the UTF-8 encoding of the garbled text.
- Separately, connect the desktop app to an SSH space, open any text file in the preview, type, and press save: the save fails.
What is the expected behavior?
Editing in the preview is opt-in and safe:
- Editing exists only on the local desktop (the device is the computer running Kiki, and the host can write files), and only after the user presses an explicit "编辑" / "Edit" in the header. Until then the editor is read-only and nothing is ever written.
- Autosave runs only after the user has entered edit mode for that tab.
- A file is never editable when its bytes do not decode losslessly as UTF-8, when it was truncated for preview, or when its type is unknown. Extension-less files count as unknown unless their name is a known text file name (for example
Makefile,Dockerfile) and they decode losslessly. - When the desktop could normally edit but this file cannot, the header shows one short reason instead of the "Edit" button, for example "只读:不是 UTF-8 文本" / "Read-only: not UTF-8 text"; the always-on "在桌面应用中打开即可编辑。" ("Open in the desktop app to edit.") strip is not shown for this case.
- SSH spaces, remote spaces, paired devices and web-entry browsers never show "Edit".
- What stays as it is: the save-time re-read and compare, which stops on a disk change and offers overwrite, reload or keep editing; the confirm before closing a tab with unsaved changes; keeping the draft when the panel is collapsed.
Where
packages/klient/src/transports/http/rest.ts:712-725(readHostFileandpreviewHostFileuseresponse.text(), which replaces invalid bytes silently). ChangepreviewHostFileto read the bytes, decode withnew TextDecoder('utf-8', { fatal: true }), and return{ text, truncated, lossless, etag }; when strict decoding fails, return the lossy text withlossless: false. Carry the server error code through unchanged (FS_PATH_NOT_FOUND404,FS_PERMISSION_DENIED403,FS_IS_DIRECTORY409,local_owner_required403) so the GUI can tell the cases apart.apps/kiki-gui/src/lib/client.ts:2185-2187(previewHostFilewrapper) passes the new fields through.apps/kiki-gui/src/state/hostFileEditor.ts:53-54(5 s autosave, 512,000-character limit),:74-80(blur and visibility listeners),:82-84(editableis only "has a write channel and not oversized"),:93-118(load),:225-246(blur/visibility save and autosave timer). Add: aneditingflag that starts false;beginEdit()that succeeds only when the file is editable;editableadditionally requireslossless, a known text type and a caller-suppliedlocalflag; blur, visibility and timer saves do nothing unlesseditingis true. Also addreload()and a read-failure reason (from the error code) on the snapshot; the views that use them are a separate issue.- The text tab view after the split (today
apps/kiki-gui/src/components/PreviewWorkspace.tsx:2044-2060creates the controller withwriteFile: host.writeFileText;:2262-2272save button;:2319-2340the read-only strip). PasslocalfromisKikiComputerinapps/kiki-gui/src/state/previewResource.ts, render the "Edit" button and the read-only reason. packages/session-core/src/composer/media.ts:680-705(extOf,previewKindOf; extension-less files default totextat line 703) is read-only context here; the type table itself is changed in the read-states issue.- Desktop write path for reference:
apps/kiki-gui/src/host/tauri.ts:370-373andapps/kiki-gui/src-tauri/src/lib.rs:2649-2652(a plainfs::write). - New strings go into both
packages/session-core/src/i18n/en.tsandzh.ts(add keys only).
Done when
-
hostFileEditor.test.tsproves: no write happens beforebeginEdit(), even with a dirty buffer, a timer expiry, a blur and a visibility change;beginEdit()fails forlossless: false, a truncated read, an unknown type andlocal: false; afterbeginEdit()the existing autosave and conflict behaviour is unchanged. - A test in
packages/klient/test/http-rest.test.tsshowspreviewHostFilereportslossless: falsefor GBK bytes and for an ELF header,truefor UTF-8 text, and returns theetagheader. - In the desktop app (checked by hand, since the browser harness cannot write files): a GBK file and an extension-less binary show the read-only reason and no "Edit"; a UTF-8 source file shows "Edit", and only after pressing it does autosave write; an SSH space shows no "Edit".
- Desktop and phone width screenshots from
apps/kiki-gui/scripts/visual-proof.mjswith a mocked desktop host show the header with "Edit" and with the read-only reason, in en and zh. -
pnpm --filter @kiki/klient test:fast,pnpm --filter @kiki/gui typecheckandpnpm --filter @kiki/gui test:fastpass. - Phone-width screenshots are taken in a touch context (
isMobile: true, hasTouch: true, asapps/kiki-gui/scripts/visual-proof-mobile-reading.mjs:294-300does). Phone mode is(pointer: coarse) and (max-width: 639px)(apps/kiki-gui/src/lib/layoutHooks.ts:57), so a width-only--viewport narrowrun ofvisual-proof.mjsshows the desktop layout squeezed, not the phone layout.
Additional information
The write-back was established by reading the code (lossy decode, extension-less files as text, autosave on timer, blur and hide, fs::write on the desktop); the garbled-but-editable view of an ELF file was seen in the browser build, but the write itself was not executed in the desktop shell. This issue starts after the split of PreviewWorkspace.tsx, and the read-states issue edits the same text view afterwards. apps/kiki-gui/src/lib/client.ts also carries a small change from the pending GUI interaction and mobile pass; start from a branch that includes it.
Order and scope. Paths and line numbers refer to the code after the pending GUI interaction and mobile pull request is merged into kiki.
Depends on: #27, #30.
Main files: packages/klient/src/transports/http/rest.ts, packages/klient/test/http-rest.test.ts, apps/kiki-gui/src/lib/client.ts, apps/kiki-gui/src/state/hostFileEditor.ts, apps/kiki-gui/src/state/hostFileEditor.test.ts, apps/kiki-gui/src/components/preview/TextTabView.tsx, packages/session-core/src/i18n/en.ts, packages/session-core/src/i18n/zh.ts.
- Dominant language
- TypeScript
- Stars
- 54
- Forks
- 5
- Avg merge
- 2h 54m
- Merged PRs (30d)
- 2
Getting set up
- No Dockerfile or Docker Compose file
- Has a pull request template
- Read the contributing guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
More from X-T-E-R/kiki
-
Document PowerShell shell semantics and read-only Bash deduplication in Built-in Tools referenceOpendocumentation
Difficulty 2/5 1-3 hours Newbie friendliness 78/100
-
bug documentation
Difficulty 2/5 1-3 hours Newbie friendliness 74/100
-
bug
Difficulty 4/5 3-5 days Newbie friendliness 54/100
-
enhancement
Difficulty 5/5 Over a week Newbie friendliness 1/100
-
documentation
Difficulty 5/5 Over a week Newbie friendliness 25/100
Similar issues
-
area: cli priority: P3 type: bug
Difficulty 2/5 1-3 hours Newbie friendliness 78/100
appandflow/stim#5640 · 1 comment ·
Maintainers usually reply within 1 day
-
Claude Code: hook systemMessage lines never reach the chatPossibly taken @chphch claimed this today. Open
Difficulty 2/5 1-3 hours Newbie friendliness 78/100
slopus/happy-agent#139 ·
Maintainers usually reply within 1 day
-
Difficulty 2/5 1-3 hours Newbie friendliness 68/100
NangoHQ/nango#8285 · 1 comment ·
Maintainers usually reply within 1 day
-
community first-timers-only good first issue hacktoberfest help wanted low hanging fruit up-for-grabs
Difficulty 1/5 Under an hour Newbie friendliness 85/100
lingdojo/kana-dojo#34009 · 1 comment · 5 reactions ·
Maintainers usually reply within 1 day
-
Difficulty 2/5 1-3 hours Newbie friendliness 73/100
paperclipai/paperclip#21197 ·
Maintainers usually reply within 1 day