Skip to content

Tags: inkeep/open-knowledge

Tags

v0.86.0-beta.1

Toggle v0.86.0-beta.1's commit message
PRD-9298 Fix desktop second-launch exit error on Linux (#6118)

* PRD-9298 Open the desktop log file before the first line is logged

On Linux the desktop main process logs its shared-memory posture at module
load, before it asks for the single-instance lock. A second launch therefore
creates the pino logger and then calls app.quit() in the same tick. The log
destination opened its file asynchronously, so pino's exit hook called
flushSync() on a stream with no fd yet and threw "sonic boom is not ready yet".

Open the file descriptor synchronously and hand it to the async destination.
Writes stay asynchronous, and the exit-time flush now writes any buffered
lines instead of throwing.

* PRD-9298 Show the probe's stderr when its exit status is wrong

GitOrigin-RevId: 9a418746b812444304973e314abea5284928f399

v0.86.0-beta.0

Toggle v0.86.0-beta.0's commit message
Let users turn off desktop auto-updates (PRD-7875) (#6016)

* Let users turn off desktop auto-updates (PRD-7875)

Add a per-machine "Download and install updates automatically" switch to
Settings, About & updates. When it is off the desktop app makes no
background checks or downloads, does not install on quit, and shows no
update notices. Check for updates still works and offers the releases page.

Dismissing the ready-to-install card now persists per version, and an
install that keeps failing is tombstoned after the retry limit instead of
being re-offered on every launch.

The three update request channels fold into one ok:update:dispatch channel
so the new kinds fit under the request-channel cap.

* Retract the ready-to-install card in every window on dismissal (PRD-7875)

Closing the card in one window now broadcasts the stand-down so other open windows drop it too, instead of waiting for a reload.

* Close the review gaps in the desktop update switch (PRD-7875)

Turning automatic updates back on now records an install commitment for a
build that finished downloading while they were off, and an explicit
relaunch records the attempt on every platform, so a failing install stays
capped. The deferred launch check and check bookkeeping honor the live mode.

The unrecognized-mode warning moves to state load, where the raw value is
still visible. The manual-download dialog reports failures through the
updater log and names the setting as Settings shows it. Settings copy and
the docs are accurate for Linux and for a download already in progress.

A dismissal retracts the card only for the staged build. A state read that
started before a mode change no longer overrides the switch. Adds preload
dispatch tests and merges duplicate registration tests.

* Commit a re-enabled staged install only where quit can run it (PRD-7875)

On macOS electron-updater hands a finished download to Squirrel only if
install-on-quit was on when it finished, so a build staged while updates
were off cannot be installed by quitting. Recording it as committed there
would count a quit as a failed install and eventually tombstone the build.
The commit on re-enable now applies to Windows only; an explicit relaunch
still records the attempt everywhere.

The unrecognized-mode warning now goes to the desktop log file.

* Re-stage a build downloaded while updates were off (PRD-7875)

electron-updater wires a download's install path when the download
finishes, and only if install-on-quit is on then: the Windows quit handler
and the macOS Squirrel handoff. A build staged while updates were off has
neither, so quitting cannot install it and Restart times out on macOS.

Turning updates back on now re-downloads such a build from the cache before
offering it, instead of committing it in place. A re-download that binds the
install path records the install commitment for the already-pending version,
which also covers a build staged off in an earlier session.

* Hide a build until its install hook is bound everywhere it is offered (PRD-7875)

The late-window replay and Restart could still offer a build staged while
updates were off before its re-download wired up install-on-quit. The live
broadcast, the replay and Restart now share one predicate that hides such a
build until a download finishes with install-on-quit on, including when the
re-stage check settles without downloading.

Both download-time commit paths now use one predicate and one field set, and
the given-up and Linux tests exercise the re-download path that guards them.

* Scope the re-stage hiding to the session in the update docs (PRD-7875)

A build staged by an earlier session has no install hook in a fresh process whatever the mode was, and is offered at launch as before. Say so, and name the re-stage test for what it observes.

* State the Restart refresh timeout in the update known-limit note (PRD-7875)

GitOrigin-RevId: 11eff52c4dae695c674948d55aabad980df9f8ed

v0.85.1-beta.0

Toggle v0.85.1-beta.0's commit message
Refuse stables that lack a fix a published stable shipped (#5851)

* Add a check that a stable keeps every published fix

A point release ships commits that no later beta contains, so a stable
promoted from an older beta, or a re-fired older tag, can lack a fix that
users already received from a published stable.

shipped-fix-containment.mjs takes every published stable Release whose tag
is not an ancestor of the candidate and requires each commit that git
cherry marks + to be covered by the origin the Release notes record as
Applied (same author, author date and message, and reachable from the
candidate) or by a reachable commit with the same terminal PR number. It
refuses anything else and names each missing commit, its PR and the stable
that shipped it. It checks history, not the final tree: a candidate that
also contains a later revert still passes.

It is a CLI too: --candidate checks one ref, and --matrix checks several
against expected verdicts and prints the totals for every pair.

* Run the shipped-fix check on every stable route

promote-stable refuses before it tags. desktop-release refuses a stable
tag in prepare, with the check loaded from the workflow revision so a
re-fire of an older tag runs it too; publish-assets and finalize then never
run. The point-release planner refuses when the newest stable tag has no
published Release and when the synthetic commit lacks a published fix,
before anything is tagged.

The selector checks the beta it would dispatch inside the window, and a
fast-tier candidate before smoking it, so a beta promote-stable would
refuse is not dispatched again on every tick. The bug lane holds its batch
while a point release over the newest stable would be refused. The release
re-run decider pages on such a refusal instead of re-running it.

Shape tests pin each call site, its condition and its place before the
first step that tags, publishes or dispatches.

* Document the shipped-fix check in the release runbooks

RELEASES.md describes the rule, its limits and how to run it by hand.
Every re-fire instruction, including the attempt-timeout row, now says to
run it first, and the point-release refusal table gains base-unpublished
and drops-shipped-fix. Demoting a bad stable uses --prerelease rather
than --draft, because a draft newest tag stops the point-release lane.

The CI runbook gains an entry for the refusal, and the blocked-release
page names the command to run before a re-fire.

* Check for published fixes again right before publishing

A re-run of failed jobs keeps a prepare job that passed, and two stable
desktop-release runs can overlap, so a stable that publishes during a
build is invisible to that build's prepare check. finalize now runs the
same check after a full-history checkout, before it edits, publishes,
dispatches npm or announces the Release. It also keeps an older stable
from publishing after a newer one.

A workflow_dispatch run for a tag whose Release is already published only
re-uploads its assets, so both checks let it through and say so. A
repository_dispatch re-fire is still checked, because it stamps Latest.

The runbooks describe both, and the stuck-draft hint no longer suggests
publishing a tag the check refused.

* Sharpen the shipped-fix check's errors and drop unread outputs

resolveCommit now reports a git that cannot read the checkout (exit 128,
a signal) with its status and stderr, and keeps "does not resolve to a
commit" for exit 1, appending git's message when there is one. Before,
every failure read as an under-fetched checkout.

The GITHUB_OUTPUT keys and COVERAGE.PATCH had no producer or consumer,
so they are gone. A test now drives the CLI through a stub gh that
serves a second page only under --paginate, so a listing cut to its
first page turns red instead of admitting a candidate. The base guard's
message no longer suggests a refused tag can still pass the check.

* Run finalize's shipped-fix check right before the draft flips

The check now sits directly before "Promote draft release to published",
after the superseded-stable step and the Downloads render, so the gap
between reading the Release listing and publishing is the check's own
run time. The shape test pins it as the step right before the flip and
ahead of every step that publishes, dispatches npm or announces.

* Warn that a revert-mode release blocks later promotions

A revert shipped in revert mode has no PR number, so the shipped-fix
check refuses every later promotion until main holds a commit with the
same patch. Every revert-mode run now says so. When the revert also
deletes a changeset the stable still has, which main-reset already
removed from main, no commit on main can carry that patch, and the
warning says to land the revert on main and use cherry-pick mode.
The main-reset skip warning is back to its original wording.

* Correct the shipped-fix runbook guidance

Revert mode: cherry-pick mode comes first, and the follow-up now names
the two cases where main cannot carry the shipped patch (a removed
changeset, or main having moved under the reverted lines).

Refusals: once prepare or finalize refuses the newest stable tag, only
a newer promotion is open; the point-release lane refuses and the bug
lane holds until it publishes, and deleting the draft does not help.
The janitor wording matches what it does.

The rule says a stable demoted to a prerelease still counts, and the
finalize paragraph describes the remaining half-minute window.

* Route revert-shaped refusals to the revert-mode section

A refusal whose missing commit has no PR number and a Revert subject
came from a revert-mode point release, and a newer beta clears it only
once main holds the same patch. Both refusal entries now say so and
point at the revert-mode section. That section keeps the clean-pick
condition on cherry-pick mode and names the normal promotion path for
a pick that conflicts.

* Pin the corrected release diagnostic wording

* Clarify release containment and recovery limits

* Align the release recovery guidance

* Keep the shipped-fix runbook paragraphs under their section

The recovery revision subsection now closes the shipped-fix containment
section, so the manual check and the refusal steps stay part of that
section instead of sitting under an unrelated heading. Its anchor is
unchanged.

The in-flight retry paragraph now says where to read the run's revision,
which is its own head SHA, how to stop an unguarded retry before
finalize publishes, and that nothing stops it automatically.

GitOrigin-RevId: 2401d6a61e9bd548e765fb3e0fa78c00af91c398

v0.85.0-beta.9

Toggle v0.85.0-beta.9's commit message
Fix red sibling links in History diffs (PRD-9206) (#6019)

* Resolve History diff links against the changed document (PRD-9206)

The rendered History and agent-change diffs built their editor from the
shared extension list without scoping it to the document, so relative
links resolved from the project root. A link from projects/ok-cloud/log
to a sibling page was marked unresolved and drawn as a red broken link.

The live editor's doc-scoping now lives in scopeExtensionsToDocument,
and RenderedDiffView applies it with the diffed document's name.

* Resolve inline images in rendered diffs against the document (PRD-9206)

Inline image views read the source document from the editor doc-context
registry, which only the live editor populated. RenderedDiffView now
registers its doc name before the view is created, so a relative inline
image in a History diff resolves from the document's folder.

* Re-anchor the link-audit composition roots on scopeExtensionsToDocument (PRD-9206)

The guard pinned the inline imageReference branch that moved into
scopeExtensionsToDocument. It now pins the live editor and the rendered
diff calling the helper, and imageReference staying in its scoped set.

GitOrigin-RevId: 8d418d7d7fb726db60141968b891802ddaff0019

v0.85.0

Toggle v0.85.0's commit message
Prompt stale browser tabs to reload after an ok upgrade (PRD-9146) (#…

…5949)

* Prompt a browser tab to reload when ok is upgraded under it (PRD-9146)

A browser tab left open while `ok start` is replaced by a newer build kept
running the old bundle against the new server with no warning. Lazily loaded
chunks then 404 (Settings fails to load) and nothing tells the user why.

/api/server-info now reports the server's runtime and protocol version. The
tab pins the version it first saw at load and, when a later refresh reports
a different one, shows a translated prompt to reload. Reload waits for any
server-restart recovery and unsynced edits to reach the server before it
reloads, and refuses with a message if they have not. The desktop app keeps
its own drift prompt, so the browser prompt is not installed when the
desktop bridge is present.

The tab compares against the server version at load rather than its own
baked version because shipped bundles carry a stale VITE_APP_VERSION
(0.83.1 and 0.83.2 both bake 0.82.4).

* Hold the stale-tab reload for edits buffered across a restart (PRD-9146)

An edit buffered only in memory across a server restart, or a replay
between claiming its outbox entry and applying it, is invisible to
hasAnyUnsyncedWork, so Reload could drop it. ProviderPool.hasPendingReplay
covers both and waitForSavedWork now requires it to be clear. A withheld
reload only brings the prompt back while the server is still on a
different version.

Adds the before and after evidence report from a real two-version ok
start swap.

* Say why a stale-tab reload was withheld (PRD-9146)

The refusal now separates a tab still reconnecting, edits not yet
acknowledged, and a check that failed, names any document whose edits
only this tab holds, stays on screen until the next Reload, and logs an
ok-stale-tab-reload-withheld event. The pool exposes one hasUnsavedWork
predicate for the reload gate, and discarding a buffered edit now wakes
anyone waiting on it.

Stubs the new prompt in the two app-shell DOM tests that stub its
sibling lifecycle components.

* Show a withheld reload's reason inside the prompt (PRD-9146)

The refusal used to be a separate toast that sat behind the returning
prompt and could outlive its cause. The prompt now carries the reason in
place of its usual line, and goes back to the usual line when the edits
are saved. Not now, a return to the tab's version, the next Reload and
teardown all clear it. Only documents with no open pool entry are named,
quoted and capped at three, since opening an already open document does
not run its replay. The reason mapping is exhaustive and the withheld
event logs the error message.

* Keep a failed check's reason in the stale-tab prompt (PRD-9146)

When the check for saved work fails, nothing on the saved-work side will
change, so watching it would clear the reason at once. That reason now
stays until Reload, Not now or a version change. The prompt wraps long
document names.

GitOrigin-RevId: 35709064854579be0cda3c47f99ad1df6ec5688e

v0.85.0-beta.8

Toggle v0.85.0-beta.8's commit message
Refuse agent edits to a path with no document (PRD-7532) (#6000)

* Refuse agent edits to a path with no document (PRD-7532)

edit's find/replace against a path with nothing behind it answered "Text not
found in document", the same error as a stale find on a real document, so
agents re-read the right file from disk and retried forever. The frontmatter
patch on the same path silently created the file.

/api/agent-patch and /api/frontmatter-patch now refuse with 404
urn:ok:error:doc-not-found when the path has no document on disk and no live
content in memory. The message names likely targets: a folder's hub doc, or
documents whose trailing path segments match (a bundle-relative path missing
its folder prefix). Nothing is created.

write with position append or prepend on a missing path still creates the
document, but its response now opens with "Created new document" instead of
a plain success line.

Fixes #1719 (PRD-8712, duplicate of PRD-7532).

* Name the missing document when edit cannot resolve an occurrence (PRD-7532)

edit with occurrence > 1 reads the document from disk first. On a path with
no document it answered that the document was "not on disk yet", which
reads as a pending document at the right path. It now says no document
exists at the path, and keeps the retry hint for a just-created document.

* Point missing-document refusals at the fix, and document them (PRD-7532)

When the doc-not-found refusal names likely targets, it now tells the agent
to retry there instead of inviting it to create the refused path. The 404
carries committed: false, so a templated write whose frontmatter patch is
refused this way reports that nothing was applied.

The append/prepend creation note names the cleanup for an unintended
create. The skill reference drops the undefined "bundle folder" wording
and routes "No document at" on a path visible on disk to the stale-session
escape hatch. The MCP reference documents the refusal and the creation
line.

* Open the occurrence refusal with the documented No document at text (PRD-7532)

* Pin the doc-not-found message when nothing resembles the path (PRD-7532)

GitOrigin-RevId: 202d8700fa69649e6daa2fd5949379df60a5c869

v0.85.0-beta.7

Toggle v0.85.0-beta.7's commit message
PRD-8207 Reject unsafe agent control bytes on main (#5857)

* test: reproduce PRD-8207 control admission on main

* fix: refuse disallowed controls in new agent content

* test: preserve main rollback contracts for control admission

* docs: preserve main control admission verification receipts

* docs: index main control admission receipts

* test: reproduce control admission gaps in template and skill bodies

Exercise all disallowed C0 values in four incoming body schemas and real HTTP/MCP mutation boundaries. Preserve body-omitted historical moves and opaque non-Markdown bundle resources, and require actionable MCP coordinate diagnostics. Existing document admission tests remain unchanged; new refusal tests are intentionally red before the source fix.

* test: reproduce Markdown skill-file control admission

Cover conditional .md/.mdx file content admission through public schemas, the real HTTP listener, disk and registered MCP write/edit tools. Preserve opaque non-Markdown resources and case/scope-independent Markdown semantics. Earlier document and body admission tests are untouched; refusal assertions are intentionally red before the source fix.

* test: qualify historical full-PUT and MCP batch admission

Pin the new full-PUT input-domain consequence for legacy template metadata, skill descriptions and partial repair, with independent clean replacement controls. Verify mixed registered MCP document batches preserve safe siblings and report the refused entry without atomic rollback. Existing 404 admission cases remain unchanged; three qualification assertions are intentionally red before the source fix.

* fix: complete Markdown input admission and actionable MCP errors

* PRD-8207 Anchor merged-main verification evidence

* test(ok): reproduce normalized admission and refusal regressions

* PRD-8207 Close normalized paths and explain refused writes

* test(ok): distinguish admission causes and composed coordinates

* PRD-8207 Identify control refusals and share path policy

* fix: clarify PRD-8207 metadata-only edit refusals

* test: settle PRD-8207 artifact attribution before snapshots

* test: settle all PRD-8207 artifact contributor snapshots

* test: force PRD-8207 file settlement interleaving

* Record current main admission verification and retained gate limits

* Bind fixture verification to exact cases and clarify historical rounds

* docs: scope PRD-8207 input hashes to their consuming runs

GitOrigin-RevId: 0e927e270a74c285660e95fc19d0f4414482c58a

v0.85.0-beta.6

Toggle v0.85.0-beta.6's commit message
Build the OK cli after the release version override (PRD-9158) (#5959)

* Build the OK cli after the release version override (PRD-9158)

release.yml built every package before it stamped the release version,
and the cli's prepublishOnly only copies the app's already-built dist.
Published browser bundles therefore baked the checked-out version into
VITE_APP_VERSION and sent it as x-ok-client-runtime: 0.83.1 and 0.83.2
sent 0.82.4.

Build the cli and its workspace dependencies after both version
overrides, and refuse to pack a browser bundle that bakes any version
but the cli's. The check is read from the workflow's own commit, so a
stable promotion of a tag cut before this change runs it too.

* Give each bundle-version refusal its own cause and a recovery path

The closing line blamed the build order for every refusal, which is
wrong when no VITE_APP_VERSION literal is found at all. Each refusal now
names its own cause, and every failure ends by pointing at the
RELEASES.md section that says how to resume a beta or a stable npm
publish.

* Keep the RELEASES.md heading check off the public mirror

The mirrored release-cascade-shape test read RELEASES.md, which the
public mirror does not ship. The heading check now lives in a
.private.uncached test beside the script, as the native-set check does.

Each refusal now names only a cause its condition can produce: an empty
bundle directory is a missing app build, not a reader gap, and a
missing version no longer blames the override. RELEASES.md covers every
refusal and says to resume with a new run, since re-running the refused
run reads the same workflow and check again.

GitOrigin-RevId: 3cacfff94cb799ea3df8b9d8f48ec4de9bf79ff2

v0.85.0-beta.5

Toggle v0.85.0-beta.5's commit message
Prompt stale browser tabs to reload after an ok upgrade (PRD-9146) (#…

…5949)

* Prompt a browser tab to reload when ok is upgraded under it (PRD-9146)

A browser tab left open while `ok start` is replaced by a newer build kept
running the old bundle against the new server with no warning. Lazily loaded
chunks then 404 (Settings fails to load) and nothing tells the user why.

/api/server-info now reports the server's runtime and protocol version. The
tab pins the version it first saw at load and, when a later refresh reports
a different one, shows a translated prompt to reload. Reload waits for any
server-restart recovery and unsynced edits to reach the server before it
reloads, and refuses with a message if they have not. The desktop app keeps
its own drift prompt, so the browser prompt is not installed when the
desktop bridge is present.

The tab compares against the server version at load rather than its own
baked version because shipped bundles carry a stale VITE_APP_VERSION
(0.83.1 and 0.83.2 both bake 0.82.4).

* Hold the stale-tab reload for edits buffered across a restart (PRD-9146)

An edit buffered only in memory across a server restart, or a replay
between claiming its outbox entry and applying it, is invisible to
hasAnyUnsyncedWork, so Reload could drop it. ProviderPool.hasPendingReplay
covers both and waitForSavedWork now requires it to be clear. A withheld
reload only brings the prompt back while the server is still on a
different version.

Adds the before and after evidence report from a real two-version ok
start swap.

* Say why a stale-tab reload was withheld (PRD-9146)

The refusal now separates a tab still reconnecting, edits not yet
acknowledged, and a check that failed, names any document whose edits
only this tab holds, stays on screen until the next Reload, and logs an
ok-stale-tab-reload-withheld event. The pool exposes one hasUnsavedWork
predicate for the reload gate, and discarding a buffered edit now wakes
anyone waiting on it.

Stubs the new prompt in the two app-shell DOM tests that stub its
sibling lifecycle components.

* Show a withheld reload's reason inside the prompt (PRD-9146)

The refusal used to be a separate toast that sat behind the returning
prompt and could outlive its cause. The prompt now carries the reason in
place of its usual line, and goes back to the usual line when the edits
are saved. Not now, a return to the tab's version, the next Reload and
teardown all clear it. Only documents with no open pool entry are named,
quoted and capped at three, since opening an already open document does
not run its replay. The reason mapping is exhaustive and the withheld
event logs the error message.

* Keep a failed check's reason in the stale-tab prompt (PRD-9146)

When the check for saved work fails, nothing on the saved-work side will
change, so watching it would clear the reason at once. That reason now
stays until Reload, Not now or a version change. The prompt wraps long
document names.

GitOrigin-RevId: 35709064854579be0cda3c47f99ad1df6ec5688e

v0.85.0-beta.4

Toggle v0.85.0-beta.4's commit message
Tag telemetry with the client surface (PRD-9145) (#5947)

* Tag telemetry with the client surface (PRD-9145)

packages/app runs in the OK Desktop window, a browser tab served by
`ok start`, and agent hosts' browser panes (Cursor, Codex, Claude Code
Desktop). Telemetry could not tell them apart: every surface sent
x-ok-client-kind: web and the frontend resource had no host attribute.

The app now derives one surface at startup from the desktop bridge and
the existing embedded-host user-agent detector: desktop, browser, or
embedded:<host>. It sends that value as the kind header and collab token
field (reusing the existing header, so no CORS allow-list changes and an
older server keeps accepting it), and stamps it on the frontend resource
as ok.client.surface. The server reads it with readClientSurface and
records ok.client.surface on the HTTP span, clientSurface on api.access
lines, and clientSurface on forwarded renderer logs. Older clients that
send web, and any unrecognized value, read as unknown; mcp, cli,
desktop-main and a missing header carry no surface.

Also fixes the fetch wrapper leaving absolute file:///api/ strings
unrewritten. The OpenTelemetry fetch instrumentation hands those to it in
the desktop window, so enabling frontend telemetry there broke the file
tree and every other API call.

* Add PRD-9145 client surface evidence and OTel docs

Records the before/after capture (spans, access logs, screenshots) from
OK Desktop, a browser tab and three embedded agent panes, and documents
filtering traces on ok.client.surface in the otel-dev README.

* Address review on client surface telemetry (PRD-9145)

Read the surface once per request and carry it on the ingress context
so client-logs uses the pipeline's value. Classify every non-app client
kind at compile time. Pin the web-mode absolute /api path in the fetch
wrapper tests and stop desktop-mode cases from asserting a browser kind.
Add post-ship notes to the client-version spec, name the pushed commit
in the evidence report, and scope the changeset and otel-dev wording to
what actually carries the attribute and when it leaves the machine.

* Scope client surface egress and span wording (PRD-9145)

Name OpenTelemetry export alongside bug reports as the ways the surface
value leaves the machine, say that browser-side collab spans carry it
through the frontend resource while server spans other than the HTTP
span do not, and add the post-ship note to the spec's AC-6.

GitOrigin-RevId: 49d71c321bef7f660b39a55be3991f5a961b6cef