Skip to content

Commit bd0757e

Browse files
tim-inkeepinkeep-oss-sync[bot]
authored andcommitted
feat(open-knowledge): preview via Claude Desktop in-app browser (#2588)
* feat(open-knowledge): preview via Claude Desktop in-app browser Claude Code Desktop's Browser pane now opens a URL directly with preview_start({url}) and moves with navigate({url}), the same way Cursor and Codex drive their in-app browsers. Migrate the preview capability ladder so Claude Desktop is treated as an in-app browser rather than the old preview-pane path, and remove the machinery that only existed to prop up the pane's base-open flow. - Skill + response-message cleanup to the preview_url -> preview_start({url}) -> navigate({url}) model (preview.md, SKILL.md, discovery, anti-patterns, preview-url.ts / get-preview-url.ts messages). - Remove the pane-target arming subsystem: the preview_url armPaneTarget param, the /api/config paneTarget field, the DELETE consume route, the ok ui base-open 302 redirect, the app PaneTargetLanding, and pane-target.ts. The presence-driven AgentFocusBroadcaster path is unchanged. - Add the spec for the remaining launch.json removal (I1/I2/I5/I6) under specs/2026-07-10-remove-launch-json-pane-arming. * feat(open-knowledge): remove launch.json + LAUNCH_JSON_PORT machinery OK no longer scaffolds a .claude/launch.json. Claude Code Desktop's in-app Browser pane opens the preview URL directly and preview_url autostarts the OK UI, so the generated launch.json dev-server recipe and its port split are dead weight. - Stop generating .claude/launch.json: remove scaffoldLaunchJson, the sh and PowerShell recipes, the version sentinels, and every wiring site (init, write-project-ai-integrations, desktop launch-json-wiring, worktree inherit, cli index export, .gitignore). - Repurpose the ok start repair sweep to remove any pre-existing open-knowledge-ui entry instead of rewriting it forward. repair-launch-json now delegates to removeOwnLaunchEntry; ok deinit removal is unchanged. - Remove the LAUNCH_JSON_PORT (39848) constant. The lock-collision proxy, the --ui-port channel, and connectUiSibling stay; they serve general ok ui collision and OK Electron, not only the launch.json spawn. - Update user-facing surfaces: the docs reference tables, the mcp reference (drop armPaneTarget), the consent and sharing UI (regenerated i18n catalogs), and AGENTS.md preview guidance. Kept on purpose: the git-exclude artifact set still lists .claude/launch.json so a legacy file left by an older OK stays excluded in local-only mode until the repair sweep removes it. The lume-qa e2e scenarios still probe the old 39848/launch.json flow; they run in a VM harness, not bun run check, and are left for a follow-up. * chore(ok-marketing): regen vendored open-knowledge-core dist Removing the paneTarget field from ApiConfigSuccessSchema in open-knowledge-core changed core's built index.mjs. Regenerate ok-marketing's vendored copy so verify-core-dist passes. * chore(open-knowledge): address PR review feedback - Add the missing changeset (minor): removes the scaffoldLaunchJson, LAUNCH_UI_CHAIN_*, and LaunchJsonResult exports from @inkeep/open-knowledge, the preview_url armPaneTarget param, and the /api/config paneTarget field. - Sweep stale launch.json / pane-target references out of JSDoc and comments (ui.ts, start.ts, write-project-ai-integrations.ts, project-integration-writers.ts, discovery/SKILL.md, ui.test.ts test name). - preview.md: drop the preview_start({name}) form, which now has no launch.json entry to spawn, so an agent can no longer pick a silently-failing invocation. - what-open-knowledge-writes.mdx: note the repair sweep now removes launch.json entries and restore the third sweep row so "all three" is accurate. - repair-launch-json: wrap removeOwnLaunchEntry so a write failure stays fail-soft (matching the "never throws" contract) instead of crashing ok start. - Rename localLockDir back to lockDir to match the surrounding convention. GitOrigin-RevId: 9b85ab89a160a444c93a2fee73c32db55dfeb6a6
1 parent be466bc commit bd0757e

48 files changed

Lines changed: 186 additions & 2430 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
---
2+
"@inkeep/open-knowledge": minor
3+
"@inkeep/open-knowledge-core": minor
4+
"@inkeep/open-knowledge-server": minor
5+
"@inkeep/open-knowledge-app": minor
6+
"@inkeep/open-knowledge-desktop": minor
7+
---
8+
9+
Remove the launch.json preview machinery and the pane-target arming subsystem. Claude Code Desktop's in-app Browser pane now opens the preview URL directly (`preview_start({url})` + `navigate({url})`), so OK no longer scaffolds `.claude/launch.json`.
10+
11+
Breaking for consumers: the `@inkeep/open-knowledge` package drops the `scaffoldLaunchJson`, `LAUNCH_UI_CHAIN_*`, and `LaunchJsonResult` exports; the `preview_url` MCP tool drops the `armPaneTarget` param; and the `/api/config` response drops the `paneTarget` field. The `ok start` repair sweep now removes any pre-existing `open-knowledge-ui` launch.json entry instead of rewriting it.

docs/content/reference/mcp.mdx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ The surface is **19 tools**. The four write verbs — `write`, `edit`, `delete`,
2121
| `skills` | Find and read agent skills. Omit `name` to list every skill across Project + Global (rows carry `installed` + `hosts`); pass `name` to read one (addressed by `name`+`scope`, never by path); pass `name` + `file` to read one bundle file's text — the read path for `references/` and `scripts/` content |
2222
| `config` | Read the effective merged config (`config({ key: "appearance.theme" })` for a sub-tree; omit `key` for the whole config) |
2323
| `palette` | Markdown-native authoring forms, themed `html preview` embed starters, and theme tokens. Pass `components` for the canonical components' full JSX prop schemas |
24-
| `preview_url` | Resolve the browser-reachable preview URL. Targets a `document`, `folder`, or `skill` in the current project, or — via `file`, an absolute path — a markdown file outside it (resolved through the session serving that file). Per-response `previewUrl` fields elsewhere are route-only (`/#/<doc>`); call this when you need the full openable URL. `armPaneTarget` briefly arms the target so a host preview pane opens on it |
24+
| `preview_url` | Resolve the browser-reachable preview URL. Targets a `document`, `folder`, or `skill` in the current project, or — via `file`, an absolute path — a markdown file outside it (resolved through the session serving that file). Per-response `previewUrl` fields elsewhere are route-only (`/#/<doc>`); call this when you need the full openable URL |
2525
| `share_link` | Build a GitHub-substrate share URL for a doc or folder to send to a teammate (`kind` disambiguates; `path: ""` with `kind: "folder"` shares the content root). Responses carry a `freshness` verdict — `current`, `stale` (unpushed changes), or `absent` (never pushed), omitted when the probe can't run — and prepend a matching warning to relay with the link. Read-only against `.git/`; never publishes |
2626
| `write` | Create or overwrite a `document`, `folder`, `template`, `skill`, or `asset`. For a document: `{ path, content }`, or `{ path, template }` to instantiate from a folder template. `position` selects `replace` (full rewrite; the only mode that touches frontmatter), `append`, or `prepend`. `extension` selects `.md` (default) or `.mdx` for a new document; an existing doc keeps its extension (the MCP cannot change it). An `asset` takes exactly one of `content` (base64, for small files) or `source` (a local path the server reads, for large files) |
2727
| `edit` | Modify a `document` (body find/replace **or** a frontmatter merge-patch), a `folder` (frontmatter merge-patch), a `template`, or a `skill`. Body edits take `{ path, find, replace, occurrence? }`; `occurrence` selects which match (1 = first) |
@@ -73,6 +73,6 @@ To detect conflict state proactively without waiting for a 409, call `conflicts(
7373

7474
## Preview links
7575

76-
Read and write tools return a `previewUrl` for any doc they touched, but **those are route-only** (`/#/<doc>` with no host:port), meant to identify the doc, not to be opened as-is. Hosts that want to open the editor (Claude Code Desktop's `preview_start`, terminal `open <url>`) call `preview_url` to resolve the full URL once per session.
76+
Read and write tools return a `previewUrl` for any doc they touched, but **those are route-only** (`/#/<doc>` with no host:port), meant to identify the doc, not to be opened as-is. Hosts that want to open the editor (Claude Code Desktop's `preview_start({url})`, terminal `open <url>`) call `preview_url` to resolve the full URL once per session.
7777

7878
`preview_url` always carries an `autoOpen` boolean (top-level on its response) reflecting the user's [`appearance.preview.autoOpen`](/docs/reference/configuration) preference. The write tools (`write`, `edit`) carry the same boolean on the `warning` object, which fires only when no browser is attached to the preview. In the common case (a browser is attached), the write response has no `warning` and no `autoOpen` field. Agents honor `autoOpen` before navigating: `true` (default) follows the host-capability routing in the bundled skill; `false` means the user is managing their own preview window, so the agent surfaces the URL on request but does not open or refresh anything. The value is resolved fresh on every tool call, so a mid-session toggle propagates within 0–1 calls, with no client restart.

docs/content/reference/what-open-knowledge-writes.mdx

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,6 @@ When you initialize or open a project, the app scaffolds the same project files
8787
| `.pi/extensions/open-knowledge.ts` | Managed bridge extension connecting [Pi](/docs/integrations/pi) (which has no MCP support) to the project | In-project, committed |
8888
| `.claude/skills/`, `.cursor/skills/`, `.codex/skills/`, `.opencode/skills/`, `.pi/skills/` | Project-local "rich" OpenKnowledge skill (`SKILL.md`) for the same five editors | In-project, committed |
8989
| `.ok/skill-targets.json` | Committed list of which editors receive skills, written when you customize the targets | In-project, committed |
90-
| `.claude/launch.json` | Configures Claude Code's preview pane to open the editor (on a local UI port, `39848`) | In-project, committed |
9190
| `~/.claude.json`, `~/Library/Application Support/Claude/claude_desktop_config.json`, `~/.cursor/mcp.json`, `~/.codex/config.toml`, `~/.config/opencode/opencode.json`, `~/.openclaw/openclaw.json`, `~/.gemini/config/mcp_config.json`, `~/.lmstudio/mcp.json`, `~/.hermes/config.yaml` | User-level `open-knowledge` MCP registration, one per detected editor, so it's available in every project (`~/.openclaw/openclaw.json` only when `~/.openclaw/` exists; `~/.gemini/config/mcp_config.json` is Antigravity's shared IDE + `agy` config, only when `~/.gemini/` exists; `~/.lmstudio/mcp.json` and `~/.hermes/config.yaml` only when those apps are installed) | Outside-project (editor config) |
9291

9392
### While a project is open
@@ -109,7 +108,7 @@ The app runs a collaboration server for the open project. It writes runtime stat
109108

110109
Diagnostic logs and telemetry are **on by default but local-only** — credential-bearing attributes are redacted (`[REDACTED]`) before anything is written, the files rotate at the size caps above, and nothing leaves the machine until you explicitly run `ok diagnose bundle`. Turn the local sink off with `telemetry.localSink.enabled: false`; see [Configuration](/docs/reference/configuration).
111110

112-
On each launch and project open, the app also runs **repair sweeps**: it rewrites *existing* `open-knowledge` MCP entries (in the editor configs above), `.claude/launch.json`, and the OpenKnowledge skill bundles (`open-knowledge-discovery` and `open-knowledge-write-skill`, in `~/.agents/skills/` and each detected editor's `~/.claude/skills/`, `~/.cursor/skills/`, `~/.codex/skills/`, `~/.opencode/skills/`) to the current canonical form — a no-op when nothing has drifted. It **never adds** an MCP entry to an editor that doesn't already have one; and when you turn on skill management for a project, it also adopts your existing editor skills into `.ok/skills/`. Same `OK_RECLAIM_DISABLE=1` opt-out.
111+
On each launch and project open, the app also runs **repair sweeps**: it rewrites *existing* `open-knowledge` MCP entries (in the editor configs above) and the OpenKnowledge skill bundles (`open-knowledge-discovery` and `open-knowledge-write-skill`, in `~/.agents/skills/` and each detected editor's `~/.claude/skills/`, `~/.cursor/skills/`, `~/.codex/skills/`, `~/.opencode/skills/`) to the current canonical form — a no-op when nothing has drifted. It also removes any stale `open-knowledge-ui` entry left in `.claude/launch.json` by an older OK version. It **never adds** an MCP entry to an editor that doesn't already have one; and when you turn on skill management for a project, it also adopts your existing editor skills into `.ok/skills/`. Same `OK_RECLAIM_DISABLE=1` opt-out.
113112

114113
### Home directory and credentials (`~/.ok/`)
115114

@@ -165,7 +164,6 @@ The `postinstall` step is **non-fatal** (install always succeeds even if it fail
165164
| `.pi/extensions/open-knowledge.ts` | Managed bridge extension connecting [Pi](/docs/integrations/pi) (which has no MCP support) to the project | In-project, committed |
166165
| `.claude/skills/`, `.cursor/skills/`, `.codex/skills/`, `.opencode/skills/`, `.pi/skills/` | Project-local "rich" OpenKnowledge skill (`SKILL.md`) for the same five editors | In-project, committed |
167166
| `.ok/skill-targets.json` | Committed list of which editors receive skills, written when you customize the targets | In-project, committed |
168-
| `.claude/launch.json` | Configures Claude Code's preview pane to open the editor (on a local UI port, `39848`) | In-project, committed |
169167

170168
With `--scope user` or `both` (the default), `ok init` also registers the `open-knowledge` MCP server in each detected editor's **user-level** config, so it's available in every project:
171169

@@ -217,8 +215,8 @@ On each boot, `ok start` also runs **repair sweeps**: it re-checks a few things
217215
| What it re-checks | Where | Scope |
218216
| --- | --- | --- |
219217
| Existing `open-knowledge` MCP entries | The same editor configs `ok init` writes — **both** user-level (`~/.claude.json`, `~/.cursor/mcp.json`, …) and project-level | Outside-project (editor config) **and** in-project |
220-
| `.claude/launch.json` | Your project | In-project, committed |
221218
| OpenKnowledge skill bundles (`open-knowledge-discovery`, `open-knowledge-write-skill`) | Project (`.claude/skills/…`) and user-global — `~/.agents/skills/` plus each detected editor's `~/.claude/skills/`, `~/.cursor/skills/`, `~/.codex/skills/`, `~/.opencode/skills/` | In-project **and** outside-project (home dir) |
219+
| Stale `open-knowledge-ui` entry in `.claude/launch.json` | Project | Removed if present — OK no longer writes launch.json |
222220

223221
Disable all three with `OK_RECLAIM_DISABLE=1`.
224222

packages/app/src/App.dom.test.tsx

Lines changed: 0 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,6 @@ let fetchApiConfigMock = mock(() =>
2929
collabUrl: null,
3030
previewUrl: null,
3131
port: 0,
32-
paneTarget: null,
3332
singleFile: false,
3433
},
3534
}),
@@ -261,7 +260,6 @@ describe('App runtime wiring', () => {
261260
collabUrl: null,
262261
previewUrl: null,
263262
port: 0,
264-
paneTarget: null,
265263
singleFile: false,
266264
},
267265
}),
@@ -365,74 +363,6 @@ describe('App runtime wiring', () => {
365363
expect(resolveNavigationTargetMock).not.toHaveBeenCalled();
366364
});
367365

368-
test('base-open pane target applies a well-formed config route once and consumes it', async () => {
369-
fetchApiConfigMock = mock(() =>
370-
Promise.resolve({
371-
status: 'ok' as const,
372-
config: {
373-
collabUrl: null,
374-
previewUrl: null,
375-
port: 0,
376-
paneTarget: '#/docs/pane-target',
377-
singleFile: false,
378-
},
379-
}),
380-
);
381-
382-
renderApp();
383-
384-
await waitFor(() => {
385-
expect(window.location.hash).toBe('#/docs/pane-target');
386-
});
387-
expect(fetchApiConfigMock).toHaveBeenCalledTimes(1);
388-
expect(globalThis.fetch).toHaveBeenCalledWith('/api/config', { method: 'DELETE' });
389-
});
390-
391-
test('base-open pane target ignores malformed and direct-navigation routes', async () => {
392-
fetchApiConfigMock = mock(() =>
393-
Promise.resolve({
394-
status: 'ok' as const,
395-
config: {
396-
collabUrl: null,
397-
previewUrl: null,
398-
port: 0,
399-
paneTarget: 'https://example.invalid/docs/readme',
400-
singleFile: false,
401-
},
402-
}),
403-
);
404-
405-
renderApp();
406-
407-
await waitFor(() => {
408-
expect(fetchApiConfigMock).toHaveBeenCalledTimes(1);
409-
});
410-
expect(window.location.hash).toBe('');
411-
expect(globalThis.fetch).not.toHaveBeenCalled();
412-
413-
cleanup();
414-
fetchApiConfigMock = mock(() =>
415-
Promise.resolve({
416-
status: 'ok' as const,
417-
config: {
418-
collabUrl: null,
419-
previewUrl: null,
420-
port: 0,
421-
paneTarget: '#/docs/pane-target',
422-
singleFile: false,
423-
},
424-
}),
425-
);
426-
setHash('#/docs/already-open');
427-
428-
renderApp();
429-
430-
await waitFor(() => {
431-
expect(fetchApiConfigMock).not.toHaveBeenCalled();
432-
});
433-
expect(window.location.hash).toBe('#/docs/already-open');
434-
});
435-
436366
test('active doc and folder targets are pushed to the desktop bridge', async () => {
437367
const bridge = createBridge();
438368
activeTarget = { kind: 'doc', target: 'docs/readme', docName: 'docs/readme' };

packages/app/src/App.tsx

Lines changed: 0 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,6 @@ import {
3131
} from '@/editor/DocumentContext';
3232
import { parseEditorTabId } from '@/editor/editor-tabs';
3333
import { useReconcileSkillTabs } from '@/hooks/use-reconcile-skill-tabs';
34-
import { fetchApiConfig } from '@/lib/api-config';
3534
import { ConfigProvider } from '@/lib/config-provider';
3635
import {
3736
assetPathFromHash,
@@ -248,52 +247,6 @@ function NavigationHandler() {
248247
return null;
249248
}
250249

251-
/**
252-
* One-shot base-open deep-link: when the UI opens at its base (no doc / asset /
253-
* dialog in the hash — e.g. the Claude pane's `preview_start`), apply an armed
254-
* pane target from `/api/config` so the pane lands on the agent's intended
255-
* doc/folder instead of an empty splash. Fires once at mount; navigates only if
256-
* the page is still at base when the fetch resolves (so it never overrides a
257-
* deep link the user opened directly or navigated to meanwhile). When no target
258-
* is armed (or it expired), it does nothing and the normal root view shows.
259-
*/
260-
function PaneTargetLanding() {
261-
// No `didRun` ref: a ref set synchronously persists across React Strict
262-
// Mode's dev double-invoke, which would make the first run's cleanup cancel
263-
// the fetch and the second run early-return — so the effect would silently do
264-
// nothing in dev. The `cancelled` flag + the `atBase` re-check already make
265-
// re-running safe and idempotent (it only navigates from a base hash).
266-
useEffect(() => {
267-
const atBase = (hash: string) =>
268-
!isAuxiliaryDialogHash(hash) &&
269-
!assetPathFromHash(hash) &&
270-
!docNameFromHash(hash) &&
271-
(hash === '' || hash === '#' || hash === '#/');
272-
if (!atBase(window.location.hash)) return;
273-
const controller = new AbortController();
274-
void fetchApiConfig(controller.signal)
275-
.then((result) => {
276-
if (controller.signal.aborted || result.status !== 'ok') return;
277-
const target = result.config.paneTarget;
278-
// Only apply a well-formed in-app route fragment, and only if we're still
279-
// at base (the user hasn't navigated during the fetch).
280-
if (!target?.startsWith('#/')) return;
281-
if (!atBase(window.location.hash)) return;
282-
window.location.hash = target;
283-
// Consume the one-shot target so a reload within its TTL doesn't yank
284-
// back here. Fire-and-forget — re-navigation is the only cost if it
285-
// fails, and the server-side TTL caps that anyway.
286-
void fetch('/api/config', { method: 'DELETE' }).catch(() => {});
287-
})
288-
// fetchApiConfig rethrows AbortError on unmount — expected, swallow it.
289-
.catch(() => {});
290-
// Aborting on unmount cancels the inflight request, not just its handler —
291-
// symmetric with the rest of the app's /api/config consumers.
292-
return () => controller.abort();
293-
}, []);
294-
return null;
295-
}
296-
297250
/**
298251
* Mounts `InstallInClaudeDesktopDialog` at the App root and opens it when
299252
* `window.location.hash === '#install-claude-desktop'`. Docs and in-app CTAs
@@ -533,7 +486,6 @@ function AppBody() {
533486
<PageListProvider>
534487
<SystemDocSubscriber />
535488
<NavigationHandler />
536-
<PaneTargetLanding />
537489
<ActiveTargetBridgePush />
538490
<NewItemShortcutHandler />
539491
{/* Settings is unavailable in single-file mode (config editing is

packages/app/src/components/ConfigSharingInfoTooltip.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ export function ConfigSharingInfoTooltip() {
2828
<p className="leading-relaxed wrap-break-word">
2929
<Trans>
3030
Setup files include: <code>.ok/</code>, AI-tool MCP configs (<code>.mcp.json</code>{' '}
31-
and per-tool files), project skills, and <code>.claude/launch.json</code>.
31+
and per-tool files), project skills.
3232
<br />
3333
<strong className="font-semibold">Shared</strong> commits them to git, so anyone who
3434
clones the repo gets the same setup. <br />

packages/app/src/components/ConsentDialogBody.tsx

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -391,10 +391,7 @@ function ConsentDialogForm({ payload, store, toast }: ConsentDialogFormProps) {
391391
<Trans>Connect to AI tools</Trans>
392392
</legend>
393393
<p className="text-1sm text-muted-foreground">
394-
<Trans>
395-
Writes a project-MCP config for each selected tool; Claude also gets{' '}
396-
<code>.claude/launch.json</code>.
397-
</Trans>
394+
<Trans>Writes a project-MCP config for each selected tool.</Trans>
398395
</p>
399396
{payload.editorOptions.map((editor) => {
400397
const checkboxId = `consent-editor-${editor.id}-cb`;

packages/app/src/lib/api-config.test.ts

Lines changed: 3 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,6 @@ describe('fetchApiConfig', () => {
3636
collabUrl: 'ws://localhost:52000/collab',
3737
previewUrl: 'http://localhost:3000/',
3838
port: 3000,
39-
paneTarget: null,
4039
singleFile: false,
4140
},
4241
});
@@ -52,7 +51,7 @@ describe('fetchApiConfig', () => {
5251
const result = await fetchApiConfig();
5352
expect(result).toEqual({
5453
status: 'ok',
55-
config: { collabUrl: null, previewUrl: null, port: 0, paneTarget: null, singleFile: false },
54+
config: { collabUrl: null, previewUrl: null, port: 0, singleFile: false },
5655
});
5756
});
5857

@@ -67,33 +66,7 @@ describe('fetchApiConfig', () => {
6766
const result = await fetchApiConfig();
6867
expect(result).toEqual({
6968
status: 'ok',
70-
config: { collabUrl: null, previewUrl: null, port: 0, paneTarget: null, singleFile: true },
71-
});
72-
});
73-
74-
it('parses an armed paneTarget route fragment', async () => {
75-
stubFetch(
76-
async () =>
77-
new Response(
78-
JSON.stringify({
79-
collabUrl: null,
80-
previewUrl: null,
81-
port: 0,
82-
paneTarget: '#/specs/foo/',
83-
}),
84-
{ status: 200 },
85-
),
86-
);
87-
const result = await fetchApiConfig();
88-
expect(result).toEqual({
89-
status: 'ok',
90-
config: {
91-
collabUrl: null,
92-
previewUrl: null,
93-
port: 0,
94-
paneTarget: '#/specs/foo/',
95-
singleFile: false,
96-
},
69+
config: { collabUrl: null, previewUrl: null, port: 0, singleFile: true },
9770
});
9871
});
9972

@@ -139,7 +112,7 @@ describe('fetchApiConfig', () => {
139112
const result = await fetchApiConfig();
140113
expect(result).toEqual({
141114
status: 'ok',
142-
config: { collabUrl: null, previewUrl: null, port: 0, paneTarget: null, singleFile: false },
115+
config: { collabUrl: null, previewUrl: null, port: 0, singleFile: false },
143116
});
144117
});
145118

0 commit comments

Comments
 (0)