文件最后提交记录最后更新时间
Merge branch 'pr_132' into release/v4.22.0 Brings in the 16-commit i18n migration (Locale enum, i18n::t() lookup, Config.language, --lang flag, /language slash command, LanguagePicker modal, full migration of user-visible TUI strings) on top of the v4.22.0 work (image attach + preview rows, sync_recalled_attachments retain-on-edit fix, body-echo reorder so marker numbers match, OH login URL omission, attachment field on UiLine::InputPrompt/StreamingBox, MenuPayload.kind). Eight conflicts resolved: * atomcode-cli/src/main.rs, atomcode-daemon/src/api_config.rs, atomcode-core/src/{coding_plan/setup,turn/tests}.rs — Config struct initializers: both sides added new fields; merged to keep all (subagent + vision_preprocessor_provider + language). * atomcode-core/src/config/mod.rs — struct gets all three new fields; HEAD's impl Config { can_handle_attached_images } retained; pr_132's language round-trip tests added (with HEAD's mandatory fields filled in and the legacy reflection_cadence field dropped — it's silently ignored on load now). * atomcode-tuix/src/event_loop/mod.rs — three conflicts. Kept HEAD's universal \<Enter> fallback hint and JediTerm banner (newer behaviour from 1f7f694c / 44a8eaea — deliberately dropped the legacy-conhost banner once alt-screen shipped; not resurrected from pr_132). Used pr_132's i18n version for the session-replay hint since the string semantics match. * atomcode-tuix/src/event_loop/commands.rs — /init flow: kept HEAD's render_instruction_status_block confirmation step, used pr_132's i18n Msg::InitWrote for the "Wrote N bytes" line. * atomcode-tuix/src/modals/session_picker.rs — kept HEAD's load-failure state cleanup (current_session_id = None, etc.) and rename_editing rendering branch; folded in pr_132's i18n SessionLoadFailed + SessionMsgCount strings. Three follow-up fixes to make the workspace compile cleanly: * language_picker.rs — added MenuPayload.kind and UiLine::InputPrompt.attachments fields the pr_132 modal didn't know about. * config/mod.rs, tool/parallel_edit.rs, vision_preprocessor.rs — three more test/helper Config initializers got language: None. cargo check --workspace --tests passes. atomcode-tuix tests 540/540 green. The 4 atomcode-core test failures (auth_token_path_consistency, sync_marker round_trips, load_plugin_layer_namespaces, datalog resolve_log_dir) are pre-existing parallel-execution HOME-env-bleed flakes — all pass individually, unrelated to this merge. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> 24 天前
Merge branch 'pr_132' into release/v4.22.0 Brings in the 16-commit i18n migration (Locale enum, i18n::t() lookup, Config.language, --lang flag, /language slash command, LanguagePicker modal, full migration of user-visible TUI strings) on top of the v4.22.0 work (image attach + preview rows, sync_recalled_attachments retain-on-edit fix, body-echo reorder so marker numbers match, OH login URL omission, attachment field on UiLine::InputPrompt/StreamingBox, MenuPayload.kind). Eight conflicts resolved: * atomcode-cli/src/main.rs, atomcode-daemon/src/api_config.rs, atomcode-core/src/{coding_plan/setup,turn/tests}.rs — Config struct initializers: both sides added new fields; merged to keep all (subagent + vision_preprocessor_provider + language). * atomcode-core/src/config/mod.rs — struct gets all three new fields; HEAD's impl Config { can_handle_attached_images } retained; pr_132's language round-trip tests added (with HEAD's mandatory fields filled in and the legacy reflection_cadence field dropped — it's silently ignored on load now). * atomcode-tuix/src/event_loop/mod.rs — three conflicts. Kept HEAD's universal \<Enter> fallback hint and JediTerm banner (newer behaviour from 1f7f694c / 44a8eaea — deliberately dropped the legacy-conhost banner once alt-screen shipped; not resurrected from pr_132). Used pr_132's i18n version for the session-replay hint since the string semantics match. * atomcode-tuix/src/event_loop/commands.rs — /init flow: kept HEAD's render_instruction_status_block confirmation step, used pr_132's i18n Msg::InitWrote for the "Wrote N bytes" line. * atomcode-tuix/src/modals/session_picker.rs — kept HEAD's load-failure state cleanup (current_session_id = None, etc.) and rename_editing rendering branch; folded in pr_132's i18n SessionLoadFailed + SessionMsgCount strings. Three follow-up fixes to make the workspace compile cleanly: * language_picker.rs — added MenuPayload.kind and UiLine::InputPrompt.attachments fields the pr_132 modal didn't know about. * config/mod.rs, tool/parallel_edit.rs, vision_preprocessor.rs — three more test/helper Config initializers got language: None. cargo check --workspace --tests passes. atomcode-tuix tests 540/540 green. The 4 atomcode-core test failures (auth_token_path_consistency, sync_marker round_trips, load_plugin_layer_namespaces, datalog resolve_log_dir) are pre-existing parallel-execution HOME-env-bleed flakes — all pass individually, unrelated to this merge. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> 24 天前
refactor(i18n): move source files to core + polish wave The i18n module previously lived in atomcode-tuix/src/i18n/ so all core renderers wanting localised output had to either reach into the tuix crate (a dependency inversion) or hardcode strings. Now that coding_plan::setup::SetupReport::render and similar core paths need the same t(Msg::*) lookup, the natural home for the i18n module is atomcode-core. Tuix keeps a one-line re-export shim so every existing crate::i18n::* call site compiles unchanged. Bundled in the same wave because they depend on the move or land naturally alongside it: * coding_plan/setup.rs — JediTerm SGR-9 fallback. When the TERMINAL_EMULATOR env var marks the host as JetBrains JediTerm (Android Studio / IntelliJ / etc.), strikethrough renders inconsistently, so locked-model rows fall back to ASCII + "(Locked: require plan upgrade)" text marker. Threaded through a testable render_with_terminal_caps(is_jediterm: bool) so both shapes are unit-coverable without env mutation. * event_loop/commands.rs/language slash command now emits the unified Msg::LanguageSwitched { label, locale } line (matches the LanguagePicker's confirmation shape, not the older bare-locale-code one). /status instruction-files block migrated to Msg::StatusInstructionFilesHeader/Present/Missing. * modals/language_picker.rs — already on LanguageSwitched, kept in sync. * render/alt_screen.rs — adds regression test command_output_survives_subsequent_input_prompt_redraw: pins the /language flow where the picker emits a CommandOutput then the event loop immediately redraws the input prompt (no menu). The confirmation must stay in body_lines AND in painted output past that second redraw, otherwise the user sees no feedback that the locale switch took effect. All existing i18n tests (13 in core, multiple in tuix), coding_plan suite (51), and the new alt_screen regression pass. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> 24 天前
feat(plugin): interactive /plugin manager modal Bare /plugin (no subcommand) now opens a full interactive manager instead of printing usage. A single modal drives a screen state machine: browse marketplaces -> list a marketplace's plugins (✓ marks installed, Enter toggles install/uninstall); add marketplace by git URL; remove marketplace; list+uninstall installed plugins. No more memorizing name@marketplace. Existing /plugin marketplace …, install x@mp, etc. subcommands are unchanged. Slow ops (clone/install) dispatch through the existing plugin_job_tx pipeline; the new Modal::on_plugin_event hook lets the open modal refresh its lists when a job completes (the plugin_job_rx select arm now redraws the modal instead of painting over it). Fast ops (uninstall, remove) run inline and refresh immediately. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> 6 天前
feat(live): webui↔TUI 模型双向实时同步 + 修复同步模式 TUI 审批不生效 模型同步:此前 webui 下拉框只改本地态、且仅在发消息时才把 provider 带给后端 (LIVE_PROVIDER),TUI 的活动模型与头部完全收不到通知。新增一条贯穿四层的 模型变更广播: - core:LiveEvent::ProviderChanged + LiveSession::notify_provider_changed; AgentEvent::ProviderChanged。 - daemon:live_set_provider(设 LIVE_PROVIDER + 广播);POST /live/provider 端点(持久化 default_provider 到 config.toml + 广播,下拉框一变即生效,不必先 发消息);/live 快照新增 provider 字段,新 tab 连上即回显正确模型。 - tuix:live_sync 转发 ProviderChanged;handle_agent_event 据此更新 default_provider/model_name + 通知 agent + 刷新头部(已是该 provider 则跳过, 避免自身 /model 切换的回声);/model 选择器切换后 live_set_provider 广播给 webui(反向)。 - webui:postLiveProvider;下拉框变更即在 sync 下上报;收到 provider/snapshot 即 setProvider(不回调 onChange,避免回环)。 切换发起方落盘一次(webui→端点;TUI→选择器 save_and_reload),TUI 收到广播只 做内存态同步,不二次落盘。 审批修复:同步模式下,工具这一轮跑在进程内 LiveSession 协调器(DaemonTurnExecutor) 里,审批只能经 LiveSession::approve 投递(webui /live/permission 即如此)。但 TUI 的 handle_approval_key 无条件把决定发给 TUI 自己的 agent——而同步模式下该 agent 没跑这一轮,决定石沉大海:工具一直 Running 卡死、webui 审批卡片也不关。新增 deliver_approval:sync_forwarder 存在时把决定投给 current_live_session().approve (A 降级为 Allow,与 webui 一致),否则照旧发 TUI agent;Ctrl+C 拒绝同样改走它。 工具随之继续并广播 ToolCallResult,触发 webui 侧清卡片逻辑,两个症状一并解决。 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> 1 天前
refactor(commands): fold /codingplan into /login /login now runs the full OAuth + CodingPlan setup flow (claim → fetch models → register providers → status); the standalone /codingplan slash command is removed. atomcode codingplan is kept as a hidden CLI alias so existing scripts and muscle memory keep working. /login is promoted to the top of the slash-menu since it's the primary onboarding entry now. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> 7 天前
style(tui): optimize plugin manager installation progress interface 1 天前
fix(tuix): /provider 识别行显示 base_url,手动 Base URL 改为必填前置步 1. "已识别"行改为展示 base_url · type · model(原来误显示 name) 2. 手动路径:Base URL 成为必填的前置步(不显示 (x/y)、去掉"留空用默认值"), 据其推断类型并回显"已识别类型:…",随后才是计数的 (1/3) API 密钥 → Model → 名称。手动不再单独问类型(由 Base URL 推断)。 新增 ProviderBaseUrlEmpty、恢复 ProviderTypeInferred 文案。 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> 6 天前
feat(tuix): QR rendering helper for onboarding redesign Building block for the upcoming single-page onboarding rewrite — isolated so it can land + be unit-tested independently of the wizard state-machine refactor that comes next. Wraps qrcode 0.14's Dense1x2 (half-block) renderer: - One terminal cell carries 2 QR modules vertically, so a 33-module QR (typical short URL) lands in ~17 rows — fits inside the wizard panel without overflowing typical terminal heights. - Returns Option<Vec<String>> per-row so callers can centre rows inside the panel without re-splitting. - ASCII-only / dumb terminals return None — caller MUST fall back to plain text URL. Half-block glyphs render as tofu on Windows conhost / TERM=dumb / LANG=C and a tofu QR would silently break the only thing the screen exists to do (let the user scan). 3 tests pin: ASCII gate returns None; short-URL renders >= 8 non-empty rows; all rows have uniform char width (so the QR doesn't render as a parallelogram and break phone scanning). PR 1 follow-up will rewrite OnboardingWizard's Step machinery to use this — currently 3 steps (Intro / Language / Setup), target is a single Confirm + QrLogin page with auto-detect language. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> 14 天前
feat(session): 恢复对话时还原轮次分隔线与每轮 token/工具统计 会话只持久化 messages,每轮的 token/时长/轮数统计来自实时 TurnComplete 事件、从不 落盘;replay_session 又只在开头/结尾画分隔线,轮与轮之间一条没有。于是恢复后上一轮 模型输出和下一条用户输入贴死,统计分隔线也丢了。 - session.rs:新增 TurnStat(after_message 锚点 + 轮数/工具数/时长/tokens/errored) 和 Session.turn_stats(#[serde(default)],老会话加载为空)。 - event_loop/mod.rs:TurnComplete 时把本轮统计按"轮结束时的消息数"锚定推入 current_session.turn_stats 再落盘(对取消/缺失的轮也稳)。 - session_picker.rs:replay_session 在每个轮边界(每条非首条用户消息前 + 末轮)画 分隔线——有统计就画与实时一致的 ✓ Done · N 轮 · M 工具 · Xs · K tokens(错误轮 ✗), 没有就画纯横线。新会话 resume 完整还原统计;老会话也能拿回轮间间隔(纯线)。 新增测试:turn_stats 落盘往返 + 老会话缺字段降级空;turn_divider_label 三态。 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> 1 天前