Repository navigation
Commit 7041b2c
feat(tui+lsp): TUI theme system, streaming phase 0, LSP subsystem, and report panel polish (#157)
* style(tui): use default foreground for diff +/- markers
Diff add/remove rows are distinguished by background tint only; line
numbers and +/- glyphs no longer use green/red accent foreground.
Co-authored-by: Cursor <cursoragent@cursor.com>
* feat(lsp): add plugin-based LSP code intelligence subsystem (PLIP-10)
Port the reference LSP subsystem to a first-class Python feature: a new `LSP`
agent tool (definition, references, hover, document/workspace symbols,
implementation, full call hierarchy), session-scoped server lifecycle over the
Host stdio abstraction, passive diagnostics injected after file edits, and
plugin-only server discovery/recommendation (no bundled binaries).
Hardening folded in from review:
- framing raises LspServerDown on EOF so the read loop fails pending requests
instead of busy-spinning (C01/C10); wired LspClient.on_crash -> instance
mark_crashed so the max_restarts cap is enforced against real crashes.
- LSP tool distinguishes "no server for file type" from an empty server
response (definition-not-found now renders guidance, not a false "no server").
- request failures return an error result instead of a false-success ok().
- file-tool edit hook (write/replace) clears delivered diagnostics for the file
and wraps change/save notifications in try/except so an LSP hiccup never fails
an already-successful write (C03).
- no-server file types surface a one-line plugin install hint (per ext/session),
gated by recommendation_disabled/never. Persisted >=5 ignore auto-disable is
deferred: save_config() rewrites the whole file with no lock/atomic rename, so
incremental concurrent writes are unsafe (multi-instance clobber risk).
Registered on default + coder agents only; excluded from offline/fail-closed
code_reviewer. Servers are plugin-only with PluginPolicy.external_exec gating.
* feat(tui): theme package, slash input UX, and streaming phase 0
Replace monolithic theme.py with spec/palette/resolver adapters, trim
periwinkle inline highlights, add slash prefix and subcommand suggest
highlighting, grey out low context-usage bar, and coalesce live
streaming repaints. Refresh native install script help and progress UX.
* feat(tui): polish theme, transcript spacing, usage activity, and install UX
Switch inline code and ANSI syntax highlights from cyan to accent/periwinkle
and blue, add trailing scrollback gaps between tool output and agent prose,
style the welcome banner branch with muted warning yellow, and ship the
token-activity heatmap for /usage. Refresh install banner animation and tests.
* feat(tui): pythinker-x theme port, tool header accent tokens, and diff/spacing polish
Port pythinker-x theme: 32 bundled syntax theme names, Catppuccin Frappe/Macchiato
styles, `/theme code` syntax picker, and aligned diff palette. Tool-call subject
highlights switch from cyan to brand periwinkle accent; welcome banner uses neutral
grey for branch and yellow for model name. Fix diff marker spacing for @-prefixed
lines and add composing-block blank-row before the activity line.
* feat(tui): report panel polish, secondary token, LSP subagent guard test
Report rendering:
- Add `pythinker_report_markdown()` + `report_markdown_style_overrides()` so only
H1 headings render bold inside report panels; all other roles drop bold weight
- Replace `### section` headings with `# title` routed through report markdown so
section headers are bold while body prose stays regular
- Add `REPORT_FILE_MARKER` glyph (⌁ / +) for finding location rows; use a grid
table to keep long paths indented consistently
- Add `secondary` CoreToken and `TuiTokens.secondary` field (dark #AAB0B6, light
#8A93A0) for scope/note text that needs less emphasis than `muted`
- Replace `Rule(severity …)` section separators with `_render_section_header()`
(title line + plain rule below) for cleaner visual hierarchy
- Pill-background summary line: severity dots and counts share `tool_pending_bg`
background for compact badge appearance
- Correct `PROMPT_GLYPH` dark hex to #F1F3F5 (was left behind when activity_label
was updated in b9662b7)
Worklog / blocks:
- `_tool_token_style` now raises `ValueError` on unknown token names instead of
silently falling back to `info`; all reachable style values are valid TUI tokens
- Insert `BLANK_ROW` between the collapsed card and its sub-tool activity group
Selector:
- Extract `_default_match` typed nested function in `code_theme.py` to fix
pyright `reportUnknownLambdaType` on the prior lambda
LSP gaps (from lsp-code-scan-analysis report):
- Add `test_lsp_provider_registered_in_subagent_soul` guard test: asserts
`LspDiagnosticsInjectionProvider` is in `_injection_providers` and
`rearm_injection` is wired for subagent-role `PythinkerSoul` instances
- Update blackbox port-status ledger: LSP row promoted from future-approved-only
to done (d936b32, 63 tests, PLIP-10)
* feat(tui): split markdown pipeline and add audit report rendering
Refactor shell markdown into focused modules with shared fence scanning,
size guards, and capped streaming parse cache. Add audit-profile normalization
for dense parity reports (collapsed matrices, field tables, path compaction,
and quote gutters) and fix report-prose misparsing of aligned field lines.
Align dark prompt border tokens with core border palette.
* fix(tui): correct plan approval prompt state and dialog chrome
Show awaiting approval while ExitPlanMode waits for user choice, pause the
Considering spinner during question/approval panels, reorder choices, and
improve dialog spacing and copy. Also harden LSP frame reads and sync tests.
* fix(tui+lsp): resolve CI failures and CodeRabbit findings; harden RunAgents
Make the PR branch green and address the review.
CI failures (15 tests + ruff):
- Update agent-spec / config-dump / pyinstaller snapshots for the new LSP tool
- Add explicit encoding to LSP framing/symbol_context/tool sources (static check)
- Sync dark prompt frame/separator/dialog borders to their core theme tokens
- Flush the live view immediately for external (approval/steer) messages and
supervise the frame/status refresh loops so a refresh failure surfaces instead
of silently freezing the view (fixes 3 external-approval tests)
- Wire `_mode` + completer onto the bottom-toolbar unit test's bare session
- Fix import sorting / line length
CodeRabbit findings:
- Critical: inline code spans now actually clear an inherited background
(Rich `Style(bgcolor=None)` is a no-op; mutate the copied style instead)
- LSP: bounded JSON-RPC frame size + graceful-shutdown timeout, didChange
document version tracking, open-doc state cleared on restart, empty
diagnostics payloads clear stale entries, code-0 dedup key, TOCTOU re-check,
documentSymbol file_count
- Theme picker: compare resolved themes by identity so distinct Catppuccin
variants no longer match
- Usage activity: anchor the chart to the payload window (not wall-clock) and
fix the current-streak partial-today contract
- Config: validate LSP numeric settings; `/usage` rejects extra activity args;
`/theme code <Name>` preserves case; guard install-script cursor escapes to
animated mode; drop unused worklog icon params
RunAgents: strip stray whitespace-only string entries the model emits between
agent objects so a multi-agent launch no longer fails validation.
Also: AGENTS.md gains a "Pre-PR gate" checklist (run the full gate, snapshot
fix-direction, encoding/bundling/changelog checks) to stop these slipping to CI.
* fix(tui): suppress consecutive ToolSearch probes in transcript scrollback
Multiple ToolSearch calls during deferred tool discovery now collapse to a
single scrollback entry (the last probe), mirroring the blackbox reference's
`isAbsorbedSilently` contract for ToolSearch. Intermediate discovery calls
no longer produce repeated "Tools(…)" noise lines in the transcript.
Also ships two other tested fixes from the collaborative branch:
- fix(todo): accept Cursor/Claude TodoWrite shape using `content` instead of
`title` (model_validator normalises before Pydantic validation)
- feat(ui/slash): bare-segment matching for namespaced slash commands so
`/designer` surfaces `/skill:designer-skill` without adding duplicate paths
* feat(tui): fuzzy-match slash commands by distinctive word
Skills share a common prefix (pythinker-), so segment-prefix matching
cannot disambiguate them. Add a lowest-priority fuzzy subsequence tier
on the bare segment (gated at 2+ chars) so a misspelled distinctive word
like /gurd surfaces /skill:pythinker-guard. Stronger prefix/alias/segment
tiers still rank first; the inserted text stays the canonical command.
* fix(soul): tighten truncated-response continuation reminder
Reword the output-token-limit nudge to resume mid-thought without recap,
and update the matching test assertion.
* fix(soul): align output-token-limit nudge text with reference byte-exactly
The system-reminder injected after a truncated response now matches the
blackbox reference verbatim per the AGENTS.md byte-exact text contract:
'Output token limit hit. Resume directly — no apology, no recap of
what you were doing. Pick up mid-thought if that is where the cut
happened. Break remaining work into smaller pieces.'
Update the pinning test assertion to match the new text.
* fix(tools): gate ToolSearch to models that support deferred tool search
ToolSearch only makes sense with Anthropic's tool_reference/defer_loading
beta. The type="anthropic" compat proxies (z.ai/GLM, Kimi, MiniMax,
opencode) point at their own endpoints that don't forward that beta, and
non-Anthropic providers don't have it at all. Offering ToolSearch there is
noise: it re-lists already-visible tools, and weaker tool-callers (observed:
GLM-5.2) loop on it forever instead of calling tools directly.
Add supports_deferred_tool_search() (genuine api.anthropic.com host + non-
haiku, with ENABLE_TOOL_SEARCH override) mirroring the reference's gate, and
hide ToolSearch in PythinkerToolset._is_tool_visible when unsupported. The
tool stays registered so a /model switch to Claude re-enables it instantly.
Rendering is intentionally unchanged (compact absorber kept, not reverted to
the reference's verbose generic card).
* fix(tools): stop ToolSearch description claiming nonexistent deferral
Root-cause follow-up to the ToolSearch gate: pythinker emits no defer_loading
and ToolSearch only searches already-visible, already-callable tools (it
unlocks nothing). The old description told the model that "deferred/hidden
tool loading" might leave capabilities off the prompt — a false claim that
primed weaker models to loop searching for tools they already had. Rewrite it
to state plainly that it reveals nothing new and to call tools directly.
* fix(tui): hang-indent space-aligned report preview during streaming
Run the lightweight space-column normalizer in the composing preview path
and wrap long Severity/Location/What rows with continuation indent so wrap
fragments no longer orphan at column 0. Document ToolSearch absence in the
default-agent tool snapshot test.
* fix(tools): normalize Cursor TodoWrite shape and compact failed todo cards
Boundary-normalize content→title before SetTodoList validation, persist
canonical title-only session state, and render validation failures as
compact actionable errors instead of a fake persisted todo tree.
* fix(tools): harden todo renderer and blank-title normalization
Treat blank titles as missing for Cursor-shape detection, compute indent
from ANSI-stripped text, and show invalid args for malformed complete lists.
* fix(pr-157): address CodeRabbit review and CI check failures
Resolve review findings across LSP, TUI streaming, toolset, and tests:
fail-closed git check-ignore filtering, symbol boundary fixes, report-update
refresh, markdown fence/audit hardening, ToolSearch execution gate, and lint/
pyright/test stability improvements including import sort in visualize.
* fix(lsp+ui): treat non-git dirs as unfiltered and suppress fuzzy slash noise
Allow git check-ignore exit 128 (not a repository) so LSP location filtering
works in tmp_path tests and non-git workspaces while keeping fail-closed on
real check-ignore errors. Hide fuzzy slash completions when a stronger
prefix/alias match exists so /mo resolves to /model only.
* fix(pr-157): resolve remaining CodeRabbit review threads
* fix(pr-157): address CodeRabbit audit.py and code-quality re-export findings
* fix(ui): re-export markdown shim via module attribute assignment
* fix(pr-157): satisfy code-quality on re-exports and LSP returns
* docs(lsp): expand LSP docs with operation table and plugin schema; fix empty-diagnostic clear
- Add table of all 9 LSP operations with their wire method names to lsp.md
- Document plugin server config schema (.lsp.json / lspServers) with all fields,
defaults, constraints, and ${VAR} / ${VAR:-default} env expansion including
PYTHINKER_PLUGIN_ROOT / PYTHINKER_PLUGIN_DATA built-ins
- Note .gitignore filtering on reference/definition/implementation/workspaceSymbol results
- Fix DiagnosticRegistry to clear stale pending state on empty publishDiagnostics
payloads (LSP "clear all diagnostics for this URI" signal)
* fix(pr-157): remove unused _REEXPORT_REGISTRY and _PALETTE_ONLY_FILES globals
---------
Co-authored-by: Cursor <cursoragent@cursor.com>1 parent 33595ea commit 7041b2c
155 files changed
Lines changed: 15787 additions & 2647 deletions
File tree
- docs
- .vitepress
- en
- customization
- release-notes
- public
- plips
- scripts
- src/pythinker_code
- agents/default
- lsp
- plugin
- soul
- dynamic_injections
- tools
- agent
- file
- lsp
- plan
- todo
- tool_search
- ui
- shell
- components
- markdown
- selectors
- tool_renderers
- visualize
- theme
- adapters
- utils/rich
- wire
- tasks
- tests_e2e
- tests
- core
- tools
- ui_and_conv
- ui
- utils
- web/public
Some content is hidden
Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
224 | 224 | | |
225 | 225 | | |
226 | 226 | | |
| 227 | + | |
| 228 | + | |
| 229 | + | |
| 230 | + | |
| 231 | + | |
| 232 | + | |
| 233 | + | |
| 234 | + | |
| 235 | + | |
| 236 | + | |
| 237 | + | |
| 238 | + | |
| 239 | + | |
| 240 | + | |
| 241 | + | |
| 242 | + | |
| 243 | + | |
| 244 | + | |
| 245 | + | |
| 246 | + | |
| 247 | + | |
| 248 | + | |
| 249 | + | |
| 250 | + | |
| 251 | + | |
| 252 | + | |
| 253 | + | |
| 254 | + | |
| 255 | + | |
| 256 | + | |
| 257 | + | |
| 258 | + | |
| 259 | + | |
| 260 | + | |
| 261 | + | |
227 | 262 | | |
228 | 263 | | |
229 | 264 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
15 | 15 | | |
16 | 16 | | |
17 | 17 | | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
18 | 99 | | |
19 | 100 | | |
20 | 101 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
48 | 48 | | |
49 | 49 | | |
50 | 50 | | |
| 51 | + | |
51 | 52 | | |
52 | 53 | | |
53 | 54 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
100 | 100 | | |
101 | 101 | | |
102 | 102 | | |
103 | | - | |
| 103 | + | |
104 | 104 | | |
105 | 105 | | |
106 | 106 | | |
| |||
142 | 142 | | |
143 | 143 | | |
144 | 144 | | |
| 145 | + | |
145 | 146 | | |
146 | 147 | | |
147 | 148 | | |
| |||
201 | 202 | | |
202 | 203 | | |
203 | 204 | | |
204 | | - | |
| 205 | + | |
| 206 | + | |
| 207 | + | |
| 208 | + | |
| 209 | + | |
| 210 | + | |
| 211 | + | |
| 212 | + | |
| 213 | + | |
| 214 | + | |
| 215 | + | |
| 216 | + | |
| 217 | + | |
205 | 218 | | |
206 | 219 | | |
207 | 220 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
0 commit comments