Skip to content

Plan pages, subagent cards, import from other tools, approval shortcuts, Windows fixes - #17

Merged
gaoyu06 merged 31 commits into
JuCode-Team:mainfrom
Libra1337:updates-2026-10-09
Oct 9, 2026
Merged

gaoyu06 merged 31 commits into
JuCode-Team:mainfrom
Libra1337:updates-2026-10-09

Conversation

@Libra1337

Copy link
Copy Markdown
Contributor

The desktop side of the last two days' work, ported onto JuCode's main with JuCode's names kept. One commit per change.

Works with JuCode-Team/JuCode-CLI#10. The plan card and plan pages, subagent cards and the progress panel read events from that CLI change (proposed_plan, plan_draft, agent_runs); with an older engine they stay quiet. jucode-cli.ref is not bumped here.

What's in it

  • Plan mode in the chat. A proposed plan shows as a compact card; approve it (choosing the approval mode it runs in) or ask for a revision.
    • The plan itself reads in a page of its own beside the chat, opened as soon as the model starts writing and growing as it streams.
    • Plan pages share one column and close one by one.
  • Subagents:
    • A turn's todos and subagents show at the top right of the chat.
    • Subagent calls render as subagent cards.
    • The agent trace lists subagents an engine reports by lifecycle.
  • Import from other tools (Settings → 从其他工具导入). One scan over Claude Code, Codex, opencode, zcode and omp lists their conversations, skills and MCP servers; pick and import in one go. Their files are only read.
  • Approvals: answer with 1 / 2 / 3 (y / a / n, Esc), and get a notification when one waits in the background.
  • 还原此文件 undoes only the agent's edits; the user's stay.
  • Settings:
    • Pick the image model the agent draws with.
    • The marketplace shows each source the catalog lists.
    • 更新 shows the version on Windows and opens the logs folder.
  • Windows:
    • The built-in browser opens files.
    • File links with Windows paths and non-ASCII names open.
    • A blank chat is guarded and UI errors are logged.
  • Smaller:
    • A streaming reply renders each finished paragraph once.
    • A tool card keeps a long output's head and tail (64 KB).
    • HTML files open from tool panels in the browser.
    • Short fade-only motion.
    • A guard against a click event arriving as a first message.
    • The cache-miss notice no longer reads 0。5.

Checks

  • svelte-check: 0 errors.
  • vitest: 663 passed.
  • vite build passes.
  • cargo clippy --all-targets -D warnings is clean.
  • cargo test: 133 passed.

🤖 Generated with Claude Code

Libra1337 and others added 30 commits October 9, 2026 13:56
…on older daemons

The turns list opened an HTML file as a file:// URL, which the embedded
browser refuses (http/https only): the panel stayed on 输入网址开始浏览.
It now goes through the loopback preview server like chat links do.

A daemon without settled usage answered session_usage with unknown op,
which showed as an error in every chat; it is now skipped.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The 更新 page read the version through the app plugin's getVersion, which
the window's capability does not grant on every platform: on Windows it
showed … . The version (with the bundled engine's) now comes from an app
command, which the feedback form and the required-update check use too.
更新 also gets 打开日志文件夹 for ~/.jucode (engine and daemon logs).

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The engine's generate_image tool reads image_model from config.json (empty:
the first model named like an image model). Settings → 模型 gets a 生图模型
row, cloud sync carries it, and tool rows show the saved images.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
… resizing

Popovers, menus, sheets and the composer's model label now enter with a fade
and a 4-6px move on --ease-out; the scale, spring overshoot and blur are gone.
Toasts slide 8px on cubicOut. While the window is resized or zoomed, the root
gets .win-resizing (until 150 ms after the last resize event) and nothing
transitions. ui/motion.ts gains paneIn/paneOut/popOut/rowIn and motionMs
(0 under reduced motion) for exit and list animations.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…s slide in

Settings, the workbench page, the home page and a project page fade and sink
4px as they close (they rose in already). Settings sections cross-fade in one
grid cell: the leaving section fades out while the next rises in. A session
row that joins the sidebar slides in 6px from the left; a list that fills at
once (load, clearing a search) appears without motion. Chat tiles keep their
pane-in when a conversation is switched in.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
ChatState keeps finished subagents until the next turn, reads a JuCode
subagent from its spawn_agent output and its lifecycle (model, call id),
remembers each Task subagent's latest call, reads the native agent trace's
activity and effort, takes an older engine's refusal of the trace ops
quietly, and shows proposed plans (proposed_plan, transcript role plan).
JuCode sessions get the agent trace and a plan approval mode.

agentProgress.ts derives the todo summary, the subagent rows, the wait
targets and the card's look from that state.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…and by grid rows

A new message or card comes in over 400 ms from 6px lower and a 4px blur
(msg-in), once per row: rows re-entering the virtual window do not replay.

ui/Collapse expands and collapses with grid-template-rows 0fr ↔ 1fr on the
shared size token (--t-base / --ease-base), as hark.com does, without
measuring heights. Tool card bodies, reasoning blocks and the sidebar's
project folders use it; their chevrons turn on the same token.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The progress card lists the plan's steps (the current one highlighted)
and the subagents of the turn with their model, running time and latest
action; a click opens the subagent's own conversation in the agents tile.
It folds to a pill (kept per session), folds by itself a few seconds after
the turn, and replaces the old subagent strip. The agent trace's single
subagent view moves into AgentTranscript, shared with the drawer to come.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
spawn_agent (and claude's Task / Agent) shows the agent it started: name,
the task's first line, state, running time and latest action; wait_agent
shows the agents it waits on with their states. Both open the subagent's
own conversation. A subagent call keeps its arguments once its output
replaces them, so the card can name the agent.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
A proposed plan shows as a card: title, the Markdown clipped with a fade
and a button for the full plan, copy, and a status tag once approved or
revising. While it waits as the latest message, approve and run it in a
mode picked beside the button (the mode before plan mode, else auto-edit),
or revise it: the next message goes as approve_plan feedback, with a chip
above the composer. Markdown tables get compact cells, a tinted header,
zebra rows and a box that scrolls a wide table sideways.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
A JuCode engine before agent_runs reports its subagents through
subagent_lifecycle and the spawn calls; the agents tile lists those, with
their state, model and time, so a click from the progress card always
lands on its agent.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The Changes panel's revert ran git restore / git clean on the whole file,
which also threw away the user's own uncommitted changes to it. The session
now keeps each agent edit's diff, and revert reverse-applies exactly those
(revert_agent_edits: one file, inside the project, checked before it
writes); the user's changes elsewhere in the file stay. When the file
changed too much since, the full revert is offered with a warning that says
the user's own changes go too.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…ms as plain text

The finished part of a streaming reply was one Markdown block that re-parsed,
re-highlighted and re-sanitized everything before it whenever a paragraph
completed (quadratic in the reply's length). It is now a keyed list of
paragraph chunks, each rendered once; open reasoning streams as plain text
and renders as Markdown when it ends.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
- A conversation that hit a render error left an empty pane. Each chat pane
  now has an error boundary that says so with a retry, and every UI error
  (pane or window) is appended to ~/.jucode/logs/desktop-ui.log so the
  cause can be read from the logs folder.
- The transcript's stacked edge-blur layers run only on macOS: WebView2 can
  paint masked backdrop filters over a scroller as an opaque layer, which
  blanks the conversation on Windows.
- The conversation column has one fixed width (768px); the drag handles to
  resize it are gone.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…he background

- The allow / deny card takes 1 (allow once), 2 (always), 3 or Esc (deny),
  shown on the buttons; only the active pane's card listens, never while
  typing in a field or within a second of the last keystroke, and not for
  questions, per-hunk edits or plans.
- With the window in the background, a new action to allow or a plan to
  approve raises a system notification.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
A build log or a big file read stayed whole in every session's state for
as long as the app ran. Cards now keep at most 64 KB of an output (head and
tail; JSON stays parseable, an image's pixels stay whole); the engine's
session still has all of it.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
browser_open built its window inside a synchronous command, which deadlocks
WebView2: the browser panel stayed blank and every later click waited behind
it. It is async now.

Links marked percent-encodes (a Windows backslash as %5C, Chinese names as
%E9...) are decoded, file:///C:/ keeps its drive, and C:\ or \\server paths
count as absolute instead of being joined to the project again. A resolved
path drops the \\?\ prefix canonicalize adds on Windows.

反馈问题 also attaches desktop-ui.log, where the UI writes what broke.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The + next to the session list passed its click event as the first
message; the chat then called .trim() on an Event. The button now calls
onNewChat() with nothing, and only text starts a chat.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…ty repositories)

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
A proposed plan opens a page to the right of its chat, as the browser does:
one tab per plan, closed one by one. A pending plan comes in block by block;
an approved one shows whole; approve / revise sit at its bottom. In the chat
the plan is one row (title, its first lines, open), so the clipped card that
twitched when it could not unfold is gone.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…eams

plan_draft events (JuCode CLI) grow one plan message marked 撰写中; its page
opens beside the chat at the first fragment and shows the text as it comes,
with a caret; the finished proposed_plan completes the same message.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
import_scan lists what Claude Code, Codex, opencode, zcode and omp have on
this machine: conversations in every folder (Claude's folder read from its
rows), skills (their skills folders and installed plugins) and MCP servers
as JuCode mcp_servers entries. A server JuCode could not start as
written (SSE, a command relative to the tool's folder, a ${...} only its
app fills in) is left out.

import_apply brings the picked conversations and skills over. Claude Code
and Codex go through native_import's cleaned copies. opencode and zcode
(SQLite, opened read-only) and omp (a JSONL tree) become JuCode sessions:
prompts, assistant text, and each tool call with its result; reasoning,
step markers and compactions are dropped. They are recorded in
native-imports.json, so importing again reopens the first copy. Skills
are copied into ~/.jucode/skills unless JuCode has one of that name.

Checked on this Mac: the scan finds 25 Claude Code, 34 Codex, 3 opencode
and 85 zcode conversations, 86 skills and 3 MCP servers in 1.4 s; copies
of real opencode and zcode sessions list and resume in `jucode serve`.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
A section that scans Claude Code, Codex, opencode, zcode and omp and lists
what they have: conversations by tool and folder, skills, MCP servers, each
group with its count and a select-all. Picked by default: conversations not
imported yet, and skills and servers JuCode has none of by that name,
except the ones that come with a plugin (they often rely on their tool).
一键导入 imports conversations and skills on the host side and adds the
servers through the daemon (mcp_set), as Settings → MCP does, then shows
what was imported, what was already there and what failed. The folders of
imported conversations can be added to the sidebar as projects, where
their conversations open from 历史.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The scan reads the plugin folder back from the disk, so on Windows it is
all backslashes; the expectation joined "official/android/0.1.0" in one go
and kept the forward slashes.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…ght after it shows

The chat pane under settings or the desk no longer counts as active, the
remote page passes keys only to the session on top of the shown tab, and
no key answers while a dialog or menu is open. Esc no longer denies; a
held or doubled key, or one within a second of the card coming into view,
does nothing. The elicitation decline button shows 3, the key that
declines it.
The bundled CLI 0.4.11 rejects approval mode plan, so the picker and the
+ menu must not offer it yet. Turn it on with the CLI release that adds
plan mode.
An MCP server runs a command, so the import picker leaves every one for
the user to choose. A skill copy no longer follows symlinks inside the
skill (one may point anywhere on the machine), which also drops the copy
depth limit that only guarded against link loops. The module comment now
says where the Claude Code and Codex copies are written.
…k to a whole-file revert

The listed path is matched to its recorded diffs with either separator.
When the agent's edits no longer apply, the panel reports it and leaves
the file alone instead of offering the whole-file revert that drops the
user's changes. A successful revert clears the file's recorded diffs, so
a later revert does not replay ones already undone.
A UNC path (\\server\share or //server/share) from a model-rendered link
would make Windows connect to that server and send the user's
credentials. parseFileHref now gives no path for one, and isAbsolutePath
no longer counts it as absolute.
@gaoyu06
gaoyu06 merged commit 34cfd8c into JuCode-Team:main Oct 9, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants