The model list sits above Preset/Effort, so the pointer used to steal the
submenu while crossing those rows. First open stays immediate; switching
waits 200ms and is cancelled if the pointer reaches the already-open fly-out.
- claude: parse rate_limit_event resetsAt as epoch seconds (the CLI emits
seconds, not millis) and prefer rateLimitType over the reset-delta
heuristic for 5h/7d window classification
- claude: scale over-capacity utilization (>1.0) to a real percent instead
of clamping it to ~1%
- codex: back up an unmanaged auth.json before the first post-upgrade
provider transition overwrites it, and preserve it when leaving a legacy
managed provider without a backup
- dsh: spawn --dump-config through resolveCliSpawn so Windows .cmd shims
launch via cmd.exe instead of silently failing with EINVAL
Index Codex 0.148+ sessions whose user prompt is a response_item,
and keep provider authJson inline instead of PasswordSafe.
Group DSH CLI install and local host as one product card. Portal
alert dialogs to body so confirm stays clickable, and skip phantom
scrollbars on submenus that already fit.
Merge model, effort, speed, and 1M context into one summary trigger
with fly-out submenus that stay inside the plugin viewport. Compact
mode labels on the toolbar and add a short enter animation.
Frequent mid-response BLOCK_RESET markers (one per content-block edge)
were silently discarding deltas still sitting in the 33ms throttle
window, so thinking text stopped streaming and only appeared via
updateMessages snapshots. Flush both throttlers to the frontend before
resetting, with a regression test covering the ordering.
The daemon previously awaited preloadSdks() before sending the ready
event, blocking the Java plugin's DaemonBridge startup for the full
Claude Agent SDK import duration (potentially seconds on slow disks).
Move the ready signal before preloadSdks(). The SDK is now loaded in
the background; acquireRuntime() already lazy-loads via ensureQueryFn()
with its own promise cache, so the first send simply waits for the
in-flight load instead of blocking daemon startup. Heartbeat and status
commands become available immediately.
Also emit a sdk_ready event when the background preload completes, so
the Java side can log the transition for diagnostics.
- Mirror ClaudeSettingsSyncPlan's empty-env invariant in the repair path:
a provider with an empty/missing settingsConfig.env payload is incomplete
state and must not stamp model/codemossProviderId into settings.json
- Extract isGlobalSettingsSyncExempt() so apply and repair paths share one
skip list (local settings / CLI login / disabled); repair previously
omitted DISABLED_PROVIDER_ID
- Treat a missing settingsConfig as a graceful no-op instead of throwing
IllegalArgumentException on every chat window open
- Add regression tests for disabled mode, empty-env provider, and missing
settingsConfig; fix tearDown to restore a null home cache and clean up
the temp directory
- Reuse the caller's long-lived CodemossSettingsService instead of
rebuilding the whole manager graph on every webview poll
- Align z.ai cache TTL (115s) with the 120s webview poll cadence so
back-to-back polls dedupe onto one probe
- Extract a ZaiTransport seam and add the tests the original PR body
claimed: Bearer token/URL derivation, TTL enforcement, stale fallback,
API-key fallback, and cache keyed by url+token (account switches no
longer serve the previous account's quota)
- Merge duplicate period windows (TOKENS_LIMIT + CREDIT_LIMIT both
mapping to 5h), keeping the worse usage pct
- Cap stale-cache fallback at 30 minutes and surface the stale flag in
the tooltip as a data-may-be-outdated hint
- Allow plain-HTTP monitor probes only for loopback hosts so Bearer
tokens never travel plaintext to a remote host
- Show the plan tier as the first tooltip line
- keep legacy non-absolute bridge payloads as plain text instead of
silently dropping them
- only absolute-path-looking @ markers disable the manual single-path
fallback, so emails and annotations no longer block it
- share one Gson instance and request browser focus on the EDT in
addFileReferences
Claude Code expands ${VAR} placeholders found in .mcp.json using the
env section of .claude/settings.local.json (project) and
.claude/settings.json (user), falling back to the process environment.
The plugin read the same config but passed placeholders through
literally, so spawned MCP servers received e.g.
DATABASE_URI=${NEXUS_MCP_DB_URI} verbatim - postgres-mcp then logged a
warning and kept running forever with a useless connection string
(#1722).
- config-loader: after resolving global/project mcpServers, expand
${VAR} in every server env value. Lookup order: project
settings.local.json env -> user settings.json env -> process.env
- Unresolvable placeholders are left as-is so misconfiguration stays
visible instead of silently becoming empty strings
- Original configs are not mutated; expansion happens on a copy
Closes#1722
Killing a `docker run -i --rm ...` MCP server's client process only
signals the Docker CLI, not the container: the container keeps running
and --rm never fires, so every MCP status refresh leaked one container
permanently (67 containers / 4.2 GB RAM after ~12h on the reporter's
machine) (#1721).
safeKillProcess now closes the child's stdin FIRST - EOF propagates to
the container's stdin, so a well-behaved dockerised MCP server exits on
its own and --rm cleans it up - and only falls back to SIGTERM/SIGKILL
after a 500ms grace period for local processes that don't react to EOF.
Early-exit guards (exitCode/signalCode/writableEnded) make repeated
calls and racing with natural exit safe.
Closes#1721
JCEF does not route target=_blank anchors to the system browser, so
clicking docs links in the CLI install dialog, MCP help dialog, and
MCP marketplace details did nothing. Intercept the clicks and send
them through the existing openBrowser bridge instead.
- sweep stale dsh-preset-*.patch overlays before each spawn instead of
letting them pile up in the state dir
- warn when a preset is requested but the running host was started
externally and cannot be reloaded, instead of silently ignoring it
- align the Java-side preset id list with the JS side (router-standard)
- fix preset-dir file URL on POSIX: file:////tmp/... resolved to a broken
//tmp/... pathname; build it via pathToFileURL instead
- add node:test unit tests for preset-overlay (14 cases)
- add a DSH preset selector with built-in and user-installed presets\n- persist the selected preset per tab and pass it through the session bridge\n- apply preset compositions to spawned headless DSH hosts with reload support
Extract looksLikePathSegment into webview/src/utils/pathSegment.ts so the
display-side scanner (CollapsibleTextBlock) and the input-side fallback
scanner (useFileTags) share one rule: a word after a space continues the
path when it contains a path separator or ends with a file extension,
with any trailing #L line marker stripped first.
PR #1576 applied this rule only to message display; the chat input box
still truncated absolute paths whose filenames contain spaces (e.g.
"第六章 框架开发实践.md"), and its comment promised extension support the
code did not have. Reuse the shared helper there, sync the comments, and
move the misplaced convertAtFileRefsToLinks docstring back to its
function.
Tests: new pathSegment.test.ts unit tests; useFileTags.test.ts gains
fallback cases for spaced absolute paths with and without line markers.
- NodeProcessRegistry.detectProviderFromCmd: match grok/gemini on word
boundaries so coincidental path segments (e.g. username "grokky")
no longer mislabel processes in the Node process panel
- SessionSendService: fix sendToGrok / sendToCliProvider indentation
- NodeProcessRegistryHelpersTest: pin substring false-positive cases
and .antig-grok style real paths
- resolve the configured provider/model from host.describe
- insert the default route if llm.models omits it
- retain the default model when the catalog request fails
Replace the per-request GrokCliBridge with a persistent ACP daemon runtime:
- Route grok through GrokSDKBridge in SessionProviderRouter (removed from
CLI_PROVIDER_IDS) and delete the dead GrokCliBridge
- GrokDaemonCoordinator keeps a single ACP process alive across turns;
NodeProcessRegistry learns shared collectDaemonEntry/collectChannelEntries
helpers so Claude and Grok daemons survive "kill orphans" sweeps
- grok-event-normalizer converts Grok's snapshot-style chunks into true
deltas (#emitChunk): no duplicated or resurrected text, independent
content/thinking accumulators, nested/array content shapes
- grok-acp-client liveness checks use exitCode instead of the unreliable
killed flag
- CodemossSettingsService persists grok.env custom environment injected
into daemon processes
- PathUtils.guardWorkingDirectory protects daemon cwd against deleted
project dirs
Tests: NodeProcessRegistryHelpersTest, PathUtilsGuardWorkingDirectoryTest,
CodemossSettingsServiceGrokEnvTest, grok-event-normalizer.dedup.test.js,
grok-acp-timeout.test.js, DaemonBridgeTest.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- Treat transient IO/metadata read failures as pending instead of
terminal error in CodexSubagentHistoryLoader, and fix a latent NPE
for agentId-only status requests
- Gate terminal error on success === true in history merge and subagent
status mapping so later snapshots can correct transient errors
- Validate requestId against the latest sent poll request before merging
status batches
- Show non-Codex (Claude) lookup errors again while keeping Codex
pending noise hidden
- Restore narrow start-of-output error detection for apply_patch results
- Cache Codex session scans for 2s to avoid double full-tree walks
per poll
- Reject ".." segments in agentPath validation
The Claude model mapping (MODEL_ID_TO_MAPPING_KEY / DEFAULT_MODEL_MAP /
MODEL_LABEL_KEYS, fed by the claude model-mapping setting) is keyed by
claude-* ids. Third-party catalogs — agy and the CLI providers — expose
models whose ids collide with those slots (e.g. claude-sonnet-4-6), so
the dropdown relabeled and re-iconed foreign catalog entries with the
user's Claude mapping.
Guard both lookups with currentProvider === 'claude': non-claude
providers now render catalog labels verbatim and resolve icons from the
raw model id.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Resolve conflicts with the DSH provider that landed on the base branch
after this PR was opened. Both providers now coexist:
- provider registries, CLI detection, and settings list omp + dsh
- mode/model state hooks and persistence handle both provider slices
- ModeSelect keeps the omp role-mode branch; dsh joins the headless
CLI filter branch
- i18n (en/zh/zh-TW) carries both tool entries
Verified: webview vitest 1366/1366, ai-bridge node --test (532 pass,
same 19 pre-existing local-env failures as base), gradle compile +
targeted unit tests, tsc --noEmit.
PR #1659 moved auto-detection off the EDT in ChatWindowDelegate, but two
synchronous call sites remained that could still freeze the IDE in
VM/container environments where detection subprocesses hang:
- WebviewInitializer.createUIComponents ran detectNodeWithDetails()
synchronously on the EDT when no saved path existed (and had a dead
re-detection fallback before the version gate)
- WebviewInitializer.handleNodePathSave ran detection and path
verification synchronously on the EDT from the error panel callbacks
Detection and verification now run on a pooled thread, with UI updates
dispatched back to the EDT. On detection failure the bridges fall back
to invoking "node" by name (matching NodeDetector.findNodeExecutable),
so checkEnvironment can still pass when node is on PATH but the probes
failed. The saved-path fast path is unchanged.