diff --git a/.changeset/codebase-wiki-pack-description-length.md b/.changeset/codebase-wiki-pack-description-length.md deleted file mode 100644 index abd5ec03e..000000000 --- a/.changeset/codebase-wiki-pack-description-length.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -"@inkeep/open-knowledge-server": patch -"@inkeep/open-knowledge": patch ---- - -Shorten the "Codebase wiki" starter-pack description to a single short clause ("Architecture, modules, and flows.") so its card matches the length of the other packs on the starter-pack picker instead of overflowing with a full paragraph. diff --git a/.changeset/cowork-hidden-command.md b/.changeset/cowork-hidden-command.md deleted file mode 100644 index fa97a49f6..000000000 --- a/.changeset/cowork-hidden-command.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@inkeep/open-knowledge": patch ---- - -Rename the `ok install-skill` CLI command to a deliberately hidden, unadvertised `ok cowork`. The old name implied an automatic install it never performed — it builds the `openknowledge.skill` bundle and opens the Claude Desktop App for a manual upload (the only path to the separate Skills list Claude Chat & Cowork read, which `ok init`'s editor wiring can't reach). The command is now registered hidden (absent from `ok --help`), and `ok init` no longer pushes a hint toward it — it is a power-user escape hatch discovered pull-only via the Open Knowledge skill. The underlying bundle build and the `POST /api/install-skill` route are unchanged. diff --git a/.changeset/cross-platform-handoff-dispatch.md b/.changeset/cross-platform-handoff-dispatch.md deleted file mode 100644 index 424c31162..000000000 --- a/.changeset/cross-platform-handoff-dispatch.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@inkeep/open-knowledge": patch ---- - -Make "Open in agent" (handoff to Claude, Codex, and Cursor) work on Windows and Linux, not just macOS. Install detection was already cross-platform, so on Windows/Linux a registered agent showed an enabled row that, when clicked, failed with a 500 error and a "Couldn't reach …" toast. Handoff dispatch now opens the agent's protocol URL through the OS's registered handler on every platform (`/usr/bin/open` on macOS, `rundll32` on Windows, `xdg-open` on Linux), and Cursor's workspace launch already worked cross-platform. On Windows/Linux the server first confirms the agent's URL scheme is actually registered, so an uninstalled agent reports "not installed" instead of a misleading success. diff --git a/.changeset/desktop-enable-beta-update-proxy.md b/.changeset/desktop-enable-beta-update-proxy.md deleted file mode 100644 index ff05b03af..000000000 --- a/.changeset/desktop-enable-beta-update-proxy.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@inkeep/open-knowledge": patch ---- - -Desktop: enable the openknowledge.ai update proxy for the beta channel. Beta builds now fetch updates through `openknowledge.ai/updates/beta`, which 302s to the byte-identical GitHub asset (preserving the manifest sha512 and the macOS signature) so updates can be counted per version. Stable still reads the GitHub `publish:` config; it gets the same path once an end-to-end beta update is confirmed. A feed failure reverts to the GitHub provider for the session, so auto-update reliability never drops below GitHub-direct. diff --git a/.changeset/desktop-enable-stable-update-proxy.md b/.changeset/desktop-enable-stable-update-proxy.md new file mode 100644 index 000000000..4cbf824c0 --- /dev/null +++ b/.changeset/desktop-enable-stable-update-proxy.md @@ -0,0 +1,5 @@ +--- +"@inkeep/open-knowledge": patch +--- + +Desktop: enable the openknowledge.ai update proxy for the stable (`latest`) channel too. Stable builds now fetch updates through `openknowledge.ai/updates/stable`, which 302s to the byte-identical GitHub asset (preserving the manifest sha512 and the macOS signature) so stable updates are counted per version. This follows the verified end-to-end beta update (beta.13 to beta.14) through the proxy. The stable path resolves via GitHub's authoritative `releases/latest` alias, and a feed failure still reverts to the GitHub provider for the session, so auto-update reliability never drops below GitHub-direct. diff --git a/.changeset/desktop-update-feed-proxy.md b/.changeset/desktop-update-feed-proxy.md deleted file mode 100644 index ef56bad6f..000000000 --- a/.changeset/desktop-update-feed-proxy.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@inkeep/open-knowledge": patch ---- - -Desktop: add an opt-in path to fetch updates through the openknowledge.ai proxy so updates can be counted per version. When the build's channel is enabled, electron-updater's feed is pointed at `openknowledge.ai/updates/{channel}` and requests are tagged with `x-ok-from-version` / `x-ok-channel` headers. Default-off — production keeps reading the GitHub `publish:` config until the proxy is verified live, then the enabled-channel set flips to beta-first. A feed failure on the first check reverts to the GitHub provider for the session, so auto-update reliability never drops below GitHub-direct. diff --git a/.changeset/file-menu-project-switcher-parity.md b/.changeset/file-menu-project-switcher-parity.md new file mode 100644 index 000000000..54d6a3e3d --- /dev/null +++ b/.changeset/file-menu-project-switcher-parity.md @@ -0,0 +1,6 @@ +--- +"@inkeep/open-knowledge-desktop": patch +"@inkeep/open-knowledge-app": patch +--- + +Align the macOS File menu with the in-app project switcher. The File menu's project actions now sit together directly under "New from template…" and read in the same order as the bottom-left switcher: Recent project, New project, Switch project, Open folder. "Create new project…" is renamed "New project…" and the recents submenu is renamed "Recent project" to match the switcher's labels. The switcher's own action order is updated to the same sequence (New project, Switch project, Open folder) so both surfaces are consistent. Wiring, accelerators, and behavior are unchanged. diff --git a/.changeset/fit-card-descriptions.md b/.changeset/fit-card-descriptions.md deleted file mode 100644 index e1bf19e9d..000000000 --- a/.changeset/fit-card-descriptions.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@inkeep/open-knowledge": patch ---- - -Stop starter-pack and other card descriptions from overflowing their cards. The "Codebase wiki" starter pack and the slash-command MirrorSource / Mirror block previews had descriptions long enough to wrap to many lines and stretch their cards; those are now concise. The description text on the starter-pack picker, the slash-command block preview, the Navigator project-launcher cards, and the share-receive dialog is now line-clamped, so any long description truncates cleanly instead of distorting the layout. diff --git a/.changeset/fix-dead-links-fresh-doc-false-positive.md b/.changeset/fix-dead-links-fresh-doc-false-positive.md new file mode 100644 index 000000000..b38e2f995 --- /dev/null +++ b/.changeset/fix-dead-links-fresh-doc-false-positive.md @@ -0,0 +1,6 @@ +--- +"@inkeep/open-knowledge-server": patch +"@inkeep/open-knowledge": patch +--- + +Fix `links({ kind: "dead" })` falsely reporting freshly-written docs as dead. The dead-link check decided a target existed only from the file-watcher's file index, which lags behind in-session writes, so a doc the link graph had just registered a backlink for could still be flagged dead until a server restart. Dead-link resolution now also treats any doc the graph already holds as a live node (its body has been indexed) as a valid target, so a newly-written doc is a valid link target immediately — without changing how genuinely-missing targets are reported. diff --git a/.changeset/fix-duplicate-tabs-focus-existing.md b/.changeset/fix-duplicate-tabs-focus-existing.md deleted file mode 100644 index 8c9670e10..000000000 --- a/.changeset/fix-duplicate-tabs-focus-existing.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@inkeep/open-knowledge-app": patch ---- - -Fix a bug where the same file could open in two tabs at once. Clicking a sidebar file that is already open in another tab now focuses that existing tab instead of opening a duplicate — including when a blank "New Tab" placeholder is the active tab (the active placeholder is consumed). The same focus-in-place behavior applies to folder and asset tabs. Tabs restored from a saved session that already contain two views of one file are left untouched. diff --git a/.changeset/fix-ok-start-shutdown-ws-drain.md b/.changeset/fix-ok-start-shutdown-ws-drain.md deleted file mode 100644 index 5f4dae296..000000000 --- a/.changeset/fix-ok-start-shutdown-ws-drain.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@inkeep/open-knowledge": patch ---- - -Fix `ok start` hanging for about 10 seconds on Ctrl+C when a live client was connected. If a browser preview tab or an agent/MCP session held a WebSocket open, shutdown left that socket alive, so the WebSocket-server close and the HTTP-server close each blocked until a 5-second internal timeout fired — adding ~10s of delay and printing an alarming `AggregateError` on a routine quit. Shutdown now drains the live upgrade sockets up front (mirroring the existing drain in `ok ui`), so both close steps finish promptly and the server lock is released right away. diff --git a/.changeset/fix-reinstall-pack-skill.md b/.changeset/fix-reinstall-pack-skill.md deleted file mode 100644 index 9fef3b5af..000000000 --- a/.changeset/fix-reinstall-pack-skill.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -"@inkeep/open-knowledge-server": patch -"@inkeep/open-knowledge": patch ---- - -Fix a starter-pack skill being unable to reinstall after a user uninstalls it. Pack skills are named `open-knowledge-pack-`, which sits under the `open-knowledge*` prefix reserved for OK's shipped skills. The seed installs them by copying directly, but a user-triggered reinstall re-runs the install validation, which rejected the reserved prefix and failed with "uses the reserved `open-knowledge*` prefix." The install guard now exempts the `open-knowledge-pack-*` namespace (OK's own shipped pack content), so reinstalling a pack skill works while user-authored `open-knowledge*` names stay blocked. diff --git a/.changeset/fix-skill-graph-flicker-and-seed-safety.md b/.changeset/fix-skill-graph-flicker-and-seed-safety.md deleted file mode 100644 index b61172824..000000000 --- a/.changeset/fix-skill-graph-flicker-and-seed-safety.md +++ /dev/null @@ -1,13 +0,0 @@ ---- -"@inkeep/open-knowledge-core": patch -"@inkeep/open-knowledge-server": patch -"@inkeep/open-knowledge": patch ---- - -Fix skill reference graph links, the skills-dock flicker, and re-seed data safety. - -- A `[[references/]]` wiki-link inside a skill's SKILL.md now resolves to that skill's bundle reference doc and forms a real backlink and graph edge. Previously the natural wiki form silently mis-resolved to a phantom top-level doc (only an absolute `[[.ok/skills//references/]]` or a markdown link resolved), so a skill's references never appeared as links or backlinks. Adds a shared `resolveSkillBundleWikiTarget` helper used by the link index, and updates the write-skill guidance to author references as wiki-links (a backtick code path renders dead and never joins the graph). -- The skills sidebar no longer flickers (list flashing empty then repopulating) on every skill create/edit/install/move. The list now revalidates in place instead of resetting to a loading state. -- Re-running seed no longer overwrites a user-edited starter-pack skill. `installPackSkill` only authors the source when it does not already exist; an existing skill keeps its edits and shadow history while still refreshing its editor projection and install marker. -- `POST /api/create-page` now rejects a path inside `.ok/` (or a managed-artifact doc name), so a page can no longer be created inside the indexed `.ok/skills/**` namespace and bypass skill-schema validation. -- The `install` MCP tool description now lists OpenCode (`.opencode/skills/`) as a valid projection target, matching the schema. diff --git a/.changeset/fix-skill-move-bundle-and-tabs.md b/.changeset/fix-skill-move-bundle-and-tabs.md deleted file mode 100644 index 703b14ce0..000000000 --- a/.changeset/fix-skill-move-bundle-and-tabs.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -"@inkeep/open-knowledge-server": patch -"@inkeep/open-knowledge": patch ---- - -Fix skill move/scope-change losing bundle files and dropping references from the link graph. A cross-scope skill move (global ↔ project) copied only `SKILL.md` and then deleted the source, silently losing every `references/**` and `scripts/**` file; both the MCP `move` verb and the editor's scope switch now copy the full bundle through the per-type write path (project `.md` references rejoin the backlink/tag graph; global references and all scripts are written fs-direct) before deleting the source, aborting without data loss on any partial-copy failure. A same-scope skill rename now re-indexes the relocated `SKILL.md` and its `.md` references into the live backlink/tag graph (previously they sat unindexed until a manual rescan). The editor also reconciles open skill tabs after a server-side move — a tab whose skill moved scopes retargets to the new location, and one whose skill was deleted closes — so no stale phantom tab is left behind. Also adds the new skill write routes to the mutating-route CSRF guard and the conflict gate. diff --git a/.changeset/fix-worktree-subfolder-project-root.md b/.changeset/fix-worktree-subfolder-project-root.md deleted file mode 100644 index f84686fcb..000000000 --- a/.changeset/fix-worktree-subfolder-project-root.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@inkeep/open-knowledge": patch ---- - -Fix Open Knowledge Desktop offering to set up a project inside a subfolder of a linked git worktree. Picking a subdirectory (for example `public/open-knowledge`) inside a `git worktree add` checkout misclassified it as a worktree root and showed "Setup Open Knowledge in this folder" in place, scaffolding `.ok/` in the subfolder instead of promoting to the git root. Subfolders of a linked worktree now correctly fall through to git-root promotion; only the worktree root itself is treated as a standalone project. diff --git a/.changeset/git-preflight-project-setup-boundary.md b/.changeset/git-preflight-project-setup-boundary.md deleted file mode 100644 index 5229a277e..000000000 --- a/.changeset/git-preflight-project-setup-boundary.md +++ /dev/null @@ -1,10 +0,0 @@ ---- -"@inkeep/open-knowledge": patch -"@inkeep/open-knowledge-server": patch ---- - -Run the git preflight at the project-setup boundary so a broken or PATH-invisible git surfaces recoverable install/upgrade guidance instead of a raw error. - -Creating a project, opening a folder, cloning from GitHub, and `ok init` now verify git is usable before invoking it, and run against the exact git the preflight validated (the resolved path for in-process git, or an enriched PATH for the spawned clone). When git is missing or unusable they report platform-specific install guidance; `ok init` exits 78 (EX_CONFIG) on a git-preflight failure, matching `ok start`. - -These setup paths now require git 2.31 or newer — the same floor `ok start` and the desktop app already enforce at launch. diff --git a/.changeset/global-skill-graph-participation.md b/.changeset/global-skill-graph-participation.md deleted file mode 100644 index 82be8937a..000000000 --- a/.changeset/global-skill-graph-participation.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -"@inkeep/open-knowledge-core": patch -"@inkeep/open-knowledge-server": patch -"@inkeep/open-knowledge": patch ---- - -Show global skill references in the link graph, connected to their skill. - -A global skill's `SKILL.md` and its `references/*.md` now appear as connected nodes in the link graph, the same as a project skill — even though global skills live in `~/.ok/skills/` outside the project content tree. Global bundle docs are ingested as graph nodes (at boot, on branch switch, and live via the managed-artifact watcher) and connected by structural edges derived from the bundle path. The connection is within-bundle only: a global skill is never linked into a specific project's knowledge base (a global reference's wiki-links are not followed), and its cluster is visible from every project since global skills are shared across all of them. Clicking a global reference node in the graph opens it read-only through the scope-aware skill-file viewer. diff --git a/.changeset/link-authoring-contract.md b/.changeset/link-authoring-contract.md deleted file mode 100644 index e62397624..000000000 --- a/.changeset/link-authoring-contract.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@inkeep/open-knowledge": minor ---- - -Write-time broken-link validation in the Open Knowledge MCP. `write`/`edit` now return `brokenLinks` in the same response — outbound links that don't resolve are surfaced at write time, report-only so the write still lands and you can author a doc before its link target exists. Validation covers **every** local link, not just docs: the `./`-onto-a-content-root-path doubling footgun and missing `[[wiki]]` / markdown doc targets (`no-such-doc`), root-escaping paths from one `../` too many (`unresolvable`), and links to assets or source files (`[src](../../foo.py)`) that don't exist on disk at the resolved path (`no-such-file`). That last reason closes the gap a real codebase-wiki run hit: wrong-depth source-file links that 404 silently because the doc-only link graph never tracked them. The platform and pack skills are updated to point agents at `brokenLinks` as the primary write-time check and to clarify that a same-pass forward-reference reports as `no-such-doc` until its target lands (the `links({ kind: "dead" })` audit is the authoritative end-state check). diff --git a/.changeset/pre.json b/.changeset/pre.json index ca0c23777..d15a67d1b 100644 --- a/.changeset/pre.json +++ b/.changeset/pre.json @@ -2,14 +2,14 @@ "mode": "pre", "tag": "beta", "initialVersions": { - "@inkeep/open-knowledge-docs": "0.0.3", - "@inkeep/open-knowledge-app": "0.19.2", - "@inkeep/open-knowledge": "0.19.2", - "@inkeep/open-knowledge-core": "0.19.2", - "@inkeep/open-knowledge-desktop": "0.19.2", - "@inkeep/md-conformance": "0.0.11", + "@inkeep/open-knowledge-docs": "0.0.4", + "@inkeep/open-knowledge-app": "0.20.0", + "@inkeep/open-knowledge": "0.20.0", + "@inkeep/open-knowledge-core": "0.20.0", + "@inkeep/open-knowledge-desktop": "0.20.0", + "@inkeep/md-conformance": "0.0.12", "@inkeep/open-knowledge-plugin": "0.3.1", - "@inkeep/open-knowledge-server": "0.19.2" + "@inkeep/open-knowledge-server": "0.20.0" }, "changesets": [] } diff --git a/.changeset/silent-noop-cli-shim-toast.md b/.changeset/silent-noop-cli-shim-toast.md deleted file mode 100644 index c130a4088..000000000 --- a/.changeset/silent-noop-cli-shim-toast.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@inkeep/open-knowledge": patch ---- - -Desktop: stop showing the sticky "Installed CLI shims." startup toast when an app upgrade only repoints the internal `~/.ok/bin` symlinks. The startup PATH-reclaim toast now fires only for changes the user can see or act on — a shell rc-file edit, an opt-out, a legacy-symlink cleanup, or a failure. A no-op symlink repoint (the common case on every upgrade or bundle-path change) is now silent; the repoint still happens and still emits the structured `path-install-symlink-success` event for operators. Restores the spec's "silent if no meaningful user-facing change" contract. diff --git a/.changeset/skill-authoring-ux.md b/.changeset/skill-authoring-ux.md deleted file mode 100644 index 8f5d3cb77..000000000 --- a/.changeset/skill-authoring-ux.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -"@inkeep/open-knowledge-server": patch -"@inkeep/open-knowledge-app": patch ---- - -Skill authoring UX fixes. Deleting a personal (Global) skill and then re-creating one with the same name now persists reliably — previously a same-name re-create that authored identical content was silently dropped because the managed-artifact last-known-good cache was not evicted on delete, so the re-create was classed a no-op and never re-landed on disk. Writing a raw `document` under `.ok/skills/…` (or `.ok/templates/…`) now returns a path-aware error pointing at the correct `skill` (or `template`) target instead of a generic rejection, and the `write` / `edit` tool descriptions and the project skill now name all five write targets so an agent reaches for `skill` instead of defaulting to a plain document. Skill scope is labeled "Global Skill" / "Project Skill" (the word "scope" is gone from the UI) with a colored level toggle. diff --git a/.changeset/skill-bundle-graph-and-file-viewing.md b/.changeset/skill-bundle-graph-and-file-viewing.md deleted file mode 100644 index 569fb7f0b..000000000 --- a/.changeset/skill-bundle-graph-and-file-viewing.md +++ /dev/null @@ -1,11 +0,0 @@ ---- -"@inkeep/open-knowledge-core": patch -"@inkeep/open-knowledge-server": patch -"@inkeep/open-knowledge": patch ---- - -Make a project skill's references show up connected in the graph, and let global skill bundle files be opened. - -- A project skill's `SKILL.md` and its `references/*.md` now appear connected in the link graph automatically, whether the body references them as `[[wiki-links]]` or as plain backticked paths. The references were already graph nodes; this adds the structural edges between a skill's `SKILL.md` and its own reference docs, derived strictly from the bundle path (`.ok/skills//`). Regular documents and folders are unaffected — co-membership in an ordinary folder does not create edges. Authored wiki-links keep working and are not double-drawn. -- Clicking a global skill's reference or script in the Skills sidebar now opens it (read-only) instead of failing with "could not be found." Global skill bundle files live in `~/.ok/skills/` outside the project content tree, so they are now read through the scope-aware skill-file endpoint rather than as a project content-dir asset. A fetch failure shows a terminal state instead of a perpetual loading spinner. -- The write-skill guidance is updated: project skill references auto-connect in the graph regardless of how they are referenced, a wiki-link is only needed for a clickable inline link, and global skill references should stay plain backtick paths since global references are not graph docs. diff --git a/.changeset/skill-editor-url-addressable.md b/.changeset/skill-editor-url-addressable.md deleted file mode 100644 index 7d39a5d41..000000000 --- a/.changeset/skill-editor-url-addressable.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -"@inkeep/open-knowledge": patch -"@inkeep/open-knowledge-server": patch -"@inkeep/open-knowledge-app": patch ---- - -Make skills URL-addressable in the editor and resolvable by the MCP, so a skill behaves like a document. The skill editor now has its own route (`#/__skill__//`): opening a skill updates the URL, so it is reload-stable, shareable, and deep-linkable; loading a skill URL opens straight into the editor with the file sidebar visible. Closing routes the URL back to the document underneath, and navigating to a document dismisses the skill editor. The `write` and `edit` MCP tools now ride a route-only `previewUrl` for skills (the same preview envelope documents already carry), and the `preview_url` tool accepts a `{ skill }` target, so an agent that authors a skill in Open Knowledge can hand back a URL that opens it in the running editor. - -Creating a skill now opens the editor directly instead of a modal: the "New skill" action drops a draft into the main editor pane with an inline Project/Personal scope toggle in its Properties panel. Filling in a name and description enables Create; once it commits, the editor re-points to the saved skill and switches into the same autosave edit experience, so authoring a new skill and editing an existing one are one continuous surface. diff --git a/.changeset/skill-file-rendered-markdown.md b/.changeset/skill-file-rendered-markdown.md deleted file mode 100644 index 027628e0f..000000000 --- a/.changeset/skill-file-rendered-markdown.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -"@inkeep/open-knowledge": patch ---- - -Render a global skill's `.md`/`.mdx` references as formatted read-only markdown instead of raw source. - -Opening a global skill bundle file in the Skills sidebar previously showed the raw markdown source. Markdown references now render formatted (headings, bold, lists) read-only — the same rendering the editor uses (via the shared extension set, with no editing and no collaboration binding). Scripts and other non-markdown files keep the source view. diff --git a/.changeset/skill-graph-node-styling-and-review-polish.md b/.changeset/skill-graph-node-styling-and-review-polish.md deleted file mode 100644 index f9fd14d6e..000000000 --- a/.changeset/skill-graph-node-styling-and-review-polish.md +++ /dev/null @@ -1,11 +0,0 @@ ---- -"@inkeep/open-knowledge-server": patch -"@inkeep/open-knowledge": patch ---- - -Render skill reference graph nodes as resolved, and address review follow-ups. - -- A skill-bundle reference node in the link graph now renders as a normal resolved node instead of the dashed-red "missing" treatment. The node always resolved to a real, openable read-only viewer (clicking it works), but it was misclassified as a missing link target, so it read as broken. -- A failed skill move no longer turns into a 500 when the post-rename graph re-index throws — the rename already succeeded, so a re-index failure is logged and swallowed. -- The skills-list handler now logs when `readdirSync` fails instead of silently returning an empty list, and the bundle-file path classifier rejects NUL bytes for parity with its sibling validators. -- The starter-pack update dialog and toasts show the skill's display name instead of its raw internal id, and the skill menu's update action reads as an imperative ("Update skill"). diff --git a/.changeset/skill-import-prompt-symlink-copy.md b/.changeset/skill-import-prompt-symlink-copy.md deleted file mode 100644 index 33e05c10d..000000000 --- a/.changeset/skill-import-prompt-symlink-copy.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@inkeep/open-knowledge": patch ---- - -Clarify the skills import prompt. The one-time banner now states what Import actually does: it moves the editor-dir skills into `.ok/skills` and replaces the `.claude`, `.codex`, etc. copies with symlinks back to it, so the knowledge base is the single place to edit them and every editor stays in sync. It also flags the consequences a user needs before clicking: if those folders are committed to git the change should be reviewed, and symlinks can behave differently on some editors and on Windows. diff --git a/.changeset/skills-templates-editor-tabs.md b/.changeset/skills-templates-editor-tabs.md deleted file mode 100644 index dec03482f..000000000 --- a/.changeset/skills-templates-editor-tabs.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@inkeep/open-knowledge-app": minor ---- - -Edit skills and templates as first-class editor tabs instead of separate full-screen overlays. Opening a skill or template (from the sidebar Skills section or Settings) now opens it as a normal tab through the same editor pipeline documents use — with the file sidebar, tab bar, property panel, and version history. Skills additionally carry Install / Reinstall / Uninstall + history controls in the per-document toolbar. Skill and template tabs resolve as real documents everywhere (navigation, hash round-trip, graph/links), and a doc that links to a skill/template by its `.ok/skills//SKILL` or `.ok/templates/` file path now opens the artifact editor instead of offering to create a missing page. diff --git a/.changeset/skills-templates-link-index.md b/.changeset/skills-templates-link-index.md deleted file mode 100644 index 1b864d8dd..000000000 --- a/.changeset/skills-templates-link-index.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@inkeep/open-knowledge-app": minor ---- - -Skills and templates now participate in the link / backlink / graph index like documents, while staying hidden from the file tree. A document that links to a skill or template by its `.ok/skills//SKILL` or `/.ok/templates/` file path resolves to the artifact identity, so the link connects to the skill/template entity (backlinks both directions) instead of a dangling file path. Editing a skill or template re-derives its own outgoing links. The file-tree exclusion is unchanged — they remain hidden from the tree. diff --git a/.changeset/skills-tool-builtin-skill-hint.md b/.changeset/skills-tool-builtin-skill-hint.md deleted file mode 100644 index f59aa6cfe..000000000 --- a/.changeset/skills-tool-builtin-skill-hint.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -"@inkeep/open-knowledge": patch ---- - -Stop two ways agents get derailed around the skill surface. - -- The `skills` MCP tool now short-circuits OpenKnowledge's own built-in skills instead of 404-ing. An agent told to "load the open-knowledge skill" would call `skills({ name: "open-knowledge" })`, hit a bare `Skill not found.`, and fall back to cat-ing the bundled SKILL.md. The built-ins (`open-knowledge`, `open-knowledge-discovery`, `open-knowledge-write-skill`) are runtime agent skills projected into editor host dirs, never KB content skills, so a READ aimed at one now returns a teaching error explaining it is already in the agent's loaded skill list and is not fetched through this tool. User-authored `open-knowledge-pack-*` skills are unaffected, and the tool description states the boundary up front. - -- The project SKILL.md escape hatch now tells agents that their initial tool list is not exhaustive: some clients (notably Codex) defer MCP tools behind a lazy `tool_search` step, so `mcp__open-knowledge__*` is absent until discovered. Absence from the visible list means "not discovered yet," not "not registered" — agents must run tool discovery before invoking the native-tools escape hatch. diff --git a/.changeset/terminal-launch-no-raw-command-not-found.md b/.changeset/terminal-launch-no-raw-command-not-found.md deleted file mode 100644 index e89cd1c7d..000000000 --- a/.changeset/terminal-launch-no-raw-command-not-found.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@inkeep/open-knowledge-app": patch ---- - -Docked terminal: an _Open in terminal_ launch no longer prints a raw `command not found`. The launch gate now writes the ` ''` command only when a PATH probe confirms the CLI is present. On a flaky `unknown` probe it re-probes once; a `not-found` verdict, a still-`unknown` re-probe, or an IPC-level probe failure all suppress the write and surface the existing missing-CLI banner instead. This applies to Codex / Cursor / OpenCode (via `cliPreflight`) and to Claude (gated on the fresh `claudePreflight` recheck it already runs). The trade-off is a rare false-negative — an installed CLI whose probe flakes twice won't auto-launch — in exchange for a guaranteed-clean terminal. diff --git a/.changeset/web-app-server-keepalive.md b/.changeset/web-app-server-keepalive.md deleted file mode 100644 index 4381bd702..000000000 --- a/.changeset/web-app-server-keepalive.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@inkeep/open-knowledge": patch ---- - -Keep an open browser tab's `ok start` server alive. The web editor now holds a single, app-lifetime `/collab/keepalive` WebSocket — the same presence-invisible keepalive the desktop app and MCP shim already use — so the server's 30-minute idle-shutdown can no longer fire out from under an open tab when no document is focused or during a brief reconnect. Previously, with no doc open the only liveness signal was the per-document collab connections, so an idle tab could lose its server and every editor/tool call would fail until reload. Closing the tab still lets the server idle-shut-down normally, and the keepalive reconnects across a server restart on a new port. Multiple tabs each hold their own keepalive. The keepalive adds no presence-bar entry. diff --git a/.changeset/windows-git-ssh-sync-env.md b/.changeset/windows-git-ssh-sync-env.md deleted file mode 100644 index 2cc3b081c..000000000 --- a/.changeset/windows-git-ssh-sync-env.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -"@inkeep/open-knowledge": patch ---- - -Fix Git auto-sync when server-spawned Git needs the user's home directory, SSH agent, or credential-helper environment to reach a remote. This most visibly affected Windows repositories using SSH remotes, where `ok sync` and editor sync could fail with "Could not read from remote repository" while the same `git fetch` or `git push` worked in a terminal. - -Because preserving the home directory also lets server-spawned Git read the user's global config, OK now pins `commit.gpgsign=false` and `core.autocrlf=false` for its own Git commands only (via `-c`, leaving the user's own Git untouched): the first prevents the unattended sync commit from aborting when a global signing config can't prompt for a passphrase, and the second keeps line-ending conversion from churning content against OK's byte-exact round-trip. diff --git a/bun.lock b/bun.lock index 64012d74b..002be01ad 100644 --- a/bun.lock +++ b/bun.lock @@ -19,7 +19,7 @@ }, "docs": { "name": "@inkeep/open-knowledge-docs", - "version": "0.0.3", + "version": "0.0.4", "dependencies": { "@codemirror/commands": "^6.10.3", "@codemirror/lang-markdown": "^6.5.0", @@ -68,7 +68,7 @@ }, "packages/app": { "name": "@inkeep/open-knowledge-app", - "version": "0.19.2", + "version": "0.20.0", "dependencies": { "@codemirror/autocomplete": "^6.20.1", "@codemirror/commands": "^6.10.3", @@ -212,7 +212,7 @@ }, "packages/cli": { "name": "@inkeep/open-knowledge", - "version": "0.19.2", + "version": "0.20.0", "bin": { "open-knowledge": "dist/cli.mjs", "ok": "dist/cli.mjs", @@ -254,7 +254,7 @@ }, "packages/core": { "name": "@inkeep/open-knowledge-core", - "version": "0.19.2", + "version": "0.20.0", "dependencies": { "@handlewithcare/remark-prosemirror": "0.1.5", "@opentelemetry/api": "^1.9.0", @@ -330,7 +330,7 @@ }, "packages/desktop": { "name": "@inkeep/open-knowledge-desktop", - "version": "0.19.2", + "version": "0.20.0", "dependencies": { "@inkeep/open-knowledge": "workspace:*", "@inkeep/open-knowledge-core": "workspace:*", @@ -364,7 +364,7 @@ }, "packages/server": { "name": "@inkeep/open-knowledge-server", - "version": "0.19.2", + "version": "0.20.0", "dependencies": { "@hocuspocus/server": "4.0.0-rc.1", "@inkeep/open-knowledge-core": "workspace:*", diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index a5edfcecd..c00837c34 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -1,5 +1,14 @@ # @inkeep/open-knowledge-docs +## 0.0.4 + +### Patch Changes + +- Updated dependencies [7ca9e93] +- Updated dependencies [7ca9e93] +- Updated dependencies [7ca9e93] + - @inkeep/open-knowledge-core@0.20.0 + ## 0.0.3 ### Patch Changes diff --git a/docs/package.json b/docs/package.json index fc5a8efa7..7ccda4822 100644 --- a/docs/package.json +++ b/docs/package.json @@ -1,6 +1,6 @@ { "name": "@inkeep/open-knowledge-docs", - "version": "0.0.3", + "version": "0.0.4", "license": "GPL-3.0-or-later", "private": true, "packageManager": "bun@1.3.13", diff --git a/docs/src/lib/download-links.test.ts b/docs/src/lib/download-links.test.ts index e75653118..49018b65f 100644 --- a/docs/src/lib/download-links.test.ts +++ b/docs/src/lib/download-links.test.ts @@ -40,7 +40,7 @@ function jsonResponse(payload: unknown, status = 200) { } describe('pickLatestBetaDmgUrl', () => { - test('picks the DMG from the first published beta (API order is newest-first)', () => { + test('picks the highest-versioned published beta', () => { const url = pickLatestBetaDmgUrl([ release('v0.12.0-beta.7'), release('v0.12.0-beta.6'), @@ -49,6 +49,40 @@ describe('pickLatestBetaDmgUrl', () => { expect(url).toBe(dmgUrl('v0.12.0-beta.7')); }); + test('ranks by version, not the array order GitHub returns (older beta listed first)', () => { + const url = pickLatestBetaDmgUrl([ + release('v0.20.0-beta.9'), + release('v0.20.0-beta.8'), + release('v0.20.0-beta.13'), + release('v0.20.0-beta.12'), + release('v0.20.0-beta.10'), + ]); + expect(url).toBe(dmgUrl('v0.20.0-beta.13')); + }); + + test('beta.10 outranks beta.9 (no lexical tag compare)', () => { + const url = pickLatestBetaDmgUrl([release('v0.20.0-beta.9'), release('v0.20.0-beta.10')]); + expect(url).toBe(dmgUrl('v0.20.0-beta.10')); + }); + + test('ranks across base versions (minor/patch), not just the beta counter', () => { + const url = pickLatestBetaDmgUrl([ + release('v0.20.0-beta.99'), + release('v0.21.0-beta.1'), + release('v0.20.1-beta.2'), + ]); + expect(url).toBe(dmgUrl('v0.21.0-beta.1')); + }); + + test('skips the newest beta when its DMG is missing, ranking the next-newest', () => { + const url = pickLatestBetaDmgUrl([ + release('v0.20.0-beta.13', { assetNames: ['beta-mac.yml'] }), + release('v0.20.0-beta.12'), + release('v0.20.0-beta.9'), + ]); + expect(url).toBe(dmgUrl('v0.20.0-beta.12')); + }); + test('skips stable releases even when they appear first', () => { const url = pickLatestBetaDmgUrl([ release('v0.11.0', { prerelease: false }), diff --git a/docs/src/lib/download-links.ts b/docs/src/lib/download-links.ts index b597c20b2..1c5497d3f 100644 --- a/docs/src/lib/download-links.ts +++ b/docs/src/lib/download-links.ts @@ -10,7 +10,16 @@ export const RELEASES_PAGE_URL = 'https://github.com/inkeep/open-knowledge/relea const ASSET_URL_PREFIX = 'https://github.com/inkeep/open-knowledge/releases/download/'; -const BETA_TAG_PATTERN = /^v\d+\.\d+\.\d+-beta\.\d+$/; +const BETA_TAG_PATTERN = /^v(\d+)\.(\d+)\.(\d+)-beta\.(\d+)$/; + +type BetaRank = readonly [number, number, number, number]; + +function compareBetaRank(a: BetaRank, b: BetaRank): number { + for (let i = 0; i < 4; i++) { + if (a[i] !== b[i]) return a[i] - b[i]; + } + return 0; +} const LKG_TTL_MS = 300_000; @@ -37,16 +46,22 @@ export function pickLatestBetaDmgUrl(payload: unknown): string | null { return null; } + let best: { rank: BetaRank; url: string } | null = null; for (const release of parsed.data) { if (release.draft || !release.prerelease) continue; - if (!BETA_TAG_PATTERN.test(release.tag_name)) continue; + const parts = BETA_TAG_PATTERN.exec(release.tag_name); + if (!parts) continue; const dmg = release.assets.find( (asset) => asset.name === DMG_ASSET_NAME && asset.browser_download_url.startsWith(ASSET_URL_PREFIX), ); - if (dmg) return dmg.browser_download_url; + if (!dmg) continue; + const rank: BetaRank = [Number(parts[1]), Number(parts[2]), Number(parts[3]), Number(parts[4])]; + if (!best || compareBetaRank(rank, best.rank) > 0) { + best = { rank, url: dmg.browser_download_url }; + } } - return null; + return best?.url ?? null; } export type BetaRedirect = diff --git a/packages/app/package.json b/packages/app/package.json index d6257709b..f183a0092 100644 --- a/packages/app/package.json +++ b/packages/app/package.json @@ -1,6 +1,6 @@ { "name": "@inkeep/open-knowledge-app", - "version": "0.19.2", + "version": "0.20.0", "license": "GPL-3.0-or-later", "private": true, "type": "module", diff --git a/packages/app/src/App.tsx b/packages/app/src/App.tsx index 46d2f44ff..bb3c12357 100644 --- a/packages/app/src/App.tsx +++ b/packages/app/src/App.tsx @@ -365,7 +365,7 @@ function AppBody() { inert), so the Cmd-, route handler isn't mounted. */} {!singleFile && } {SHOW_INSTALL_SKILL && } - {/* File → Create New Project… opens CreateProjectDialog here. + {/* File → New project… opens CreateProjectDialog here. Desktop-only — the `new-project` menu action never fires in the web host, so the dialog stays unmounted there. */} {desktopBridge ? : null} diff --git a/packages/app/src/components/ProjectSwitcher.dom.test.tsx b/packages/app/src/components/ProjectSwitcher.dom.test.tsx index 3bc35e64f..cc556891b 100644 --- a/packages/app/src/components/ProjectSwitcher.dom.test.tsx +++ b/packages/app/src/components/ProjectSwitcher.dom.test.tsx @@ -125,17 +125,17 @@ describe('ProjectSwitcher dropdown behavior', () => { await openMenu(); const menuText = screen.getByTestId('project-switcher-menu').textContent ?? ''; - const openFolderIndex = menuText.indexOf('Open folder'); - const switchProjectIndex = menuText.indexOf('Switch project'); const newProjectIndex = menuText.indexOf('New project'); - expect(openFolderIndex).toBeGreaterThan(-1); - expect(switchProjectIndex).toBeGreaterThan(openFolderIndex); - expect(newProjectIndex).toBeGreaterThan(switchProjectIndex); + const switchProjectIndex = menuText.indexOf('Switch project'); + const openFolderIndex = menuText.indexOf('Open folder'); + expect(newProjectIndex).toBeGreaterThan(-1); + expect(switchProjectIndex).toBeGreaterThan(newProjectIndex); + expect(openFolderIndex).toBeGreaterThan(switchProjectIndex); for (const testId of [ - 'project-switcher-open-folder', - 'project-switcher-switch-project', 'project-switcher-new-project', + 'project-switcher-switch-project', + 'project-switcher-open-folder', ]) { expect(screen.getByTestId(testId).querySelector('svg[aria-hidden="true"]')).not.toBeNull(); } diff --git a/packages/app/src/components/ProjectSwitcher.tsx b/packages/app/src/components/ProjectSwitcher.tsx index dd8f492ef..be4cb9b38 100644 --- a/packages/app/src/components/ProjectSwitcher.tsx +++ b/packages/app/src/components/ProjectSwitcher.tsx @@ -211,9 +211,9 @@ export function ProjectSwitcher({ bridge }: ProjectSwitcherProps) { )} - -