App 工作区

App 工作区是本地 dev 项目的主操作面板。当前实现里,编辑、保存、运行、结构图和环境变量都指向本地项目;线上版本只通过 Publish 上传,或通过 Pull Code 覆盖本地代码。 工作区界面同样使用极简黑白工作台系统:顶部栏聚合返回、项目身份、Env 和 Publish;Save、Refresh 只在 Files 主视图显示,Pull Code 只在 server 已连接且当前项目存在 server 版本时显示,运行入口留在 Run 主视图内部。左侧 activity rail 按 Run、Info、Files、Terminal 顺序承载主视图,进入项目后默认显示全屏 Run 主视图。Diagram 和 Logs 不再作为默认或左侧一级视图,只能从运行结果或 conversation 消息按钮打开右侧诊断抽屉。所有区域都使用一致的 8px 内圆角、清晰边框、紧凑间距和可见 focus 状态。状态色只用于运行、连接、构建、发布、危险操作等语义反馈;底部状态栏文案必须跟连接状态一致,未连接时不会显示 server connected。(issue #80、issue #89)
当前 App 截图已在 issue #80 UI 重设计后临时下线,避免继续展示旧版界面;重新截取首页、工作区、设置页和主要弹窗后再恢复图片。

文件编辑与保存

左侧文件面板来自本地项目文件列表,中间是 Monaco 编辑器。修改文件后,App 会把文件路径加入 dirty 列表,并在项目卡片上显示 dev 状态。 切换到 Files 主视图后,顶部栏会显示 Save 和 Refresh。保存按钮执行本地保存:
Save -> Electron saveLocalProjectFiles -> 更新本地文件 -> 重新读取结构和环境变量
保存不会写 server draft,也不会发布版本。源码中 saveDraft 明确把保存限定为本地逻辑。

运行项目

Run 会先检查未保存改动;确认保存后,通过 Electron 运行当前本地项目。App 本地运行会把 workflow.getRuntimePlatform() 标记为 "app",因此业务 workflow 可用 workflow.isApp() 判断当前执行宿主。运行开始时会先创建一条 pending 本地运行记录,后续 runtime events 会把它替换为真实 run id 并持续更新节点状态;同一个 requestId 对应的 pending、running 和最终完成状态始终合并为历史执行里的同一条记录,不会同时显示 running 和完成两条。普通 workflow 支持多个执行并行运行:一个 run 仍在 running 时,可以点击“新 workflow”回到可编辑输入区并再次启动新的 run;旧 run 继续留在历史执行中更新,runtime event 和最终 report 只会按 requestId / runId 回写对应历史项,不会抢占当前正在编辑的新 workflow 或另一个选中的 run。项目详情默认的 Run 主视图直接承载当前 Run workspace / conversation shared 预览版本,不再使用 Input、Logs、History、Trace 多 tab,也不再默认展示单独右侧 Run workspace 面板。普通 workflow 模式下,左侧显示“历史执行”列表,顶部提供和 conversation 一致的 + 新 workflow 入口与右侧折叠按钮;左侧历史收起后不保留窄 rail,workflow 和 conversation 都改为在 Run workspace 顶部标题栏左侧展示纯图标展开按钮。workflow 历史项和 conversation 话题项保持一致的单行标题、圆角 pill 选中态;成功状态不显示右上角标签,运行中的 pending/live run 或 running conversation 只在展示项最右侧垂直居中显示极简旋转加载图标。运行中的普通 workflow 右上角会显示 Cancel,直接终止当前本地运行并把该记录标记为 aborted;conversation 继续保留同一套取消语义。历史项只通过右键菜单查看结果、打开 Diagram、打开 Logs 或删除本地执行历史,不在最右侧展示三点/更多按钮;选中历史只切换当前查看的 Output/Diagram/Logs 运行记录,右侧显示只读“历史执行结果”,不会把历史参数变成可再次执行入口,也不会渲染 Send 按钮;点击“新 workflow”后才会回到可编辑输入区并允许发起新的运行。普通 workflow 与 conversation 现在复用同一套 shared composer shell:footer 中的 Input 标签、Form/Raw toggle、Advanced options 入口、raw args chips 和右下角 Send 主按钮都来自同一个 shared 组件。输入区标题统一为 Input,界面不再展示 target dev / local dev 这类无操作价值的运行目标标签;Input 和 Output 位于 Send 按钮上方的同一滚动内容区,Diagram/Logs 入口作为 Output 下方的轻量 icon-only contextual action 展示;内容超出时在该区域内滚动,Send 保持为底部主操作。Diagram/Logs 图标会打开右侧诊断抽屉,不会切换主视图。(issue #80、issue #84、issue #89、issue #90) Run 视图左侧的普通 workflow 历史执行栏与 conversation 话题列表,会把宽度和隐藏状态统一保存到 renderer localStorageworkflow-code.app.sidebar-layouts:v1 中的 workspace-history 项。这样用户在 conversation 中调过的话题列表宽度,切回普通 workflow 时会沿用同一份侧栏布局;反之亦然。该偏好只作用于 App 工作区左侧历史/会话侧栏,不会写入 SQLite、项目源码或远程服务。 从 issue #85 起,Electron App 会把本地 run history 写入 main 进程 SQLite:app.getPath("userData")/workflow-code.sqlitelocal_runs 保存 run 摘要、stdout、stderr 和完整 report.json,因此刷新 App 后仍能恢复本地 run,并在普通 workflow 的历史执行栏中选择查看,再从运行结果按钮打开对应 Logs/Diagram 诊断抽屉。历史执行项可用时间、状态、耗时和参数摘要生成标题;列表视觉上只显示单行标题,辅助信息保留在可访问名称和悬停标题中,不直接把 runId 当成列表主文案。SQLite 只作为本地执行数据索引,不替代 workflow 源码目录、.env 或本地项目注册表;Web 平台仍只连接 server。 Diagram 节点详情会先展示结构分析可见的静态配置,再展示运行态 input、output 和 executionInfo;选择最后的 Result 节点时,会展示最终 WorkflowOutputItem[],并保留可折叠的原始 items JSON 便于检查完整输出数组。Provider 详情会遮罩字段值、表达式源码、函数源码和 runtime binding call 参数源码中的 secret 语义内容;getLLMProvider 调用只有能归属到当前节点定义范围或名称参数匹配当前节点时才会展示,避免同文件多节点时把后续 provider 调用错挂到当前节点。runFor/runWhile 循环体在 Diagram 中只渲染一次;运行态绑定会隔离当前已收到的循环体重复 report,即使循环仍在 running 且尚未产生 endedAt,也不会把后续迭代的同名 input/output 误绑定到循环后的静态节点。(issue #80) 执行输入有两种形态:
  • workflow 声明了 executor.params 时,面板会生成结构化表单。
  • 未声明或需要原始参数时,可以输入 CLI 风格 args。
结构化表单会按 param type 和 options/control 渲染文本框、长文本 textarea、数字输入、布尔开关、单选/下拉或多选框;多选参数会生成一个 flag 加 JSON 数组字符串。数字输入会直接展示 defaultValue,并在输入框右侧提供加减 stepper,同时保留直接输入能力;例如 workspace/workflow/deltafore-agentmaxRounds 默认值为 10,但会作为 panel: "auxiliary" 高级参数收进隐藏面板,不占用首屏主输入。字段 description 会作为输入框 placeholder 使用,输入框下方不再重复展示说明或 format: json 这类实现细节。图片 file param 会作为小缩略图展示,选择区同时提供“上传图片”和“添加剪贴板图片”两个按钮;剪贴板图片会先写入本地 workflow file store,再以普通 managed file reference 写入 args。macOS Finder 复制图片文件时,App 会优先读取剪贴板里的真实文件 URL/path 并保存原图内容,避免把 Finder 的 PNG 文件图标预览当作图片附件;剪贴板里没有图片、读取失败或保存失败时必须通过当前 Run workspace 错误反馈提示原因,成功时只添加附件缩略图,不额外弹成功提示。图片点击后在当前界面弹出大图预览层,可 Escape、点击背景或关闭按钮退出,不会打开系统应用、浏览器新窗口或 about:blank;图片可移除,但不在界面暴露 managed file JSON 或文件名文本 chip;同一图片引用的缩略图会在文本输入、表单重算和 args 重新解析时保持稳定,不会短暂闪回图片 icon;实际运行时仍把文件引用写入对应 args。Form 模式只展示表单控件,不再在表单区域额外展示 args chips;切到 Raw 模式时仍可查看和编辑 CLI 风格 args。panel: "auxiliary" 的参数默认收进二级输入面板,首屏保留主输入;Advanced options 弹窗里的 radio/checkbox 选项按钮会保留稳定点击高度、清晰的选中状态和可换行说明,避免长描述把选项挤成拥堵窄块。布尔参数如果默认值是 "true",关闭时会显式传入 false,便于 workflow 把该值继续传给 SDK 或外部 API;例如 workspace/workflow/codex--json 开关默认开启 Codex SDK structured output,关闭后回到普通文本输出。(issue #62、issue #66、issue #68、issue #80、issue #83) 如果 executor 声明了 tools,Run workspace 顶部标题栏右侧会出现一个紧凑的“工具权限”统计区域,不放在 Input/composer/footer 内。触发区会显示工具主图标,以及全部、启用、自动批准三组图标和数量;弹层从标题栏向下展开,并用表格展示可用工具、“启用工具”和“自动批准”两列开关;默认值来自 workflow 注册项,App 只把用户修改后的覆盖值保存到 renderer localStorage(key 按 workflow id/name 区分),不写入 workflow 源码、registry 或 SQLite。运行和提交 user-input 恢复时都会把已注册工具的覆盖值作为本次 run 的策略快照传给 main 进程;未知工具会被忽略。工具启用但未自动批准时,workflow 运行会复用 user-input 等待表单显示审批请求,批准后继续同一个 run,拒绝后以工具拒绝错误结束。(issue #92) 运行输出优先来自 output node 的流式输出;普通 workflow 会直接消费本地 runtime events 中的 node_chunk,在执行仍为 running 时就增量更新 Output,不再等 Electron 进程结束和最终 report 返回后一次性显示。多个 output stream node 的内容会保持可读分隔,结束后再用最终 report 校准输出;如果没有可读输出,界面会展示执行诊断。通过 workflow.createTimerNode 启动的业务计时会随 timer_started / timer_finished runtime event 写入当前 live run,普通 Output、conversation assistant 消息、Diagram Result 和历史回放都会展示同一套计时卡片;workflow 收尾时 runtime 会把未显式结束的计时标记为 cleared,所以最终 report 不会留下 running timer。Input 和 Output 位于 Send 按钮上方的同一个内部滚动区,Diagram/Logs 图标位于 Output 下方;小窗口或长 options/radio 表单不会把 Output 压到不可达位置,Output 卡片会保留稳定最小高度并在自身内部滚动;短表单或大窗口中,Output 会弹性填充 Send 按钮上方的剩余空间,避免因固定高度在结果区下方留下大段空白。Diagram 会在右侧诊断抽屉中展示本次运行的调用链路、正在执行的节点和已经走过的路线;节点卡片会展示基本结构摘要,例如 run-if 条件与分支数量、分支 path/when、LLM provider 与 prompt/mapInput 摘要、classifier 分类数量与提示词摘要。点击节点后,底部详情层会展示原 Trace 中的 input、output、executionInfo 和错误详情;input、output、executionInfo 纵向排列为可折叠区块,详情层顶部可以拖拽调整高度,所有节点都会在右上角提供关闭按钮。Provider 和 LLM 节点会先展示静态结构配置,即使还没有运行也能看到 provider 引用、env fallback 名称、baseURL/model/type 等可见字段,以及 LLM 的 system/prompt/mapInput 源码;字面量 apiKey/token 等 secret 会遮罩。如果节点仍在 running,详情层会先显示执行中占位并等待 runtime event 回填,不会把缺失字段渲染成 undefined。Logs 会在同一右侧诊断抽屉中展示当前 run 或 active conversation 的 stdout、stderr、runner diagnostics 和 report.jsonreport.json 以及 Diagram 节点详情中的 input/output/executionInfo/原始 items JSON 都使用只读可搜索查看器,支持当前匹配定位和上一个/下一个跳转。Run/Send 不再自动切换到 Diagram,诊断只能由运行结果或消息按钮手动打开。(issue #88、issue #89) 当本地 workflow 执行到 workflow.createUserInputNode(...) 时,App 会把 run 保存为 waiting_for_input 并在 Output 区显示等待表单;conversation 模式下,同一份等待表单会显示在当前 transcript 末尾,直接接在仍处于 running 的 assistant 消息后面。表单字段复用节点 params,和 Run workspace 的 executor.params 使用同一套控件;提交时按钮显示 loading 并禁用重复点击,失败时错误会留在等待卡片中。Diagram 会把当前等待用户输入的节点标记为 waiting for input,使用 warning/loading 语义,而不是把可恢复暂停显示成 failed。提交成功后,main 进程从 SQLite 中读取原始 run record,校验 requestId,再用同一个 runId、原始 args 和 resolvedUserInputs 重新运行本地 workflow;新的 report 会覆盖同一条 run history,并继续更新 Diagram、Logs、Output 或当前 conversation assistant 消息。刷新 App 后,local_runs.pendingUserInput 仍可恢复等待表单;renderer 只能通过 preload 暴露的 submitLocalWorkflowUserInput IPC 提交答案,不直接操作 SQLite。(issue #87、issue #92) 如果 executor 配置 tokenUsage: { enabled: true, display: true },普通 workflow 的 Output 区右下角会显示本次 run 的 token badge。badge 展示完整数字和完整 tokens 单位,例如 55 tokens1,234 tokens;hover tooltip 展示 input、output、total、reasoning、cached 和 calls 明细。display: false 时仍会统计并写入 KV/report,但 App 不展示 badge。 workspace/workflow/openai-agents 是外部 Agent SDK 的参考示例:它通过 executor params 暴露 message/model/workdir,开启 conversation 和 tokenUsage,把 App 会话上下文传入 @openai/agents,并把 SDK 工具结果写回 conversation KV。真实运行需要在 Env 中配置 OPENAI_API_KEY、可选的 OPENAI_BASE_URL。示例还可通过 --local-shell 接入 Agents SDK 的本地 shellTool,由 workflow 实现受控 shell runner,把小型本地命令限制在 workdir 内执行。它同时包含一个自定义 test_tool function tool,用于发起 小型 HTTP GET/POST 测试请求并返回状态码、content type 和响应预览;对应单测 会启动本地 HTTP server,避免普通测试依赖外网。 workspace/workflow/claude-agent 是 Claude Agent SDK 示例:它同样开启 conversation 和 tokenUsage,把 Claude Agent session id 存在当前 App 会话的 workflow conversation state 里;同一个 conversationId 后续运行会 resume 同一 个 Claude Agent session。真实运行需要在 Env 中配置 ANTHROPIC_API_KEY,并通过 --tools / --permission-mode 控制 Claude Agent 可用工具和权限模式。普通 pnpm test:workspace 只覆盖 fixture 与 structure,真实 SDK 行为按示例 README 中的 opt-in 命令验证。

会话模式

当 workflow 的 executor 开启 conversation: { enabled: true } 后,运行面板会进入对话体验。App 会为每个本地 chat session 复用同一个 conversationId,让 workflow runtime 的 conversation KV 能跨消息延续。 本地 conversation sessions/messages 也持久化到 workflow-code.sqliteconversation_sessionsconversation_messages。首次升级时,App 会把旧的 workflow-code:run-conversations:v1 localStorage 内容迁移进 SQLite,并清除旧 key;后续 localStorage 只继续保存主题、布局、active workspace 等 UI 偏好。SQLite 保存的是可恢复会话历史,不会恢复运行中的 activeRequestIdactiveRunId,避免刷新后把已不存在的进程状态误当成仍可取消的运行。 会话面板包含本地话题选择、新建话题入口、平铺 transcript、运行中状态、失败状态和附件预览/下载入口。共享对话组件会按自身容器宽度响应式布局:宽容器下左侧显示话题列表和新建入口,右侧显示当前 transcript 与 input/composer;左侧话题列表支持拖拽分隔条调整宽度,也能隐藏和重新展示;话题按创建时间新到旧排列,新建话题必须位于第一条,长列表默认展示最新一页并向下分页加载更早话题;重复点击 New 时会优先复用当前 workflow 中未发送、未运行的空白话题并清空输入草稿,不会生成多个空白话题;空白话题在列表和选择器里显示“默认话题”,不直接展示 conversation id。当前话题没有消息时,右侧主区会显示“你想用 <项目名> 做什么?”并把 composer 放在欢迎标题下方的中部位置,不再只显示 No messages.;已有消息后恢复为 transcript 滚动区和底部 composer。窄容器下退回顶部会话选择器,保持单列聊天体验。Conversation 也支持多个话题请求并行运行:某个话题运行中时只锁住该话题自己的 composer/Send,用户仍可切换或新建其它话题并继续发送;旧话题的 runtime event 和最终 report 会按 conversationId / requestId 写回原 assistant 消息和 run history,不会覆盖当前 active 话题的输入状态。 从 issue #98 起,conversation workflow 可以通过 executor.conversation.defaultInput 显式声明共享默认输入框协议。启用后,App 会把主输入固定映射成顶部 composer:
  • Enter 发送,Shift+Enter 换行,IME 组合输入中不会误发。
  • 主文本固定写入 --message
  • 开启图片/文件能力时,左下角附件菜单会把上传、粘贴或拖拽得到的文件先写入本地 workflow file store,再分别序列化到 --images / --files
  • 待发送附件会先显示在 composer 上方,发送后清空;辅助参数仍保留在 Advanced options 中,不再要求 workflow 把主消息或主附件重复声明在 params
没有声明 conversation.defaultInput 的旧 workflow 仍保持原有基于 params 的 conversation 输入行为,因此旧示例和渐进迁移流程不会被强制打断。 从 issue #99 起,conversation workflow 还可以通过 executor.conversation.inputQueue: { enabled: true } 打开输入队列。开启后:
  • 当前话题正在运行时继续发送的新输入不会立刻执行,而是显示在 composer 上方的等待队列中。
  • 队列项支持引导、编辑、删除和拖动排序;引导会先中断当前运行,再立即执行该项。
  • App 会把等待队列持久化到本地 SQLite。退出并重新打开后,队列仍保留,但不会自动续跑; 用户需要先手动发送一次新输入,随后等待中的队列项才会继续按顺序执行。
assistant 输出现在保存为 items: WorkflowOutputItem[]。Conversation 和只读 replay 中,用户 input 消息使用右侧轻量气泡展示,assistant 文本和 output item 按顺序平铺展示,消息与 item 间距约 5px;默认 Output 的 markdown/text item 直接作为纯文本或 Markdown 展示,工具调用、JSON、带自定义 title/icon/metadata 或默认折叠的 item 才显示为独立折叠块。折叠块 summary 行包含 icon、title 和可选状态;当 metadata.statusrunningsuccessfailed 时会显示执行中、完成或失败标记,running 状态带轻量 spinner,便于跟踪网络/工具延迟。展开后正文按 contentType 渲染 Markdown、纯文本、格式化 JSON 或音频播放器;音频 item 的 content 使用 { src, mimeType, name, size, durationMs?, format? },播放器只接受安全 data:audio/...;base64,...http(s) URL;长内容在块内滚动,避免工具参数和结果撑爆对话或普通 Output 面板,滚到块内顶部或底部后继续滚轮会带动外层工作区滚动。Markdown 代码块会对 JavaScript、TypeScript、JSON、Shell、CSS、HTML/XML、Markdown、Python、SQL、YAML 和 Diff 等常用语言提供基础高亮,未知语言仍按普通代码块展示并保留横向滚动。Markdown 图片支持安全的 data:image/png|jpeg|webp|gif;base64,... 预览,适配 workspace/workflow/gpt-image 这类直接返回 data URL 的 output item;点击图片会在当前界面打开基于 react-zoom-pan-pinch 的大图预览层,可通过按钮、键盘、Cmd/Ctrl + 鼠标滚轮或 mac 触摸板双指缩放来放大/缩小,快捷缩放会围绕当前鼠标或触摸板指针位置展开;放大后可按住鼠标左键拖动平移查看不同区域,也可重置比例、Escape、点击背景或关闭按钮退出;非图片 data URL 仍会被默认安全策略过滤。普通 workflow Output、conversation 和只读 replay 使用同一套 item 渲染。Conversation 运行中的多个 output node 和结构化 output_item_* chunk 会按 item 边界增量拼接,字符串 chunk 会写入默认 Markdown item,output_item_delta.item 可以更新同一张卡片的标题、图标和状态,createDetailsOutputNode 会输出默认折叠的独立 item,并保留对象或数组原始 JSON。workspace/workflow/codex 会把 Codex SDK 的 command、MCP tool、web search、todo、file change、reasoning 和 error 事件映射成独立折叠 JSON item;结构化输出开启时,最终回答仍作为默认 Output Markdown 直接平铺展示,完整 title/branch/result/path 另作为折叠 JSON item 留给检查。若最终 report 失败但没有 output item,App 会把 report 中的 errMessage、标准 error cause 或 runner stderr 转成一个未折叠的错误 item,避免 assistant 只显示 failed 状态。图片上传后只在 composer 输入区显示一次小缩略图,不再额外展示参数 JSON 文本;发送后用户消息会把缩略图显示在消息上方,图片-only 消息不会把文件 JSON 渲染成消息文本。发送期间会在对应会话列表项上显示 running 标记,只禁用该会话自身的 composer/Send,不阻止切换到其它会话或新建空白会话;切走后原会话仍继续执行并把流式输出写回原会话。Advanced options 在 composer 左下角显示为小按钮,点击后只在 composer 区域内从下向上展开局部弹窗,不占用主表单空间。小窗口或长主参数让 composer 变高时,右侧会话面板会保留纵向滚动兜底或 composer 内部滚动,确保发送和取消入口仍可达。Cancel 会停止当前本地 workflow 进程并把正在运行的 assistant 消息标记为取消。(issue #62、issue #68、issue #80、issue #83) 话题标题优先展示 workflow 通过 context.conversation.setTitle() 或用户手动改名得到的标题,空白新话题显示“默认话题”;左侧列表只显示单行标题,不显示日期分组、更新时间、消息数或完整 conversation id;这些辅助信息保留在可访问名称中。话题项只通过右键菜单管理,不在最右侧或窄屏选择器旁展示三点/更多按钮;菜单支持重命名、删除和锁定标题。锁定后 App 会忽略 workflow 代码和最终 report 推来的标题更新,用户手动解锁后才能继续编辑。Raw 输入框按 Enter 发送、Shift+Enter 换行;结构化 Form 输入在文本类输入框中按 Enter 发送,组合输入法输入中不会误触发。(issue #83、issue #89) 每条完成后的 assistant 消息会在消息内容下方外侧显示当前消息的 Trace、Logs 和 Copy 小图标。Trace 点击后,App 会根据该消息绑定的 runId 选择对应运行记录,并在右侧诊断抽屉中打开 Diagram;Logs 点击后在同一抽屉中打开日志。同一条消息的同一诊断入口再次点击会关闭当前诊断抽屉,不改变 Run 主视图;不同 run 或不同诊断类型会更新抽屉内容。Copy 使用独立复制图标和中性分隔样式,与 Logs 的文件图标区分,并在复制成功或失败后显示反馈。所有小图标都有 hover 文字和可访问名称。右上角不再保留全局 Trace / Logs 小图标,避免诊断入口脱离消息上下文。(issue #80、issue #89) 会话附件会先上传到当前本地文件 store,再作为 file param 的 JSON 引用传给 workflow。不要在 workflow KV 或会话历史里保存 base64 原文,保存 toJSON() 后的引用即可。 本地图片/附件本体仍保存在 userData/workflow-files/<fileId>/content。SQLite 的 workflow_files 只保存 fileId、文件名、MIME、大小、kind、storage path、workflow/conversation 关联和访问时间;file_refs 记录该文件被 message 或 run 引用。读取图片预览时通过 preload IPC 从 main 进程取 metadata 和 data URL。清理附件必须先确认 file_refs 没有任何引用,再删除 workflow-files/<fileId> 目录,避免同一图片仍被其它 message 或 run 使用时被误删。(issue #85) 会话 workflow 开启 token 用量展示时,每次 assistant 回复完成后,会在同一条消息操作行右侧显示该轮 run 的 token badge。badge 同样展示完整 token 数和 tokens 单位,不使用 tok 缩写。运行中的 token_usage_updated event 只更新运行诊断,不提前写入 transcript;最终 report 回来后才把用量持久化到本地会话记录。

工作区主视图

工作区左侧 activity rail 管理四个主视图:
  • Run 视图是进入项目后的默认视图,直接承载普通 workflow 输入/输出或 conversation transcript/composer。普通 workflow 左侧有历史执行栏和图标式“新 workflow”入口,历史栏可折叠,历史项只支持右键菜单,不展示最右侧三点/更多按钮;workflow 与 conversation 历史项使用一致的话题式单行标题列表,running 状态只在右侧显示极简旋转图标,不显示大号 running 标签,workflow 成功记录也不显示 success 标签;workflow 与 conversation 左侧历史栏现在复用同一套 shared sidebar shell,桌面宽度下都支持拖拽调宽和键盘调宽,收起后都在 Run workspace 顶部标题栏左侧显示纯图标展开按钮,不保留左侧窄 rail;浅色主题下右侧主体内容使用白色 surface,左侧历史栏使用浅灰 panel,hover 使用浅色 panel-hover,选中历史使用更清晰的白色 surface pill、描边和轻阴影,深色主题下才使用深色 rail 背景和深灰选中 pill,不能把深色截图色无条件用于浅色主题,也不能让浅色选中态和普通背景难以区分;历史只负责选择查看已有 run,选中历史时右侧是只读结果视图且没有 Run workflow 按钮;运行中的 live run 也会出现在列表中;右侧新 workflow 输入区是唯一执行入口,且其它 run 仍在运行时也可以继续启动新 workflow。Conversation 中某个话题运行时,仍可新建或切换到其它话题并发送新请求。普通运行和 conversation 运行都停留在该主视图,Diagram/Logs 只能通过结果区或消息下方按钮打开右侧诊断抽屉。(issue #89)
  • Info 视图展示项目显示名、类型和卡片图标编辑表单,并占满项目工作区可用宽度;workflow 默认图标预览、TopBar 左上角项目图标和首页项目卡片会共用同一枚内置 Workflow 图标,旧的 sparkles 元数据会自动兼容到这枚图标;保存后写回本地 package.jsonworkflowCode.projectCard。(issue #89)
  • Files 视图保留原文件树和 Monaco 编辑器;切换到其它视图前会同步当前编辑器内容到 store,避免未保存内容因为视图卸载而丢失。顶部栏 Save/Refresh 只在 Files 视图显示;Publish 或 Pull Code 会使用已经同步到 store 的文件快照,不会把未挂载编辑器当作空文件内容写回。(issue #80、issue #89)
  • Terminal 视图连接 Electron 本地项目目录,适合运行 workflow-code structure . 或其它项目命令。
  • 右侧诊断抽屉展示 Diagram 或 Logs,支持关闭、拖拽调宽和键盘调宽;Run workspace 顶部标题栏右侧默认显示同一个纯图标诊断按钮,抽屉打开时用于收起 Diagram/Logs,隐藏后切换为恢复入口,不再要求先点击隐藏后才出现标题栏控制,也不保留独立右侧窄列。结构图支持按住 Ctrl/Meta 后滚轮缩放,也支持鼠标拖拽平移,视图控件保留放大、缩小、适配和重置入口。Logs 中的 report.json 会占满卡片剩余滚动区域,并支持搜索定位。(issue #89、issue #92)

发布与 Pull Code

Publish 的真实顺序是:
  1. 连接 server,验证 server URL 和 token。
  2. 先保存本地文件。
  3. 如果当前本地项目还没有绑定 server UUID,先调用 POST /api/workflows 创建远程项目,并把返回 UUID 回写到本地顶层 package.json.id、本地项目注册表、SQLite 会话/运行历史和 renderer store。
  4. Electron 环境下用 server CLI 上传本地项目包,并把当前 App 已保存的浏览器登录态自动注入到上传命令里,在对话框中展示保存、上传、发布三个阶段的进度。
  5. 调用 server publish,生成新版本并刷新版本列表。
发布期间对话框会停留在当前工作流上,不再复用空状态。上传中可以点击“停止上传”取消当前 CLI 上传;进入发布阶段后按钮会变为“停止等待”,只终止前端等待结果,服务端仍可能完成版本生成,因此取消后会主动刷新工作流和版本列表。取消后会进入取消结果页,并清理 Publish loading;保存、上传、发布任一阶段失败或取消时,步骤条会标出实际发生问题的阶段。上传成功后显示“发布完成”和生成的版本号;上传、构建或发布失败时显示失败页和错误详情,方便修复后重试。(issue #39) 从 issue #95 起,App 里的项目身份被拆成两层:目录名称只负责本地文件夹命名和本地导航,真正的远程项目身份固定在顶层 package.json.id UUID。已登录新建项目时,App 会在创建本地文件前先向 server 申请 UUID;未登录新建项目仍可直接本地运行,但只会先生成一个本地 UUID,首次 Publish 时再绑定 server 返回的 UUID。绑定发生后,App 会同步迁移本地项目列表、server project 列表、当前选中项目、会话历史、运行历史、附件引用和当前选中的 run,避免发布后丢失本地 replay 或 conversation 上下文。后续 Publish、远程运行和 Pull Code 都使用这个 UUID 与 server 对齐,不再从目录名或显示名推导远程项目。(issue #95) Pull Code 反向执行:选择 server 的 latest、draft 或具体版本,下载文件后完整替换本地可编辑源码。执行前会要求保存本地未保存改动。只有 server 连接状态为 connected、当前项目存在对应 server 项目且有可选版本时,TopBar 才展示 Pull Code;server 未连接时底部状态栏会显示 disconnected/idle 文案,而不是 server connected

深色模式

App 工作区通过 CSS 变量支持主题切换。浅色模式以亮灰背景、白色面板、slate 灰边框和墨黑正文为主;深色模式以近黑背景和低亮度中性色为主,状态色使用降饱和版本以保持可读性。

追踪

本文档首版由 issue #32 记录。核心行为对齐 app/src/renderer/src/store/index.tsExecutionPanel.tsxTopBar.tsx