Repository navigation
Tags: inkeep/open-knowledge
Tags
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
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
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
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
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
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
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
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
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
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
PreviousNext