Skip to content

feat: agent ability to focus a page in the editor (PRD-7183)#385

Merged
inkeep-oss-sync[bot] merged 1 commit into
mainfrom
copybara/sync
Jun 30, 2026
Merged

feat: agent ability to focus a page in the editor (PRD-7183)#385
inkeep-oss-sync[bot] merged 1 commit into
mainfrom
copybara/sync

Conversation

@inkeep-oss-sync

Copy link
Copy Markdown
Contributor

No description provided.

* docs(spec): PRD-7183 agent ability to focus a page in the editor

Rationalize how the OK editor is exposed to agents for "focus page N"
across hosts. Two worlds: pane/browser agent apps (Cursor, Codex Desktop,
Claude Code Desktop) focus in-app via their own host tool + preview_url;
no-pane hosts (Claude CLI, OK Desktop built-in terminal) focus the OK
Desktop window via ok open. Surviving scope: reliable window foreground
(app.focus steal), ok open -> world-aware selector reusing existing IPC,
per-host SKILL.md guidance. Zero new MCP tools. CC1 focus channel cut to
Future Work (auto-follow). Grounded + cold-reader audited.

* feat(desktop): reliably foreground the editor window on agent focus (PRD-7183)

When an agent focuses a page and the project window already exists, OK only
called BrowserWindow.focus() — which on macOS reorders within the app but does
not pull a backgrounded app to the front (electron/electron#19920). So an
agent-driven "focus this page" silently left OpenKnowledge behind the user's
current app unless the focus happened to ride the openknowledge:// +
LaunchServices path (which activates the bundle as a side effect).

Add a single bringToFront() recipe — restore -> show -> moveTop -> focus +
app.focus({steal:true}) — used by every focus-an-existing-window path
(deep-link warm path + createProjectWindow + ephemeral dedup). Skip the
app-level steal when the window is already frontmost (e.g. the OK Desktop
built-in terminal focusing a doc in its own active window). app.focus is
injected via WindowManagerDeps.activateApp (macOS-guarded in index.ts) so the
manager stays Electron-free for tests.

SKILL.md: note that ok open from the OK Desktop built-in terminal re-targets
the same window. Per-host focus guidance (W1 in-app, W2 ok open) was already
present.

Spec: specs/2026-06-26-agent-editor-page-focus. Zero new MCP tools; CC1 focus
channel deferred to Future Work (auto-follow). Window foreground is unit-tested;
true OS foreground is a packaged-build smoke check (OQ7).

* feat(desktop+skill): make CLI agents reliably ok-open into the app (PRD-7183)

Two seams from real OK Desktop built-in-terminal usage:

1. The embedded terminal gave an agent no signal it was running inside OK
   Desktop, so it guessed preview_url (the browser path) and had to be
   corrected repeatedly. Fix: buildShellEnv now exports OK_DESKTOP_TERMINAL=1
   so the agent can detect it and `ok open <doc>` re-targets the same window.

2. Skill guidance under-named the CLI track. Reframe it around capability,
   not vendor: ANY CLI with no in-app browser (Claude Code CLI, Codex CLI,
   Cursor CLI, any pure shell agent) uses `ok open <doc>`, never a preview
   URL. Apps with a pane/browser (Claude Code Desktop, Cursor, Codex desktop)
   navigate their own. Stated up-front in the core TL;DR and in
   references/preview.md so the agent leads with the right path.

No code beyond the one env marker; the rest is skill clarity. Tests:
pty-host marker assertions; skill bundles recompose clean.

* feat(cli): ok open works for docs, folders, and skills — no --folder needed (PRD-7183)

Make `ok open <name>` consistent across content types and deep-link them all
into OK Desktop (browser-UI fallback), instead of docs-to-app / folders-to-browser.

- Auto-detect doc vs folder by stat'ing <name> against the project (directory →
  folder, else doc), so `--folder` is no longer required (kept as an explicit
  override for a not-yet-created folder).
- Folders now deep-link to the app: openknowledge://open gains a `folder=` param.
  parseOpenKnowledgeUrl returns a {kind:'doc'|'folder'} discriminator (same
  traversal/null-byte validation for both); routeUrl threads parsed.kind to the
  existing kind-aware deep-link payload + pendingDeepLinkTarget. Renderer +
  check-target-exists already handled 'folder' (share flow), so no renderer change.
- Skills: `ok open <name> --skill [--scope project|global]` opens the skill editor.
  A skill rides the existing doc= param as the synthetic __skill__/<scope>/<name>
  docName (resolves via docNameFromHash as an editor tab) — zero new scheme
  plumbing. Assets deliberately excluded: split-brained target (viewer route vs
  OS shell-open) with a disproportionate desktop delta.
- export encodeSkillRoute from the server package index (single source of truth).
- Skill guidance + `ok open --help` updated to be explicit: doc/folder
  auto-detected, --skill for skills, all deep-link into the app.

Tests: open.test (auto-detect, folder deep-link, skill desktop+browser, bad
scope); url-scheme parser folder= cases + both/neither rejection + traversal.

* feat(mcp): preview_url steers to `ok open` when in the OK Desktop terminal (PRD-7183)

Skill prose alone wasn't getting agents in OK Desktop's built-in terminal to use
`ok open` — they kept reaching for preview_url + a browser. Add a runtime nudge
that fires at the wrong call: when preview_url runs in the OK Desktop terminal,
its response leads with `run \`ok open <target>\` … don't navigate the URL`.

Detection needs no carrier: `ok mcp` (bare, no --port) runs in global-server mode
(server.ts → registerAllTools), so preview_url executes IN the `ok mcp` process —
which inherited `OK_DESKTOP_TERMINAL=1` from the terminal pty. server.ts passes
`isDesktopTerminal: process.env.OK_DESKTOP_TERMINAL === '1'` into registerAllTools
→ preview_url. The shared collab server (`ok start`) never has the marker, so it
passes false and is unaffected; Cursor/Codex/plain-CLI processes don't have it
either, so they're unchanged (they correctly drive their own browser/pane).

Steer only fires for an in-project doc/folder/skill target (root + the off-cwd
`file` branch are untouched). Tests cover doc/folder/skill-global steers, the
no-target no-steer case, and the not-a-desktop-terminal regression.

* fix(cli): address PR #2269 review — skill name validation + steer test/structured gaps

- Move the `isUnsafeName` traversal guard ABOVE the `--skill` branch so skill
  names get the same `..`/leading-slash/backslash rejection as docs and folders
  (pullfrog + claude: the skill branch returned before the check). Defense-in-
  depth — the desktop parser already rejects `..` — but keeps CLI-layer
  validation symmetric and avoids a false-success.
- Surface the steer command as `okOpenCommand` in preview_url's structuredContent
  (nullable/optional; non-null only in the OK Desktop terminal with a target) so
  agents can consume it programmatically, not just parse the text body.
- Tests: skill no-target → error (symmetry with doc/folder); skill traversal
  rejection; default-scope skill steer (`ok open <name> --skill`, no --scope);
  okOpenCommand assertions incl. the not-a-terminal null case.

* fix: address PR #2269 re-review — shell-quote steer, dedupe scopes, fill steer tests

- okOpenCommand now shell-quotes doc/folder paths containing spaces/specials
  (`shellQuoteArg`); clean slug paths pass through unquoted; skill names are
  already [a-z0-9-] so they're untouched. The field is documented "the exact
  command to run", so it must be shell-safe.
- Replace local SKILL_SCOPES with core's canonical MANAGED_ARTIFACT_SCOPES
  (single source of truth; cli already deps on core).
- Tests: folder steer asserts structuredContent.okOpenCommand; desktop-terminal
  + no-UI keeps the steer + okOpenCommand (ok open doesn't need the UI);
  space-containing doc → quoted okOpenCommand.

* fix: address PR #2269 3rd review — narrow stat catches + edge-case steer tests

- classifyName (open.ts) + isFileishTarget (single-file-dispatch.ts): narrow the
  bare statSync catch — ENOENT/ENOTDIR is the expected "doesn't resolve" case
  (silent fallthrough); any other code (EACCES/ELOOP/…) logs to stderr so a
  misclassification is diagnosable, mirroring the isServerLive pattern.
- Tests: shellQuoteArg embedded single-quote POSIX escape (`what's new` →
  `'…what'\''s new'`); no-UI + folder + desktop-terminal okOpenCommand.

---------

GitOrigin-RevId: c73dfbf00ceead6b09979cbbadf07c568191ee7c

@inkeep-internal-ci inkeep-internal-ci Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Automated approval from agents-private public-mirror-sync (run: https://github.com/inkeep/agents-private/actions/runs/28413855696). Source of truth is the monorepo; direct edits on inkeep/open-knowledge are overwritten on next sync.

@inkeep-oss-sync inkeep-oss-sync Bot merged commit 3d2a0ef into main Jun 30, 2026
1 check passed
@CLAassistant

Copy link
Copy Markdown

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you sign our Contributor License Agreement before we can accept your contribution.
You have signed the CLA already but the status is still pending? Let us recheck it.

@inkeep-oss-sync inkeep-oss-sync Bot deleted the copybara/sync branch June 30, 2026 01:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants