zen-gitsync 2.17.12 → 2.17.14
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +6 -2
- package/package.json +1 -1
- package/scripts/release.js +201 -9
- package/src/cli/ai/agent.js +16 -0
- package/src/ui/public/assets/AgentView-DLHlVWRg.js +5 -0
- package/src/ui/public/assets/AgentView-vvVhbIQ5.css +1 -0
- package/src/ui/public/assets/{AppVersionBadge-D5tJzJfa.css → AppVersionBadge-CJrDr7GV.css} +1 -1
- package/src/ui/public/assets/AppVersionBadge-JxpMuGwP.js +2 -0
- package/src/ui/public/assets/BranchSelector-B0eLkAdv.css +1 -0
- package/src/ui/public/assets/BranchSelector-XIN87Mkw.js +1 -0
- package/src/ui/public/assets/CommitForm-CQ0K8Yy2.css +1 -0
- package/src/ui/public/assets/CommitForm-CW53Er5m.js +6 -0
- package/src/ui/public/assets/CommonDialog-BiNTGpA-.js +1 -0
- package/src/ui/public/assets/CommonDialog-jP0E9mco.css +1 -0
- package/src/ui/public/assets/EditorView-D0JoJhgt.js +1 -0
- package/src/ui/public/assets/EditorView-DZMLvQds.css +1 -0
- package/src/ui/public/assets/FileDiffViewer-B9EkuKdF.css +1 -0
- package/src/ui/public/assets/FileDiffViewer-Yas2nO2U.js +15 -0
- package/src/ui/public/assets/FlowExecutionViewer-D9Vzgh91.js +1 -0
- package/src/ui/public/assets/FlowExecutionViewer-jNHI5zdm.css +1 -0
- package/src/ui/public/assets/FlowOrchestrationWorkspace-CYGp-PqS.css +1 -0
- package/src/ui/public/assets/FlowOrchestrationWorkspace-DQ3fg5b9.js +21 -0
- package/src/ui/public/assets/IconButton-DysyaC1j.js +1 -0
- package/src/ui/public/assets/IconButton-tjkOjzkC.css +1 -0
- package/src/ui/public/assets/LogList-BlJplIi1.css +1 -0
- package/src/ui/public/assets/LogList-QDgok-UJ.js +7 -0
- package/src/ui/public/assets/MindmapView-BQTqx842.css +1 -0
- package/src/ui/public/assets/MindmapView-CeZsQNBK.js +2 -0
- package/src/ui/public/assets/MonitorView-D1tgmjjS.js +1 -0
- package/src/ui/public/assets/MonitorView-DetlFFXq.css +1 -0
- package/src/ui/public/assets/ProjectStartupButton-COntA4q1.js +1 -0
- package/src/ui/public/assets/ProjectStartupButton-QLPltCK5.css +1 -0
- package/src/ui/public/assets/RemoteManagerDialog-3dihAOab.js +4 -0
- package/src/ui/public/assets/RemoteManagerDialog-BauAeH2w.css +1 -0
- package/src/ui/public/assets/RemoteRepoCard-Bn9cKt1D.js +7 -0
- package/src/ui/public/assets/RemoteRepoCard-CG-jARTe.css +1 -0
- package/src/ui/public/assets/SourceMapView-C8UdzQXF.js +3 -0
- package/src/ui/public/assets/SourceMapView-CN4Hkyp4.css +1 -0
- package/src/ui/public/assets/{SvgIcon-BQ6bR7l0.css → SvgIcon-CDNsk4-Q.css} +1 -1
- package/src/ui/public/assets/SvgIcon-CvtoU5yo.js +1 -0
- package/src/ui/public/assets/TemplateManager-DMuG4i3G.css +1 -0
- package/src/ui/public/assets/TemplateManager-saqC9kdQ.js +1 -0
- package/src/ui/public/assets/UserInputNode-BVgQkB2l.css +1 -0
- package/src/ui/public/assets/UserInputNode-CvEfvX3i.js +1 -0
- package/src/ui/public/assets/WorkbenchView-B1BJhWHi.css +1 -0
- package/src/ui/public/assets/WorkbenchView-B7WAu1Ay.js +56 -0
- package/src/ui/public/assets/_plugin-vue_export-helper-BdTxl34g.js +19 -0
- package/src/ui/public/assets/configStore-AQMSazCM.js +1 -0
- package/src/ui/public/assets/element-plus-CMSkP_w2.js +48 -0
- package/src/ui/public/assets/element-plus-Dc1iTOWq.css +1 -0
- package/src/ui/public/assets/{flow-mindmap-C_w8GJXm.js → flow-mindmap-CHxAWdLw.js} +16 -16
- package/src/ui/public/assets/gitStore-BgC8OY0k.js +6 -0
- package/src/ui/public/assets/index-Dpx9Bcqn.css +1 -0
- package/src/ui/public/assets/index-qAmzFO10.js +104 -0
- package/src/ui/public/assets/office-docx-CmBY5bpF.js +32 -0
- package/src/ui/public/assets/{office-excel-CDjN3Va1.js → office-excel-BEhsBUNX.js} +1 -1
- package/src/ui/public/assets/office-pptx-DWfi413x.js +74 -0
- package/src/ui/public/assets/{previewSandbox-B6Ud9g6a.css → previewSandbox-CgdwPcuW.css} +1 -1
- package/src/ui/public/assets/previewSandbox-CyuMMYaq.js +0 -0
- package/src/ui/public/assets/socket-io-BFqQXqAp.js +1 -0
- package/src/ui/public/assets/{useThemeObserver-DAWKXvWv.js → useThemeObserver-DhCU3SIo.js} +1 -1
- package/src/ui/public/assets/{vendor-DcK6TCKZ.js → vendor-CZnXb2r9.js} +46 -39
- package/src/ui/public/assets/vue-flow-7_n4vJqi.js +39 -0
- package/src/ui/public/index.html +24 -25
- package/src/ui/server/index.js +4 -0
- package/src/ui/server/routes/fs.js +3 -1
- package/src/ui/server/routes/git/clone.js +166 -0
- package/src/ui/server/routes/git/clone.test.js +253 -0
- package/src/ui/server/routes/gitOps.js +5 -0
- package/src/ui/server/routes/localRepos.js +60 -0
- package/src/ui/server/routes/localRepos.test.js +151 -0
- package/src/ui/server/routes/workbench/agentChat.js +16 -0
- package/src/ui/server/routes/workbench/envContext.js +16 -2
- package/src/ui/server/routes/workbench/envContext.test.js +14 -0
- package/src/ui/server/routes/workbench/remoteCliPromptParity.test.js +9 -0
- package/src/ui/server/utils/directoryGitState.js +49 -0
- package/src/ui/server/utils/directoryGitState.test.js +47 -0
- package/src/ui/server/utils/localRepoScan.js +314 -0
- package/src/ui/server/utils/localRepoScan.test.js +291 -0
- package/src/ui/public/assets/AgentView-BNH92bKu.js +0 -5
- package/src/ui/public/assets/AgentView-BV15UtEF.css +0 -1
- package/src/ui/public/assets/AppVersionBadge-DXWTExsY.js +0 -2
- package/src/ui/public/assets/BranchSelector-CJI-I8JY.js +0 -1
- package/src/ui/public/assets/BranchSelector-T_rJm-JY.css +0 -1
- package/src/ui/public/assets/CommitForm-CTYhgpkj.js +0 -6
- package/src/ui/public/assets/CommitForm-Oij8R6P-.css +0 -1
- package/src/ui/public/assets/CommonDialog-C_RjF9Mp.css +0 -1
- package/src/ui/public/assets/CommonDialog-DNnN70HC.js +0 -1
- package/src/ui/public/assets/EditorView-BgA-_8WV.css +0 -1
- package/src/ui/public/assets/EditorView-C2AbXelw.js +0 -1
- package/src/ui/public/assets/FileDiffViewer-B2_ghtbv.css +0 -1
- package/src/ui/public/assets/FileDiffViewer-ZD705xXx.js +0 -14
- package/src/ui/public/assets/FlowExecutionViewer-B5kh7VxS.css +0 -1
- package/src/ui/public/assets/FlowExecutionViewer-BP9w_OQb.js +0 -1
- package/src/ui/public/assets/FlowOrchestrationWorkspace-BAQDU9Jd.css +0 -1
- package/src/ui/public/assets/FlowOrchestrationWorkspace-DeSI8Mlj.js +0 -21
- package/src/ui/public/assets/IconButton-BxRsG5E1.js +0 -1
- package/src/ui/public/assets/IconButton-CTwyZrv2.css +0 -1
- package/src/ui/public/assets/LogList-1sIFUx4e.js +0 -7
- package/src/ui/public/assets/LogList-DlWwSZet.css +0 -1
- package/src/ui/public/assets/MindmapView-6_fbvhh3.js +0 -1
- package/src/ui/public/assets/MindmapView-CS2t30Ko.css +0 -1
- package/src/ui/public/assets/MonitorView-CURagJDe.js +0 -1
- package/src/ui/public/assets/MonitorView-CphDOlQu.css +0 -1
- package/src/ui/public/assets/ProjectStartupButton-B7zvqRj_.css +0 -1
- package/src/ui/public/assets/ProjectStartupButton-COyb4Fbk.js +0 -1
- package/src/ui/public/assets/RemoteManagerDialog-DoS9EWQr.js +0 -1
- package/src/ui/public/assets/RemoteManagerDialog-bpwaVAvX.css +0 -1
- package/src/ui/public/assets/RemoteRepoCard-BwrdI5UH.js +0 -1
- package/src/ui/public/assets/RemoteRepoCard-CDykPlPj.css +0 -1
- package/src/ui/public/assets/SourceMapView-DADzBGfb.js +0 -3
- package/src/ui/public/assets/SourceMapView-DjYKJZLj.css +0 -1
- package/src/ui/public/assets/SvgIcon-VCh_kGGV.js +0 -1
- package/src/ui/public/assets/TemplateManager-C0rm8xfC.css +0 -1
- package/src/ui/public/assets/TemplateManager-C4go4RZu.js +0 -1
- package/src/ui/public/assets/UserInputNode-Cl5-bI42.js +0 -1
- package/src/ui/public/assets/UserInputNode-DDtvv9Iq.css +0 -1
- package/src/ui/public/assets/WorkbenchView-B8QOp8nM.css +0 -1
- package/src/ui/public/assets/WorkbenchView-DtCyyW3b.js +0 -6
- package/src/ui/public/assets/_plugin-vue_export-helper-Dcylt9fO.js +0 -19
- package/src/ui/public/assets/configStore-BlqdtNUA.js +0 -1
- package/src/ui/public/assets/element-plus-C1PloHQu.css +0 -1
- package/src/ui/public/assets/element-plus-IG-bwpR5.js +0 -28
- package/src/ui/public/assets/gitStore-BKkZm2m3.js +0 -4
- package/src/ui/public/assets/index-Bq7iCtof.css +0 -1
- package/src/ui/public/assets/index-DGHrUfrh.js +0 -28
- package/src/ui/public/assets/office-docx-CkLOvV7H.js +0 -31
- package/src/ui/public/assets/office-pptx-CVu3fXsL.js +0 -60
- package/src/ui/public/assets/previewSandbox-DYMhXJ91.js +0 -0
- package/src/ui/public/assets/socket-io-TBtw0msS.js +0 -1
- package/src/ui/public/assets/toolsStore-BlRHNqXl.js +0 -1
- package/src/ui/public/assets/vue-flow-B3gZmkCI.js +0 -39
package/README.md
CHANGED
|
@@ -45,7 +45,7 @@ npm install -g zen-gitsync
|
|
|
45
45
|
- **Visual GUI** — Full graphical interface for Git operations
|
|
46
46
|
- **Branch management** — Create, switch, and track local/remote branches
|
|
47
47
|
- **Remote management** — Manage multiple remotes (add / rename / retarget / delete) from one dialog, configure multi push URLs, and push to a chosen remote or to all remotes at once
|
|
48
|
-
- **Repository browser** — GitHub / Gitee tabs listing every repository your CLI account can see (private ones included), with search, sorting (recently pushed / recently created / most starred / name) and cards that carry last-push date, fork count, default branch and license
|
|
48
|
+
- **Repository browser** — GitHub / Gitee tabs listing every repository your CLI account can see (private ones included), with search, sorting (recently pushed / recently created / most starred / name), grouping by workspace, and cards that carry last-push date, fork count, default branch and license
|
|
49
49
|
- **Stash management** — Save and restore stashes with locked-file filtering
|
|
50
50
|
- **Tag management** — Create lightweight and annotated tags
|
|
51
51
|
- **Merge support** — Detect and complete in-progress merges
|
|
@@ -169,6 +169,7 @@ In either mode, click **AI Generate** to fill in the fields automatically based
|
|
|
169
169
|
- **Zero-config guidance** — a missing CLI shows the install command for your platform (winget / Homebrew / `npm install -g @gitee/gitee-cli`) with one-click install and auto-refresh; an installed but signed-out CLI shows the sign-in command plus one-click sign-in, then polls until you finish the interactive flow in the terminal
|
|
170
170
|
- **Search** — filters by name, full path and description; the header switches to `匹配 M / 共 N 个仓库` so you can tell how much got filtered out
|
|
171
171
|
- **Sort** — recently pushed (default) / recently created / most starred / name. Sorting happens in the frontend, so both tabs behave identically — their CLIs do not (`gh` returns most-recently-pushed first, `gitee` returns `owner/name` alphabetical)
|
|
172
|
+
- **Group by workspace** — repositories are grouped by their `owner` by default, so everything under one account or organisation sits together instead of being scattered across the grid by push date; group order follows the current sort rule (the workspace pushed most recently comes first) and so does the order inside each group, with the header showing how many repositories that workspace holds. Switch to **No grouping** for a flat, cross-workspace timeline
|
|
172
173
|
- **No refetch on tab switch** — the list is cached per account, so coming back to the tab paints instantly instead of shelling out to `gh repo list` again; once the cache is a minute old it paints from cache first and refreshes quietly in the background, while **刷新** always pulls for real
|
|
173
174
|
- **Informative cards** — repository name, description and privacy / fork / language / star badges, plus a third line with last-push date, fork count, non-`main` default branch and license (each omitted when there is nothing to say)
|
|
174
175
|
- **One click to open or copy** — clicking a card opens the repository page in your browser; the actions that appear on hover copy the URL or open it
|
|
@@ -412,6 +413,7 @@ A dedicated view (robot icon in the activity bar) for chatting with the built-in
|
|
|
412
413
|
| Tool call display | Each tool invocation (run_command, read_file, edit_file, list_files, search_text, write_file) is shown as a collapsible card with arguments preview and execution result |
|
|
413
414
|
| Recent-projects awareness | Ask "which of my projects need a pull?" and the agent calls its built-in `list_projects` tool instead of scanning the disk: it returns exactly the list behind the GUI's **Recent projects** panel (recent directories plus any directory a task was created in, with branch / ahead / behind / uncommitted counts and task progress), so the agent's answer and the UI agree. Ahead/behind reads local refs, so the agent can pass `refresh=true` to run a `git fetch` pass first when the question is about pulling |
|
|
414
415
|
| Session persistence | All conversations are saved to `~/.zen-gitsync/agent-sessions/` as JSON files; the CLI agent (`g ai`) writes to the same directory so Web and CLI sessions are unified |
|
|
416
|
+
| SSH-first cloning | When you ask it to clone a repo (or add a remote) it uses the SSH form — `git@github.com:owner/repo.git` / `git@gitee.com:owner/repo.git` — converting an `https://` URL first, so the clone never stalls on a Git Credential Manager username/password prompt; it falls back to https only when SSH genuinely fails (`Permission denied (publickey)` / host-key verification) and says which one it used. The same preference is injected into every workbench task, whose executor is an external CLI with a system prompt this app does not own |
|
|
415
417
|
| Per-turn tool limit | A single message may trigger up to N tool calls in a row (default **200**, range 1–2000). Configurable in **Settings → AI models → Agent Runtime**; hitting the limit ends the turn and asks you to send another message. The same setting drives the CLI agent |
|
|
416
418
|
| Preset questions | Quick-start buttons on the welcome screen for common tasks (view project structure, analyze code quality, write tests, check git status) |
|
|
417
419
|
| Stop generation | A floating stop button appears during streaming; aborts the LLM request and any running child processes |
|
|
@@ -647,7 +649,7 @@ npm install -g zen-gitsync
|
|
|
647
649
|
- **可视化 GUI** — 完整的 Git 图形操作界面
|
|
648
650
|
- **分支管理** — 创建、切换、追踪本地/远程分支
|
|
649
651
|
- **远程仓库管理** — 在一个弹窗里管理多个远程仓库(添加/重命名/改地址/删除)、配置多推送地址,并支持推送到指定远程或一键推送全部
|
|
650
|
-
- **仓库浏览器** — GitHub / Gitee 两个 Tab 列出 CLI
|
|
652
|
+
- **仓库浏览器** — GitHub / Gitee 两个 Tab 列出 CLI 账号下的全部仓库(含私有),支持搜索、排序(最近推送 / 最近创建 / 星标最多 / 仓库名)与按工作空间分组,卡片带最近推送日期、Fork 数、默认分支与许可证
|
|
651
653
|
- **Stash 管理** — 储藏与恢复变更,支持排除锁定文件
|
|
652
654
|
- **Tag 管理** — 创建轻量/附注标签
|
|
653
655
|
- **合并支持** — 自动检测并引导完成进行中的合并
|
|
@@ -802,6 +804,7 @@ $ ZEN_ALLOWED_ORIGINS="https://zen.example.com,http://10.0.0.5:8080" g ui
|
|
|
802
804
|
- **零配置引导** — 没装 CLI 时按平台给出安装命令(winget / Homebrew / `npm install -g @gitee/gitee-cli`),支持一键安装并自动刷新;装了但没登录时给出登录命令 + 一键登录,然后轮询等你走完终端里的交互流程
|
|
803
805
|
- **搜索** — 按仓库名、完整路径、描述过滤;顶部提示同时显示 `匹配 M / 共 N 个仓库`,一眼看出筛掉了多少
|
|
804
806
|
- **排序** — 最近推送(默认)/ 最近创建 / 星标最多 / 仓库名。排序在前端做,两个 Tab 口径一致 —— 它们的 CLI 并不一致(`gh` 按推送时间倒序,`gitee` 按 `owner/name` 字母序)
|
|
807
|
+
- **按工作空间分组** — 默认按 `owner` 分组,同一账号/组织下的仓库收拢在一起,不再被推送时间打散在整屏里;组间顺序跟随当前排序规则(最近有推送的空间排前面),组内同样排序,组头写明该空间下的仓库数(只有一个空间时不显示组头)。切到「不分组」即回到跨空间的平铺视图
|
|
805
808
|
- **切 Tab 不重拉** — 列表按账号各缓存一份,切回来直接渲染,不再重跑一遍 `gh repo list`;缓存超过一分钟后先用它画出来、再在后台静默刷新,点「刷新」则永远真的去拉
|
|
806
809
|
- **信息更全的卡片** — 仓库名、描述,以及私有 / Fork / 语言 / 星标徽标,第三行再给最近推送日期、Fork 数、非 `main` 的默认分支与许可证(没有的项直接省略,不留占位)
|
|
807
810
|
- **一键打开 / 复制** — 点击卡片在浏览器打开仓库主页,悬浮时出现的按钮可复制地址或直接打开
|
|
@@ -1047,6 +1050,7 @@ Activity Bar 中的机器人图标视图,可直接在浏览器中与内置 AI
|
|
|
1047
1050
|
| 工具调用展示 | 每次工具调用(run_command、read_file、edit_file、list_files、search_text、write_file)以可折叠卡片形式展示,含参数预览和执行结果 |
|
|
1048
1051
|
| 最近项目感知 | 问「我哪些项目需要 pull」时,智能体调用内置的 `list_projects` 工具,而不是自己去扫盘:返回的就是 GUI「最近项目」面板那份清单(最近目录 + 建过任务的目录,带分支 / 领先 / 落后 / 未提交数与任务进度),回答与界面对得上。领先/落后读的是本地引用,因此问到"要不要拉"时它可以带 `refresh=true` 先联网 fetch 一轮再答 |
|
|
1049
1052
|
| 会话持久化 | 所有对话保存为 JSON 文件到 `~/.zen-gitsync/agent-sessions/`;CLI 智能体(`g ai`)写入同一目录,Web 端与 CLI 端会话统一管理 |
|
|
1053
|
+
| 克隆优先 SSH | 让它克隆仓库(或加远端)时走 SSH 形式 —— `git@github.com:owner/repo.git` / `git@gitee.com:owner/repo.git`;拿到 `https://` 地址先换算,克隆不会停在 Git Credential Manager 的账号密码弹窗上。只有 SSH 真的不可用(`Permission denied (publickey)` / 主机密钥校验失败)才退回 https,并说明这次走的是哪条。同一条偏好也会注入到每个工作台任务的 prompt —— 那里执行器是外部 CLI,系统提示词不归本应用管,环境上下文块是唯一的注入口 |
|
|
1050
1054
|
| 单轮工具调用上限 | 一条消息内智能体最多连续调用多少次工具(默认 **200**,可调范围 1–2000)。在 **设置 → AI 模型配置 → 智能体运行时** 中修改;达到上限本轮会被强制结束并提示再发一条消息继续。CLI 智能体共用同一项设置 |
|
|
1051
1055
|
| 预设问题 | 开场界面提供快捷按钮(查看项目结构、分析代码质量、写测试、Git 状态检查)|
|
|
1052
1056
|
| 停止生成 | 流式输出期间出现浮动停止按钮;中止 LLM 请求及正在运行的子进程 |
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "zen-gitsync",
|
|
3
|
-
"version": "2.17.
|
|
3
|
+
"version": "2.17.14",
|
|
4
4
|
"description": "Auto commit, scheduled sync, and visual GUI for Git. Run `g` in any repo for one-key commit & push, AI commit messages, scheduled background sync, and a drag-and-drop workflow builder.",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"type": "module",
|
package/scripts/release.js
CHANGED
|
@@ -24,6 +24,7 @@
|
|
|
24
24
|
* 用法:
|
|
25
25
|
* npm run release # 全流程,自伤护栏全部开启
|
|
26
26
|
* npm run release -- --skip-self-update # 发布后不自动 npm install -g zen-gitsync
|
|
27
|
+
* npm run release -- --keep-instances # 装全局前不停掉运行中的 UI 实例(默认会停)
|
|
27
28
|
* npm run release -- --skip-push # 只发布到 npm,不 push git
|
|
28
29
|
* npm run release -- --dry-run # 只打印计划,不真正改 package.json / commit / publish
|
|
29
30
|
* npm run release -- --poll-interval=20 --poll-timeout=600 # 调自更新重试节奏(秒)
|
|
@@ -32,15 +33,20 @@
|
|
|
32
33
|
* tarball URL 直连)都试,装上后校验全局版本,失败把原因打出来。
|
|
33
34
|
* 原因见 tarballUrl() / selfUpdateGlobal() 处注释 —— publish 成功不等于
|
|
34
35
|
* packument 立即可见,也不等于 tarball 立即可取(两种先后顺序都实测出现过)。
|
|
36
|
+
*
|
|
37
|
+
* 自更新前置步骤:先把运行中的 UI 实例停掉(见 stopRunningInstances 处注释)——
|
|
38
|
+
* Windows 上全局包目录被实例占着时,npm 删旧目录会 EPERM,装不上或装出半成品。
|
|
35
39
|
*/
|
|
36
40
|
|
|
37
41
|
import fs from 'node:fs'
|
|
38
42
|
import fsp from 'node:fs/promises'
|
|
43
|
+
import os from 'node:os'
|
|
39
44
|
import path from 'node:path'
|
|
40
45
|
import { fileURLToPath } from 'node:url'
|
|
41
46
|
import { execSync, spawn } from 'node:child_process'
|
|
42
47
|
import chalk from 'chalk'
|
|
43
48
|
import readline from 'node:readline/promises'
|
|
49
|
+
import { createInstanceRegistry, getRegistryPath } from '../src/ui/server/utils/instanceRegistry.js'
|
|
44
50
|
|
|
45
51
|
const __filename = fileURLToPath(import.meta.url)
|
|
46
52
|
const __dirname = path.dirname(__filename)
|
|
@@ -50,6 +56,7 @@ const argv = process.argv.slice(2)
|
|
|
50
56
|
const DRY_RUN = argv.includes('--dry-run')
|
|
51
57
|
const SKIP_SELF_UPDATE = argv.includes('--skip-self-update')
|
|
52
58
|
const SKIP_PUSH = argv.includes('--skip-push')
|
|
59
|
+
const KEEP_INSTANCES = argv.includes('--keep-instances')
|
|
53
60
|
|
|
54
61
|
const NPM_REGISTRY = 'https://registry.npmjs.org/'
|
|
55
62
|
const PKG_NAME = 'zen-gitsync'
|
|
@@ -582,22 +589,28 @@ function readLatestDistTag() {
|
|
|
582
589
|
}
|
|
583
590
|
}
|
|
584
591
|
|
|
585
|
-
//
|
|
586
|
-
//
|
|
587
|
-
|
|
588
|
-
// 直接读"当前 npm 的全局根"下该包的 package.json 更确定,也和 `npm install -g` 落点一致。
|
|
589
|
-
function readGlobalInstalledVersion() {
|
|
590
|
-
let globalRoot
|
|
592
|
+
// 当前 npm 的全局根(即 `npm install -g` 的落点)。
|
|
593
|
+
// `npm root -g` 不可用 / 超时:按 Node 安装目录兜底(Windows 下 npm 默认全局根就在这里)。
|
|
594
|
+
function readGlobalRoot() {
|
|
591
595
|
try {
|
|
592
|
-
|
|
596
|
+
const out = execSync('npm root -g', {
|
|
593
597
|
encoding: 'utf8',
|
|
594
598
|
stdio: ['ignore', 'pipe', 'pipe'],
|
|
595
599
|
timeout: 30000,
|
|
596
600
|
}).trim()
|
|
601
|
+
if (out) return out
|
|
597
602
|
} catch {
|
|
598
|
-
|
|
599
|
-
globalRoot = path.join(path.dirname(process.execPath), 'node_modules')
|
|
603
|
+
/* npm 不可用,走兜底 */
|
|
600
604
|
}
|
|
605
|
+
return path.join(path.dirname(process.execPath), 'node_modules')
|
|
606
|
+
}
|
|
607
|
+
|
|
608
|
+
// 读本地全局已安装的版本,读不到返回 null。
|
|
609
|
+
// 不走 `npm ls -g <pkg> --json`:该包不存在时它退出码为 1 且输出里没有 dependencies
|
|
610
|
+
// 字段(实测只返回 {"name":"<node 版本目录名>"}),字段结构还随 npm 版本变;
|
|
611
|
+
// 直接读"当前 npm 的全局根"下该包的 package.json 更确定,也和 `npm install -g` 落点一致。
|
|
612
|
+
function readGlobalInstalledVersion() {
|
|
613
|
+
const globalRoot = readGlobalRoot()
|
|
601
614
|
if (!globalRoot) return null
|
|
602
615
|
|
|
603
616
|
try {
|
|
@@ -643,6 +656,147 @@ function tryInstallGlobal(spec) {
|
|
|
643
656
|
}
|
|
644
657
|
}
|
|
645
658
|
|
|
659
|
+
// ===========================================================================
|
|
660
|
+
// 安装前停止运行中的实例
|
|
661
|
+
// ===========================================================================
|
|
662
|
+
//
|
|
663
|
+
// 为什么必须做:全局包在 Windows 上"装不上/装不干净",根因通常不是权限,是**文件被占**。
|
|
664
|
+
// `g ui` 起的每个实例都是 `node <globalRoot>/zen-gitsync/src/gitCommit.js ui`,进程握着
|
|
665
|
+
// 全局包目录下的一堆模块句柄;npm 装新版前要先删掉旧的全局包目录 → rmdir EPERM →
|
|
666
|
+
// 一屏 `npm warn cleanup Failed to remove some directories: ... EPERM ...`,安装失败
|
|
667
|
+
// (2026-09-22 v2.17.12 实测:发布成功、全局停在 2.17.11)。
|
|
668
|
+
//
|
|
669
|
+
// 实例清单不靠猜:每个 UI 实例都把自己的 pid/port/projectPath 写进实例注册表
|
|
670
|
+
// (`~/.zen-gitsync/instances/<pid>.json`)—— 那份数据就是 UI 右上角"运行中的实例",
|
|
671
|
+
// 也是 `/api/instances` 的数据源。这里读同一份注册表,按 PID 发 SIGTERM 再摘条目,
|
|
672
|
+
// 与 UI 的"关闭全部"(routes/instances.js close-all)走同一条链路。
|
|
673
|
+
//
|
|
674
|
+
// 注:注册表的旧路径(~/.zen-gitsync-instances 目录、~/.zen-gitsync-instances.json 文件)
|
|
675
|
+
// 由 app 侧 dataDirMigration / instanceRegistry.migrateLegacy 在启动时收进当前目录,
|
|
676
|
+
// 这里不单独兼容。
|
|
677
|
+
const STOP_WAIT_MS = 8000 // 等实例退出的上限
|
|
678
|
+
const LOCK_SETTLE_MS = 1200 // 实例退出后留给 Windows 释放句柄 / 杀软松手的缓冲
|
|
679
|
+
|
|
680
|
+
// 本轮被停掉的实例数(结尾提示用户重新起)。--skip-self-update / --dry-run / --keep-instances 时为 0。
|
|
681
|
+
let stoppedInstanceCount = 0
|
|
682
|
+
|
|
683
|
+
// 存活性检查:信号 0 只做检查不发信号。EPERM = 进程存在但没权限,按存活处理
|
|
684
|
+
// (与 instanceRegistry.defaultIsProcessAlive 同一判定)。
|
|
685
|
+
function isPidAlive(pid) {
|
|
686
|
+
if (!Number.isInteger(pid) || pid <= 0) return false
|
|
687
|
+
try {
|
|
688
|
+
process.kill(pid, 0)
|
|
689
|
+
return true
|
|
690
|
+
} catch (err) {
|
|
691
|
+
if (err && (err.code === 'ESRCH' || err.code === 'ENOENT')) return false
|
|
692
|
+
return true
|
|
693
|
+
}
|
|
694
|
+
}
|
|
695
|
+
|
|
696
|
+
// 列出注册表里仍存活的实例(pruneStale 会顺手清掉 PID 已死 / 心跳超时的条目,不会误杀)。
|
|
697
|
+
// 注册表本身是 app 的模块,直接复用,避免在这里重写一遍 stale 判定 / 损坏文件自愈。
|
|
698
|
+
async function listRunningInstances() {
|
|
699
|
+
try {
|
|
700
|
+
const registry = createInstanceRegistry({
|
|
701
|
+
fs: fsp,
|
|
702
|
+
path,
|
|
703
|
+
os,
|
|
704
|
+
registryPath: getRegistryPath(),
|
|
705
|
+
})
|
|
706
|
+
const all = await registry.list({ pruneStale: true })
|
|
707
|
+
// 别把自己写进 kill 名单:release 脚本不是 UI 实例,理论上不会出现在表里,
|
|
708
|
+
// 但"自杀"这种事不该有理论上的可能。
|
|
709
|
+
return { registry, instances: all.filter((i) => i.pid !== process.pid && i.pid !== process.ppid) }
|
|
710
|
+
} catch (err) {
|
|
711
|
+
console.log(chalk.yellow(` 读实例注册表失败(${err?.message || err}),按"没有运行实例"继续`))
|
|
712
|
+
return { registry: null, instances: [] }
|
|
713
|
+
}
|
|
714
|
+
}
|
|
715
|
+
|
|
716
|
+
// 停掉所有已注册实例,返回真正停掉的条目(供结尾提示用户重新起)。
|
|
717
|
+
async function stopRunningInstances({ quiet = false } = {}) {
|
|
718
|
+
if (!quiet) {
|
|
719
|
+
console.log(chalk.blue('\n=== 安装前停止运行中的实例 ==='))
|
|
720
|
+
console.log(chalk.gray('数据来源:实例注册表(与 UI 右上角"运行中的实例"同一份)'))
|
|
721
|
+
}
|
|
722
|
+
|
|
723
|
+
const { registry, instances } = await listRunningInstances()
|
|
724
|
+
if (instances.length === 0) {
|
|
725
|
+
if (!quiet) console.log(chalk.gray('没有运行中的实例,跳过'))
|
|
726
|
+
return []
|
|
727
|
+
}
|
|
728
|
+
|
|
729
|
+
for (const ins of instances) {
|
|
730
|
+
const label = `${ins.projectName || '(未命名)'} pid=${ins.pid} port=${ins.port}`
|
|
731
|
+
try {
|
|
732
|
+
process.kill(ins.pid, 'SIGTERM')
|
|
733
|
+
console.log(chalk.gray(` → SIGTERM ${label}`))
|
|
734
|
+
} catch (err) {
|
|
735
|
+
if (err?.code === 'ESRCH' || err?.code === 'ENOENT') {
|
|
736
|
+
console.log(chalk.gray(` · 已自行退出 ${label}`))
|
|
737
|
+
} else {
|
|
738
|
+
console.log(chalk.yellow(` ✗ 停止失败 ${label}: ${err?.message || err}`))
|
|
739
|
+
}
|
|
740
|
+
}
|
|
741
|
+
// Windows 的 process.kill 直接终止目标,目标来不及执行自己的 unregister,
|
|
742
|
+
// 由发起侧立即摘条目(与 routes/instances.js 的 close 同一策略);
|
|
743
|
+
// 目标自己也会 unregister 的情况重复删同一个文件,幂等(deleteEntry 容忍 ENOENT)。
|
|
744
|
+
try {
|
|
745
|
+
await registry?.unregister(ins.pid)
|
|
746
|
+
} catch (err) {
|
|
747
|
+
console.log(chalk.yellow(` · 摘除注册条目失败 pid=${ins.pid}: ${err?.message || err}`))
|
|
748
|
+
}
|
|
749
|
+
}
|
|
750
|
+
|
|
751
|
+
// 必须确认真的退出了再往下走 —— 没退出就等于没停,文件照样被占
|
|
752
|
+
const alivePids = new Set(instances.map((i) => i.pid).filter(isPidAlive))
|
|
753
|
+
const deadline = Date.now() + STOP_WAIT_MS
|
|
754
|
+
while (alivePids.size > 0 && Date.now() < deadline) {
|
|
755
|
+
await sleep(200)
|
|
756
|
+
for (const pid of [...alivePids]) {
|
|
757
|
+
if (!isPidAlive(pid)) alivePids.delete(pid)
|
|
758
|
+
}
|
|
759
|
+
}
|
|
760
|
+
|
|
761
|
+
const stopped = instances.filter((i) => !alivePids.has(i.pid))
|
|
762
|
+
if (alivePids.size > 0) {
|
|
763
|
+
console.log(chalk.yellow(
|
|
764
|
+
` ⚠ ${alivePids.size} 个实例 ${STOP_WAIT_MS / 1000}s 内没退出`
|
|
765
|
+
+ `(pid: ${[...alivePids].join(', ')}),安装仍可能因文件占用失败`
|
|
766
|
+
))
|
|
767
|
+
}
|
|
768
|
+
if (stopped.length > 0) {
|
|
769
|
+
console.log(chalk.green(`已停止 ${stopped.length} 个实例`))
|
|
770
|
+
// 进程没了 ≠ 目录马上能删:Windows 上杀软 / 索引器可能还捏着句柄一小会儿
|
|
771
|
+
await sleep(LOCK_SETTLE_MS)
|
|
772
|
+
stoppedInstanceCount += stopped.length
|
|
773
|
+
}
|
|
774
|
+
return stopped
|
|
775
|
+
}
|
|
776
|
+
|
|
777
|
+
// npm 的失败输出里出现这些字样 = Windows 文件占用,不是"registry 还没同步"。
|
|
778
|
+
// 这两类失败的处理方式相反:文件占用要"再杀一轮 + 强删旧目录",registry 滞后只能等。
|
|
779
|
+
const LOCKED_FILE_PATTERN = /EPERM|EBUSY|ENOTEMPTY|operation not permitted|Failed to remove/i
|
|
780
|
+
|
|
781
|
+
function looksLikeFileLock(output) {
|
|
782
|
+
return LOCKED_FILE_PATTERN.test(String(output || ''))
|
|
783
|
+
}
|
|
784
|
+
|
|
785
|
+
// 手动强删旧的全局包目录。fs.rm 自带 Windows 重试(EBUSY/EPERM/ENOTEMPTY 退避重试),
|
|
786
|
+
// 比 npm 自己那层浅清理更能啃下被占的目录。
|
|
787
|
+
//
|
|
788
|
+
// 只在真撞上文件占用时才调:提前删掉会让"还得等 tarball 就绪"的那几分钟里
|
|
789
|
+
// 用户的全局命令彻底不可用 —— 宁可先让 npm 自己去删,失败了再补刀。
|
|
790
|
+
async function forceRemoveGlobalPackage() {
|
|
791
|
+
const target = path.join(readGlobalRoot(), PKG_NAME)
|
|
792
|
+
try {
|
|
793
|
+
await fsp.rm(target, { recursive: true, force: true, maxRetries: 10, retryDelay: 400 })
|
|
794
|
+
console.log(chalk.gray(` 已清掉被占用的旧全局目录: ${target}`))
|
|
795
|
+
} catch (err) {
|
|
796
|
+
console.log(chalk.yellow(` ✗ 清旧全局目录失败: ${err?.message || err}`))
|
|
797
|
+
}
|
|
798
|
+
}
|
|
799
|
+
|
|
646
800
|
// 自更新全局版本:反复尝试安装,直到全局版本校验通过或超时。
|
|
647
801
|
//
|
|
648
802
|
// 为什么不是"先等 dist-tags 翻牌,再安装"(v2.17.4 之前的老写法):
|
|
@@ -671,6 +825,9 @@ async function selfUpdateGlobal(version) {
|
|
|
671
825
|
const deadline = startedAt + POLL_TIMEOUT_MS
|
|
672
826
|
let attempt = 0
|
|
673
827
|
let lastOutput = ''
|
|
828
|
+
// 实例只在"第一次真要装"之前停一次,不在进循环时就停:前面的探测阶段可能还要等好几分钟
|
|
829
|
+
// (tarball 还没对外可取),提前停等于白白占掉用户几分钟的 UI。
|
|
830
|
+
let stopDone = false
|
|
674
831
|
|
|
675
832
|
for (;;) {
|
|
676
833
|
attempt += 1
|
|
@@ -686,6 +843,17 @@ async function selfUpdateGlobal(version) {
|
|
|
686
843
|
))
|
|
687
844
|
|
|
688
845
|
if (probe.ok) {
|
|
846
|
+
// 真要装之前,先把运行中的实例停掉:tarball 已可取,接下来就是 npm 删旧目录 →
|
|
847
|
+
// 目录被实例占着会 EPERM(见 stopRunningInstances 处注释)。只做一次。
|
|
848
|
+
if (!stopDone) {
|
|
849
|
+
stopDone = true
|
|
850
|
+
if (KEEP_INSTANCES) {
|
|
851
|
+
console.log(chalk.yellow('--keep-instances: 不停运行中的实例,若安装报 EPERM / 文件占用属预期'))
|
|
852
|
+
} else {
|
|
853
|
+
await stopRunningInstances()
|
|
854
|
+
}
|
|
855
|
+
}
|
|
856
|
+
|
|
689
857
|
// packument 已同步 → 先走常规精确版本;还没同步 → tarball 优先,争取一轮命中
|
|
690
858
|
const targets = packumentSynced
|
|
691
859
|
? [`${PKG_NAME}@${version}`, tarball]
|
|
@@ -696,6 +864,13 @@ async function selfUpdateGlobal(version) {
|
|
|
696
864
|
if (!res.ok) {
|
|
697
865
|
lastOutput = res.output
|
|
698
866
|
console.log(chalk.yellow(` ✗ ${summarizeInstallError(res.output)}`))
|
|
867
|
+
// 文件占用和"registry 还没同步"是两类失败:前者要再杀一轮 + 强删旧目录,
|
|
868
|
+
// 后者只能等。混在一起会让前者白等满 600s。
|
|
869
|
+
if (looksLikeFileLock(res.output)) {
|
|
870
|
+
console.log(chalk.yellow(' 检测到文件占用(Windows 常见):再停一轮实例 + 强制清旧全局目录'))
|
|
871
|
+
if (!KEEP_INSTANCES) await stopRunningInstances({ quiet: true })
|
|
872
|
+
await forceRemoveGlobalPackage()
|
|
873
|
+
}
|
|
699
874
|
continue
|
|
700
875
|
}
|
|
701
876
|
const installed = readGlobalInstalledVersion()
|
|
@@ -716,6 +891,12 @@ async function selfUpdateGlobal(version) {
|
|
|
716
891
|
if (remain <= 0) {
|
|
717
892
|
console.error(chalk.red(`已尝试 ${attempt} 次,仍未装上 ${PKG_NAME}@${version}`))
|
|
718
893
|
if (lastOutput) console.error(chalk.gray(lastOutput))
|
|
894
|
+
if (looksLikeFileLock(lastOutput)) {
|
|
895
|
+
console.error(chalk.yellow(
|
|
896
|
+
'看起来是文件被占(不是 registry 滞后):关掉所有 UI 实例 / 编辑器后重试,\n'
|
|
897
|
+
+ '必要时手动删掉全局包目录再装(注意会短暂失去全局命令)。'
|
|
898
|
+
))
|
|
899
|
+
}
|
|
719
900
|
console.error(chalk.gray(
|
|
720
901
|
'可稍后手动重试:\n'
|
|
721
902
|
+ ` npm install -g ${PKG_NAME}@${version}\n`
|
|
@@ -739,6 +920,9 @@ async function publishToNpm(version) {
|
|
|
739
920
|
console.log(chalk.yellow(
|
|
740
921
|
`[dry-run] 反复探测并安装,直到全局 ${PKG_NAME}@${version} 校验通过(见 selfUpdateGlobal)`
|
|
741
922
|
))
|
|
923
|
+
console.log(chalk.yellow(
|
|
924
|
+
'[dry-run] 安装前先停掉实例注册表里的所有运行实例(见 stopRunningInstances)'
|
|
925
|
+
))
|
|
742
926
|
return
|
|
743
927
|
}
|
|
744
928
|
execSync(`npm publish --registry=${NPM_REGISTRY}`, { stdio: 'inherit' })
|
|
@@ -766,6 +950,7 @@ async function main() {
|
|
|
766
950
|
console.log(chalk.yellow('--dry-run: type-check / vue-tsc / npm run build 仍会真跑(可在失败前中止)'))
|
|
767
951
|
}
|
|
768
952
|
if (SKIP_SELF_UPDATE) console.log(chalk.yellow('--skip-self-update: 发版后不自动 npm install -g'))
|
|
953
|
+
if (KEEP_INSTANCES) console.log(chalk.yellow('--keep-instances: 装全局前不停运行中的实例'))
|
|
769
954
|
if (SKIP_PUSH) console.log(chalk.yellow('--skip-push: 不 push git'))
|
|
770
955
|
|
|
771
956
|
try {
|
|
@@ -777,6 +962,13 @@ async function main() {
|
|
|
777
962
|
await commitChanges(newVersion)
|
|
778
963
|
await publishToNpm(newVersion)
|
|
779
964
|
|
|
965
|
+
if (stoppedInstanceCount > 0) {
|
|
966
|
+
console.log(chalk.yellow(
|
|
967
|
+
`提示:刚才停掉的 ${stoppedInstanceCount} 个实例不会自动恢复,`
|
|
968
|
+
+ '需要时到对应目录重新执行 `g ui`。'
|
|
969
|
+
))
|
|
970
|
+
}
|
|
971
|
+
|
|
780
972
|
console.log(chalk.green('\n🎉 发布完成!'))
|
|
781
973
|
} catch (err) {
|
|
782
974
|
console.error(chalk.red('\n❌ 发布失败:'), err.message || err)
|
package/src/cli/ai/agent.js
CHANGED
|
@@ -252,6 +252,13 @@ ${isWin ? `- 当前是 Windows cmd.exe,以下 Unix 命令**不存在**,用了必
|
|
|
252
252
|
报"不是内部或外部命令" / command not found 时,**不要换写法反复重试**,更不要凭印象编仓库名或目录名。
|
|
253
253
|
直接告诉用户未检测到该 CLI,可在 ZenGitSync 的「远程仓库」页一键安装/登录;
|
|
254
254
|
若只是想回答本项目的问题,退回 \`git remote -v\`
|
|
255
|
+
- 克隆仓库 / 添加远端时**优先用 SSH**(用户偏好,本机已配好密钥,实测走 https 会弹凭据窗口把任务打断):
|
|
256
|
+
· GitHub 用 \`git@github.com:owner/repo.git\`,Gitee 用 \`git@gitee.com:owner/repo.git\`
|
|
257
|
+
· 用户给的是 \`https://...\` 或 \`gh repo clone owner/repo\` 时,先换算成 SSH 地址再执行 ——
|
|
258
|
+
走 https 会弹 Git Credential Manager 让用户输账号密码,任务就停在半路等输入
|
|
259
|
+
· 已有仓库换协议:\`git remote set-url origin <ssh 地址>\`(先 \`git remote -v\` 看当前是什么)
|
|
260
|
+
· 只有 SSH 真的不可用(报 \`Permission denied (publickey)\` / \`Host key verification failed\`)才退回 https,
|
|
261
|
+
并用一句话说明这次走的是 https、配好密钥后可改回;两边都失败就停下来问用户,不要反复重试
|
|
255
262
|
|
|
256
263
|
# 权限(用户已明确授权,无需反复征求同意)
|
|
257
264
|
- 工作目录内:读写文件、执行命令等所有操作直接执行
|
|
@@ -322,6 +329,15 @@ ${isWin ? `- This is Windows cmd.exe. The following Unix commands do NOT exist h
|
|
|
322
329
|
repo or directory names. Tell the user the CLI was not found and point them to ZenGitSync's
|
|
323
330
|
"Remote repositories" page (one-click install / login); if you only need to answer for this project,
|
|
324
331
|
fall back to \`git remote -v\`
|
|
332
|
+
- Cloning a repo or adding a remote: **prefer SSH** (the user's preference — keys are already set up,
|
|
333
|
+
and https has been observed to pop a credential window that stalls the task):
|
|
334
|
+
· GitHub → \`git@github.com:owner/repo.git\`; Gitee → \`git@gitee.com:owner/repo.git\`
|
|
335
|
+
· If the user hands you an \`https://...\` URL (or \`gh repo clone owner/repo\`), convert it to the SSH
|
|
336
|
+
form first — https pops up Git Credential Manager asking for a username/password and blocks the task
|
|
337
|
+
· Switching an existing repo: \`git remote set-url origin <ssh url>\` (check \`git remote -v\` first)
|
|
338
|
+
· Fall back to https only when SSH genuinely fails (\`Permission denied (publickey)\` /
|
|
339
|
+
\`Host key verification failed\`), and say in one line that this one used https and can go back to SSH
|
|
340
|
+
once the key is set up; if both fail, stop and ask the user — do not keep retrying
|
|
325
341
|
|
|
326
342
|
# Permissions (explicitly granted by the user — do not keep asking)
|
|
327
343
|
- Inside the working directory: read/write files and run commands directly
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import"./rolldown-runtime-C0FnF6B9.js";import{$ as e,$r as t,A as n,Dn as r,E as i,En as a,Fn as o,H as s,Jt as c,K as l,Mn as u,Nn as d,On as f,Ot as p,Pr as m,Q as h,Qn as g,Rt as _,Tn as v,Un as y,Vt as b,Wt as x,Xn as S,Yr as C,_r as w,a as T,ar as E,bn as D,cn as O,cr as k,ct as ee,et as te,fr as A,gn as j,i as M,in as N,j as P,kt as F,mt as I,o as L,ot as ne,pt as re,qr as R,sr as z,tr as ie,un as B,wn as V,wt as ae,yn as H,yr as U,zn as W}from"./element-plus-CMSkP_w2.js";import{i as oe,n as G,t as K}from"./vendor-CZnXb2r9.js";import{n as q,t as J}from"./_plugin-vue_export-helper-BdTxl34g.js";import{t as Y}from"./configStore-AQMSazCM.js";A();var X=65536;function Z(e){if(!e||!Array.isArray(e.messages))return[];let t=[],n=e.messages.length;for(let r=0;r<n;r++){let i=e.messages[r];if(i.role!==`system`){if(i.role===`user`){let e=``,n;if(typeof i.content==`string`)e=i.content;else if(Array.isArray(i.content)){e=i.content.filter(e=>e?.type===`text`).map(e=>e.text||``).join(` `);let t=i.content.filter(e=>e?.type===`image_url`&&typeof e.image_url?.url==`string`).map((e,t)=>({id:`att-${r}-${t}`,name:`image`,size:0,type:$(e.image_url?.url||``)||`image/*`,preview:e.image_url?.url}));t.length>0&&(n=t)}(e||n)&&t.push({id:`msg-${r}`,role:`user`,content:e,attachments:n,status:`done`,createdAt:Date.now()})}else if(i.role===`assistant`){let a=``;typeof i.content==`string`&&(a=i.content),a.length>X&&(a=`…(前文已截断)\n${a.slice(-65536)}`);let o=[];if(i.tool_calls&&i.tool_calls.length>0)for(let e of i.tool_calls)o.push({id:e.id||e.function?.name||K(),name:e.function?.name||``,arguments:e.function?.arguments||``,argsPreview:Q(e.function?.name||``,e.function?.arguments||``),status:`done`,result:``});let s=r+1;for(;s<n&&e.messages[s].role===`tool`;){let t=e.messages[s],n=t.tool_call_id||t.name||``,i=o.find(e=>e.id===n);if(i){let e=t.content;typeof e!=`string`&&(e=`(non-text result)`),e.length>X&&(e=`…(前文已截断)\n${e.slice(-65536)}`),i.result=e}r=s,s++}let c=!!a,l=o.length>0;(c||l)&&t.push({id:`msg-${r}`,role:`assistant`,content:a||``,toolCalls:l?o:void 0,status:`done`,createdAt:Date.now()})}}}return t}function Q(e,t){try{let n=JSON.parse(t);switch(e){case`run_command`:return String(n.command||``).slice(0,200);case`read_file`:case`write_file`:case`edit_file`:return String(n.path||``);case`list_files`:return String(n.path||`.`);case`search_text`:return String(n.pattern||``);default:return JSON.stringify(n).slice(0,200)}}catch{return t.slice(0,200)}}function se(e){return new Promise((t,n)=>{let r=new FileReader;r.onload=()=>t(String(r.result||``)),r.onerror=()=>n(r.error||Error(`FileReader failed`)),r.readAsDataURL(e)})}function $(e){let t=/^data:([^;,]+)/.exec(e);return t?t[1]:``}function ce(){let e=Y(),t=U([]),n=U(!1),r=U(null),i=U([]),a=U(!1),o=U(!1),s=U(null),c=U(!1),l=null,u=0,d=0;async function f(){let r=++d,i=e.currentDirectory||``;if(!i){t.value=[],n.value=!1;return}n.value=!0;try{let e=`/api/agent/sessions?cwd=${encodeURIComponent(i)}`,n=await fetch(e).then(e=>e.json());if(r!==d)return;if(!n.success){T.error(n.error||q(`@AGENT:加载会话列表失败`));return}t.value=Array.isArray(n.sessions)?n.sessions:[]}catch(e){if(r!==d)return;T.error(q(`@AGENT:加载会话列表失败`)+`: `+(e?.message||e))}finally{r===d&&(n.value=!1)}}function p(n,r){let i=new Date().toISOString(),a=t.value.find(e=>e.sessionId===n);if(a){a.isGenerating=!0,a.updatedAt=i;return}t.value=[{sessionId:n,title:r,source:`web`,cwd:e.currentDirectory||``,model:``,createdAt:i,updatedAt:i,messageCount:1,size:0,isGenerating:!0},...t.value]}function m(e){let n=t.value.find(t=>t.sessionId===e);n&&(n.isGenerating=!1)}async function h(e){o.value=!0,r.value=e;try{let t=await fetch(`/api/agent/sessions/${encodeURIComponent(e)}`).then(e=>e.json());if(!t.success){T.error(t.error||q(`@AGENT:加载会话失败`));return}i.value=Z(t.session)}catch(e){T.error(q(`@AGENT:加载会话失败`)+`: `+(e?.message||e))}finally{o.value=!1}}async function g(e){try{await M.confirm(q(`@AGENT:确认删除该会话`),q(`@AGENT:删除后无法恢复`),{type:`warning`})}catch{return}try{let n=await fetch(`/api/agent/sessions/${encodeURIComponent(e)}`,{method:`DELETE`}).then(e=>e.json());if(!n.success){T.error(n.error||q(`@AGENT:删除失败`));return}t.value=t.value.filter(t=>t.sessionId!==e),r.value===e&&(r.value=null,i.value=[]),T.success(q(`@AGENT:已删除`))}catch(e){T.error(q(`@AGENT:删除失败`)+`: `+(e?.message||e))}}async function _(e,n){try{let r=await fetch(`/api/agent/sessions/${encodeURIComponent(e)}`,{method:`PUT`,headers:{"Content-Type":`application/json`},body:JSON.stringify({title:n})}).then(e=>e.json());if(!r.success){T.error(r.error||q(`@AGENT:重命名失败`));return}let i=t.value.find(t=>t.sessionId===e);i&&(i.title=n),T.success(q(`@AGENT:已重命名`))}catch(e){T.error(q(`@AGENT:重命名失败`)+`: `+(e?.message||e))}}function v(){r.value=null,i.value=[],s.value=null,t.value=t.value.filter(e=>!e.isGenerating)}async function y(t,n=[]){let o=n.filter(e=>e?.file?.type?.startsWith(`image/`));if(o.length<n.length&&T.warning(q(`@AGENT:仅支持发送图片,非图片文件已忽略`)),!t.trim()&&o.length===0||a.value)return;let d=(await Promise.allSettled(o.map(e=>se(e.file)))).map(e=>e.status===`fulfilled`?e.value:``).filter(e=>e.startsWith(`data:image/`)),h=++u;l=new AbortController;let g=l,_={id:K(),role:`user`,content:t,status:`done`,createdAt:Date.now()};o.length>0&&(_.attachments=o.map(e=>({id:e.id,name:e.file.name||`image`,size:e.file.size||0,type:e.file.type||``,preview:e.preview}))),i.value.push(_);let v=w({id:K(),role:`assistant`,content:``,status:`pending`,createdAt:Date.now()});i.value.push(v),a.value=!0;let y=[],b=null;try{let n=await fetch(`/api/agent/chat`,{method:`POST`,headers:{"Content-Type":`application/json`,Accept:`text/event-stream`},body:JSON.stringify({sessionId:r.value||``,userMessage:t,cwd:e.currentDirectory||``,...d.length>0?{images:d}:{}}),signal:g.signal});if(h!==u)return;if(!n.ok||!n.body){let e=await n.text().catch(()=>``);throw Error(e||`HTTP ${n.status}`)}let a=n.body.getReader(),o=new TextDecoder(`utf-8`),c=``,l=r.value;for(;;){let{value:e,done:n}=await a.read();if(h!==u)return;if(n)break;c+=o.decode(e,{stream:!0});let d=c.split(`
|
|
2
|
+
`);c=d.pop()??``;for(let e of d){let n=e.trim();if(!n.startsWith(`data:`))continue;let i=n.slice(5).trim();if(!i)continue;let a;try{a=JSON.parse(i)}catch{continue}switch(a.type){case`meta`:if(a.sessionId){l=a.sessionId,b=a.sessionId,r.value=a.sessionId;let e=String(a.title||``).trim()||t.trim().split(`
|
|
3
|
+
`)[0].trim().slice(0,40)||q(`@AGENT:无标题`);p(a.sessionId,e)}break;case`thinking`:v.reasoning||(v.reasoning=``,v.reasoningStatus=`streaming`),v.reasoning+=String(a.delta||``),v.status=`streaming`;break;case`content`:v.status===`pending`&&(v.status=`streaming`);{let e=String(a.delta||``);v.content+=e;let t=G(v.content);t.reasoning&&(v.reasoning||(v.reasoning=``,v.reasoningStatus=`streaming`),v.reasoning=t.reasoning,v.content=t.content)}break;case`tool_call_start`:{let e=w({id:a.toolCallId||K(),name:a.name||``,argsPreview:a.argsPreview||``,arguments:a.argsPreview||``,status:`running`,result:``});y.push(e),v.toolCalls||=[],v.toolCalls.push(e),v.status===`pending`&&(v.status=`streaming`);break}case`tool_result`:{let e=y.find(e=>e.id===a.toolCallId);e&&(e.result=String(a.result||``),e.status=`done`,e.name===`ask_user`&&(s.value=null));break}case`ask_user`:s.value={interactionId:String(a.interactionId||``),question:String(a.question||``),options:Array.isArray(a.options)?a.options.map(e=>String(e)):[],allowFreeText:a.allowFreeText!==!1};break;case`done`:{let e=a.content||v.content,t=G(e);t.reasoning&&!v.reasoning&&(v.reasoning=t.reasoning),v.content=t.content,v.status=`done`,v.reasoningStatus===`streaming`&&(v.reasoningStatus=`done`);break}case`error`:v.status=`error`,v.error=String(a.error||q(`@AGENT:未知错误`)),v.reasoningStatus===`streaming`&&(v.reasoningStatus=`done`)}}i.value=[...i.value]}if(h!==u)return;v.status===`pending`&&(v.status=`done`),l&&l!==r.value&&(r.value=l),f().catch(()=>{})}catch(e){if(h!==u)return;e?.name===`AbortError`||g.signal.aborted?(v.content=(v.content||``)+`
|
|
4
|
+
|
|
5
|
+
[`+q(`@AGENT:已停止`)+`]`,v.status=`done`,v.reasoningStatus===`streaming`&&(v.reasoningStatus=`done`)):(v.status=`error`,v.error=e?.message||String(e),T.error(v.error||q(`@AGENT:对话失败`)))}finally{h===u&&(a.value=!1,s.value=null,c.value=!1,l=null,b&&m(b))}}async function b(e){let t=s.value,n=r.value,i=String(e||``).trim();if(!t||!n||!i||c.value)return!1;c.value=!0;try{let e=await fetch(`/api/agent/respond`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({sessionId:n,interactionId:t.interactionId,answer:i})}).then(e=>e.json());if(!e.success)throw Error(e.error||q(`@AGENT:回答提交失败`));return s.value=null,!0}catch(e){return T.error(e?.message||q(`@AGENT:回答提交失败`)),!1}finally{c.value=!1}}function x(){l&&=(l.abort(),null)}return{sessions:t,sessionsLoading:n,currentSessionId:r,messages:i,isStreaming:a,sessionLoading:o,pendingQuestion:s,answeringQuestion:c,loadSessions:f,loadSession:h,deleteSession:g,renameSession:_,newSession:v,sendMessage:y,answerQuestion:b,stop:x}}W(),A();var le=o({__name:`MarketplacePanel`,props:{type:{type:String,required:!0}},setup(e,{expose:t}){t();let n=e,r=Y(),i=U([]),a=U([]),o=U(!1),s=U(``),l=U(``),u=U([]),d=U(`project`),f=U(new Set),m=U(new Set),h=V(()=>r.currentDirectory||``),g=null;async function _(){if(!o.value){o.value=!0;try{let e=new URLSearchParams({type:n.type,cwd:h.value});l.value&&e.set(`q`,l.value),u.value.length&&e.set(`sources`,u.value.join(`,`));let t=await(await fetch(`/api/agent/marketplace/catalog?${e}`)).json();t?.success?(i.value=t.groups||[],a.value=t.installed||[]):T.error(t?.error||q(`@MKT:加载失败`))}catch{T.error(q(`@MKT:加载失败`))}finally{o.value=!1}}}E(s,e=>{g&&clearTimeout(g),g=setTimeout(()=>{l.value=e.trim(),_()},400)}),E(u,()=>_()),E(()=>n.type,()=>{u.value=[],l.value=``,s.value=``,_()}),E(h,()=>_()),_();let v=V(()=>{let e=h.value?h.value.split(/[\\/]/).filter(Boolean).pop():``;return d.value===`project`?e||q(`@MKT:当前项目`):q(`@MKT:g ai 智能体`)});function y(e){return e.stars?`${S(e.stars)} ★`:e.downloads?`${S(e.downloads)} ${q(`@MKT:周下载`)}`:e.uses?`${S(e.uses)} ${q(`@MKT:次使用`)}`:``}function S(e){return e>=1e3?`${(e/1e3).toFixed(e>=1e4?0:1)}k`:String(e)}function C(e){return`${e.id}`}function D(e){return f.value.has(C(e))}let O=V(()=>{let e={project:[],global:[]};for(let t of a.value)(e[t.target]||=[]).push(t);return e}),k=w({visible:!1,item:null,env:{},args:``});function A(e){return n.type===`mcp`&&(!!e.envKeys?.length||!!e.args?.length)}function j(e){k.item=e,k.env=Object.fromEntries((e.envKeys||[]).map(e=>[e,``])),k.args=(e.args||[]).join(` `),k.visible=!0}function P(){let e=k.item;if(k.visible=!1,!e)return;let t=Object.fromEntries(Object.entries(k.env).filter(([,e])=>e.trim()!==``)),n=k.args.trim()?k.args.trim().match(/(?:[^\s"]+|"[^"]*")+/g)?.map(e=>e.replace(/^"|"$/g,``))??void 0:void 0;I(e,{env:t,...n?{args:n}:{}})}async function F(e){if(!e.installed||await L(e)){if(A(e)){j(e);return}await I(e,{})}}async function I(e,t){let r=C(e);f.value.add(r);try{let r=await fetch(`/api/agent/marketplace/install`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({type:n.type,target:d.value,cwd:h.value,item:{...e,...t}})}),i=await r.json().catch(()=>null);if(!r.ok||!i?.success){T.error(i?.error||q(`@MKT:安装失败`));return}i.item?.warning&&T.warning(i.item.warning),i.item?.envKeys?.length?T.warning(`${q(`@MKT:还缺环境变量`)}: ${i.item.envKeys.join(`, `)}`):T.success(q(`@MKT:安装成功`)),await _()}catch{T.error(q(`@MKT:安装失败`))}finally{f.value.delete(r)}}async function L(e){try{return await M.confirm(`${e.name} ${q(`@MKT:已安装,要重新安装吗?`)}`,q(`@MKT:重新安装`),{confirmButtonText:q(`@MKT:重装`),cancelButtonText:q(`@MKT:取消`),type:`warning`}),!0}catch{return!1}}async function ne(e){try{await M.confirm(`${q(`@MKT:确定卸载`)} ${e.name}?`,q(`@MKT:卸载`),{confirmButtonText:q(`@MKT:卸载`),cancelButtonText:q(`@MKT:取消`),type:`warning`})}catch{return}let t=`${e.target}:${e.id}`;m.value.add(t);try{let t=new URLSearchParams({target:e.target,cwd:h.value}),r=await fetch(`/api/agent/marketplace/item/${n.type}/${encodeURIComponent(e.id)}?${t}`,{method:`DELETE`}),i=await r.json().catch(()=>null);if(!r.ok||!i?.success){T.error(i?.error||q(`@MKT:卸载失败`));return}T.success(q(`@MKT:已卸载`)),await _()}catch{T.error(q(`@MKT:卸载失败`))}finally{m.value.delete(t)}}let R={props:n,configStore:r,groups:i,installed:a,loading:o,searchInput:s,query:l,selectedSources:u,installTarget:d,installing:f,removing:m,cwd:h,get searchTimer(){return g},set searchTimer(e){g=e},loadCatalog:_,targetLabel:v,metricText:y,formatCount:S,cardKey:C,isBusy:D,installedByTarget:O,configDialog:k,needsConfig:A,openConfigDialog:j,confirmConfig:P,onInstall:F,doInstall:I,confirmReinstall:L,onRemove:ne,get $t(){return q},get Search(){return x},get Refresh(){return b},get Delete(){return ee},get Link(){return p},get Check(){return te},get Star(){return c},get Download(){return re},get Warning(){return N}};return Object.defineProperty(R,"__isScriptSetup",{enumerable:!1,value:!0}),R}});W(),B(),m();var ue={class:`marketplace-panel`},de={class:`mp-toolbar`},fe={class:`mp-search`},pe=[`placeholder`],me={class:`mp-toolbar-sub`},he={class:`mp-target-hint`},ge={class:`mp-source-filter`},_e=[`onClick`],ve={class:`mp-body`},ye={class:`mp-group-header`},be={class:`mp-group-title`},xe={key:0,class:`mp-group-count`},Se={key:1,class:`mp-group-error`},Ce=[`href`,`title`],we={key:0,class:`mp-grid`},Te={class:`mp-card-head`},Ee=[`title`],De={key:0,class:`mp-card-metric`},Oe=[`title`],ke={class:`mp-card-meta`},Ae=[`title`],je=[`title`],Me={key:2,class:`mp-tag remote`},Ne={class:`mp-card-foot`},Pe=[`href`],Fe={key:1,class:`mp-installed-chip`},Ie=[`disabled`,`onClick`],Le={key:3,class:`mp-not-installable`},Re={key:1,class:`mp-empty`},ze={key:0,class:`mp-group installed`},Be={class:`mp-group-header`},Ve={class:`mp-group-title`},He={class:`mp-group-count`},Ue={key:0,class:`mp-installed-block`},We={class:`mp-installed-target`},Ge={class:`mp-installed-list`},Ke={class:`mp-installed-name`},qe={key:0,class:`mp-meta-pkg`},Je={key:1,class:`mp-tag warn`},Ye=[`disabled`,`onClick`],Xe={key:1,class:`mp-empty all`},Ze={key:0,class:`mkt-form`},Qe={class:`mkt-form-name`},$e=[`onUpdate:modelValue`,`placeholder`],et={key:0,class:`mkt-field`},tt={class:`mkt-hint`};function nt(e,o,c,p,m,h){let _=l,y=n,b=P,x=s,C=i,w=L;return S(),f(`div`,ue,[r(` ── 工具栏 ───────────────────────────────── `),v(`div`,de,[v(`div`,fe,[d(_,{class:`mp-search-icon`},{default:z(()=>[d(p.Search)]),_:1}),k(v(`input`,{"onUpdate:modelValue":o[0]||=e=>p.searchInput=e,class:`mp-search-input`,type:`text`,placeholder:c.type===`skill`?p.$t(`@MKT:搜索 Skill...`):p.$t(`@MKT:搜索 MCP 服务...`)},null,8,pe),[[j,p.searchInput]])]),d(b,{modelValue:p.installTarget,"onUpdate:modelValue":o[1]||=e=>p.installTarget=e,size:`small`,class:`mp-target`},{default:z(()=>[d(y,{value:`project`},{default:z(()=>[u(t(p.$t(`@MKT:当前项目`)),1)]),_:1}),d(y,{value:`global`},{default:z(()=>[u(t(p.$t(`@MKT:g ai 智能体`)),1)]),_:1})]),_:1},8,[`modelValue`]),d(x,{content:p.$t(`@MKT:刷新`),placement:`top`,"show-after":300},{default:z(()=>[v(`button`,{class:R([`mp-refresh`,{spinning:p.loading}]),onClick:p.loadCatalog},[d(_,null,{default:z(()=>[d(p.Refresh)]),_:1})],2)]),_:1},8,[`content`])]),v(`div`,me,[v(`span`,he,[u(t(p.$t(`@MKT:安装到`))+` `,1),v(`b`,null,t(p.targetLabel),1)]),v(`div`,ge,[(S(!0),f(D,null,g(p.groups,e=>(S(),f(`button`,{key:e.id,class:R([`mp-chip`,{active:p.selectedSources.includes(e.id)}]),onClick:()=>{let t=p.selectedSources.indexOf(e.id);t>=0?p.selectedSources.splice(t,1):p.selectedSources.push(e.id)}},t(e.label),11,_e))),128)),p.selectedSources.length?(S(),f(`button`,{key:0,class:`mp-chip clear`,onClick:o[2]||=e=>p.selectedSources=[]},t(p.$t(`@MKT:全部来源`)),1)):r(`v-if`,!0)])]),r(` ── 内容 ─────────────────────────────────── `),k((S(),f(`div`,ve,[(S(!0),f(D,null,g(p.groups,e=>(S(),f(`section`,{key:e.id,class:`mp-group`},[v(`header`,ye,[v(`h3`,be,t(e.label),1),e.status===`ok`?(S(),f(`span`,xe,t(e.items.length),1)):(S(),f(`span`,Se,[d(_,null,{default:z(()=>[d(p.Warning)]),_:1}),u(` `+t(e.error||p.$t(`@MKT:来源不可用`)),1)])),e.homepage?(S(),f(`a`,{key:2,class:`mp-group-link`,href:e.homepage,target:`_blank`,rel:`noopener noreferrer`,title:e.homepage},[d(_,null,{default:z(()=>[d(p.Link)]),_:1})],8,Ce)):r(`v-if`,!0)]),e.status===`ok`&&e.items.length?(S(),f(`div`,we,[(S(!0),f(D,null,g(e.items,e=>(S(),f(`article`,{key:p.cardKey(e),class:`mp-card`},[v(`div`,Te,[v(`span`,{class:`mp-card-name`,title:e.name},t(e.name),9,Ee),p.metricText(e)?(S(),f(`span`,De,[d(_,null,{default:z(()=>[e.stars?(S(),a(p.Star,{key:0})):(S(),a(p.Download,{key:1}))]),_:2},1024),u(` `+t(p.metricText(e)),1)])):r(`v-if`,!0)]),v(`p`,{class:`mp-card-desc`,title:e.description},t(e.description||p.$t(`@MKT:暂无描述`)),9,Oe),v(`div`,ke,[e.package?(S(),f(`code`,{key:0,class:`mp-meta-pkg`,title:e.package},t(e.package),9,Ae)):e.repository?(S(),f(`span`,{key:1,class:`mp-meta-repo`,title:e.repository+(e.subpath?` · `+e.subpath:``)},[u(t(e.repository),1),e.subpath?(S(),f(D,{key:0},[u(` · `+t(e.subpath),1)],64)):r(`v-if`,!0)],8,je)):r(`v-if`,!0),e.transport===`remote`?(S(),f(`span`,Me,t(p.$t(`@MKT:远程服务`)),1)):r(`v-if`,!0),(S(!0),f(D,null,g((e.tags||[]).slice(0,2),e=>(S(),f(`span`,{key:e,class:`mp-tag`},t(e),1))),128))]),v(`div`,Ne,[e.upstream?(S(),f(`a`,{key:0,class:`mp-card-link`,href:e.upstream,target:`_blank`,rel:`noopener noreferrer`},t(p.$t(`@MKT:查看来源`)),9,Pe)):r(`v-if`,!0),o[6]||=v(`span`,{class:`mp-foot-spacer`},null,-1),e.installed?(S(),f(`span`,Fe,[d(_,null,{default:z(()=>[d(p.Check)]),_:1}),u(t(p.$t(`@MKT:已安装`)),1)])):e.installable===!1?(S(),f(`span`,Le,t(p.$t(`@MKT:暂不支持一键安装`)),1)):(S(),f(`button`,{key:2,class:`mp-install-btn`,disabled:p.isBusy(e),onClick:t=>p.onInstall(e)},t(p.isBusy(e)?p.$t(`@MKT:安装中...`):p.$t(`@MKT:安装`)),9,Ie))])]))),128))])):e.status===`ok`?(S(),f(`div`,Re,t(p.$t(`@MKT:该来源暂无结果`)),1)):r(`v-if`,!0)]))),128)),r(` ── 已安装 ─────────────────────────────── `),p.installed.length?(S(),f(`section`,ze,[v(`header`,Be,[v(`h3`,Ve,t(p.$t(`@MKT:已安装`)),1),v(`span`,He,t(p.installed.length),1)]),(S(),f(D,null,g([`project`,`global`],e=>v(`div`,{key:e},[p.installedByTarget[e]?.length?(S(),f(`div`,Ue,[v(`div`,We,t(e===`project`?p.$t(`@MKT:当前项目`):p.$t(`@MKT:g ai 智能体`)),1),v(`div`,Ge,[(S(!0),f(D,null,g(p.installedByTarget[e],n=>(S(),f(`div`,{key:e+n.id,class:`mp-installed-row`},[v(`span`,Ke,t(n.name),1),n.package?(S(),f(`code`,qe,t(n.package),1)):r(`v-if`,!0),n.requiredEnv?.length?(S(),f(`span`,Je,t(p.$t(`@MKT:待配置`))+`: `+t(n.requiredEnv.join(`, `)),1)):r(`v-if`,!0),o[7]||=v(`span`,{class:`mp-foot-spacer`},null,-1),v(`button`,{class:`mp-remove-btn`,disabled:p.removing.has(e+n.id),onClick:e=>p.onRemove(n)},[d(_,null,{default:z(()=>[d(p.Delete)]),_:1}),u(` `+t(p.removing.has(e+n.id)?p.$t(`@MKT:卸载中...`):p.$t(`@MKT:卸载`)),1)],8,Ye)]))),128))])])):r(`v-if`,!0)])),64))])):r(`v-if`,!0),!p.loading&&!p.groups.length?(S(),f(`div`,Xe,t(p.$t(`@MKT:加载失败`)),1)):r(`v-if`,!0)])),[[w,p.loading]]),r(` ── MCP 安装前配置 ───────────────────────── `),d(C,{modelValue:p.configDialog.visible,"onUpdate:modelValue":o[5]||=e=>p.configDialog.visible=e,title:p.$t(`@MKT:配置 MCP`),width:`460px`,"close-on-click-modal":!1,"append-to-body":``},{footer:z(()=>[v(`button`,{class:`mkt-cancel`,onClick:o[4]||=e=>p.configDialog.visible=!1},t(p.$t(`@MKT:取消`)),1),v(`button`,{class:`mkt-confirm`,onClick:p.confirmConfig},t(p.$t(`@MKT:安装`)),1)]),default:z(()=>[p.configDialog.item?(S(),f(`div`,Ze,[v(`p`,Qe,t(p.configDialog.item.name),1),(S(!0),f(D,null,g(Object.keys(p.configDialog.env),e=>(S(),f(`div`,{key:e,class:`mkt-field`},[v(`label`,null,t(e),1),k(v(`input`,{"onUpdate:modelValue":t=>p.configDialog.env[e]=t,type:`text`,autocomplete:`off`,placeholder:p.$t(`@MKT:环境变量值`),spellcheck:`false`},null,8,$e),[[j,p.configDialog.env[e]]])]))),128)),p.configDialog.item.args?.length?(S(),f(`div`,et,[v(`label`,null,t(p.$t(`@MKT:启动参数`)),1),k(v(`input`,{"onUpdate:modelValue":o[3]||=e=>p.configDialog.args=e,type:`text`,autocomplete:`off`,spellcheck:`false`},null,512),[[j,p.configDialog.args]]),v(`p`,tt,t(p.$t(`@MKT:参数提示`)),1)])):r(`v-if`,!0)])):r(`v-if`,!0)]),_:1},8,[`modelValue`,`title`])])}var rt=J(le,[[`render`,nt],[`__scopeId`,`data-v-e9f9e851`],[`__file`,`C:/workspace/github_workspace/xz333221/zen-gitsync/src/ui/client/src/components/MarketplacePanel.vue`]]);W(),A();var it=o({__name:`AgentView`,setup(t,{expose:n}){n();let r=Y(),i=U(`chat`),a=V(()=>i.value===`mcp`?`mcp`:`skill`),o=V(()=>[{id:`chat`,label:q(`@AGENT:对话`),icon:h},{id:`skill`,label:q(`@AGENT:Skill 广场`),icon:ae},{id:`mcp`,label:q(`@AGENT:MCP 广场`),icon:ne}]),{sessions:c,sessionsLoading:u,currentSessionId:d,messages:f,isStreaming:p,sessionLoading:m,loadSessions:g,loadSession:v,deleteSession:b,renameSession:S,newSession:C,sendMessage:w,pendingQuestion:D,answeringQuestion:O,answerQuestion:k,stop:A}=ce(),j=V(()=>{let e=r.theme;return e===`dark`||e===`auto`&&window.matchMedia(`(prefers-color-scheme: dark)`).matches?`dark`:`light`}),N=U(``),P=V(()=>{if(!N.value.trim())return c.value;let e=N.value.toLowerCase();return c.value.filter(t=>(t.title||``).toLowerCase().includes(e)||(t.model||``).toLowerCase().includes(e))}),L=V(()=>[{id:`p1`,label:q(`@AGENT:查看项目结构`),prompt:q(`@AGENT:prompt_p1`)},{id:`p2`,label:q(`@AGENT:分析代码质量`),prompt:q(`@AGENT:prompt_p2`)},{id:`p3`,label:q(`@AGENT:帮我写测试`),prompt:q(`@AGENT:prompt_p3`)},{id:`p4`,label:q(`@AGENT:Git 状态检查`),prompt:q(`@AGENT:prompt_p4`)},{id:`p5`,label:q(`@AGENT:帮我启动项目`),prompt:q(`@AGENT:prompt_p5`)}]);async function re(e){await w(e.text,e.files),await y(),H()}async function R(e){await w(e.prompt),await y(),H()}let z=U(``);async function ie(e=z.value){await k(e)&&(z.value=``)}let B=U(null);function H(e=!0){B.value?.scrollToBottom(e)}E(()=>f.value.length,()=>{y(()=>H(!1))});function W(e){if(p.value){T.warning(q(`@AGENT:请先停止当前生成`));return}v(e)}function G(){if(p.value){T.warning(q(`@AGENT:请先停止当前生成`));return}C()}function K(e,t){if(t.stopPropagation(),p.value&&d.value===e){T.warning(q(`@AGENT:请先停止当前生成`));return}b(e)}async function J(e,t,n){n.stopPropagation();try{let{value:n}=await M.prompt(q(`@AGENT:请输入新的会话标题`),q(`@AGENT:重命名会话`),{inputValue:t,inputPattern:/.+/,inputErrorMessage:q(`@AGENT:标题不能为空`)});n&&n!==t&&await S(e,n)}catch{}}function X(e){if(!e)return``;try{let t=new Date(e);if(Number.isNaN(t.getTime()))return e;let n=new Date,r=n.getTime()-t.getTime(),i=e=>String(e).padStart(2,`0`);if(t.toDateString()===n.toDateString())return`${i(t.getHours())}:${i(t.getMinutes())}`;if(r<6048e5){let e=Math.floor(r/864e5);return e===0?q(`@AGENT:今天`):`${e}${q(`@AGENT:天前`)}`}return`${t.getFullYear()}-${i(t.getMonth()+1)}-${i(t.getDate())}`}catch{return e}}let Z=U(280),Q=U(!1);function se(e){Q.value=!0;let t=e.clientX,n=Z.value,r=e=>{let r=e.clientX-t,i=Math.max(200,Math.min(500,n+r));Z.value=i},i=()=>{Q.value=!1,document.removeEventListener(`mousemove`,r),document.removeEventListener(`mouseup`,i)};document.addEventListener(`mousemove`,r),document.addEventListener(`mouseup`,i)}E(()=>[r.currentDirectory,p.value],async([e,t],n)=>{let r=!n||e!==n[0],i=!!n&&n[1]===!0&&!t;(r||i)&&await g(),d.value&&!p.value&&!c.value.some(e=>e.sessionId===d.value)&&C()},{immediate:!0});let $={configStore:r,activeTab:i,marketplaceType:a,tabs:o,sessions:c,sessionsLoading:u,currentSessionId:d,messages:f,isStreaming:p,sessionLoading:m,loadSessions:g,loadSession:v,deleteSession:b,renameSession:S,newSession:C,sendMessage:w,pendingQuestion:D,answeringQuestion:O,answerQuestion:k,stop:A,chatTheme:j,searchQuery:N,filteredSessions:P,presetQuestions:L,onSend:re,onSelectPreset:R,pendingAnswer:z,submitPendingAnswer:ie,chatContainerRef:B,scrollToBottom:H,selectSession:W,handleNewSession:G,handleDelete:K,handleRename:J,formatDate:X,sidebarWidth:Z,isResizing:Q,startResize:se,get $t(){return q},get ElTooltip(){return s},get ElIcon(){return l},get Plus(){return _},get Search(){return x},get Delete(){return ee},get Edit(){return I},get ChatLineRound(){return e},get Loading(){return F},get Check(){return te},get ChatContainer(){return oe},MarketplacePanel:rt};return Object.defineProperty($,"__isScriptSetup",{enumerable:!1,value:!0}),$}});W(),m(),B();var at={class:`agent-view`},ot={class:`sidebar-header`},st={class:`sidebar-search`},ct=[`placeholder`],lt={class:`session-list`},ut={key:0,class:`empty-state`},dt={class:`empty-text`},ft={key:0,class:`empty-hint`},pt=[`onClick`],mt={class:`session-item-main`},ht={class:`session-item-title`},gt={class:`session-item-meta`},_t={key:0,class:`meta-generating`},vt={class:`meta-time`},yt={class:`meta-count`},bt={key:2,class:`meta-source cli`},xt=[`onClick`],St=[`onClick`],Ct={class:`agent-chat-area`},wt={class:`agent-tabs`,role:`tablist`},Tt=[`aria-selected`,`onClick`],Et={class:`agent-tab-body`},Dt={key:0,class:`agent-chat-pane`},Ot={key:0,class:`chat-loading`},kt={key:0,class:`ask-user-panel`,"aria-live":`polite`},At={class:`ask-user-title`},jt={class:`ask-user-question`},Mt={key:0,class:`ask-user-options`},Nt=[`disabled`,`onClick`],Pt=[`disabled`,`placeholder`,`aria-label`],Ft=[`disabled`],It={key:0,class:`stop-button-bar`};function Lt(e,n,i,o,s,c){let l=L;return S(),f(`div`,at,[r(` ═══ 左侧:会话列表(只在「对话」Tab 显示)═══ `),o.activeTab===`chat`?(S(),f(D,{key:0},[v(`aside`,{class:`agent-sidebar`,style:C({width:o.sidebarWidth+`px`})},[r(` 顶部操作栏 `),v(`div`,ot,[v(`button`,{class:`new-session-btn`,onClick:o.handleNewSession},[d(o.ElIcon,null,{default:z(()=>[d(o.Plus)]),_:1}),v(`span`,null,t(o.$t(`@AGENT:新建会话`)),1)])]),r(` 搜索框 `),v(`div`,st,[d(o.ElIcon,{class:`search-icon`},{default:z(()=>[d(o.Search)]),_:1}),k(v(`input`,{"onUpdate:modelValue":n[0]||=e=>o.searchQuery=e,placeholder:o.$t(`@AGENT:搜索会话...`),class:`search-input`,type:`text`},null,8,ct),[[j,o.searchQuery]])]),r(` 会话列表 `),k((S(),f(`div`,lt,[o.filteredSessions.length===0&&!o.sessionsLoading?(S(),f(`div`,ut,[d(o.ElIcon,{size:28,color:`var(--text-tertiary)`},{default:z(()=>[d(o.ChatLineRound)]),_:1}),v(`div`,dt,t(o.searchQuery?o.$t(`@AGENT:未找到匹配的会话`):o.$t(`@AGENT:暂无会话`)),1),o.searchQuery?r(`v-if`,!0):(S(),f(`div`,ft,t(o.$t(`@AGENT:点击上方按钮开始对话`)),1))])):r(`v-if`,!0),(S(!0),f(D,null,g(o.filteredSessions,e=>(S(),f(`div`,{key:e.sessionId,class:R([`session-item`,{active:o.currentSessionId===e.sessionId}]),onClick:t=>o.selectSession(e.sessionId)},[v(`div`,mt,[v(`div`,ht,t(e.title||o.$t(`@AGENT:无标题`)),1),v(`div`,gt,[e.isGenerating?(S(),f(`span`,_t,[d(o.ElIcon,{class:`is-loading`},{default:z(()=>[d(o.Loading)]),_:1}),u(` `+t(o.$t(`@AGENT:正在生成中...`)),1)])):(S(),f(D,{key:1},[v(`span`,vt,t(o.formatDate(e.updatedAt)),1),n[5]||=v(`span`,{class:`meta-dot`},`·`,-1),v(`span`,yt,t(e.messageCount)+` `+t(o.$t(`@AGENT:条`)),1)],64)),e.source===`cli`?(S(),f(`span`,bt,`CLI`)):r(`v-if`,!0)])]),v(`div`,{class:`session-item-actions`,onClick:n[1]||=H(()=>{},[`stop`])},[d(o.ElTooltip,{content:o.$t(`@AGENT:重命名`),placement:`top`,"show-after":500},{default:z(()=>[v(`button`,{class:`item-action-btn`,onClick:t=>o.handleRename(e.sessionId,e.title,t)},[d(o.ElIcon,null,{default:z(()=>[d(o.Edit)]),_:1})],8,xt)]),_:2},1032,[`content`]),d(o.ElTooltip,{content:o.$t(`@AGENT:删除`),placement:`top`,"show-after":500},{default:z(()=>[v(`button`,{class:`item-action-btn danger`,onClick:t=>o.handleDelete(e.sessionId,t)},[d(o.ElIcon,null,{default:z(()=>[d(o.Delete)]),_:1})],8,St)]),_:2},1032,[`content`])])],10,pt))),128))])),[[l,o.sessionsLoading]])],4),r(` 拖拽分隔条 `),v(`div`,{class:R([`sidebar-resizer`,{active:o.isResizing}]),onMousedown:o.startResize},null,34)],64)):r(`v-if`,!0),r(` ═══ 右侧:Tab 栏 + 内容区 ═══ `),v(`main`,Ct,[v(`nav`,wt,[(S(!0),f(D,null,g(o.tabs,e=>(S(),f(`button`,{key:e.id,type:`button`,class:R([`agent-tab`,{active:o.activeTab===e.id}]),role:`tab`,"aria-selected":o.activeTab===e.id,onClick:t=>o.activeTab=e.id},[d(o.ElIcon,null,{default:z(()=>[(S(),a(ie(e.icon)))]),_:2},1024),v(`span`,null,t(e.label),1)],10,Tt))),128))]),v(`div`,Et,[r(` ── 对话 ── `),o.activeTab===`chat`?(S(),f(`div`,Dt,[r(` 加载中 `),o.sessionLoading?(S(),f(`div`,Ot,[d(o.ElIcon,{class:`is-loading`,size:32},{default:z(()=>[d(o.Loading)]),_:1}),v(`span`,null,t(o.$t(`@AGENT:加载会话中...`)),1)])):(S(),f(D,{key:1},[r(` ChatContainer `),d(o.ChatContainer,{ref:`chatContainerRef`,messages:o.messages,"preset-questions":o.presetQuestions,"welcome-title":o.$t(`@AGENT:智能体助手`),"welcome-description":o.$t(`@AGENT:我可以帮你阅读代码、执行命令、修改文件。选择下方话题或直接输入你的问题。`),"assistant-name":`g ai`,theme:o.chatTheme,disabled:o.isStreaming,"upload-config":{accept:`image/*`},placeholder:o.isStreaming?o.$t(`@AGENT:正在生成中...`):o.$t(`@AGENT:输入消息,Enter 发送`),onSend:o.onSend,onSelect:o.onSelectPreset},null,8,[`messages`,`preset-questions`,`welcome-title`,`welcome-description`,`theme`,`disabled`,`placeholder`])],2112)),d(O,{name:`fade`},{default:z(()=>[o.pendingQuestion?(S(),f(`section`,kt,[v(`div`,At,[d(o.ElIcon,null,{default:z(()=>[d(o.ChatLineRound)]),_:1}),v(`span`,null,t(o.$t(`@AGENT:等待你的回答`)),1)]),v(`div`,jt,t(o.pendingQuestion.question),1),o.pendingQuestion.options.length?(S(),f(`div`,Mt,[(S(!0),f(D,null,g(o.pendingQuestion.options,e=>(S(),f(`button`,{key:e,type:`button`,class:`ask-user-option`,disabled:o.answeringQuestion,onClick:t=>o.submitPendingAnswer(e)},[d(o.ElIcon,null,{default:z(()=>[d(o.Check)]),_:1}),v(`span`,null,t(e),1)],8,Nt))),128))])):r(`v-if`,!0),o.pendingQuestion.allowFreeText||o.pendingQuestion.options.length===0?(S(),f(`form`,{key:1,class:`ask-user-form`,onSubmit:n[3]||=H(e=>o.submitPendingAnswer(),[`prevent`])},[k(v(`input`,{"onUpdate:modelValue":n[2]||=e=>o.pendingAnswer=e,type:`text`,disabled:o.answeringQuestion,placeholder:o.$t(`@AGENT:输入回答`),"aria-label":o.$t(`@AGENT:输入回答`)},null,8,Pt),[[j,o.pendingAnswer]]),v(`button`,{type:`submit`,disabled:o.answeringQuestion||!o.pendingAnswer.trim()},[d(o.ElIcon,null,{default:z(()=>[d(o.Check)]),_:1}),v(`span`,null,t(o.$t(`@AGENT:提交回答`)),1)],8,Ft)],32)):r(`v-if`,!0)])):r(`v-if`,!0)]),_:1}),r(` 停止按钮浮层 `),d(O,{name:`fade`},{default:z(()=>[o.isStreaming?(S(),f(`div`,It,[v(`button`,{class:`stop-button`,onClick:n[4]||=(...e)=>o.stop&&o.stop(...e)},[d(o.ElIcon,null,{default:z(()=>[d(o.Loading,{class:`is-loading`})]),_:1}),v(`span`,null,t(o.$t(`@AGENT:停止生成`)),1)])])):r(`v-if`,!0)]),_:1})])):(S(),f(D,{key:1},[r(` ── Skill 广场 / MCP 广场 ── `),d(o.MarketplacePanel,{type:o.marketplaceType},null,8,[`type`])],2112))])])])}var Rt=J(it,[[`render`,Lt],[`__scopeId`,`data-v-bd681ddd`],[`__file`,`C:/workspace/github_workspace/xz333221/zen-gitsync/src/ui/client/src/views/AgentView.vue`]]);export{Rt as default};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
.marketplace-panel[data-v-e9f9e851]{background:var(--bg-container);flex-direction:column;height:100%;min-height:0;display:flex}.mp-toolbar[data-v-e9f9e851]{flex-shrink:0;align-items:center;gap:12px;padding:12px 16px 8px;display:flex}.mp-search[data-v-e9f9e851]{border:1px solid var(--border-color);border-radius:var(--radius-md);background:var(--bg-panel);flex:1;align-items:center;gap:6px;max-width:420px;height:32px;padding:0 10px;transition:border-color .15s;display:flex}.mp-search[data-v-e9f9e851]:focus-within{border-color:var(--color-primary)}.mp-search .mp-search-icon[data-v-e9f9e851]{color:var(--text-tertiary);flex-shrink:0}.mp-search .mp-search-input[data-v-e9f9e851]{color:var(--text-primary);background:0 0;border:none;outline:none;flex:1;font-family:inherit;font-size:13px}.mp-search .mp-search-input[data-v-e9f9e851]::placeholder{color:var(--text-tertiary)}.mp-target[data-v-e9f9e851]{flex-shrink:0}.mp-refresh[data-v-e9f9e851]{border:1px solid var(--border-color);border-radius:var(--radius-md);background:var(--bg-panel);width:30px;height:30px;color:var(--text-secondary);cursor:pointer;justify-content:center;align-items:center;transition:all .15s;display:flex}.mp-refresh[data-v-e9f9e851]:hover{color:var(--color-primary);border-color:var(--color-primary)}.mp-refresh.spinning svg[data-v-e9f9e851]{animation:.9s linear infinite mkt-spin-e9f9e851}@keyframes mkt-spin-e9f9e851{to{transform:rotate(360deg)}}.mp-toolbar-sub[data-v-e9f9e851]{flex-wrap:wrap;flex-shrink:0;align-items:center;gap:12px;padding:0 16px 10px;display:flex}.mp-target-hint[data-v-e9f9e851]{color:var(--text-tertiary);font-size:12px}.mp-target-hint b[data-v-e9f9e851]{color:var(--color-primary);font-weight:600}.mp-source-filter[data-v-e9f9e851]{flex-wrap:wrap;align-items:center;gap:6px;display:flex}.mp-chip[data-v-e9f9e851]{border:1px solid var(--border-color);color:var(--text-tertiary);cursor:pointer;background:0 0;border-radius:12px;padding:2px 10px;font-family:inherit;font-size:12px;transition:all .15s}.mp-chip[data-v-e9f9e851]:hover{color:var(--text-secondary);border-color:var(--text-tertiary)}.mp-chip.active[data-v-e9f9e851]{color:var(--color-primary);border-color:var(--color-primary);background:color-mix(in srgb, var(--color-primary) 8%, transparent)}.mp-chip.clear[data-v-e9f9e851]{color:var(--text-tertiary);border-style:dashed}.mp-body[data-v-e9f9e851]{flex:1;min-height:0;padding:0 16px 20px;overflow-y:auto}.mp-group[data-v-e9f9e851]{margin-bottom:20px}.mp-group.installed[data-v-e9f9e851]{border-top:1px dashed var(--border-color);padding-top:14px}.mp-group-header[data-v-e9f9e851]{align-items:center;gap:8px;margin-bottom:10px;display:flex}.mp-group-title[data-v-e9f9e851]{color:var(--text-primary);margin:0;font-size:13px;font-weight:600}.mp-group-count[data-v-e9f9e851]{background:var(--bg-hover);min-width:20px;height:18px;color:var(--text-tertiary);border-radius:9px;justify-content:center;align-items:center;padding:0 6px;font-size:11px;display:inline-flex}.mp-group-error[data-v-e9f9e851]{color:var(--color-warning);align-items:center;gap:4px;font-size:12px;display:inline-flex}.mp-group-link[data-v-e9f9e851]{color:var(--text-tertiary);transition:color .15s;display:inline-flex}.mp-group-link[data-v-e9f9e851]:hover{color:var(--color-primary)}.mp-grid[data-v-e9f9e851]{grid-template-columns:repeat(auto-fill,minmax(280px,1fr));gap:10px;display:grid}.mp-card[data-v-e9f9e851]{border:1px solid var(--border-color);border-radius:var(--radius-md);background:var(--bg-panel);flex-direction:column;gap:6px;padding:12px;transition:border-color .15s,box-shadow .15s;display:flex}.mp-card[data-v-e9f9e851]:hover{border-color:color-mix(in srgb, var(--color-primary) 40%, var(--border-color));box-shadow:var(--shadow-sm)}.mp-card-head[data-v-e9f9e851]{align-items:center;gap:8px;display:flex}.mp-card-name[data-v-e9f9e851]{min-width:0;color:var(--text-primary);white-space:nowrap;text-overflow:ellipsis;flex:1;font-size:13px;font-weight:600;overflow:hidden}.mp-card-metric[data-v-e9f9e851]{color:var(--text-tertiary);flex-shrink:0;align-items:center;gap:3px;font-size:11px;display:inline-flex}.mp-card-desc[data-v-e9f9e851]{color:var(--text-secondary);-webkit-line-clamp:2;-webkit-box-orient:vertical;min-height:36px;margin:0;font-size:12px;line-height:1.5;display:-webkit-box;overflow:hidden}.mp-card-meta[data-v-e9f9e851]{flex-wrap:wrap;align-items:center;gap:6px;min-height:18px;display:flex}.mp-meta-pkg[data-v-e9f9e851],.mp-meta-repo[data-v-e9f9e851]{color:var(--text-tertiary);white-space:nowrap;text-overflow:ellipsis;max-width:220px;font-size:11px;overflow:hidden}.mp-tag[data-v-e9f9e851]{background:var(--bg-hover);color:var(--text-tertiary);border-radius:8px;flex-shrink:0;padding:1px 6px;font-size:10px}.mp-tag.remote[data-v-e9f9e851]{background:color-mix(in srgb, var(--color-info,#06b6d4) 14%, transparent);color:var(--color-info,#06b6d4)}.mp-tag.warn[data-v-e9f9e851]{background:color-mix(in srgb, var(--color-warning) 14%, transparent);color:var(--color-warning)}.mp-card-foot[data-v-e9f9e851]{align-items:center;gap:8px;margin-top:2px;display:flex}.mp-card-link[data-v-e9f9e851]{color:var(--text-tertiary);font-size:11px;text-decoration:none}.mp-card-link[data-v-e9f9e851]:hover{color:var(--color-primary);text-decoration:underline}.mp-foot-spacer[data-v-e9f9e851]{flex:1}.mp-install-btn[data-v-e9f9e851]{border:1px solid var(--color-primary);border-radius:var(--radius-sm);color:var(--color-primary);cursor:pointer;background:0 0;padding:4px 14px;font-family:inherit;font-size:12px;transition:all .15s}.mp-install-btn[data-v-e9f9e851]:hover:not(:disabled){background:var(--color-primary);color:#fff}.mp-install-btn[data-v-e9f9e851]:disabled{opacity:.5;cursor:not-allowed}.mp-installed-chip[data-v-e9f9e851]{color:var(--color-success,#34d399);align-items:center;gap:3px;font-size:11px;display:inline-flex}.mp-not-installable[data-v-e9f9e851]{color:var(--text-tertiary);font-size:11px}.mp-empty[data-v-e9f9e851]{color:var(--text-tertiary);padding:16px 0;font-size:12px}.mp-empty.all[data-v-e9f9e851]{text-align:center;padding:48px 0}.mp-installed-block[data-v-e9f9e851]{margin-bottom:12px}.mp-installed-target[data-v-e9f9e851]{color:var(--text-tertiary);text-transform:uppercase;letter-spacing:.4px;margin-bottom:6px;font-size:11px;font-weight:600}.mp-installed-list[data-v-e9f9e851]{flex-direction:column;gap:4px;display:flex}.mp-installed-row[data-v-e9f9e851]{border:1px solid var(--border-color);border-radius:var(--radius-sm);background:var(--bg-panel);align-items:center;gap:10px;padding:6px 10px;display:flex}.mp-installed-name[data-v-e9f9e851]{color:var(--text-primary);white-space:nowrap;text-overflow:ellipsis;font-size:12px;font-weight:500;overflow:hidden}.mp-remove-btn[data-v-e9f9e851]{border:1px solid var(--border-color);border-radius:var(--radius-xs);color:var(--text-tertiary);cursor:pointer;background:0 0;align-items:center;gap:4px;padding:3px 10px;font-family:inherit;font-size:11px;transition:all .15s;display:inline-flex}.mp-remove-btn[data-v-e9f9e851]:hover:not(:disabled){color:var(--color-danger);border-color:var(--color-danger)}.mp-remove-btn[data-v-e9f9e851]:disabled{opacity:.5;cursor:not-allowed}@media (prefers-reduced-motion:reduce){.mp-refresh.spinning svg[data-v-e9f9e851]{animation:none}}.mkt-form[data-v-e9f9e851]{flex-direction:column;gap:12px;display:flex}.mkt-form-name[data-v-e9f9e851]{color:var(--text-primary);margin:0;font-size:13px;font-weight:600}.mkt-field[data-v-e9f9e851]{flex-direction:column;gap:4px;display:flex}.mkt-field label[data-v-e9f9e851]{color:var(--text-secondary);font-size:12px;font-weight:600}.mkt-field input[data-v-e9f9e851]{border:1px solid var(--border-color);background:var(--bg-container);height:30px;color:var(--text-primary);border-radius:6px;padding:0 8px;font-family:inherit;font-size:13px;transition:border-color .15s}.mkt-field input[data-v-e9f9e851]:focus{border-color:var(--color-primary);outline:none}.mkt-hint[data-v-e9f9e851]{color:var(--text-tertiary);margin:0;font-size:11px}.mkt-cancel[data-v-e9f9e851],.mkt-confirm[data-v-e9f9e851]{border-radius:var(--radius-sm);cursor:pointer;padding:6px 16px;font-family:inherit;font-size:13px;transition:all .15s}.mkt-cancel[data-v-e9f9e851]{border:1px solid var(--border-color);color:var(--text-secondary);background:0 0;margin-right:8px}.mkt-cancel[data-v-e9f9e851]:hover{color:var(--text-primary);border-color:var(--text-tertiary)}.mkt-confirm[data-v-e9f9e851]{border:1px solid var(--color-primary);background:var(--color-primary);color:#fff}.mkt-confirm[data-v-e9f9e851]:hover{opacity:.9}.agent-view[data-v-bd681ddd]{background:var(--bg-container);height:100%;min-height:0;display:flex}.agent-sidebar[data-v-bd681ddd]{background:var(--bg-panel);border-right:1px solid var(--border-color);flex-direction:column;flex-shrink:0;display:flex;overflow:hidden}.sidebar-header[data-v-bd681ddd]{flex-shrink:0;padding:10px 12px}.new-session-btn[data-v-bd681ddd]{border:1px dashed var(--border-color);border-radius:var(--radius-md);width:100%;color:var(--text-secondary);cursor:pointer;background:0 0;justify-content:center;align-items:center;gap:6px;padding:8px 12px;font-family:inherit;font-size:13px;transition:all .15s;display:flex}.new-session-btn[data-v-bd681ddd]:hover{border-color:var(--color-primary);color:var(--color-primary);background:color-mix(in srgb, var(--color-primary) 6%, transparent)}.sidebar-search[data-v-bd681ddd]{flex-shrink:0;align-items:center;gap:6px;padding:0 12px 8px;display:flex}.sidebar-search .search-icon[data-v-bd681ddd]{color:var(--text-tertiary);flex-shrink:0}.sidebar-search .search-input[data-v-bd681ddd]{color:var(--text-primary);background:0 0;border:none;outline:none;flex:1;padding:4px 0;font-family:inherit;font-size:13px}.sidebar-search .search-input[data-v-bd681ddd]::placeholder{color:var(--text-tertiary)}.session-list[data-v-bd681ddd]{flex:1;min-height:0;padding:0 6px 8px;overflow-y:auto}.empty-state[data-v-bd681ddd]{text-align:center;color:var(--text-tertiary);flex-direction:column;justify-content:center;align-items:center;padding:48px 16px;display:flex}.empty-state .empty-text[data-v-bd681ddd]{color:var(--text-secondary);margin-top:10px;font-size:14px}.empty-state .empty-hint[data-v-bd681ddd]{margin-top:4px;font-size:12px}.session-item[data-v-bd681ddd]{border-radius:var(--radius-sm);cursor:pointer;align-items:flex-start;gap:4px;padding:8px 10px;transition:background .12s;display:flex;position:relative}.session-item[data-v-bd681ddd]:hover{background:var(--bg-hover)}.session-item:hover .session-item-actions[data-v-bd681ddd]{opacity:1}.session-item.active[data-v-bd681ddd]{background:color-mix(in srgb, var(--color-primary) 10%, transparent)}.session-item.active .session-item-title[data-v-bd681ddd]{color:var(--color-primary)}.session-item.active[data-v-bd681ddd]:before{content:"";background:var(--color-primary);border-radius:0 2px 2px 0;width:3px;height:20px;position:absolute;top:50%;left:0;transform:translateY(-50%)}.session-item-main[data-v-bd681ddd]{flex:1;min-width:0}.session-item-title[data-v-bd681ddd]{color:var(--text-primary);white-space:nowrap;text-overflow:ellipsis;margin-bottom:2px;font-size:13px;font-weight:500;overflow:hidden}.session-item-meta[data-v-bd681ddd]{color:var(--text-tertiary);align-items:center;gap:4px;font-size:11px;display:flex}.session-item-meta .meta-dot[data-v-bd681ddd]{opacity:.5}.session-item-meta .meta-generating[data-v-bd681ddd]{color:var(--color-primary);align-items:center;gap:3px;display:inline-flex}.session-item-meta .meta-source[data-v-bd681ddd]{border-radius:3px;padding:0 4px;font-size:10px;font-weight:600}.session-item-meta .meta-source.cli[data-v-bd681ddd]{background:color-mix(in srgb, var(--color-warning) 20%, transparent);color:var(--color-warning)}.session-item-actions[data-v-bd681ddd]{opacity:0;flex-shrink:0;gap:2px;transition:opacity .12s;display:flex}.item-action-btn[data-v-bd681ddd]{width:24px;height:24px;color:var(--text-tertiary);cursor:pointer;border-radius:var(--radius-xs);background:0 0;border:none;justify-content:center;align-items:center;padding:0;transition:all .12s;display:flex}.item-action-btn[data-v-bd681ddd]:hover{background:var(--bg-hover);color:var(--text-secondary)}.item-action-btn.danger[data-v-bd681ddd]:hover{color:var(--color-danger);background:color-mix(in srgb, var(--color-danger) 10%, transparent)}.sidebar-resizer[data-v-bd681ddd]{cursor:col-resize;background:0 0;flex-shrink:0;width:4px;transition:background .15s}.sidebar-resizer[data-v-bd681ddd]:hover,.sidebar-resizer.active[data-v-bd681ddd]{background:var(--color-primary);opacity:.3}.agent-chat-area[data-v-bd681ddd]{flex-direction:column;flex:1;min-width:0;display:flex;position:relative;overflow:hidden}.agent-tabs[data-v-bd681ddd]{border-bottom:1px solid var(--border-color);background:var(--bg-panel);flex-shrink:0;align-items:center;gap:4px;padding:8px 12px 0;display:flex}.agent-tab[data-v-bd681ddd]{color:var(--text-tertiary);cursor:pointer;border-radius:var(--radius-sm) var(--radius-sm) 0 0;background:0 0;border:none;border-bottom:2px solid #0000;align-items:center;gap:6px;padding:7px 14px 9px;font-family:inherit;font-size:13px;transition:color .15s,border-color .15s,background .15s;display:inline-flex}.agent-tab[data-v-bd681ddd]:hover{color:var(--text-secondary);background:var(--bg-hover)}.agent-tab.active[data-v-bd681ddd]{color:var(--color-primary);border-bottom-color:var(--color-primary);font-weight:600}.agent-tab-body[data-v-bd681ddd]{flex-direction:column;flex:1;min-height:0;display:flex;overflow:hidden}.agent-chat-pane[data-v-bd681ddd]{flex-direction:column;flex:1;min-height:0;display:flex;position:relative;overflow:hidden}.agent-tab-body[data-v-bd681ddd]>.marketplace-panel{flex:1;min-height:0}.chat-loading[data-v-bd681ddd]{color:var(--text-tertiary);flex-direction:column;flex:1;justify-content:center;align-items:center;gap:12px;font-size:14px;display:flex}.ask-user-panel[data-v-bd681ddd]{z-index:9;border:1px solid var(--color-primary);border-radius:var(--radius-md);background:var(--bg-container);flex-direction:column;gap:10px;padding:12px 14px;display:flex;position:absolute;bottom:132px;left:16px;right:16px;box-shadow:0 4px 16px #00000029}.ask-user-title[data-v-bd681ddd]{color:var(--color-primary);align-items:center;gap:6px;font-size:12px;font-weight:600;display:flex}.ask-user-question[data-v-bd681ddd]{color:var(--text-primary);white-space:pre-wrap;overflow-wrap:anywhere;font-size:14px;line-height:1.45}.ask-user-options[data-v-bd681ddd]{flex-wrap:wrap;gap:8px;display:flex}.ask-user-option[data-v-bd681ddd],.ask-user-form button[data-v-bd681ddd]{border:1px solid var(--border-color);border-radius:var(--radius-sm);background:var(--bg-hover);min-height:32px;color:var(--text-primary);font:inherit;cursor:pointer;justify-content:center;align-items:center;gap:5px;padding:5px 10px;font-size:13px;transition:border-color .15s,color .15s,background .15s;display:inline-flex}.ask-user-option[data-v-bd681ddd]:hover:not(:disabled),.ask-user-form button[data-v-bd681ddd]:hover:not(:disabled){border-color:var(--color-primary);color:var(--color-primary);background:color-mix(in srgb, var(--color-primary) 8%, var(--bg-hover))}.ask-user-option[data-v-bd681ddd]:disabled,.ask-user-form button[data-v-bd681ddd]:disabled{cursor:wait;opacity:.6}.ask-user-form[data-v-bd681ddd]{gap:8px;display:flex}.ask-user-form input[data-v-bd681ddd]{border:1px solid var(--border-color);border-radius:var(--radius-sm);background:var(--bg-input);min-width:0;height:32px;color:var(--text-primary);font:inherit;outline:none;flex:1;padding:5px 9px;font-size:13px}.ask-user-form input[data-v-bd681ddd]:focus{border-color:var(--color-primary)}.stop-button-bar[data-v-bd681ddd]{z-index:10;position:absolute;bottom:80px;left:50%;transform:translate(-50%)}.stop-button[data-v-bd681ddd]{border:1px solid var(--color-danger);background:var(--bg-container);color:var(--color-danger);cursor:pointer;border-radius:20px;align-items:center;gap:6px;padding:6px 16px;font-family:inherit;font-size:13px;transition:all .15s;display:flex;box-shadow:0 2px 8px #0000001f}.stop-button[data-v-bd681ddd]:hover{background:var(--color-danger);color:#fff}.fade-enter-active[data-v-bd681ddd],.fade-leave-active[data-v-bd681ddd]{transition:opacity .2s}.fade-enter-from[data-v-bd681ddd],.fade-leave-to[data-v-bd681ddd]{opacity:0}[data-theme=dark]{background:var(--bg-panel)}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
.upgrade-status[data-v-
|
|
1
|
+
.upgrade-status[data-v-bc566bba]{align-items:center;gap:var(--spacing-base);margin-bottom:var(--spacing-md);font-size:14px;font-weight:500;display:flex}.upgrade-status.is-running[data-v-bc566bba]{color:var(--el-color-primary)}.upgrade-status.is-success[data-v-bc566bba]{color:var(--el-color-success)}.upgrade-status.is-failed[data-v-bc566bba]{color:var(--el-color-danger)}.upgrade-status .is-loading[data-v-bc566bba]{animation:2s linear infinite rotating-bc566bba}.upgrade-log[data-v-bc566bba]{color:#d4d4d4;white-space:pre-wrap;word-break:break-all;background:#1e1e1e;border-radius:4px;height:320px;margin:0;padding:12px;font-family:JetBrains Mono,Cascadia Code,Consolas,monospace;font-size:12px;line-height:1.6;overflow:auto}.upgrade-hint[data-v-bc566bba]{margin:0 0 var(--spacing-md) 0;border-left:3px solid var(--el-color-success);color:var(--el-color-success);background:#67c23a14;border-radius:4px;padding:8px 12px;font-size:13px}.upgrade-countdown[data-v-bc566bba]{background:var(--el-color-success);color:#fff;border-radius:10px;margin-left:8px;padding:1px 8px;font-size:12px;font-weight:600;animation:1s ease-in-out infinite pulse-bc566bba;display:inline-block}.upgrade-manual[data-v-bc566bba]{margin:0 0 var(--spacing-md) 0;border-left:3px solid var(--el-color-danger);background:#f56c6c14;border-radius:4px;padding:8px 12px;font-size:13px}.upgrade-manual__label[data-v-bc566bba]{color:var(--el-color-danger);margin-bottom:4px;font-weight:500;display:block}.upgrade-manual__cmd[data-v-bc566bba]{color:var(--text-primary,#303133);word-break:break-all;-webkit-user-select:all;user-select:all;background:#0000000a;border-radius:3px;padding:6px 8px;font-family:JetBrains Mono,Cascadia Code,Consolas,monospace;font-size:12px;display:block}@keyframes pulse-bc566bba{0%,to{opacity:1}50%{opacity:.55}}@keyframes rotating-bc566bba{0%{transform:rotate(0)}to{transform:rotate(360deg)}}.app-version-badge[data-v-7e0300ec]{align-items:center;gap:var(--spacing-base);margin-left:auto;display:inline-flex}.badge-icon-link[data-v-7e0300ec]{width:22px;height:22px;color:var(--text-tertiary);opacity:.7;border-radius:4px;justify-content:center;align-items:center;text-decoration:none;transition:color .18s,opacity .18s,background .18s;display:inline-flex}.badge-icon-link[data-v-7e0300ec]:hover{opacity:1;color:var(--text-secondary);background:var(--bg-hover,#0000000f)}.badge-icon-link--npm[data-v-7e0300ec]:hover{color:var(--color-npm)}.badge-icon-link[data-v-7e0300ec]:first-child:hover{color:var(--text-primary)}.version-link[data-v-7e0300ec]{color:var(--text-secondary);border-radius:3px;padding:2px 6px;font-family:monospace;font-size:11px;text-decoration:none;transition:color .2s,background-color .2s}.version-link[data-v-7e0300ec]:hover{color:var(--color-primary);background-color:#0000000a}.upgrade-btn[data-v-7e0300ec]{appearance:none;cursor:pointer;color:#fff;background:linear-gradient(135deg, var(--color-primary) 0%, #3a8ee6 100%);height:22px;box-shadow:var(--shadow-sm);transition:transform var(--transition-fast) var(--ease-custom), box-shadow var(--transition-fast) var(--ease-custom), filter var(--transition-fast) var(--ease-custom);white-space:nowrap;-webkit-user-select:none;user-select:none;border:0;border-radius:11px;outline:none;align-items:center;gap:5px;margin:0;padding:0 10px 0 8px;font-family:inherit;font-size:11px;font-weight:600;line-height:1;display:inline-flex}.upgrade-btn[data-v-7e0300ec]:hover{filter:brightness(1.08);box-shadow:var(--shadow-md);transform:translateY(-1px)}.upgrade-btn[data-v-7e0300ec]:active{filter:brightness(.96);box-shadow:var(--shadow-sm);transform:translateY(0)}.upgrade-btn[data-v-7e0300ec]:focus-visible{outline:2px solid var(--color-primary);outline-offset:2px}.upgrade-btn__dot[data-v-7e0300ec]{background:#fff;border-radius:50%;flex-shrink:0;width:6px;height:6px;animation:1.6s ease-in-out infinite upgrade-pulse-7e0300ec;box-shadow:0 0 0 2px #ffffff59}.upgrade-btn__label[data-v-7e0300ec]{letter-spacing:.5px}.upgrade-btn__version[data-v-7e0300ec]{background:#ffffff38;border-radius:6px;padding:1px 5px;font-family:monospace;font-size:10px;font-weight:500;line-height:1.2}@keyframes upgrade-pulse-7e0300ec{0%,to{opacity:1;transform:scale(1)}50%{opacity:.55;transform:scale(.8)}}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import"./rolldown-runtime-C0FnF6B9.js";import{$r as e,Dn as t,E as n,En as r,Fn as i,H as a,Jn as o,K as s,Kn as c,L as l,Mn as u,Nn as d,On as f,Pr as p,Tn as m,Un as h,Xn as g,a as _,ar as v,fr as y,i as b,kt as x,nt as S,qr as C,sr as w,tt as T,wn as E,yr as D,zn as O}from"./element-plus-CMSkP_w2.js";import{n as k,t as A}from"./_plugin-vue_export-helper-BdTxl34g.js";async function j(e,t){let n=e.body.getReader(),r=new TextDecoder(`utf-8`),i=``;for(;;){let{done:e,value:a}=await n.read();if(e)break;i+=r.decode(a,{stream:!0});let o=i.split(`
|
|
2
|
+
`);i=o.pop()??``;for(let e of o)e.trim()&&t(e)}i.trim()&&t(i)}async function M(){let e=await fetch(`/api/app-version`);return e.ok?e.json():{success:!1,current:``,latest:null,hasUpdate:!1,error:`HTTP ${e.status}`}}async function N(e){let t=await fetch(`/api/app-upgrade`,{method:`POST`});if(!t.ok){let n=`HTTP ${t.status}`;try{let e=await t.json();e?.error&&(n=e.error)}catch{}e({type:`error`,message:n}),e({type:`done`,code:t.status});return}if(!t.body){e({type:`error`,message:`响应无 body`}),e({type:`done`,code:-1});return}await j(t,t=>{try{e(JSON.parse(t))}catch{}})}async function P(){let e=await fetch(`/api/app-restart`,{method:`POST`});if(!e.ok){let t=`HTTP ${e.status}`;try{let n=await e.json();n?.error&&(t=n.error)}catch{}throw Error(t)}if(!e.body)throw Error(`响应无 body`);return new Promise((t,n)=>{let r=!1,i=e=>{r||(r=!0,e())};j(e,e=>{try{let r=JSON.parse(e);r.type===`ready`&&typeof r.port==`number`&&r.port>0?i(()=>t(r.port)):r.type===`timeout`?i(()=>n(Error(`restart.timeout`))):r.type===`error`&&i(()=>n(Error(r.message||`restart.failed`)))}catch{}}).then(()=>{i(()=>n(Error(`restart.stream-closed`)))}).catch(()=>{})})}O(),y();var F=`npm install -g zen-gitsync --registry https://registry.npmjs.org/`,I=i({__name:`UpgradeDialog`,props:{modelValue:{type:Boolean,required:!0},logs:{type:String,required:!0},status:{type:String,required:!0},countdown:{type:Number,required:!1,default:0}},emits:[`update:modelValue`,`retry`,`restart`,`cancel`],setup(e,{expose:t,emit:n}){t();let r=e,i=n,a=D(null);v(()=>r.logs,async()=>{await h(),a.value&&(a.value.scrollTop=a.value.scrollHeight)});function o(){r.status!==`running`&&(r.status===`success`&&r.countdown>0&&i(`cancel`),i(`update:modelValue`,!1))}function s(){i(`retry`)}function c(){i(`restart`)}function l(){i(`cancel`),i(`update:modelValue`,!1)}async function u(){try{await navigator.clipboard.writeText(F),_.success(k(`@F13B4:已复制升级命令`))}catch{_.warning(k(`@F13B4:复制失败,请手动复制`))}}let d={MANUAL_COMMAND:F,props:r,emit:i,logEl:a,close:o,onRetry:s,onRestart:c,onLater:l,onCopyCommand:u,get Loading(){return x},get CircleCheck(){return T},get CircleClose(){return S},get $t(){return k}};return Object.defineProperty(d,"__isScriptSetup",{enumerable:!1,value:!0}),d}});O(),p();var L={key:3},R={key:4},z={key:5},B={key:0,class:`upgrade-hint`},V={key:0,class:`upgrade-countdown`},H={key:1,class:`upgrade-manual`},U={class:`upgrade-manual__label`};function W(i,a,o,c,p,h){let _=s,v=l,y=n;return g(),r(y,{"model-value":o.modelValue,"onUpdate:modelValue":a[0]||=e=>c.emit(`update:modelValue`,e),title:c.$t(`@F13B4:升级`),width:`680px`,"close-on-click-modal":!1,"close-on-press-escape":!1,"show-close":o.status!==`running`,"append-to-body":``,onClose:c.close},{footer:w(()=>[o.status===`failed`?(g(),r(v,{key:0,type:`primary`,onClick:c.onRetry},{default:w(()=>[u(e(c.$t(`@F13B4:重试`)),1)]),_:1})):t(`v-if`,!0),o.status===`failed`?(g(),r(v,{key:1,onClick:c.onCopyCommand},{default:w(()=>[u(e(c.$t(`@F13B4:复制升级命令`)),1)]),_:1})):t(`v-if`,!0),o.status===`success`?(g(),r(v,{key:2,type:`primary`,onClick:c.onRestart},{default:w(()=>[u(e(c.$t(`@F13B4:立即重启并刷新`)),1)]),_:1})):t(`v-if`,!0),o.status===`success`?(g(),r(v,{key:3,onClick:c.onLater},{default:w(()=>[u(e(c.$t(`@F13B4:稍后手动重启`)),1)]),_:1})):t(`v-if`,!0),o.status===`running`?(g(),r(v,{key:4,disabled:``},{default:w(()=>[u(e(c.$t(`@F13B4:升级中`))+`... `,1)]),_:1})):t(`v-if`,!0)]),default:w(()=>[m(`div`,{class:C([`upgrade-status`,`is-${o.status}`])},[o.status===`running`?(g(),r(_,{key:0,class:`is-loading`},{default:w(()=>[d(c.Loading)]),_:1})):o.status===`success`?(g(),r(_,{key:1,color:`#67c23a`},{default:w(()=>[d(c.CircleCheck)]),_:1})):(g(),r(_,{key:2,color:`#f56c6c`},{default:w(()=>[d(c.CircleClose)]),_:1})),o.status===`running`?(g(),f(`span`,L,e(c.$t(`@F13B4:升级中`)),1)):o.status===`success`?(g(),f(`span`,R,e(c.$t(`@F13B4:升级完成`)),1)):(g(),f(`span`,z,e(c.$t(`@F13B4:升级失败`)),1))],2),o.status===`success`?(g(),f(`p`,B,[u(e(c.$t(`@F13B4:新版本已全局安装,需要重启服务才能生效`))+` `,1),o.countdown>0?(g(),f(`span`,V,e(c.$t(`@F13B4:{seconds} 秒后自动刷新`,{seconds:o.countdown})),1)):t(`v-if`,!0)])):t(`v-if`,!0),o.status===`failed`?(g(),f(`p`,H,[m(`span`,U,e(c.$t(`@F13B4:手动升级命令`)),1),m(`code`,{class:`upgrade-manual__cmd`},e(c.MANUAL_COMMAND))])):t(`v-if`,!0),m(`pre`,{ref:`logEl`,class:`upgrade-log`},e(o.logs||c.$t(`@F13B4:等待日志输出`)),513)]),_:1},8,[`model-value`,`title`,`show-close`])}var G=A(I,[[`render`,W],[`__scopeId`,`data-v-bc566bba`],[`__file`,`C:/workspace/github_workspace/xz333221/zen-gitsync/src/ui/client/src/components/UpgradeDialog.vue`]]);O(),y();var K=`https://github.com/xz333221/zen-gitsync/releases`,q=5,J=`app-version-check`,Y=36e5,X=i({__name:`AppVersionBadge`,setup(e,{expose:t}){t();let n=`2.17.14`,r=D(n),i=E(()=>r.value||n),a=D(null),s=D(!1),l=D(``),u=D(`running`),d=D(0),f=null,p=D(!1);function m(){try{let e=sessionStorage.getItem(J);if(!e)return null;let{at:t,data:n}=JSON.parse(e);return Date.now()-t>Y?null:n}catch{return null}}function h(e){try{sessionStorage.setItem(J,JSON.stringify({at:Date.now(),data:e}))}catch{}}async function g(e=!1){let t=m();t&&(a.value=t);try{let t=await M();a.value=t,h(t),t.current&&(r.value=t.current),!e&&t.success&&t.hasUpdate&&_({type:`success`,message:k(`@F13B4:发现新版本 {version}`,{version:t.latest??``}),duration:4e3})}catch(t){e||_({type:`warning`,message:k(`@F13B4:检查更新失败 {error}`,{error:t?.message||``})})}}async function v(){if(a.value?.hasUpdate){try{await b.confirm(k(`@F13B4:确定要从 {current} 升级到 {latest} 吗?`,{current:a.value.current,latest:a.value.latest}),k(`@F13B4:升级`),{confirmButtonText:k(`@F13B4:确定升级`),cancelButtonText:k(`@F13B4:取消`),type:`info`})}catch{return}l.value=``,u.value=`running`,s.value=!0,await N(e=>{if(e.type===`done`){if(u.value=e.code===0?`success`:`failed`,e.code===0){try{sessionStorage.removeItem(J)}catch{}a.value?.latest&&(r.value=a.value.latest),y()}}else e.message&&(l.value+=e.message)})}}function y(){x(),d.value=q,f=setInterval(()=>{--d.value,d.value<=0&&(f&&=(clearInterval(f),null),C())},1e3)}function x(){f&&=(clearInterval(f),null),d.value=0}function S(){x()}async function C(){if(x(),!p.value){p.value=!0;try{let e=await P(),{pathname:t,search:n,hash:r}=window.location;window.location.href=`http://localhost:${e}${t}${n}${r}`}catch(e){let t=e?.message||``,n={"restart.timeout":`@F13B4:重启超时`,"restart.stream-closed":`@F13B4:重启失败,请刷新页面重试`,"restart.failed":`@F13B4:重启失败`}[t];_({type:`warning`,message:n?k(n):k(`@F13B4:重启失败 {error}`,{error:t})}),p.value=!1}}}c(()=>{x()}),o(()=>{g(!0)});let w={buildVersion:n,releasesUrl:K,runtimeVersion:r,displayVersion:i,latestInfo:a,upgradeDialogVisible:s,upgradeLogs:l,upgradeStatus:u,AUTO_REFRESH_SECONDS:q,countdown:d,get countdownTimer(){return f},set countdownTimer(e){f=e},restartInFlight:p,CACHE_KEY:J,CACHE_TTL_MS:Y,readCache:m,writeCache:h,checkUpdate:g,handleUpgrade:v,startAutoRefreshCountdown:y,cancelAutoRefreshCountdown:x,handleCancelAutoRefresh:S,handleRestart:C,get $t(){return k},UpgradeDialog:G};return Object.defineProperty(w,"__isScriptSetup",{enumerable:!1,value:!0}),w}});O(),p();var Z={class:`app-version-badge`},Q=[`aria-label`],$=[`aria-label`],ee=[`title`,`aria-label`],te={class:`upgrade-btn__label`},ne={class:`upgrade-btn__version`};function re(n,r,i,o,s,c){let l=a;return g(),f(`div`,Z,[t(` GitHub 链接 `),d(l,{content:o.$t(`@F13B4:在 GitHub 上查看源码`),placement:`top`,effect:`dark`,"show-after":300},{default:w(()=>[m(`a`,{href:`https://github.com/xz333221/zen-gitsync`,target:`_blank`,rel:`noopener noreferrer`,class:`badge-icon-link`,"aria-label":o.$t(`@F13B4:在 GitHub 上查看源码`)},[...r[1]||=[m(`svg`,{viewBox:`0 0 24 24`,width:`15`,height:`15`,"aria-hidden":`true`,fill:`currentColor`,xmlns:`http://www.w3.org/2000/svg`},[m(`path`,{d:`M12 2C6.477 2 2 6.484 2 12.017c0 4.425 2.865 8.18 6.839 9.504.5.092.682-.217.682-.483 0-.237-.008-.868-.013-1.703-2.782.605-3.369-1.343-3.369-1.343-.454-1.158-1.11-1.466-1.11-1.466-.908-.62.069-.608.069-.608 1.003.07 1.531 1.032 1.531 1.032.892 1.53 2.341 1.088 2.91.832.092-.647.35-1.088.636-1.338-2.22-.253-4.555-1.113-4.555-4.951 0-1.093.39-1.988 1.029-2.688-.103-.253-.446-1.272.098-2.65 0 0 .84-.27 2.75 1.026A9.564 9.564 0 0 1 12 6.844a9.59 9.59 0 0 1 2.504.337c1.909-1.296 2.747-1.027 2.747-1.027.546 1.379.202 2.398.1 2.651.64.7 1.028 1.595 1.028 2.688 0 3.848-2.339 4.695-4.566 4.943.359.309.678.92.678 1.855 0 1.338-.012 2.419-.012 2.747 0 .268.18.58.688.482A10.02 10.02 0 0 0 22 12.017C22 6.484 17.522 2 12 2z`})],-1)]],8,Q)]),_:1},8,[`content`]),t(` NPM 链接 `),d(l,{content:o.$t(`@F13B4:在 npm 上查看包`),placement:`top`,effect:`dark`,"show-after":300},{default:w(()=>[m(`a`,{href:`https://www.npmjs.com/package/zen-gitsync`,target:`_blank`,rel:`noopener noreferrer`,class:`badge-icon-link badge-icon-link--npm`,"aria-label":o.$t(`@F13B4:在 npm 上查看包`)},[...r[2]||=[m(`svg`,{viewBox:`0 0 24 24`,width:`15`,height:`15`,"aria-hidden":`true`,fill:`currentColor`,xmlns:`http://www.w3.org/2000/svg`},[m(`path`,{d:`M2 2v20h20V2H2zm17.167 17.167H12.5v-10h-3.333v10H4.833V4.833h14.334v14.334z`})],-1)]],8,$)]),_:1},8,[`content`]),t(` 版本号 `),d(l,{content:o.$t(`@F13B4:查看更新`),placement:`top`,effect:`dark`,"show-after":300},{default:w(()=>[m(`a`,{href:o.releasesUrl,target:`_blank`,rel:`noopener noreferrer`,class:`version-link`},`v`+e(o.displayVersion),1)]),_:1},8,[`content`]),o.latestInfo?.hasUpdate?(g(),f(`button`,{key:0,type:`button`,class:`upgrade-btn`,title:o.$t(`@F13B4:发现新版本 {version},点击升级`,{version:o.latestInfo.latest??``}),"aria-label":o.$t(`@F13B4:发现新版本 {version},点击升级`,{version:o.latestInfo.latest??``}),onClick:o.handleUpgrade},[r[3]||=m(`span`,{class:`upgrade-btn__dot`,"aria-hidden":`true`},null,-1),m(`span`,te,e(o.$t(`@F13B4:升级`)),1),m(`span`,ne,`v`+e(o.latestInfo.latest),1)],8,ee)):t(`v-if`,!0),d(o.UpgradeDialog,{modelValue:o.upgradeDialogVisible,"onUpdate:modelValue":r[0]||=e=>o.upgradeDialogVisible=e,logs:o.upgradeLogs,status:o.upgradeStatus,countdown:o.countdown,onRetry:o.handleUpgrade,onRestart:o.handleRestart,onCancel:o.handleCancelAutoRefresh},null,8,[`modelValue`,`logs`,`status`,`countdown`])])}var ie=A(X,[[`render`,re],[`__scopeId`,`data-v-7e0300ec`],[`__file`,`C:/workspace/github_workspace/xz333221/zen-gitsync/src/ui/client/src/components/AppVersionBadge.vue`]]);export{ie as default};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
.branch-wrapper[data-v-9548a76f]{align-items:center;gap:2px;display:inline-flex}.branch-btn[data-v-9548a76f]{cursor:pointer;height:22px;color:var(--color-text);font-family:var(--font-mono,monospace);white-space:nowrap;background:0 0;border:none;border-radius:3px;align-items:center;gap:4px;padding:0 6px;font-size:12px;transition:background .15s;display:inline-flex}.branch-btn[data-v-9548a76f]:hover{background:var(--bg-hover,#ffffff14)}.branch-btn[data-v-9548a76f]:active{background:var(--bg-active,#ffffff1f)}[data-v-9548a76f] .branch-btn-icon{flex-shrink:0;width:14px;height:14px}.branch-btn-name[data-v-9548a76f]{text-overflow:ellipsis;max-width:160px;overflow:hidden}.branch-btn-caret[data-v-9548a76f]{opacity:.6;align-items:center;font-size:10px;display:flex}.branch-popover-inner[data-v-9548a76f]{flex-direction:column;gap:0;display:flex}.branch-search[data-v-9548a76f]{padding-bottom:8px}.branch-list[data-v-9548a76f]{max-height:240px;margin:0 -16px;padding:0 4px;overflow-y:auto}.branch-list[data-v-9548a76f]::-webkit-scrollbar{width:4px}.branch-list[data-v-9548a76f]::-webkit-scrollbar-thumb{background:var(--border-color,#8080804d);border-radius:2px}.branch-item[data-v-9548a76f]{cursor:pointer;height:28px;color:var(--color-text);border-radius:3px;align-items:center;gap:6px;padding:0 12px;font-size:13px;transition:background .1s;display:flex}.branch-item[data-v-9548a76f]:hover{background:var(--bg-hover,#ffffff14)}.branch-item.is-active[data-v-9548a76f]{color:var(--color-primary)}.branch-item-check[data-v-9548a76f]{color:var(--color-primary);flex-shrink:0;font-size:12px}.branch-item-check-placeholder[data-v-9548a76f]{flex-shrink:0;width:12px;display:inline-block}[data-v-9548a76f] .branch-item-icon{opacity:.7;flex-shrink:0;width:13px;height:13px}.branch-item-name[data-v-9548a76f]{text-overflow:ellipsis;white-space:nowrap;flex:1;overflow:hidden}.branch-empty[data-v-9548a76f]{text-align:center;color:var(--color-text-secondary,#888);padding:12px;font-size:12px}.branch-popover-footer[data-v-9548a76f]{margin-top:4px;padding-top:6px}.branch-create-btn[data-v-9548a76f]{cursor:pointer;width:100%;height:28px;color:var(--color-text);text-align:left;background:0 0;border:none;border-radius:3px;align-items:center;gap:6px;padding:0 12px;font-size:13px;transition:background .1s;display:flex}.branch-create-btn[data-v-9548a76f]:hover{background:var(--bg-hover,#ffffff14)}.branch-info[data-v-9548a76f]{align-items:center;display:flex}.create-branch-content[data-v-9548a76f]{padding:var(--spacing-base) 0}.is-loading[data-v-9548a76f]{animation:2s linear infinite rotating-9548a76f}@keyframes rotating-9548a76f{0%{transform:rotate(0)}to{transform:rotate(360deg)}}.branch-popover{border-radius:4px!important;padding:12px 16px!important;box-shadow:0 4px 16px #0000002e!important}.create-branch-dialog .modern-select .el-select__wrapper{border-radius:var(--radius-lg);border:1px solid var(--border-input);box-shadow:var(--shadow-sm);padding:10px var(--spacing-md);background:var(--bg-container);transition:all .2s}.create-branch-dialog .modern-select .el-select__wrapper:hover{border-color:var(--color-gray-300);box-shadow:var(--shadow-md)}.create-branch-dialog .modern-select.is-focus .el-select__wrapper{border-color:#3498db;box-shadow:0 0 0 2px #3498db1a,0 2px 6px #00000014}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import"./rolldown-runtime-C0FnF6B9.js";import{$r as e,Dn as t,En as n,F as r,Fn as i,K as a,Mt as o,Nn as s,On as c,P as l,Pr as u,Qn as d,Rt as f,Tn as p,U as m,V as h,Vt as g,W as _,Xn as v,bn as y,et as b,fr as x,qr as S,r as C,sr as w,un as T,vn as E,wn as D,yr as O,zn as k}from"./element-plus-CMSkP_w2.js";import{n as A,t as j}from"./_plugin-vue_export-helper-BdTxl34g.js";import{t as M}from"./SvgIcon-CvtoU5yo.js";import{t as N}from"./IconButton-DysyaC1j.js";import{r as P}from"./gitStore-BgC8OY0k.js";import{t as F}from"./CommonDialog-BiNTGpA-.js";k(),x();var I=i({__name:`BranchSelector`,emits:[`branchChanged`],setup(e,{expose:t,emit:n}){t();let r=P(),i=n,a=O(!1),s=O(``),c=D(()=>{let e=s.value.trim().toLowerCase();return e?r.allBranches.filter(t=>t.toLowerCase().includes(e)):r.allBranches});async function l(e){if(e===r.currentBranch){a.value=!1;return}a.value=!1,await r.changeBranch(e)&&(i(`branchChanged`),r.refreshLog())}let u=O(!1),d=O(``),p=O(``);function m(){a.value=!1,p.value=r.currentBranch,u.value=!0}async function h(){await r.createBranch(d.value,p.value)&&(u.value=!1,d.value=``,i(`branchChanged`))}let _=O(!1);async function v(){if(!_.value){_.value=!0;try{await Promise.all([r.getCurrentBranch(!0),r.getBranchStatus(!0),r.getAllBranches()]),i(`branchChanged`),r.refreshLog()}finally{_.value=!1}}}let y={gitStore:r,emit:i,branchPopoverVisible:a,branchFilter:s,filteredBranches:c,selectBranch:l,createBranchDialogVisible:u,newBranchName:d,selectedBaseBranch:p,openCreateBranchDialog:m,createNewBranch:h,isRefreshingBranch:_,refreshCurrentBranch:v,get $t(){return A},get Plus(){return f},get Menu(){return o},get Check(){return b},get Refresh(){return g},CommonDialog:F,IconButton:N,SvgIcon:M};return Object.defineProperty(y,"__isScriptSetup",{enumerable:!1,value:!0}),y}});k(),u(),T();var L={key:0,class:`branch-info`},R={class:`branch-wrapper`},z={class:`branch-btn`},B={class:`branch-btn-name`},V={class:`branch-btn-caret`},H={class:`branch-popover-inner`},U={class:`branch-search`},W={class:`branch-list`},G=[`onClick`],K={key:1,class:`branch-item-check-placeholder`},q={class:`branch-item-name`},J={key:0,class:`branch-empty`},Y={class:`branch-popover-footer`},X={class:`create-branch-content`},Z={class:`form-label`},Q={class:`form-label`},$={class:`dialog-footer`},ee={class:`footer-actions`},te=[`disabled`];function ne(i,o,u,f,g,b){let x=a,T=h,D=C,O=_,k=l,A=r,j=m;return f.gitStore.currentBranch?(v(),c(`div`,L,[p(`div`,R,[t(` VSCode 风格分支按钮 + 弹出列表 `),s(D,{visible:f.branchPopoverVisible,"onUpdate:visible":o[1]||=e=>f.branchPopoverVisible=e,placement:`top-start`,width:260,trigger:`click`,"popper-class":`branch-popover`,"show-arrow":!1,onShow:o[2]||=e=>f.branchFilter=``},{reference:w(()=>[p(`button`,z,[s(f.SvgIcon,{"icon-class":`git-branch`,"class-name":`branch-btn-icon`}),p(`span`,B,e(f.gitStore.currentBranch),1),p(`span`,V,[s(x,null,{default:w(()=>[...o[7]||=[p(`svg`,{viewBox:`0 0 1024 1024`,xmlns:`http://www.w3.org/2000/svg`},[p(`path`,{fill:`currentColor`,d:`M831.872 340.864 512 652.672 192.128 340.864a30.592 30.592 0 0 0-42.752 0 29.12 29.12 0 0 0 0 41.6L489.664 714.24a32 32 0 0 0 44.672 0l340.288-331.776a29.12 29.12 0 0 0 0-41.6 30.592 30.592 0 0 0-42.752 0z`})],-1)]]),_:1})])])]),default:w(()=>[p(`div`,H,[t(` 搜索框 `),p(`div`,U,[s(T,{modelValue:f.branchFilter,"onUpdate:modelValue":o[0]||=e=>f.branchFilter=e,placeholder:f.$t(`@F13B4:搜索或签出分支`),size:`small`,clearable:``,autofocus:``},null,8,[`modelValue`,`placeholder`])]),t(` 分支列表 `),p(`div`,W,[(v(!0),c(y,null,d(f.filteredBranches,t=>(v(),c(`div`,{key:t,class:S([`branch-item`,{"is-active":t===f.gitStore.currentBranch}]),onClick:e=>f.selectBranch(t)},[t===f.gitStore.currentBranch?(v(),n(x,{key:0,class:`branch-item-check`},{default:w(()=>[s(f.Check)]),_:1})):(v(),c(`span`,K)),s(f.SvgIcon,{"icon-class":`git-branch`,"class-name":`branch-item-icon`}),p(`span`,q,e(t),1)],10,G))),128)),f.filteredBranches.length===0?(v(),c(`div`,J,e(f.$t(`@F13B4:没有匹配的分支`)),1)):t(`v-if`,!0)]),t(` 底部:创建新分支 `),p(`div`,Y,[p(`button`,{class:`branch-create-btn`,onClick:f.openCreateBranchDialog},[s(x,null,{default:w(()=>[s(f.Plus)]),_:1}),p(`span`,null,e(f.$t(`@F13B4:创建新分支`)),1)])])])]),_:1},8,[`visible`]),t(` 刷新按钮 `),s(f.IconButton,{tooltip:f.$t(`@CMDCON:刷新`),onClick:f.refreshCurrentBranch},{default:w(()=>[s(x,{class:S({"is-loading":f.isRefreshingBranch})},{default:w(()=>[s(f.Refresh)]),_:1},8,[`class`])]),_:1},8,[`tooltip`])]),t(` 创建分支对话框 `),s(f.CommonDialog,{modelValue:f.createBranchDialogVisible,"onUpdate:modelValue":o[6]||=e=>f.createBranchDialogVisible=e,title:f.$t(`@F13B4:创建新分支`),size:`small`,"destroy-on-close":!0,"append-to-body":!0,"custom-class":`create-branch-dialog`},{footer:w(()=>[p(`div`,$,[p(`div`,ee,[p(`button`,{type:`button`,class:`dialog-cancel-btn`,onClick:o[5]||=e=>f.createBranchDialogVisible=!1},e(f.$t(`@F13B4:取消`)),1),p(`button`,{type:`button`,class:`dialog-confirm-btn`,onClick:f.createNewBranch,disabled:f.gitStore.isCreatingBranch},[f.gitStore.isCreatingBranch?(v(),n(x,{key:1,class:`is-loading`},{default:w(()=>[...o[8]||=[p(`svg`,{viewBox:`0 0 1024 1024`,xmlns:`http://www.w3.org/2000/svg`},[p(`path`,{fill:`currentColor`,d:`M512 64a32 32 0 0 1 32 32v192a32 32 0 0 1-64 0V96a32 32 0 0 1 32-32zm0 640a32 32 0 0 1 32 32v192a32 32 0 1 1-64 0V736a32 32 0 0 1 32-32zm448-192a32 32 0 0 1-32 32H736a32 32 0 1 1 0-64h192a32 32 0 0 1 32 32zm-640 0a32 32 0 0 1-32 32H96a32 32 0 0 1 0-64h192a32 32 0 0 1 32 32z`})],-1)]]),_:1})):(v(),n(x,{key:0},{default:w(()=>[s(f.Check)]),_:1})),p(`span`,null,e(f.$t(`@F13B4:创建`)),1)],8,te)])])]),default:w(()=>[p(`div`,X,[s(j,{model:{newBranchName:f.newBranchName,selectedBaseBranch:f.selectedBaseBranch},"label-position":`top`},{default:w(()=>[s(O,null,{label:w(()=>[p(`div`,Z,[s(x,{class:`label-icon`},{default:w(()=>[s(f.Plus)]),_:1}),p(`span`,null,e(f.$t(`@F13B4:新分支名称`)),1)])]),default:w(()=>[s(T,{modelValue:f.newBranchName,"onUpdate:modelValue":o[3]||=e=>f.newBranchName=e,placeholder:f.$t(`@F13B4:请输入新分支名称`),class:`modern-input`,size:`large`,onKeyup:E(f.createNewBranch,[`enter`])},null,8,[`modelValue`,`placeholder`])]),_:1}),s(O,null,{label:w(()=>[p(`div`,Q,[s(x,{class:`label-icon`},{default:w(()=>[s(f.Menu)]),_:1}),p(`span`,null,e(f.$t(`@F13B4:基于分支`)),1)])]),default:w(()=>[s(A,{modelValue:f.selectedBaseBranch,"onUpdate:modelValue":o[4]||=e=>f.selectedBaseBranch=e,placeholder:f.$t(`@F13B4:选择基础分支`),class:`modern-select`,size:`large`,style:{width:`100%`}},{default:w(()=>[(v(!0),c(y,null,d(f.gitStore.allBranches,e=>(v(),n(k,{key:e,label:e,value:e},null,8,[`label`,`value`]))),128))]),_:1},8,[`modelValue`,`placeholder`])]),_:1})]),_:1},8,[`model`])])]),_:1},8,[`modelValue`,`title`])])):t(`v-if`,!0)}var re=j(I,[[`render`,ne],[`__scopeId`,`data-v-9548a76f`],[`__file`,`C:/workspace/github_workspace/xz333221/zen-gitsync/src/ui/client/src/components/BranchSelector.vue`]]);export{re as default};
|