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-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/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-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/cli/package.json b/packages/cli/package.json index 77c3c5a25..4f00ad342 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -1,6 +1,6 @@ { "name": "@inkeep/open-knowledge", - "version": "0.19.2", + "version": "0.20.0", "license": "GPL-3.0-or-later", "private": false, "type": "module", diff --git a/packages/core/package.json b/packages/core/package.json index 66171022d..6764c3ed9 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -1,6 +1,6 @@ { "name": "@inkeep/open-knowledge-core", - "version": "0.19.2", + "version": "0.20.0", "license": "GPL-3.0-or-later", "private": true, "type": "module", diff --git a/packages/desktop/package.json b/packages/desktop/package.json index 64d75ebd1..2a5ef0e41 100644 --- a/packages/desktop/package.json +++ b/packages/desktop/package.json @@ -1,7 +1,7 @@ { "name": "@inkeep/open-knowledge-desktop", "productName": "OpenKnowledge", - "version": "0.19.2", + "version": "0.20.0", "license": "GPL-3.0-or-later", "private": true, "type": "module", diff --git a/packages/desktop/src/main/index.ts b/packages/desktop/src/main/index.ts index 1b7344e62..e5e656658 100644 --- a/packages/desktop/src/main/index.ts +++ b/packages/desktop/src/main/index.ts @@ -2889,6 +2889,7 @@ function bootPrimaryInstance(): void { }); electronAutoUpdater.on('before-quit-for-update', () => { getLogger('updater').info({}, 'before-quit-for-update — update install will relaunch the app'); + wm?.signalStopAllOwnedServers(); flushDesktopLogger(); }); diff --git a/packages/desktop/src/main/signal-detached-server-stop.test.ts b/packages/desktop/src/main/signal-detached-server-stop.test.ts new file mode 100644 index 000000000..5586ef3a7 --- /dev/null +++ b/packages/desktop/src/main/signal-detached-server-stop.test.ts @@ -0,0 +1,115 @@ +import { describe, expect, mock, test } from 'bun:test'; +import { + signalDetachedServerStop, + signalStopOwnedUtilityForks, + type UtilityProcessLike, +} from './window-manager.ts'; + +function ctx( + ownsServer: boolean, + kill: ((signal: NodeJS.Signals) => void) | null, + projectPath = '/proj', +) { + return { + ownsServer, + utility: (kill ? { kill } : null) as unknown as UtilityProcessLike | null, + projectPath, + }; +} + +describe('signalDetachedServerStop (before-quit-for-update teardown)', () => { + test('sends SIGTERM to every detached server pid', () => { + const killProbe = mock((_pid: number, _signal: number | NodeJS.Signals) => {}); + const signalled = signalDetachedServerStop( + [ + ['/proj/a', 101], + ['/proj/b', 202], + ], + killProbe, + ); + expect(signalled).toBe(2); + expect(killProbe).toHaveBeenCalledTimes(2); + expect(killProbe).toHaveBeenNthCalledWith(1, 101, 'SIGTERM'); + expect(killProbe).toHaveBeenNthCalledWith(2, 202, 'SIGTERM'); + }); + + test('treats an already-exited server (ESRCH) as done without logging a failure', () => { + const killProbe = mock((_pid: number, _signal: number | NodeJS.Signals) => { + const err = new Error('no such process') as NodeJS.ErrnoException; + err.code = 'ESRCH'; + throw err; + }); + const log = { warn: mock((_o: object, _m: string) => {}) }; + const signalled = signalDetachedServerStop([['/proj/gone', 303]], killProbe, log); + expect(signalled).toBe(0); + expect(log.warn).not.toHaveBeenCalled(); + }); + + test('logs but never throws on a non-ESRCH signal failure, and continues to later pids', () => { + const killProbe = mock((pid: number, _signal: number | NodeJS.Signals) => { + if (pid === 404) { + const err = new Error('operation not permitted') as NodeJS.ErrnoException; + err.code = 'EPERM'; + throw err; + } + }); + const log = { warn: mock((_o: object, _m: string) => {}) }; + const signalled = signalDetachedServerStop( + [ + ['/proj/locked', 404], + ['/proj/ok', 505], + ], + killProbe, + log, + ); + expect(signalled).toBe(1); + expect(killProbe).toHaveBeenCalledTimes(2); + expect(log.warn).toHaveBeenCalledTimes(1); + expect(log.warn.mock.calls[0]?.[0]).toMatchObject({ + event: 'update-install-server-stop-failed', + code: 'EPERM', + pid: 404, + projectPath: '/proj/locked', + }); + }); + + test('no entries (already drained — e.g. the Relaunch-now path) is a clean no-op', () => { + const killProbe = mock((_pid: number, _signal: number | NodeJS.Signals) => {}); + expect(signalDetachedServerStop([], killProbe)).toBe(0); + expect(killProbe).not.toHaveBeenCalled(); + }); +}); + +describe('signalStopOwnedUtilityForks (shared utility-fork hard-kill)', () => { + test('SIGKILLs every owned utility fork', () => { + const killA = mock((_s: NodeJS.Signals) => {}); + const killB = mock((_s: NodeJS.Signals) => {}); + signalStopOwnedUtilityForks([ctx(true, killA, '/a'), ctx(true, killB, '/b')]); + expect(killA).toHaveBeenCalledWith('SIGKILL'); + expect(killB).toHaveBeenCalledWith('SIGKILL'); + }); + + test('skips contexts that do not own their server or have no utility', () => { + const killOwned = mock((_s: NodeJS.Signals) => {}); + const killNotOwned = mock((_s: NodeJS.Signals) => {}); + signalStopOwnedUtilityForks([ + ctx(false, killNotOwned), // attached (sibling-owned) server — must not touch + ctx(true, null), // detached server, no in-process utility fork + ctx(true, killOwned), // the only one to kill + ]); + expect(killNotOwned).not.toHaveBeenCalled(); + expect(killOwned).toHaveBeenCalledWith('SIGKILL'); + }); + + test('logs but never throws on a kill failure, and continues to later forks', () => { + const killLater = mock((_s: NodeJS.Signals) => {}); + const throwing = mock((_s: NodeJS.Signals) => { + throw new Error('already dead'); + }); + const log = { warn: mock((_o: object, _m: string) => {}) }; + signalStopOwnedUtilityForks([ctx(true, throwing, '/boom'), ctx(true, killLater, '/ok')], log); + expect(killLater).toHaveBeenCalledWith('SIGKILL'); + expect(log.warn).toHaveBeenCalledTimes(1); + expect(log.warn.mock.calls[0]?.[0]).toMatchObject({ projectPath: '/boom' }); + }); +}); diff --git a/packages/desktop/src/main/window-manager.ts b/packages/desktop/src/main/window-manager.ts index 5566f8f8e..b735ea1ca 100644 --- a/packages/desktop/src/main/window-manager.ts +++ b/packages/desktop/src/main/window-manager.ts @@ -159,6 +159,51 @@ export interface WindowManagerDeps { onUtilityExit?(utility: UtilityProcessLike): void; } +export function signalDetachedServerStop( + entries: ReadonlyArray, + killProbe: (pid: number, signal: number | NodeJS.Signals) => void, + log?: { warn(obj: object, msg: string): void }, +): number { + let signalled = 0; + for (const [projectPath, pid] of entries) { + try { + killProbe(pid, 'SIGTERM'); + signalled++; + } catch (err) { + const code = (err as NodeJS.ErrnoException).code; + if (code === 'ESRCH') continue; + log?.warn( + { + event: 'update-install-server-stop-failed', + err: (err as Error).message, + code, + pid, + projectPath, + }, + 'SIGTERM failed during before-quit-for-update teardown', + ); + } + } + return signalled; +} + +export function signalStopOwnedUtilityForks( + contexts: Iterable>, + log?: { warn(obj: object, msg: string): void }, +): void { + for (const ctx of contexts) { + if (!ctx.ownsServer || !ctx.utility) continue; + try { + ctx.utility.kill('SIGKILL'); + } catch (err) { + log?.warn( + { err: (err as Error).message, projectPath: ctx.projectPath }, + 'utility SIGKILL failed during owned-server teardown', + ); + } + } +} + export class WindowManager { private readonly windowsByPath = new Map(); @@ -215,17 +260,7 @@ export class WindowManager { } async stopAllOwnedServers(): Promise { - for (const ctx of this.windowsByPath.values()) { - if (!ctx.ownsServer || !ctx.utility) continue; - try { - ctx.utility.kill('SIGKILL'); - } catch (err) { - this.deps.log?.warn( - { err: (err as Error).message, projectPath: ctx.projectPath }, - 'utility SIGKILL failed during pre-relaunch teardown', - ); - } - } + signalStopOwnedUtilityForks(this.windowsByPath.values(), this.deps.log); const readLock = this.deps.readServerLock; const stopOne = async (canonicalKey: string, pid: number): Promise => { @@ -291,6 +326,25 @@ export class WindowManager { ]); } + signalStopAllOwnedServers(): void { + signalStopOwnedUtilityForks(this.windowsByPath.values(), this.deps.log); + + const detached = [...this.spawnedDetachedPids.entries()]; + this.spawnedDetachedPids.clear(); + const ephemeral = [...this.windowsByPath.values()] + .map((ctx) => ctx.ephemeral) + .filter((e): e is NonNullable => e !== undefined) + .map((e) => [e.projectDir, e.pid] as const); + const entries = [...detached, ...ephemeral]; + const signalled = signalDetachedServerStop(entries, this.deps.killProbe, this.deps.log); + if (entries.length > 0) { + this.deps.log?.info( + { event: 'update-install-server-stop', count: entries.length, signalled }, + '[window-manager] signalled owned detached servers to stop for update install', + ); + } + } + private async terminateServerByPid( lockDir: string, pid: number, diff --git a/packages/desktop/tests/main/window-manager-ephemeral.test.ts b/packages/desktop/tests/main/window-manager-ephemeral.test.ts index 77c300039..ef8c7ad9c 100644 --- a/packages/desktop/tests/main/window-manager-ephemeral.test.ts +++ b/packages/desktop/tests/main/window-manager-ephemeral.test.ts @@ -336,6 +336,27 @@ describe('createEphemeralWindow', () => { expect(env.removedDirs).toEqual(['/tmp/ok-ephemeral-1']); }); + test('signalStopAllOwnedServers (before-quit-for-update) SIGTERMs detached + ephemeral pids and drains the detached map', async () => { + const wm = new WindowManager(env.deps); + (wm as unknown as { spawnedDetachedPids: Map }).spawnedDetachedPids.set( + '/proj/detached', + 77001, + ); + await wm.createEphemeralWindow({ + canonicalFilePath: FILE, + contentDir: PARENT, + docName: 'todo', + }); // ephemeral server pid = 42001 + + wm.signalStopAllOwnedServers(); + + expect(env.killCalls).toContainEqual({ pid: 77001, signal: 'SIGTERM' }); + expect(env.killCalls).toContainEqual({ pid: 42001, signal: 'SIGTERM' }); + + wm.signalStopAllOwnedServers(); + expect(env.killCalls.filter((k) => k.pid === 77001 && k.signal === 'SIGTERM')).toHaveLength(1); + }); + test('requires the ephemeral deps to be wired', async () => { const partial = buildEphemeralEnv(); partial.deps.createEphemeralProjectDir = undefined; diff --git a/packages/server/assets/skills/discovery/SKILL.md b/packages/server/assets/skills/discovery/SKILL.md index 8a8240306..90733cfc5 100644 --- a/packages/server/assets/skills/discovery/SKILL.md +++ b/packages/server/assets/skills/discovery/SKILL.md @@ -3,7 +3,7 @@ name: open-knowledge-discovery description: "Read when the user asks what OpenKnowledge is, wants to install it on a repository, wants to share an OpenKnowledge project with collaborators, or asks how `ok init` / `ok cowork` / OK Desktop set up a project. Do NOT load to perform OpenKnowledge reads/writes — the runtime guidance for editing markdown inside an initialized OK project ships as a separate project-local skill at `.claude/skills/open-knowledge/` whenever `ok init` runs. If the user appears to be editing markdown inside a `.ok/` project and this is the only OK skill loaded, advise them to re-run `ok init` to install the project-local skill." compatibility: "Any agent host — no MCP server required. Pure discovery + install guidance." metadata: - version: "0.19.2" + version: "0.20.0" author: "Inkeep" repository: "https://github.com/inkeep/open-knowledge" --- diff --git a/packages/server/assets/skills/project/SKILL.md b/packages/server/assets/skills/project/SKILL.md index bb7cf3ec2..52e9b236d 100644 --- a/packages/server/assets/skills/project/SKILL.md +++ b/packages/server/assets/skills/project/SKILL.md @@ -3,7 +3,7 @@ name: open-knowledge description: "Authoritative agent-runtime contract for working inside an OpenKnowledge project — a markdown-CRDT knowledge base exposed over MCP. Use whenever reading, listing, searching, or editing any `.md` or `.mdx` file in the project, and before any `mcp__open-knowledge__*` tool call (`exec`, `search`, `write`, `edit`, and the rest). Installed by `ok init`, so its presence means this is an OpenKnowledge project and it governs every markdown file here. Covers the read/write tool surface, grounding and linking rules, folder/template conventions, the live browser preview, and the rule that OK's MCP tools — never native file tools — handle in-scope markdown." compatibility: "Claude Code, Claude Desktop, Claude Cowork, Claude.ai web. Requires OpenKnowledge MCP server + code execution." metadata: - version: "0.19.2" + version: "0.20.0" author: "Inkeep" repository: "https://github.com/inkeep/open-knowledge" --- diff --git a/packages/server/assets/skills/write-skill/SKILL.md b/packages/server/assets/skills/write-skill/SKILL.md index 242686b1f..eaf3a5219 100644 --- a/packages/server/assets/skills/write-skill/SKILL.md +++ b/packages/server/assets/skills/write-skill/SKILL.md @@ -3,7 +3,7 @@ name: open-knowledge-write-skill description: "Use when the user wants to create, author, write, or design a new Agent Skill (a SKILL.md) — for OpenKnowledge or for their editors — including requests like 'help me write a skill', 'make a skill that…', 'turn this workflow into a skill', or improving an existing skill's triggering and discipline. Also use when capturing reusable agent guidance that should live as an installable skill rather than a one-off prompt. Covers choosing scope (project vs global), the SKILL.md frontmatter contract, progressive-disclosure structure, evaluating the skill, and installing it into the user's editors." compatibility: "OpenKnowledge project recommended (uses the `write` / `edit` / `install` MCP verbs). Authoring + validation are pure file ops; live preview + eval want a running server (`ok start`)." metadata: - version: "0.9.1" + version: "0.20.0" author: "Inkeep" repository: "https://github.com/inkeep/open-knowledge" --- diff --git a/packages/server/package.json b/packages/server/package.json index 9d3d3432d..2914f3a6b 100644 --- a/packages/server/package.json +++ b/packages/server/package.json @@ -1,6 +1,6 @@ { "name": "@inkeep/open-knowledge-server", - "version": "0.19.2", + "version": "0.20.0", "license": "GPL-3.0-or-later", "private": true, "type": "module",