Patch Changes
-
Path containment holds on Windows.
The check that keeps agent tools inside the project root compared the resolved relative path against a literal
../prefix. On Windows the separator is a backslash, so a traversal written as..\was not recognised and the path was treated as contained.execdoes sandbox its shell to a root, but that root is whatever thecwdargument resolved to. When thecwditself escaped, the sandbox was faithfully rooted at the escaped directory and had nothing left to catch. That asymmetry is what made this reachable.Separators are now normalised before the check. Absolute paths, other drives, and UNC shares were already refused and still are. Windows was the only platform at risk, though one behaviour changes everywhere: a file whose name literally begins with
..\is now refused as well. -
Detailed diagnostic bundles now collect the macOS crash reports the OS wrote for the app and its helpers, so an ending the app could not record itself can still be attributed.
When the operating system ends one of the app's processes, it writes its own report naming the cause: the signal or exception, the code-signing verdict, and whatever text the process left behind as it died. That record exists whether or not a crash handler ran to leave a dump, which is what makes it the only account of a whole class of endings, and those files were not being collected. A Detailed-level bundle now carries the matching ones under
diagnostic-reports/, alongside astate/diagnostic-reports-status.txtrecord that says what the search found even when the answer is nothing, so a triage can tell "the OS recorded nothing" from "nobody looked".Only this app's own reports are collected, never another application's, and they pass through the same redaction and secret-scrubbing as every other bundled file. macOS stores paths in these reports with every forward slash escaped, which the scrub cannot read, so a report is normalised as it enters a bundle rather than inside any one pass over it. The identifiers that link one machine's bundles to each other are replaced at the same point: measured over a year of real reports,
crashReporterKeyheld one distinct value andbootSessionUUIDtwo, so either re-identifies a user across every bundle they file. The per-incident id and the sleep/wake id are kept, since those are what correlating reports inside a bundle actually uses. The bug-report dialog's Detailed-diagnostics description, shown only on macOS, and the "What OpenKnowledge writes" reference both name the new category and what a report carries.ok diagnose bundlecollects them too, and prints what the search found before it writes the zip. -
Agent
execcan no longer write to the project.execis documented read-only, and that promise was enforced by comparing each argument against a list of blocked flags. The comparison was exact, so it caughtsort -o notes.mdand missedsort -onotes.md— the same flag with its value attached, whichsortaccepts. A command that only reads was able to create a file, and to replace an existing document with the contents of another:sort -oimportant.md other.mdNothing about that goes through
writeoredit, so the replacement carried no attribution and left no history to restore from.sortis the only one of the ten allowed commands whose-owrites, so the guard is scoped to it and now covers the flag however it is spelled, including bundled forms like-ro.--output-delimiter, which only changes how output is printed, keeps working. A bare-oon its own stays refused for every command, as it was before this change, sogrep -ostill asks for--only-matchinginstead; the clustered forms it appears in, such asgrep -oE, are unaffected.A companion suite runs every write and delete attempt we know of through the real command pipeline and asserts the project is byte-identical afterwards, so the read-only promise is checked rather than assumed.
-
A document whose last block is a table, list, or code fence no longer grows a blank line at the end of the file that nobody typed.
The visual editor used to keep an empty paragraph below such a block so there was somewhere to click. That paragraph was a real part of the document rather than a piece of interface, so it serialized to a blank line and landed on disk, and an MD012 lint warning came with it.
That paragraph is gone. In its place, hovering the empty space below the final block shows the same plus you already see beside every other block, at the same spot in the gutter. Clicking anywhere in that space adds the line and puts the cursor in it, so the newline in your file is one you asked for. On a touch device, where there is no hover to read, the plus stays visible whenever the space is there to use, and on a narrow screen it sits at the left edge of the text rather than out in the gutter. Arrow keys still move past the final block as before, and the cursor that lands there is now visible on the dark theme instead of drawing in black.
Two things worth knowing. A file that already picked up the extra blank line keeps it, because OpenKnowledge no longer removes trailing blank lines it did not write. Clear it with Auto-fix in the Problems panel, with
ok lint --fix, or by hand. And Backspace immediately after a list autoformats (typing-and getting a bullet) now restores the literal characters you typed no matter where you are in the document. It used to do something different on the last line than everywhere else.
Downloads
| Platform | Architecture | Download |
|---|---|---|
| macOS | Apple Silicon | OpenKnowledge-arm64.dmg |
| Windows | x64 | OpenKnowledge-Setup-x64.exe |
| Windows | arm64 | OpenKnowledge-Setup-arm64.exe |
| Debian / Ubuntu | x64 | OpenKnowledge-amd64.deb |
| Debian / Ubuntu | arm64 | OpenKnowledge-arm64.deb |
| Fedora / RHEL | x64 | OpenKnowledge-x86_64.rpm |
| Fedora / RHEL | arm64 | OpenKnowledge-aarch64.rpm |