Commit Graph
10 Commits
Author SHA1 Message Date
Sergey BessonovandShaojin Wen 0e92f135c9 feat(cli): enable LSP through a user-scoped setting and env pair (#14613)
* feat(cli): enable LSP through a user-scoped setting and env pair

The LSP service ships already working inside the daemon, but the flag was the only entrance, and the clients that need code intelligence most are exactly the ones that cannot pass it: the Desktop client pins the daemon's argument list, as does any host embedding the Web Shell. #14507 asked for an opt-in channel rather than general availability, and the triage named the model to follow, so the setting arrives with both halves of that model's safety pairing: a user/system-scoped key, and an environment pair in which the disable switch wins over the enable variable and over the flag.

Workspace scope is deliberately excluded and a workspace value is stripped before the merge with a warning, because enabling LSP lets a session start language servers with the user's own permissions; a project environment file can neither opt in nor clear the kill switch. Enablement is read at startup only, matching the design decision that rules out toggling the service mid-session.

The daemon now resolves the same question per workspace runtime, from the settings and environment it actually gives that runtime, rather than only from the arguments it forwards. Forwarding was reachable from one of the daemon's two start-up paths and not the other, so a settings-enabled daemon could certify a session as compatible with a paired managed engine host while that session really did spawn language servers under the user's permissions.

An embedding host can also refuse the service for a configuration it owns and never uses it for. Passing the flag as off stopped expressing a refusal as soon as a second entrance existed, so the refusal is now a runtime-only policy: three internal configurations that exist only to enumerate MCP servers, run one hosted model turn, or run one hook operation no longer each start - and never stop - a full set of language servers.

Refs #14507

* fix(cli): guard every host-owned config against LSP

Close the gaps the first review round found in the settings entrance: the pre-sandbox auth config and the hosted workflow turn now refuse LSP like their siblings, safe mode refuses the setting entrance, and the daemon recomputes its per-session answer on settings reload instead of freezing it at boot.

Also publish the Web Shell alias and zh-CN strings the panel requires, group the row under Experimental while keeping the tools.lspEnabled key, and pin each guard against removal in tests.

* docs: record the LSP enablement contract

The precedence, the host-refusal policy and the list of configs that owe lspDisabled lived only in code comments and a PR thread. Add the bilingual design record, correct the user docs that still called the flag the only switch, and align the managed-engine spec tables with the non-argv trigger.

* fix(cli): resolve LSP compatibility from the evaluated snapshot

The cached per-runtime boolean went stale on every path that did not reload: a settings write (the panel toggle this PR exists for) reached no recompute, a model-provider reload replaced the environment without one, and caught read failures narrowed the inputs it was derived from.

Apply the resolver inside evaluateManagedCompatibility instead, to the settings snapshot and effective environment it already reads, with the forwarded flag as the argv entrance. Nothing is cached, so a write, an env swap or a failed read cannot certify a session that starts language servers.

* fix(core): block shell and npm loader vectors in LSP env

npm maps npm_config_node_options onto the child's NODE_OPTIONS, so blocking NODE_OPTIONS alone left the same preload reachable through a workspace .lsp.json env entry; BASH_ENV and ENV are the shell-startup equivalents. Add all three to the LSP denylist and pin them in the existing buildProcessEnv case.

* docs: correct LSP enablement wording after review

Name both trust gates (folder trust and an IDE Restricted Mode report), the execution-sandbox refusal with its escape hatches, the provenance limit on the env pair, and safe mode in the LSP and safe-mode lists. Fix the Experimental-group note so it no longer claims a false uniqueness, and align the design validation section with what the tests actually witness.

* docs(cli): trim the LSP setting description

The panel row had grown into a paragraph. Keep what a user decides on - what the setting does, the trust gate, the execution-sandbox conflict and the env precedence - and leave the re-evaluated IDE gate and the debug hint to the LSP page, where troubleshooting already lives.

* docs: point the /lsp hints at the setting and add C# setup

The not-enabled hint and the LSP page's debug/FAQ examples still told users to pass --experimental-lsp, which the hosts this change exists for cannot do. Name the setting first and keep the flag as the alternative, and add a Roslyn language-server row plus a .lsp.json example to the prerequisites.

* docs: document the Windows cmd shim for the Roslyn server

Qwen Code starts LSP servers without a shell, so the global dotnet tool's .cmd shim under C:\Users\heatw\.dotnet\tools cannot be spawned directly: a bare name is found by where but fails with command not found. Show the cmd /c form and the absolute-executable alternative next to the POSIX example.

* test(cli): pin the bare-mode LSP refusal

* fix(cli): refuse LSP in two more host-owned Configs

* fix(cli): read the LSP env pair as a spawned process sees it

* docs: record the new guarded Configs and drop the fixed teardown follow-up

* docs: describe explicit folder trust for workspace LSP servers

---------

Co-authored-by: Shaojin Wen <[email protected]>
2026-11-08 02:48:42 +00:00
ChiGao 4339775208 fix(cli): preserve OpenTUI clipboard source across draft recovery (#15396)
* fix(cli): align OpenTUI cancellation and retry with Ink

* fix(cli): discard abandoned OpenTUI tool attempts

* feat(cli): preserve OpenTUI session replay and rewind

* fix(cli): preserve checkpoint restore ownership and cold continuation

* test(cli): cover committed conversation rewind across renderers

* feat(cli): capture and restore OpenTUI checkpoints

Candidate checkpoint before parent test integration; full normal and combined product validation are still pending.

* test(cli): remove duplicate checkpoint regression declarations

* fix(cli): preserve Ink compact tool summaries after restore

* fix(cli): preserve OpenTUI clipboard source through draft recovery

* test(cli): cover OpenTUI raw recall and framed Vim submissions

* fix(ci): register clipboard regression in TUI parity gate

* fix(cli): preserve logical restore identity across authorized edits

* test(cli): assert saved restore call identity in permanent acceptance

* test(cli): align native tool result provenance assertion
2026-10-25 13:51:23 +08:00
ChiGao d6102c04e1 fix(cli): align OpenTUI cancellation and retry with Ink (#15283)
* fix(cli): align OpenTUI cancellation and retry with Ink

* fix(cli): discard abandoned OpenTUI tool attempts
2026-10-24 23:46:45 +08:00
易良andQwen-Coder 7c296dbe3c fix(ci): stabilize TUI attachment wait and allow full acceptance run (#15372)
* fix(ci): stabilize TUI attachment wait and allow full acceptance run

* fix(ci): record the tui-parity budget at its new 75-minute total

The parity job moved from 30 to 45 minutes, so the two jobs in the workflow
now declare 45 + 30 = 75. check-ci-budget.mjs treats a raised total as a
deliberate ratchet and refuses the ledger entry, so Lint & Static failed on
this PR's own change. Update the line it names; the workflow and the guard
test are unchanged.

Co-authored-by: Qwen-Coder <[email protected]>

---------

Co-authored-by: Qwen-Coder <[email protected]>
2026-10-23 23:15:19 +08:00
ChiGao a1b2d8596f feat(cli): align OpenTUI Vim, history and live output with Ink (#15067)
* fix(cli): restore bounded OpenTUI dialogs and add migration gates

* fix(cli): preserve OpenTUI input and attachment ownership

* feat(cli): align OpenTUI status lines with Ink

* fix(cli): align OpenTUI editor and cancellation transactions

* fix(tui): harden migration cleanup and evidence after review

* test(tui): fail acceptance on unhandled errors

* docs(cli): clarify consolidated OpenTUI delivery status

* test(cli): isolate system settings in TUI parity fixtures

* fix(cli): settle OpenTUI cancellation when replay resets a session

* feat(cli): align OpenTUI Vim, history and session output

Reuse the shared editing and history contracts, preserve cancellation ownership, and connect accepted interactive turns to the existing output bridge.

* style(cli): format merged OpenTUI test callbacks

* test(cli): preserve visible input across session rotation

* test(cli): cover shell recall provenance and streaming search selection

* test(cli): await cancellation before releasing held response

* fix(cli): preserve imported history ownership and active search

* docs(cli): synchronize consolidated OpenTUI validation status

* test(cli): await AppContainer configuration cleanup

* test(cli): mock Vim clipboard imports before module loading

* test(cli): share clipboard mocks across module export views

* test(cli): verify finalized MOD parts and shared JSON projection

* fix(cli): reuse Ink editing history for OpenTUI Unicode input

* test(cli): keep native Vim input callbacks void

* test(cli): preserve Escape boundaries in Unicode Vim fixtures

* test(cli): read the current composer across Vim remounts

* test(cli): align Unicode deletion cursor with Ink oracle

* fix(cli): preserve completion and escape precedence and validate status colors

* fix(cli): use boundary selection for the OpenTUI composer

* fix(cli): preserve attachment navigation with one completion

* test(cli): preserve Shift in the native redo key sequence

* fix(cli): display session titles in the OpenTUI composer border

* fix(cli): discard generated command work after cancellation

* test(cli): align Unicode unit cursor with Ink oracle

* test(cli): model native selection key delegation

* fix(cli): preserve Vim Escape ownership across listeners

* fix(cli): preserve shared Vim command messages in OpenTUI

* test(cli): observe rendered Vim mode during parity checks

* docs(cli): record integrated OpenTUI validation checkpoint

* fix(ci): account for dedicated TUI parity coverage

* fix(cli): preserve collapsed paste payloads across Vim undo
2026-10-22 14:52:40 +00:00
ChiGao 0ac1fcca91 feat(cli): align OpenTUI input, editing and status lines with Ink (#14964)
* fix(cli): restore bounded OpenTUI dialogs and add migration gates

* fix(cli): preserve OpenTUI input and attachment ownership

* feat(cli): align OpenTUI status lines with Ink

* fix(cli): align OpenTUI editor and cancellation transactions

* fix(tui): harden migration cleanup and evidence after review

* test(tui): fail acceptance on unhandled errors

* docs(cli): clarify consolidated OpenTUI delivery status

* test(cli): isolate system settings in TUI parity fixtures

* fix(cli): settle OpenTUI cancellation when replay resets a session

* style(cli): format merged OpenTUI test callbacks

* test(cli): preserve visible input across session rotation

* test(cli): await cancellation before releasing held response

* fix(cli): preserve completion and escape precedence and validate status colors

* fix(cli): preserve attachment navigation with one completion

* fix(cli): display session titles in the OpenTUI composer border

* fix(cli): discard generated command work after cancellation
2026-10-22 08:22:04 +08:00
ChiGao 6e6598e35c fix(cli): restore bounded OpenTUI dialogs and add migration gates (#14933)
* fix(cli): restore bounded OpenTUI dialogs and add migration gates

* fix(tui): harden migration cleanup and evidence after review

* test(tui): fail acceptance on unhandled errors
2026-10-21 10:05:14 +08:00
ChiGaoandgary.gq 7504faf336 fix(cli): bound short OpenTUI scroll dialogs (MYWO-3, MYWO-7) (#14034)
Co-authored-by: gary.gq <[email protected]>
2026-10-14 05:50:41 +00:00
ChiGao 74b5eb9e6d chore(cli): bump the OpenTUI renderer to 0.5.10 (#12321)
* chore(cli): bump the OpenTUI renderer to 0.5.11

The upstream release makes wrapped layout byte-accurate, which removes an
extra leading space on wrapped paragraph continuations and stops greedy
wrapping from breaking a line short. Both were visible divergences from the
incumbent renderer. It also adds line breaking between CJK characters.

* chore(cli): pin the OpenTUI renderer to 0.5.10 and gate the wrap fix

0.5.11 stops printing the markdown link target text, which is the only
thing link-click.ts can match on to implement click-to-open, so the
newer release silently breaks that path. 0.5.10 carries the same three
wrapping fixes without that regression and declares no engines floor.

Add a wrap-parity golden covering the paragraphs whose framing drove the
bump, wired into the tui-parity workflow, so re-pinning to 0.5.8 or
accepting a later release that regresses wrapping turns CI red. Verified
in both directions: green on 0.5.10, all three cases red on 0.5.8 while
the pre-existing parity scripts stay green there.

Also correct the two places whose claims measurement disproved — the
link-click header comment asserted no 0.5.x release emits OSC 8, and the
migration design doc still called 0.5.8 the pinned version — and record
in the parity sweep that whole-row divergence narrowed rather than
closed, since the rows carrying these paragraphs also carry two
unresolved divergences.
2026-09-22 08:11:25 +00:00
ChiGao cd1ac72874 feat(opentui): bundle assets, CI matrix and parity tooling (Batch 7) (#10770)
* feat(opentui): add the build, CI and parity tooling for the renderer migration

Batch 7 of the ink→OpenTUI migration (#8662): everything the renderer
needs to be built, verified and shipped — ink stays the default.

Bundled builds silently lose code-block syntax highlighting because
@opentui/core resolves its tree-sitter assets package-relatively, which
misses inside the esbuild bundle. Relocate the runtime assets (parser
worker, grammar wasms/scm, web-tree-sitter, native render library) next
to the bundle, and gate OTUI_ASSET_ROOT on the tree being complete for
the running platform — @opentui/core throws on any missing key, so an
incomplete relocation must fall back instead of half-configuring.
Standalone archives gain a Bun runtime (the renderer needs bun:ffi) and
per-target @opentui platform packages via the existing release
packaging, with --runtime=node restoring classic packaging.

The renderer matrix drives interactive E2E under node+ink and bun+opentui,
but Batch 6's renderer gate silently falls back to ink on an unsupported
runtime, so a green opentui leg could be a false green. QWEN_TUI_RENDERER_STRICT
turns that fallback into a loud startup failure for the matrix legs only;
user-facing default behavior is unchanged.

Parity tooling: a tui-parity workflow with component snapshots and a
no-flicker gate (zero full-screen clears, balanced DEC 2026) that runs
offline without model credentials, an ink→opentui codemod with a
self-test, the PTY/tmux comparison harnesses, and the cli scripts/ tree
is now covered by the package typecheck.

* fix(ci): build all packages in the tui-parity jobs

With prepare skipped, npm ci leaves the CLI's workspace dependencies
unbuilt, and a workspace-scoped build of the CLI alone resolves their
types from a dist that does not exist yet. The parity jobs must run the
repository-root build like the other E2E legs.

* fix(build): enforce renderer strict mode and drop musl from standalone packages

Address yiliang114's review on the Batch 7 build/CI work:

- propagate QWEN_TUI_RENDERER_STRICT into RendererSelection so the
  dispatcher also fails loudly when the OpenTUI entry returns false or
  throws, closing the false-green path in the E2E renderer matrix
- stage the OpenTUI platform packages only for the bun runtime and drop
  the -musl variants: the bundled Bun binaries are glibc-linked and
  cannot start on musl hosts, so the musl render packages claimed
  support the archives cannot deliver
- wipe dist/opentui-assets before re-copying so a stale tree from an
  earlier bundle cannot satisfy the key-existence runtime gate
- route the script-PTY capture branch through spawnScriptPty so the
  argv form follows the platform, and give it the destroy() that
  finish() expects from the node-pty-like interface
- harden pty-e2e.sh (set -euo pipefail, mktemp+trap, full TCL escaping
  of the prompt) and tmux-compare.sh (missing-binary check, mktemp+trap)
- pin the CI Bun setups to 1.3.14 = DEFAULT_BUN_VERSION so an upstream
  Bun release cannot flip the gating legs on its own

* fix(build): keep classic Node packaging as the standalone default

The temporary OpenTUI preview flavor (--runtime=bun) stays available but
no longer replaces the default release archives, keeping Batch 7 additive
for existing standalone users.

* fix(scripts): compare prettier-normalized output in the codemod self-test

Address F1 and F3 from the deep verification report:

- The self-test compared the codemod's raw output against the
  prettier-formatted fixtures/after.tsx, so 2 of 17 tests failed as
  committed. Normalize both sides through the repo prettier config
  before comparing (tests 1 and 6); the harness awaits because
  prettier 3's format() is async-only.
- Refresh the tui-parity.yml baseline entry from 2190 to the measured
  2508 bytes so the ratchet tracks real growth.

* fix(build): gate standalone opentui assets by runtime flavor

Node archives carry no opentui-assets tree at all: the renderer needs
bun:ffi, and cross-built archives would only hold another platform's
native library that the all-or-nothing asset gate could never activate.
Bun archives now prune every @opentui/core-* directory that does not
belong to the build target, dropping the build host's library from the
archive. The npm-package allowlist comment is corrected to match the
observed fallback behavior.

* test(cli): cover the OpenTUI strict-mode dispatch and e2e renderer matrix

main() now has coverage for the four dispatch outcomes: strict mode
throws both when the OpenTUI entry declines to start and when it boots
with an error, and non-strict mode falls through to startInteractiveUI.
resolveE2eCliCommand gains coverage for the opentui leg — bun on PATH
resolves to bun, and a missing bun fails with the actionable error.
2026-09-02 08:36:20 +00:00