Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
68c54e7
feat(web-shell): declutter workspace sidebar and add loopback open ac…
wenshao Aug 31, 2026
4d24284
Merge remote-tracking branch 'origin/main' into feat/webshell-workspa…
wenshao Aug 31, 2026
5459500
fix(web-shell): keep session dates in the hover popover with yyyy-MM-…
wenshao Aug 31, 2026
dbe608f
fix(web-shell): show HH:mm:ss for same-day sessions in the hover popover
wenshao Aug 31, 2026
ad677a3
fix(cli): register local-path-open in the serve process.env guard
wenshao Aug 31, 2026
0731457
Merge remote-tracking branch 'origin/main' into feat/webshell-workspa…
wenshao Aug 31, 2026
c98701a
fix(web-shell): address review findings on accessibility and platform…
wenshao Aug 31, 2026
4936045
Merge remote-tracking branch 'origin/main' into feat/webshell-workspa…
wenshao Aug 31, 2026
9338a61
fix(cli,web-shell): address review round 2 — linux terminal gates, wo…
wenshao Aug 31, 2026
650d2f3
docs(developers): sync daemon capability counts with the registry
wenshao Sep 1, 2026
ab48b21
fix(cli): make the spawn hang guards testable without fake timers
wenshao Sep 1, 2026
0120f70
Merge remote-tracking branch 'origin/main' into feat/webshell-workspa…
wenshao Sep 1, 2026
bea3818
fix(cli,web-shell): address re-review — wt hang fallback guard, menu-…
wenshao Sep 1, 2026
f25d0d3
Merge remote-tracking branch 'origin/main' into feat/webshell-workspa…
wenshao Sep 1, 2026
b2fe0ab
fix(serve): mirror runtime-only capability tags in the bootstrap enve…
wenshao Sep 1, 2026
7e7e250
fix(web-shell): drop duplicate language declarations in ChatEditor test
wenshao Sep 1, 2026
e5398dc
Merge branch 'main' into feat/webshell-workspace-hover-details
wenshao Sep 1, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion docs/developers/qwen-serve-protocol.md
Original file line number Diff line number Diff line change
Expand Up @@ -482,7 +482,7 @@ operator diagnostic snapshot documented below.
<!-- conditional-serve-features:start -->

| Tag | Advertised when … |
| ----------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| ----------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------- |
| `require_auth` | the daemon was started with `--require-auth` (or `requireAuth: true` via the embedded API). Bearer token is mandatory on every normal API route, including `/health` on loopback binds; channel webhook ingress keeps its independent shared-secret authentication, and Web Shell document and asset routes remain pre-auth. |
| `mcp_workspace_pool` | the shared MCP transport pool is active. Omitted when `QWEN_SERVE_NO_MCP_POOL=1` disables the pool. |
| `mcp_pool_restart` | the shared MCP transport pool is active; restart responses may include pool-aware multi-entry shapes. |
Expand Down Expand Up @@ -513,6 +513,8 @@ operator diagnostic snapshot documented below.
| `scratch_workspace_registration` | managed scratch workspace creation is available — a runtime factory, a validated managed scratch root, and runtime disposal are wired, and every managed runtime respects the scratch root boundary. |
| `workspace_runtime_removal` | removable dynamic or persistence-restored secondary runtimes can be drained and removed through the management route. |
| `native_directory_picker` | the daemon host can open a native OS directory picker (`osascript` on macOS, PowerShell on Windows, `zenity` on a Linux host with a display). Headless hosts omit the tag so clients hide the Browse affordance instead of surfacing a guaranteed picker failure. |
| `workspace_local_open` | the daemon host can open a workspace directory in the host's OS file manager (`open` on macOS, `explorer.exe` on Windows, `xdg-open` on a Linux host with a display). Headless hosts omit the tag so clients hide the Open-locally affordance instead of surfacing a guaranteed launch failure. The opened path is always the resolved registered workspace cwd, via `POST /workspaces/:workspace/open`; the route accepts an optional JSON body `{ "target": "terminal" }` (absent/other = folder) and answers `{ kind: 'workspace-local-open', opened: true, target: 'folder' | 'terminal' }`. |
| `workspace_local_terminal` | the daemon host can open a terminal window in a workspace directory (`open -a Terminal` on macOS, `wt.exe` with `cmd.exe` fallback on Windows, `gnome-terminal`/`konsole`/`xterm` on a Linux host with a display). Headless hosts omit the tag so clients hide the Open-in-terminal affordance instead of surfacing a guaranteed launch failure. Served by `POST /workspaces/:workspace/open` with body `{ "target": "terminal" }`. |
| `workspace_qualified_acp` | ACP HTTP and multi-workspace runtimes are active, so the plural ACP endpoint can select a secondary runtime. |
| `workspace_qualified_voice` | multi-workspace runtimes and the shared ACP/Voice WebSocket listener are active, so every workspace-qualified Voice modality is reachable for a secondary runtime. |
| `workspace_qualified_memory` | ACP HTTP and multi-workspace runtimes are active, so workspace-qualified managed-memory routes can select a per-workspace task lane for remember, forget, and dream operations. |
Expand Down
12 changes: 12 additions & 0 deletions integration-tests/cli/qwen-serve-routes.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,10 @@ import {
type ChatRecord,
} from '@qwen-code/qwen-code-core';
import { isNativeDirectoryPickerAvailable } from '../../packages/cli/src/serve/native-directory-picker.js';
import {
isLocalPathOpenAvailable,
isLocalTerminalAvailable,
} from '../../packages/cli/src/serve/local-path-open.js';

const __dirname = path.dirname(fileURLToPath(import.meta.url));
// Match the rest of the integration suite: prefer the bundled CLI
Expand All @@ -67,6 +71,10 @@ let client: DaemonClient;
// assertion time minutes later diverged when the host's GUI session state
// drifted mid-run (red macOS E2E runs after #9406, tracked in #10453).
let nativeDirectoryPickerAtBoot = false;
// Same boot-time probe pinning as above, for the workspace_local_open tag.
let localPathOpenAtBoot = false;
// Same boot-time probe pinning as above, for the workspace_local_terminal tag.
let localTerminalOpenAtBoot = false;

function writePersistedTranscript(
sessionId: string,
Expand Down Expand Up @@ -119,6 +127,8 @@ function chatRecord(
beforeAll(async () => {
homeDir = mkdtempSync(path.join(tmpdir(), 'qwen-serve-routes-home-'));
nativeDirectoryPickerAtBoot = isNativeDirectoryPickerAvailable();
localPathOpenAtBoot = isLocalPathOpenAvailable();
localTerminalOpenAtBoot = isLocalTerminalAvailable();
daemon = spawn(
process.execPath,
[
Expand Down Expand Up @@ -426,6 +436,8 @@ describe('qwen serve — capabilities envelope', () => {
'workspace_display_name',
'workspace_runtime_removal',
...(nativeDirectoryPickerAtBoot ? ['native_directory_picker'] : []),
...(localPathOpenAtBoot ? ['workspace_local_open'] : []),
...(localTerminalOpenAtBoot ? ['workspace_local_terminal'] : []),
'workspace_qualified_rest_core',
'extension_management_v2',
'extension_git_credentials',
Expand Down
22 changes: 22 additions & 0 deletions packages/cli/src/serve/capabilities.ts
Original file line number Diff line number Diff line change
Expand Up @@ -372,6 +372,18 @@ export const SERVE_CAPABILITY_REGISTRY = {
// with a display). Headless hosts omit the tag so clients hide the
// Browse affordance instead of surfacing a guaranteed picker failure.
native_directory_picker: { since: 'v1' },
// The daemon host can open a workspace directory in the host's OS file
// manager (Finder via `open` on macOS, Explorer via `explorer.exe` on
// Windows, xdg-open on a Linux host with a display). Headless hosts omit
// the tag so clients hide the Open-locally affordance instead of
// surfacing a guaranteed launch failure.
workspace_local_open: { since: 'v1' },
// The daemon host can open a terminal window in a workspace directory
// (`open -a Terminal` on macOS, wt.exe/cmd.exe on Windows, a common
// terminal emulator on a Linux host with a display). Headless hosts omit
// the tag so clients hide the Open-in-terminal affordance instead of
// surfacing a guaranteed launch failure.
workspace_local_terminal: { since: 'v1' },
// Workspace-qualified core REST routes under `/workspaces/:workspace/...`.
// Covers core file read/write/upload, status/permissions/trust/lifecycle/MCP/tool,
// memory, workspace agent CRUD, and persisted session organization surfaces.
Expand Down Expand Up @@ -518,6 +530,8 @@ export interface AdvertiseFeatureToggles {
scratchWorkspaceRegistrationAvailable?: boolean;
workspaceRuntimeRemovalAvailable?: boolean;
nativeDirectoryPickerAvailable?: boolean;
localPathOpenAvailable?: boolean;
localTerminalOpenAvailable?: boolean;
/**
* Whether the HTTP ACP surface is enabled (default on; opts out via
* QWEN_SERVE_ACP_HTTP=0). Workspace-qualified ACP is only advertised when on.
Expand Down Expand Up @@ -660,6 +674,14 @@ export const CONDITIONAL_SERVE_FEATURES: ReadonlyMap<
'native_directory_picker',
(toggles) => toggles.nativeDirectoryPickerAvailable === true,
],
[
'workspace_local_open',
(toggles) => toggles.localPathOpenAvailable === true,
],
[
'workspace_local_terminal',
(toggles) => toggles.localTerminalOpenAvailable === true,
],
[
'workspace_qualified_acp',
// The plural routes are pre-mounted for workspaces registered after app
Expand Down
Loading
Loading