zen-gitsync 2.18.9 → 2.18.10

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.
Files changed (33) hide show
  1. package/README.md +2 -2
  2. package/package.json +1 -1
  3. package/src/cli/ai/tools.js +152 -1
  4. package/src/cli/ai/tools.test.js +70 -1
  5. package/src/ui/public/assets/{AgentView-CV_8sYX6.css → AgentView-BnEgu3NT.css} +1 -1
  6. package/src/ui/public/assets/AgentView-DQQe_ivW.js +1 -0
  7. package/src/ui/public/assets/{AppVersionBadge-C4OhcUi8.js → AppVersionBadge-D7PiBP0p.js} +1 -1
  8. package/src/ui/public/assets/{BranchSelector-CrLieQyJ.js → BranchSelector-BzHoMBOc.js} +1 -1
  9. package/src/ui/public/assets/{CommitForm-KGQisnPQ.js → CommitForm-CNTjLYTR.js} +1 -1
  10. package/src/ui/public/assets/{CopySessionButton-y5Rzmact.js → CopySessionButton-Dy5t8Mjy.js} +1 -1
  11. package/src/ui/public/assets/{EditorView-CkZb2kw5.js → EditorView-CwcdA0Ei.js} +1 -1
  12. package/src/ui/public/assets/{FlowOrchestrationWorkspace-BMQSVm3V.js → FlowOrchestrationWorkspace-CJHpEBCw.js} +1 -1
  13. package/src/ui/public/assets/{LogList-BxH6QNlK.js → LogList-KUePBjAt.js} +1 -1
  14. package/src/ui/public/assets/{MindmapView-D9_qjJsR.js → MindmapView-CwdvsuEK.js} +1 -1
  15. package/src/ui/public/assets/{MonitorView-z_fsnE8Y.js → MonitorView-CjEnnrTL.js} +1 -1
  16. package/src/ui/public/assets/{ProjectStartupButton-CFB_JpYG.js → ProjectStartupButton-B36lRb6-.js} +1 -1
  17. package/src/ui/public/assets/{RecentDirectoriesChat-BYI8lkjQ.js → RecentDirectoriesChat-DNiji9Pr.js} +1 -1
  18. package/src/ui/public/assets/{RemoteManagerDialog-DXDcN8e7.js → RemoteManagerDialog-Dj_GpA-c.js} +1 -1
  19. package/src/ui/public/assets/{RemoteRepoCard-C_TYGsXi.js → RemoteRepoCard-C8u9M6dn.js} +1 -1
  20. package/src/ui/public/assets/{SourceMapView-D6cSweDt.js → SourceMapView-eng0B9U2.js} +1 -1
  21. package/src/ui/public/assets/{WorkbenchView-D4UDurhF.js → WorkbenchView-CZO18THH.js} +1 -1
  22. package/src/ui/public/assets/agentConversations-De3wKTsN.js +10 -0
  23. package/src/ui/public/assets/{index-C7Y9odvZ.js → index-DQ82h1aq.js} +5 -5
  24. package/src/ui/public/assets/{useOrchestrator-C236G5P5.js → useOrchestrator-BjC7oHpt.js} +1 -1
  25. package/src/ui/public/index.html +1 -1
  26. package/src/ui/server/routes/git/clone.js +5 -13
  27. package/src/ui/server/routes/workbench/agentChat.js +5 -2
  28. package/src/ui/server/routes/workbench/agentRoutes.js +17 -0
  29. package/src/ui/server/routes/workbench/index.js +16 -4
  30. package/src/ui/server/routes/workbench/scheduler.js +3 -0
  31. package/src/utils/gitRepoName.js +33 -0
  32. package/src/ui/public/assets/AgentView-DxmnqJxE.js +0 -1
  33. package/src/ui/public/assets/agentConversations-DyzaxUXm.js +0 -10
@@ -1 +1 @@
1
- import"./rolldown-runtime-C0FnF6B9.js";import{i as e,mr as t,xr as n}from"./element-plus-J45pKUrE.js";import{n as r}from"./_plugin-vue_export-helper-Csn085FF.js";import{t as i}from"./configStore-DOaPZ6Mq.js";import{m as a}from"./index-C7Y9odvZ.js";var o=[0,5,10,15,30,60].map(e=>e*60*1e3),s=6e5;function c(e){let t=Number(e);return o.includes(t)?t:s}function l(e){return e?e>=36e5?`@WORKBENCH:每 {n} 小时报告`:`@WORKBENCH:每 {n} 分钟报告`:`@WORKBENCH:关闭自动报告`}function u(e){return e?{n:Math.round(e>=36e5?e/36e5:e/6e4)}:{}}function d(e){switch(e){case`NO_MODEL`:return`@WORKBENCH:没有可用的 AI 模型,只记录了任务事实`;case`LLM_TIMEOUT`:return`@WORKBENCH:生成超时,只记录了任务事实`;case`LLM_EMPTY`:return`@WORKBENCH:模型没有返回正文,只记录了任务事实`;case`LLM_FAILED`:return`@WORKBENCH:生成失败,只记录了任务事实`;default:return`@WORKBENCH:生成失败,只记录了任务事实`}}function f(e){if(e==null||e===``)return null;let t=Number(e);if(!Number.isFinite(t))return null;let n=Math.round(t);return n>=0&&n<=100?n:null}function p(e){return typeof e!=`number`||!Number.isFinite(e)||e<=0?null:Math.floor(e)}var m=`@WORKBENCH:AI 估计`,h=`@WORKBENCH:百分比是主 Agent 根据任务思考与工具调用推测的大致估计,不是精确进度`;t();var g=1e5;function _(){let t=n(!0),o=n([]),l=n([]),u=n(g),d=n([]),f=n(null),p=n(!1),m=n(!1),h=n(!1),_=n(``),v=n({}),y=n([]),b=n(!1),x=n(!1),S=n(s);async function C(n=!1){try{let i=await fetch(`/api/workbench/orchestrator`,{cache:`no-store`}).then(e=>e.json());return i?.success?(t.value=i.active!==!1,Number.isInteger(i.maxInstructionChars)&&i.maxInstructionChars>0&&(u.value=i.maxInstructionChars),o.value=Array.isArray(i.instructions)?i.instructions:[],l.value=Array.isArray(i.activity)?i.activity:[],d.value=Array.isArray(i.running)?i.running:[],a().setRunning(d.value.length),f.value=i.updatedAt||null,_.value=typeof i.defaultPrompt==`string`?i.defaultPrompt:``,v.value=i.projectPrompts&&typeof i.projectPrompts==`object`?i.projectPrompts:{},S.value=c(i.reportIntervalMs),p.value=!0,!0):(n||e.error(i?.error||r(`@WORKBENCH:读取编排状态失败`)),!1)}catch(t){return n||e.error(r(`@WORKBENCH:网络错误: `)+(t?.message||t)),!1}}async function w(t=!1){if(b.value)return!1;b.value=!0;try{let n=await fetch(`/api/workbench/orchestrator/reports`,{cache:`no-store`}).then(e=>e.json());return n?.success?(y.value=Array.isArray(n.reports)?n.reports:[],!0):(t||e.error(n?.error||r(`@WORKBENCH:读取进度报告失败`)),!1)}catch(n){return t||e.error(r(`@WORKBENCH:网络错误: `)+(n?.message||n)),!1}finally{b.value=!1}}async function T(){if(x.value)return null;x.value=!0;try{let t=String(i().locale||``).startsWith(`en`)?`en`:`zh`,n=await fetch(`/api/workbench/orchestrator/report`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({locale:t})}).then(e=>e.json());return n?.success?n.report?(y.value=[n.report,...y.value].slice(0,20),n.report):(e.info(r(`@WORKBENCH:当前没有正在执行的任务,没有可汇报的进度`)),null):(e.error(n?.error||r(`@WORKBENCH:生成进度报告失败`)),null)}catch(t){return e.error(r(`@WORKBENCH:网络错误: `)+(t?.message||t)),null}finally{x.value=!1}}async function E(t){try{let n=await fetch(`/api/workbench/orchestrator/report-interval`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({intervalMs:t})}).then(e=>e.json());return n?.success?(S.value=c(n.reportIntervalMs),!0):(e.error(n?.error||r(`@WORKBENCH:保存失败`)),!1)}catch(t){return e.error(r(`@WORKBENCH:网络错误: `)+(t?.message||t)),!1}}async function D(t){try{let n=await fetch(`/api/workbench/orchestrator/default-prompt`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({prompt:t})}).then(e=>e.json());return n?.success?(_.value=typeof n.defaultPrompt==`string`?n.defaultPrompt:``,e.success(r(`@WORKBENCH:已保存全局预设提示词`)),!0):(e.error(n?.error||r(`@WORKBENCH:保存失败`)),!1)}catch(t){return e.error(r(`@WORKBENCH:网络错误: `)+(t?.message||t)),!1}}async function O(t,n){try{let i=await fetch(`/api/workbench/orchestrator/project-prompt`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({projectPath:t,prompt:n})}).then(e=>e.json());return i?.success?(v.value=i.projectPrompts&&typeof i.projectPrompts==`object`?i.projectPrompts:{},e.success(r(`@WORKBENCH:已保存项目预设提示词`)),!0):(e.error(i?.error||r(`@WORKBENCH:保存失败`)),!1)}catch(t){return e.error(r(`@WORKBENCH:网络错误: `)+(t?.message||t)),!1}}async function k(n){if(m.value)return!1;let i=t.value;t.value=n,m.value=!0;try{let a=await fetch(`/api/workbench/orchestrator/state`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({active:n})}).then(e=>e.json());return a?.success?(t.value=a.active!==!1,e.success(t.value?r(`@WORKBENCH:已恢复调度`):r(`@WORKBENCH:已暂停调度,派发将只建任务不执行`)),!0):(t.value=i,e.error(a?.error||r(`@WORKBENCH:切换调度状态失败`)),!1)}catch(n){return t.value=i,e.error(r(`@WORKBENCH:网络错误: `)+(n?.message||n)),!1}finally{m.value=!1}}async function A(t){if(h.value)return null;h.value=!0;try{let n=await fetch(`/api/workbench/orchestrator/dispatch`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({text:t.text,projectPath:t.projectPath||``,autoRun:t.autoRun!==!1,useDefaultPrompt:t.useDefaultPrompt!==!1,executor:t.executor,attachments:(t.attachments||[]).map(e=>({id:e.id,ext:e.ext,originalName:e.originalName}))})}).then(e=>e.json());return n?.success?(await C(!0),{task:n.task||null,ran:!!n.ran}):(e.error(n?.error||r(`@WORKBENCH:派发失败`)),null)}catch(t){return e.error(r(`@WORKBENCH:网络错误: `)+(t?.message||t)),null}finally{h.value=!1}}return{active:t,instructions:o,activity:l,running:d,updatedAt:f,loaded:p,togglingSchedule:m,dispatching:h,maxInstructionChars:u,defaultPrompt:_,projectPrompts:v,reports:y,loadingReports:b,generatingReport:x,reportIntervalMs:S,loadOrchestrator:C,setSchedulingActive:k,dispatch:A,saveDefaultPrompt:D,saveProjectPrompt:O,loadReports:w,generateReport:T,setReportInterval:E}}export{d as a,f as c,m as i,p as l,o as n,l as o,h as r,u as s,_ as t};
1
+ import"./rolldown-runtime-C0FnF6B9.js";import{i as e,mr as t,xr as n}from"./element-plus-J45pKUrE.js";import{n as r}from"./_plugin-vue_export-helper-Csn085FF.js";import{t as i}from"./configStore-DOaPZ6Mq.js";import{m as a}from"./index-DQ82h1aq.js";var o=[0,5,10,15,30,60].map(e=>e*60*1e3),s=6e5;function c(e){let t=Number(e);return o.includes(t)?t:s}function l(e){return e?e>=36e5?`@WORKBENCH:每 {n} 小时报告`:`@WORKBENCH:每 {n} 分钟报告`:`@WORKBENCH:关闭自动报告`}function u(e){return e?{n:Math.round(e>=36e5?e/36e5:e/6e4)}:{}}function d(e){switch(e){case`NO_MODEL`:return`@WORKBENCH:没有可用的 AI 模型,只记录了任务事实`;case`LLM_TIMEOUT`:return`@WORKBENCH:生成超时,只记录了任务事实`;case`LLM_EMPTY`:return`@WORKBENCH:模型没有返回正文,只记录了任务事实`;case`LLM_FAILED`:return`@WORKBENCH:生成失败,只记录了任务事实`;default:return`@WORKBENCH:生成失败,只记录了任务事实`}}function f(e){if(e==null||e===``)return null;let t=Number(e);if(!Number.isFinite(t))return null;let n=Math.round(t);return n>=0&&n<=100?n:null}function p(e){return typeof e!=`number`||!Number.isFinite(e)||e<=0?null:Math.floor(e)}var m=`@WORKBENCH:AI 估计`,h=`@WORKBENCH:百分比是主 Agent 根据任务思考与工具调用推测的大致估计,不是精确进度`;t();var g=1e5;function _(){let t=n(!0),o=n([]),l=n([]),u=n(g),d=n([]),f=n(null),p=n(!1),m=n(!1),h=n(!1),_=n(``),v=n({}),y=n([]),b=n(!1),x=n(!1),S=n(s);async function C(n=!1){try{let i=await fetch(`/api/workbench/orchestrator`,{cache:`no-store`}).then(e=>e.json());return i?.success?(t.value=i.active!==!1,Number.isInteger(i.maxInstructionChars)&&i.maxInstructionChars>0&&(u.value=i.maxInstructionChars),o.value=Array.isArray(i.instructions)?i.instructions:[],l.value=Array.isArray(i.activity)?i.activity:[],d.value=Array.isArray(i.running)?i.running:[],a().setRunning(d.value.length),f.value=i.updatedAt||null,_.value=typeof i.defaultPrompt==`string`?i.defaultPrompt:``,v.value=i.projectPrompts&&typeof i.projectPrompts==`object`?i.projectPrompts:{},S.value=c(i.reportIntervalMs),p.value=!0,!0):(n||e.error(i?.error||r(`@WORKBENCH:读取编排状态失败`)),!1)}catch(t){return n||e.error(r(`@WORKBENCH:网络错误: `)+(t?.message||t)),!1}}async function w(t=!1){if(b.value)return!1;b.value=!0;try{let n=await fetch(`/api/workbench/orchestrator/reports`,{cache:`no-store`}).then(e=>e.json());return n?.success?(y.value=Array.isArray(n.reports)?n.reports:[],!0):(t||e.error(n?.error||r(`@WORKBENCH:读取进度报告失败`)),!1)}catch(n){return t||e.error(r(`@WORKBENCH:网络错误: `)+(n?.message||n)),!1}finally{b.value=!1}}async function T(){if(x.value)return null;x.value=!0;try{let t=String(i().locale||``).startsWith(`en`)?`en`:`zh`,n=await fetch(`/api/workbench/orchestrator/report`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({locale:t})}).then(e=>e.json());return n?.success?n.report?(y.value=[n.report,...y.value].slice(0,20),n.report):(e.info(r(`@WORKBENCH:当前没有正在执行的任务,没有可汇报的进度`)),null):(e.error(n?.error||r(`@WORKBENCH:生成进度报告失败`)),null)}catch(t){return e.error(r(`@WORKBENCH:网络错误: `)+(t?.message||t)),null}finally{x.value=!1}}async function E(t){try{let n=await fetch(`/api/workbench/orchestrator/report-interval`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({intervalMs:t})}).then(e=>e.json());return n?.success?(S.value=c(n.reportIntervalMs),!0):(e.error(n?.error||r(`@WORKBENCH:保存失败`)),!1)}catch(t){return e.error(r(`@WORKBENCH:网络错误: `)+(t?.message||t)),!1}}async function D(t){try{let n=await fetch(`/api/workbench/orchestrator/default-prompt`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({prompt:t})}).then(e=>e.json());return n?.success?(_.value=typeof n.defaultPrompt==`string`?n.defaultPrompt:``,e.success(r(`@WORKBENCH:已保存全局预设提示词`)),!0):(e.error(n?.error||r(`@WORKBENCH:保存失败`)),!1)}catch(t){return e.error(r(`@WORKBENCH:网络错误: `)+(t?.message||t)),!1}}async function O(t,n){try{let i=await fetch(`/api/workbench/orchestrator/project-prompt`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({projectPath:t,prompt:n})}).then(e=>e.json());return i?.success?(v.value=i.projectPrompts&&typeof i.projectPrompts==`object`?i.projectPrompts:{},e.success(r(`@WORKBENCH:已保存项目预设提示词`)),!0):(e.error(i?.error||r(`@WORKBENCH:保存失败`)),!1)}catch(t){return e.error(r(`@WORKBENCH:网络错误: `)+(t?.message||t)),!1}}async function k(n){if(m.value)return!1;let i=t.value;t.value=n,m.value=!0;try{let a=await fetch(`/api/workbench/orchestrator/state`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({active:n})}).then(e=>e.json());return a?.success?(t.value=a.active!==!1,e.success(t.value?r(`@WORKBENCH:已恢复调度`):r(`@WORKBENCH:已暂停调度,派发将只建任务不执行`)),!0):(t.value=i,e.error(a?.error||r(`@WORKBENCH:切换调度状态失败`)),!1)}catch(n){return t.value=i,e.error(r(`@WORKBENCH:网络错误: `)+(n?.message||n)),!1}finally{m.value=!1}}async function A(t){if(h.value)return null;h.value=!0;try{let n=await fetch(`/api/workbench/orchestrator/dispatch`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({text:t.text,projectPath:t.projectPath||``,autoRun:t.autoRun!==!1,useDefaultPrompt:t.useDefaultPrompt!==!1,executor:t.executor,attachments:(t.attachments||[]).map(e=>({id:e.id,ext:e.ext,originalName:e.originalName}))})}).then(e=>e.json());return n?.success?(await C(!0),{task:n.task||null,ran:!!n.ran}):(e.error(n?.error||r(`@WORKBENCH:派发失败`)),null)}catch(t){return e.error(r(`@WORKBENCH:网络错误: `)+(t?.message||t)),null}finally{h.value=!1}}return{active:t,instructions:o,activity:l,running:d,updatedAt:f,loaded:p,togglingSchedule:m,dispatching:h,maxInstructionChars:u,defaultPrompt:_,projectPrompts:v,reports:y,loadingReports:b,generatingReport:x,reportIntervalMs:S,loadOrchestrator:C,setSchedulingActive:k,dispatch:A,saveDefaultPrompt:D,saveProjectPrompt:O,loadReports:w,generateReport:T,setReportInterval:E}}export{d as a,f as c,m as i,p as l,o as n,l as o,h as r,u as s,_ as t};
@@ -10,7 +10,7 @@
10
10
  <meta name="theme-color" content="#141820" media="(prefers-color-scheme: dark)" />
11
11
  <title>Zen GitSync</title>
12
12
  <!-- 字体改为自托管(@font-face 见 src/main.css),不再依赖 Google Fonts 外链 -->
13
- <script type="module" crossorigin src="/assets/index-C7Y9odvZ.js"></script>
13
+ <script type="module" crossorigin src="/assets/index-DQ82h1aq.js"></script>
14
14
  <link rel="modulepreload" crossorigin href="/assets/rolldown-runtime-C0FnF6B9.js">
15
15
  <link rel="modulepreload" crossorigin href="/assets/dagre-DPkLmI0C.js">
16
16
  <link rel="modulepreload" crossorigin href="/assets/element-plus-J45pKUrE.js">
@@ -33,6 +33,7 @@ import { HttpError } from '../../utils/asyncRoute.js'
33
33
  import { assertGitRemoteUrl } from '../../utils/gitArgs.js'
34
34
  import { rememberRepo } from '../../utils/localRepoScan.js'
35
35
  import { augmentEnvPath } from '../../../../utils/shellPath.js'
36
+ import { repoNameFromUrl } from '../../../../utils/gitRepoName.js'
36
37
 
37
38
  const execFileAsync = promisify(execFile)
38
39
 
@@ -40,19 +41,10 @@ const execFileAsync = promisify(execFile)
40
41
  const CLONE_TIMEOUT_MS = 180_000
41
42
  const MAX_BUFFER = 10 * 1024 * 1024
42
43
 
43
- /**
44
- * 从远程地址里取出仓库目录名(clone 出来的子目录就用它)。
45
- * git@github.com:owner/repo.git → repo
46
- * https://gitee.com/owner/repo.git → repo
47
- * https://github.com/owner/repo/ → repo
48
- * 取不出来返回空串,调用方兜底成 repository。
49
- */
50
- export function repoNameFromUrl(url) {
51
- const s = String(url || '').trim().replace(/\/+$/, '')
52
- if (!s) return ''
53
- const tail = s.split(/[/:]/).filter(Boolean).pop() || ''
54
- return tail.replace(/\.git$/i, '')
55
- }
44
+ // repoNameFromUrl 的实现已挪到 utils/gitRepoName.js —— g ai 的 run_command 后处理
45
+ // 也要用它推导 git clone 的落点,两份同规则实现迟早分叉。这里保留 re-export,
46
+ // 既有调用点(clone.test.js)不必改。
47
+ export { repoNameFromUrl }
56
48
 
57
49
  /**
58
50
  * 校验父目录:必须是**已存在的目录**的绝对路径。
@@ -347,6 +347,9 @@ ${isWin ? `- This is Windows. The following Unix commands do NOT exist here:
347
347
  // - askUser: (args, meta) => Promise<string> 等待用户回答
348
348
  // - listProjects: (args) => Promise<string> list_projects 工具的数据源
349
349
  // (由 agentRoutes 注入:最近目录/tasks.json/看板统计只有 GUI 侧拿得到)
350
+ // - registerProject: (dir) => Promise<void> register_project 工具的实现,以及
351
+ // run_command 里"建了仓库就顺手登记进常用目录"那一步的落点(同一个注入、同一个
352
+ // 效果)。不注入 = 没有登记能力(CLI 与测试环境),对应工具回一句可照做的说明。
350
353
  // - dispatchTask: (payload) => Promise<string> dispatch_task 工具的实现 —— 派发一条
351
354
  // 工作台任务。同样由 agentRoutes 注入,但**只在主 Agent 控制台发起的对话里**注入
352
355
  // (别的入口不注入 = 那个入口没有派发能力,工具会回一句可照做的 unavailable)
@@ -371,8 +374,8 @@ ${isWin ? `- This is Windows. The following Unix commands do NOT exist here:
371
374
  // 分流、摘要注进请求副本(agentParity.test.js 有守卫)。
372
375
  //
373
376
  // 返回: { aborted: boolean }
374
- export async function runAgentTurn({ session, model, userMessage, images = [], cwd, locale, openFilePath, attachments = [], dirStatusBlock = '', signal, send, onChild, askUser, listProjects, dispatchTask, getContextBlock, requestBudget = null, resume = false, streamFn = streamChatOnce, promptSection }) {
375
- const ctx = { cwd, locale, onChild, askUser, listProjects, dispatchTask };
377
+ export async function runAgentTurn({ session, model, userMessage, images = [], cwd, locale, openFilePath, attachments = [], dirStatusBlock = '', signal, send, onChild, askUser, listProjects, registerProject, dispatchTask, getContextBlock, requestBudget = null, resume = false, streamFn = streamChatOnce, promptSection }) {
378
+ const ctx = { cwd, locale, onChild, askUser, listProjects, registerProject, dispatchTask };
376
379
 
377
380
  // 确保 session.messages 存在
378
381
  if (!Array.isArray(session.messages)) session.messages = [];
@@ -201,6 +201,21 @@ export function registerAgentRoutes({ app, getCurrentProjectPath, configManager,
201
201
  // 不给它加缓存:agent 一轮里最多问一两次,而"项目状态"本来就要现读才准。
202
202
  const listProjects = createProjectListProvider({ configManager, getCurrentProjectPath });
203
203
 
204
+ // 把目录登记进「常用目录」(config.json 的 recentDirectories)。register_project 工具
205
+ // 与 run_command 里"建了仓库就顺手登记"那一步共用它 —— 智能体建/克隆完新项目,
206
+ // 用户下次在「切换工作目录」弹窗里就能直接看到,不必重启 GUI 或自己翻路径。
207
+ //
208
+ // 失败只 warn 不外抛:登记是锦上添花,不能让一条命令/一次工具调用因为写配置失败而报错。
209
+ const registerProject = (configManager && typeof configManager.saveRecentDirectory === 'function')
210
+ ? async (dir) => {
211
+ try {
212
+ await configManager.saveRecentDirectory(dir);
213
+ } catch (err) {
214
+ logger.warn(`[agent] 登记常用目录失败 ${dir}: ${err?.message || err}`);
215
+ }
216
+ }
217
+ : undefined;
218
+
204
219
  // dispatch_task 的实现 —— 与 POST /api/workbench/orchestrator/dispatch 共用**同一份**
205
220
  // 派发实现(见 dispatchInstruction.js 的文件头):落点怎么判、预设提示词附加哪一级、
206
221
  // 指令流水记什么、执行器怎么回落,只有一套。这里只是把同一套依赖再绑一次
@@ -231,6 +246,7 @@ export function registerAgentRoutes({ app, getCurrentProjectPath, configManager,
231
246
  configManager,
232
247
  getCurrentProjectPath,
233
248
  listProjects,
249
+ registerProject,
234
250
  dispatchTask: scheduleDispatchTask,
235
251
  getContextBlock,
236
252
  });
@@ -743,6 +759,7 @@ export function registerAgentRoutes({ app, getCurrentProjectPath, configManager,
743
759
  }),
744
760
  dispatchTask,
745
761
  listProjects,
762
+ registerProject,
746
763
  getContextBlock,
747
764
  // 每轮请求的上下文预算(解析结果)。agentChat 拿它调 prepareRequestMessages,
748
765
  // 与 CLI turn.js 同一条口径。
@@ -548,10 +548,20 @@ export function registerWorkbenchRoutes({
548
548
  app.post('/api/workbench/jobs/:id/continue', asyncRoute(async (req, res) => {
549
549
  const userMessage = String(req.body?.userMessage || '').trim();
550
550
  if (!userMessage) throw new HttpError(400, 'userMessage 不能为空');
551
- const prevJob = jobs.get(req.params.id);
551
+ // 内存里没有就退回「磁盘历史 ∪ 别的实例正在跑」——续接要用到的三样东西
552
+ // (claudeSessionId / agent / taskId)全在持久化记录里,**不依赖本进程的 child 句柄**
553
+ // (那是 §14 取消路径非有不可的东西,所以那条 404 是对的,这条不是)。
554
+ // 只认内存的话:在 A 窗口跑完、到 B 窗口接着聊,B 的看板明明列着这条记录,
555
+ // 一发送却弹 "job 不存在" —— 2026-10-12 用户实测就是这个(本机同时开着 4 个实例)。
556
+ // 与 GET /jobs/:id、/jobs/:id/image 同一个口径。
557
+ await refreshJobsFromDisk();
558
+ const prevJob = jobs.get(req.params.id) || mergedJobs().get(req.params.id);
552
559
  if (!prevJob) throw new HttpError(404, 'job 不存在');
553
560
  if (prevJob.status === 'running' || prevJob.status === 'pending') {
554
- throw new HttpError(400, '上一轮还在执行,请等结束后再续接');
561
+ // 这一轮在**别的**实例里跑着:本进程停不了也接不上,别让用户以为是"上一轮"没结束
562
+ throw new HttpError(400, jobs.has(prevJob.id)
563
+ ? '上一轮还在执行,请等结束后再续接'
564
+ : '这个任务正在另一个 g ui 实例里执行,请等它结束后再续接');
555
565
  }
556
566
  if (!prevJob.claudeSessionId) {
557
567
  throw new HttpError(400, '无法续接:会话标识未捕获');
@@ -559,10 +569,12 @@ export function registerWorkbenchRoutes({
559
569
  const data = await readJson(TASKS_FILE, { tasks: [] });
560
570
  const task = (data.tasks || []).find(t => t.id === prevJob.taskId);
561
571
  if (!task) throw new HttpError(404, '所属任务不存在');
562
- // 计算续接轮次号
572
+ // 计算续接轮次号。**必须走合并表**:轮次是跨实例共享的编号,只看本进程内存的话,
573
+ // 另一个实例已经续过 #1 了,这边还会再发一个 #1 出去(两条 subId 撞车,前端按 subId
574
+ // 归组时那两轮会混在一起)。
563
575
  const subIdPrefix = `${task.id}__simple`;
564
576
  let maxRound = 0;
565
- for (const j of jobs.values()) {
577
+ for (const j of mergedJobs().values()) {
566
578
  if (j.taskId !== task.id) continue;
567
579
  if (j.subId === subIdPrefix) continue;
568
580
  const m = j.subId && j.subId.match(/__simple__r(\d+)$/);
@@ -64,6 +64,7 @@ export const MAX_RUN_MS = 60 * 60_000;
64
64
  * @param {object} deps.configManager 读全局模型配置(与对话链路同源)
65
65
  * @param {() => string} [deps.getCurrentProjectPath]
66
66
  * @param {Function} [deps.listProjects] list_projects 工具的实现(GUI 侧注入)
67
+ * @param {Function} [deps.registerProject] register_project / 建仓库后登记常用目录的实现
67
68
  * @param {Function} [deps.dispatchTask] dispatch_task 工具的实现(已绑定默认参数)
68
69
  * @param {Function} [deps.getContextBlock] 工作区状态快照
69
70
  * @param {Function} [deps.runTurn] 执行一轮对话(默认 runAgentTurn;测试注入替身)
@@ -74,6 +75,7 @@ export function createScheduler({
74
75
  configManager,
75
76
  getCurrentProjectPath,
76
77
  listProjects,
78
+ registerProject,
77
79
  dispatchTask,
78
80
  getContextBlock,
79
81
  runTurn = runAgentTurn,
@@ -221,6 +223,7 @@ export function createScheduler({
221
223
  + '请基于已有信息自行判断并继续;如果这一步必须由人决定,跳过它,'
222
224
  + '并在最终答复里明确说明需要用户确认什么。',
223
225
  listProjects,
226
+ registerProject,
224
227
  dispatchTask,
225
228
  getContextBlock,
226
229
  requestBudget,
@@ -0,0 +1,33 @@
1
+ // Copyright 2026 xz333221
2
+ //
3
+ // Licensed under the Apache License, Version 2.0 (the "License");
4
+ // you may not use this file except in compliance with the License.
5
+ // You may obtain a copy of the License at
6
+ //
7
+ // http://www.apache.org/licenses/LICENSE-2.0
8
+ //
9
+ // Unless required by applicable law or agreed to in writing, software
10
+ // distributed under the License is distributed on an "AS IS" BASIS,
11
+ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ // See the License for the specific language governing permissions and
13
+ // limitations under the License.
14
+ //
15
+ // 「从远程地址推导仓库目录名」的唯一实现。
16
+ //
17
+ // 两处调用方:GUI 的克隆路由(/api/clone 决定 clone 出来的子目录名)与 g ai 的
18
+ // run_command 后处理(把 git clone 的落点登记进常用目录时,地址里没写目标目录,
19
+ // 只能按仓库名猜)。两边口径必须一致 —— 否则"认为克隆到了 A、实际在 B"。
20
+
21
+ /**
22
+ * 从远程地址里取出仓库目录名(clone 出来的子目录就用它)。
23
+ * git@github.com:owner/repo.git → repo
24
+ * https://gitee.com/owner/repo.git → repo
25
+ * https://github.com/owner/repo/ → repo
26
+ * 取不出来返回空串,调用方兜底成 repository。
27
+ */
28
+ export function repoNameFromUrl(url) {
29
+ const s = String(url || '').trim().replace(/\/+$/, '')
30
+ if (!s) return ''
31
+ const tail = s.split(/[/:]/).filter(Boolean).pop() || ''
32
+ return tail.replace(/\.git$/i, '')
33
+ }
@@ -1 +0,0 @@
1
- import"./rolldown-runtime-C0FnF6B9.js";import{$r as e,$t as t,An as n,At as r,Ct as i,Dn as a,Dr as o,En as s,Fn as c,Fr as l,Gn as u,Gt as d,Ht as f,J as p,Jn as m,Jr as h,Jt as g,Ln as _,M as v,On as y,Pn as b,Qn as x,Sn as S,Tt as C,Vn as w,W as ee,Xn as T,Xr as E,Yt as D,_n as O,a as k,an as te,dn as A,er as j,et as M,gn as N,i as P,j as ne,kn as F,kt as I,lr as L,lt as R,mn as z,mr as B,mt as re,r as V,rr as H,sr as U,st as W,tt as G,ur as K,vn as q,xr as J,yr as ie}from"./element-plus-J45pKUrE.js";import{a as Y,r as ae}from"./vendor-B3NyhlYR.js";import{n as X,t as Z}from"./_plugin-vue_export-helper-Csn085FF.js";import{t as oe}from"./configStore-DOaPZ6Mq.js";import{t as se}from"./CommonDialog-j_53ORvj.js";import{G as Q,K as ce,y as le}from"./index-C7Y9odvZ.js";import{a as ue,c as de,i as fe,l as pe,m as me,n as he,o as ge,r as _e,s as ve,t as ye,u as be}from"./agentConversations-DyzaxUXm.js";import{c as xe,s as Se,t as Ce}from"./CopySessionButton-y5Rzmact.js";import{t as we}from"./useOrchestrator-C236G5P5.js";w(),B(),A(),l();var Te={class:`marketplace-panel`},Ee={class:`mp-toolbar`},De={class:`mp-search`},Oe=[`placeholder`],ke={class:`mp-toolbar-sub`},Ae={class:`mp-target-hint`},je={class:`mp-source-filter`},Me=[`onClick`],Ne={class:`mp-body`},Pe={class:`mp-group-header`},Fe={class:`mp-group-title`},Ie={key:0,class:`mp-group-count`},Le={key:1,class:`mp-group-error`},Re=[`href`,`title`],ze={key:0,class:`mp-grid`},Be={class:`mp-card-head`},Ve=[`title`],He={key:0,class:`mp-card-metric`},Ue=[`title`],We={class:`mp-card-meta`},Ge=[`title`],Ke=[`title`],qe={key:2,class:`mp-tag remote`},Je={class:`mp-card-foot`},Ye=[`href`],Xe={key:1,class:`mp-installed-chip`},Ze=[`disabled`,`onClick`],Qe={key:3,class:`mp-not-installable`},$e={key:1,class:`mp-empty`},et={key:0,class:`mp-group installed`},tt={class:`mp-group-header`},nt={class:`mp-group-title`},rt={class:`mp-group-count`},it={key:0,class:`mp-installed-block`},at={class:`mp-installed-target`},ot={class:`mp-installed-list`},st=[`title`],ct=[`title`],lt={key:1,class:`mp-meta-pkg`},ut={key:2,class:`mp-tag warn`},dt=[`disabled`,`title`,`onClick`],ft=[`disabled`,`onClick`],pt={key:1,class:`mp-empty all`},mt={key:0,class:`mkt-form`},ht={class:`mkt-form-name`},gt=[`onUpdate:modelValue`,`placeholder`],_t={key:0,class:`mkt-field`},vt={class:`mkt-hint`},yt=Z(_({__name:`MarketplacePanel`,props:{type:{}},setup(t){let r=t,l=oe(),u=J([]),m=J([]),g=J(!1),_=J(``),C=J(``),w=J([]),T=J(`project`),E=J(new Set),O=J(new Set),A=J(new Set),M=s(()=>l.currentDirectory||``),N=null;async function z(){if(!g.value){g.value=!0;try{let e=new URLSearchParams({type:r.type,cwd:M.value});C.value&&e.set(`q`,C.value),w.value.length&&e.set(`sources`,w.value.join(`,`));let t=await(await fetch(`/api/agent/marketplace/catalog?${e}`)).json();t?.success?(u.value=t.groups||[],m.value=t.installed||[]):P.error(t?.error||X(`@MKT:加载失败`))}catch{P.error(X(`@MKT:加载失败`))}finally{g.value=!1}}}U(_,e=>{N&&clearTimeout(N),N=setTimeout(()=>{C.value=e.trim(),z()},400)}),U(w,()=>z()),U(()=>r.type,()=>{w.value=[],C.value=``,_.value=``,z()}),U(M,()=>z()),z();let B=s(()=>{let e=M.value?M.value.split(/[\\/]/).filter(Boolean).pop():``;return T.value===`project`?e||X(`@MKT:当前项目`):X(`@MKT:g ai 智能体`)});function H(e){return e.stars?`${W(e.stars)} ★`:e.downloads?`${W(e.downloads)} ${X(`@MKT:周下载`)}`:e.uses?`${W(e.uses)} ${X(`@MKT:次使用`)}`:``}function W(e){return e>=1e3?`${(e/1e3).toFixed(e>=1e4?0:1)}k`:String(e)}function Y(e){return`${e.id}`}function ae(e){return E.value.has(Y(e))}let Z=s(()=>{let e={project:[],global:[]};for(let t of m.value)(e[t.target]||=[]).push(t);return e}),Q=ie({visible:!1,item:null,env:{},args:``});function ce(e){return r.type===`mcp`&&(!!e.envKeys?.length||!!e.args?.length)}function le(e){Q.item=e,Q.env=Object.fromEntries((e.envKeys||[]).map(e=>[e,``])),Q.args=(e.args||[]).join(` `),Q.visible=!0}function ue(){let e=Q.item;if(Q.visible=!1,!e)return;let t=Object.fromEntries(Object.entries(Q.env).filter(([,e])=>e.trim()!==``)),n=Q.args.trim()?Q.args.trim().match(/(?:[^\s"]+|"[^"]*")+/g)?.map(e=>e.replace(/^"|"$/g,``))??void 0:void 0;fe(e,{env:t,...n?{args:n}:{}})}async function de(e){if(!e.installed||await pe(e)){if(ce(e)){le(e);return}await fe(e,{})}}async function fe(e,t){let n=Y(e);E.value.add(n);try{let n=await fetch(`/api/agent/marketplace/install`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({type:r.type,target:T.value,cwd:M.value,item:{...e,...t}})}),i=await n.json().catch(()=>null);if(!n.ok||!i?.success){P.error(i?.error||X(`@MKT:安装失败`));return}i.item?.warning&&P.warning(i.item.warning),i.item?.envKeys?.length?P.warning(`${X(`@MKT:还缺环境变量`)}: ${i.item.envKeys.join(`, `)}`):P.success(X(`@MKT:安装成功`)),await z()}catch{P.error(X(`@MKT:安装失败`))}finally{E.value.delete(n)}}async function pe(e){try{return await V.confirm(`${e.name} ${X(`@MKT:已安装,要重新安装吗?`)}`,X(`@MKT:重新安装`),{confirmButtonText:X(`@MKT:重装`),cancelButtonText:X(`@MKT:取消`),type:`warning`}),!0}catch{return!1}}async function me(e){let t=`${e.target}:${e.id}`;A.value.add(t);try{let t=await fetch(`/api/agent/marketplace/reveal`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({type:r.type,target:e.target,cwd:M.value,id:e.id})}),n=await t.json().catch(()=>null);(!t.ok||!n?.success)&&P.error(n?.error||X(`@MKT:打开失败`))}catch{P.error(X(`@MKT:打开失败`))}finally{A.value.delete(t)}}async function he(e){try{await V.confirm(`${X(`@MKT:确定卸载`)} ${e.name}?`,X(`@MKT:卸载`),{confirmButtonText:X(`@MKT:卸载`),cancelButtonText:X(`@MKT:取消`),type:`warning`})}catch{return}let t=`${e.target}:${e.id}`;O.value.add(t);try{let t=new URLSearchParams({target:e.target,cwd:M.value}),n=await fetch(`/api/agent/marketplace/item/${r.type}/${encodeURIComponent(e.id)}?${t}`,{method:`DELETE`}),i=await n.json().catch(()=>null);if(!n.ok||!i?.success){P.error(i?.error||X(`@MKT:卸载失败`));return}P.success(X(`@MKT:已卸载`)),await z()}catch{P.error(X(`@MKT:卸载失败`))}finally{O.value.delete(t)}}return(r,s)=>{let l=p,C=ne,E=v,M=ee,N=k;return x(),n(`div`,Te,[a(`div`,Ee,[a(`div`,De,[c(l,{class:`mp-search-icon`},{default:L(()=>[c(o(d))]),_:1}),K(a(`input`,{"onUpdate:modelValue":s[0]||=e=>_.value=e,class:`mp-search-input`,type:`text`,placeholder:t.type===`skill`?o(X)(`@MKT:搜索 Skill...`):o(X)(`@MKT:搜索 MCP 服务...`)},null,8,Oe),[[q,_.value]])]),c(E,{modelValue:T.value,"onUpdate:modelValue":s[1]||=e=>T.value=e,size:`small`,class:`mp-target`},{default:L(()=>[c(C,{value:`project`},{default:L(()=>[b(e(o(X)(`@MKT:当前项目`)),1)]),_:1}),c(C,{value:`global`},{default:L(()=>[b(e(o(X)(`@MKT:g ai 智能体`)),1)]),_:1})]),_:1},8,[`modelValue`]),c(M,{content:o(X)(`@MKT:刷新`),placement:`top`,"show-after":300},{default:L(()=>[a(`button`,{class:h([`mp-refresh`,{spinning:g.value}]),onClick:z},[c(l,null,{default:L(()=>[c(o(f))]),_:1})],2)]),_:1},8,[`content`])]),a(`div`,ke,[a(`span`,Ae,[b(e(o(X)(`@MKT:安装到`))+` `,1),a(`b`,null,e(B.value),1)]),a(`div`,je,[(x(!0),n(S,null,j(u.value,t=>(x(),n(`button`,{key:t.id,class:h([`mp-chip`,{active:w.value.includes(t.id)}]),onClick:()=>{let e=w.value.indexOf(t.id);e>=0?w.value.splice(e,1):w.value.push(t.id)}},e(t.label),11,Me))),128)),w.value.length?(x(),n(`button`,{key:0,class:`mp-chip clear`,onClick:s[2]||=e=>w.value=[]},e(o(X)(`@MKT:全部来源`)),1)):F(``,!0)])]),K((x(),n(`div`,Ne,[(x(!0),n(S,null,j(u.value,t=>(x(),n(`section`,{key:t.id,class:`mp-group`},[a(`header`,Pe,[a(`h3`,Fe,e(t.label),1),t.status===`ok`?(x(),n(`span`,Ie,e(t.items.length),1)):(x(),n(`span`,Le,[c(l,null,{default:L(()=>[c(o(te))]),_:1}),b(` `+e(t.error||o(X)(`@MKT:来源不可用`)),1)])),t.homepage?(x(),n(`a`,{key:2,class:`mp-group-link`,href:t.homepage,target:`_blank`,rel:`noopener noreferrer`,title:t.homepage},[c(l,null,{default:L(()=>[c(o(I))]),_:1})],8,Re)):F(``,!0)]),t.status===`ok`&&t.items.length?(x(),n(`div`,ze,[(x(!0),n(S,null,j(t.items,t=>(x(),n(`article`,{key:Y(t),class:`mp-card`},[a(`div`,Be,[a(`span`,{class:`mp-card-name`,title:t.name},e(t.name),9,Ve),H(t)?(x(),n(`span`,He,[c(l,null,{default:L(()=>[t.stars?(x(),y(o(D),{key:0})):(x(),y(o(re),{key:1}))]),_:2},1024),b(` `+e(H(t)),1)])):F(``,!0)]),a(`p`,{class:`mp-card-desc`,title:t.description},e(t.description||o(X)(`@MKT:暂无描述`)),9,Ue),a(`div`,We,[t.package?(x(),n(`code`,{key:0,class:`mp-meta-pkg`,title:t.package},e(t.package),9,Ge)):t.repository?(x(),n(`span`,{key:1,class:`mp-meta-repo`,title:t.repository+(t.subpath?` · `+t.subpath:``)},[b(e(t.repository),1),t.subpath?(x(),n(S,{key:0},[b(` · `+e(t.subpath),1)],64)):F(``,!0)],8,Ke)):F(``,!0),t.transport===`remote`?(x(),n(`span`,qe,e(o(X)(`@MKT:远程服务`)),1)):F(``,!0),(x(!0),n(S,null,j((t.tags||[]).slice(0,2),t=>(x(),n(`span`,{key:t,class:`mp-tag`},e(t),1))),128))]),a(`div`,Je,[t.upstream?(x(),n(`a`,{key:0,class:`mp-card-link`,href:t.upstream,target:`_blank`,rel:`noopener noreferrer`},e(o(X)(`@MKT:查看来源`)),9,Ye)):F(``,!0),s[6]||=a(`span`,{class:`mp-foot-spacer`},null,-1),t.installed?(x(),n(`span`,Xe,[c(l,null,{default:L(()=>[c(o(G))]),_:1}),b(e(o(X)(`@MKT:已安装`)),1)])):t.installable===!1?(x(),n(`span`,Qe,e(o(X)(`@MKT:暂不支持一键安装`)),1)):(x(),n(`button`,{key:2,class:`mp-install-btn`,disabled:ae(t),onClick:e=>de(t)},e(ae(t)?o(X)(`@MKT:安装中...`):o(X)(`@MKT:安装`)),9,Ze))])]))),128))])):t.status===`ok`?(x(),n(`div`,$e,e(o(X)(`@MKT:该来源暂无结果`)),1)):F(``,!0)]))),128)),m.value.length?(x(),n(`section`,et,[a(`header`,tt,[a(`h3`,nt,e(o(X)(`@MKT:已安装`)),1),a(`span`,rt,e(m.value.length),1)]),(x(),n(S,null,j([`project`,`global`],t=>a(`div`,{key:t},[Z.value[t]?.length?(x(),n(`div`,it,[a(`div`,at,e(t===`project`?o(X)(`@MKT:当前项目`):o(X)(`@MKT:g ai 智能体`)),1),a(`div`,ot,[(x(!0),n(S,null,j(Z.value[t],r=>(x(),n(`div`,{key:t+r.id,class:`mp-installed-row`},[a(`span`,{class:`mp-installed-name`,title:r.name},e(r.name),9,st),r.id&&r.id!==r.name?(x(),n(`code`,{key:0,class:`mp-installed-id`,title:r.dir||r.file||r.id},e(r.id),9,ct)):F(``,!0),r.package?(x(),n(`code`,lt,e(r.package),1)):F(``,!0),r.requiredEnv?.length?(x(),n(`span`,ut,e(o(X)(`@MKT:待配置`))+`: `+e(r.requiredEnv.join(`, `)),1)):F(``,!0),s[7]||=a(`span`,{class:`mp-foot-spacer`},null,-1),a(`button`,{class:`mp-reveal-btn`,disabled:A.value.has(t+r.id),title:r.dir||r.file||``,onClick:e=>me(r)},[c(l,null,{default:L(()=>[c(o(i))]),_:1}),b(` `+e(o(X)(`@MKT:打开文件夹`)),1)],8,dt),a(`button`,{class:`mp-remove-btn`,disabled:O.value.has(t+r.id),onClick:e=>he(r)},[c(l,null,{default:L(()=>[c(o(R))]),_:1}),b(` `+e(O.value.has(t+r.id)?o(X)(`@MKT:卸载中...`):o(X)(`@MKT:卸载`)),1)],8,ft)]))),128))])])):F(``,!0)])),64))])):F(``,!0),!g.value&&!u.value.length?(x(),n(`div`,pt,e(o(X)(`@MKT:加载失败`)),1)):F(``,!0)])),[[N,g.value]]),c(se,{modelValue:Q.visible,"onUpdate:modelValue":s[5]||=e=>Q.visible=e,title:o(X)(`@MKT:配置 MCP`),width:`460px`,type:`flex`,"close-on-click-modal":!1,"append-to-body":``},{footer:L(()=>[a(`button`,{class:`mkt-cancel`,onClick:s[4]||=e=>Q.visible=!1},e(o(X)(`@MKT:取消`)),1),a(`button`,{class:`mkt-confirm`,onClick:ue},e(o(X)(`@MKT:安装`)),1)]),default:L(()=>[Q.item?(x(),n(`div`,mt,[a(`p`,ht,e(Q.item.name),1),(x(!0),n(S,null,j(Object.keys(Q.env),t=>(x(),n(`div`,{key:t,class:`mkt-field`},[a(`label`,null,e(t),1),K(a(`input`,{"onUpdate:modelValue":e=>Q.env[t]=e,type:`text`,autocomplete:`off`,placeholder:o(X)(`@MKT:环境变量值`),spellcheck:`false`},null,8,gt),[[q,Q.env[t]]])]))),128)),Q.item.args?.length?(x(),n(`div`,_t,[a(`label`,null,e(o(X)(`@MKT:启动参数`)),1),K(a(`input`,{"onUpdate:modelValue":s[3]||=e=>Q.args=e,type:`text`,autocomplete:`off`,spellcheck:`false`},null,512),[[q,Q.args]]),a(`p`,vt,e(o(X)(`@MKT:参数提示`)),1)])):F(``,!0)])):F(``,!0)]),_:1},8,[`modelValue`,`title`])])}}}),[[`__scopeId`,`data-v-536d7952`]]);async function $(e,t){let n=await fetch(e,{headers:{"Content-Type":`application/json`},...t}),r={};try{r=await n.json()}catch{}if(!n.ok||r.success===!1)throw Error(r.error||`请求失败 (${n.status})`);return r}async function bt(){let e=await $(`/api/schedules`);return Array.isArray(e.tasks)?e.tasks:[]}async function xt(e){return(await $(`/api/schedules`,{method:`POST`,body:JSON.stringify(e)})).task}async function St(e,t){return(await $(`/api/schedules/${encodeURIComponent(e)}`,{method:`PUT`,body:JSON.stringify(t)})).task}async function Ct(e){await $(`/api/schedules/${encodeURIComponent(e)}`,{method:`DELETE`})}async function wt(e){await $(`/api/schedules/${encodeURIComponent(e)}/run`,{method:`POST`})}async function Tt(e){await $(`/api/schedules/${encodeURIComponent(e)}/stop`,{method:`POST`})}function Et(e){if(typeof EventSource>`u`)return()=>{};let t=new EventSource(`/api/schedules/events`);return t.onmessage=t=>{try{e(JSON.parse(t.data))}catch{}},()=>t.close()}var Dt=e=>/^\d+$/.test(e)?Number(e):null;function Ot(e){let t=String(e||``).trim(),n=t.split(/\s+/);if(n.length!==5)return{kind:`custom`,raw:t};let[r,i,a,o,s]=n,c=Dt(r),l=Dt(i);if(t===`* * * * *`)return{kind:`every-minute`,raw:t};let u=r.match(/^\*\/(\d+)$/);if(u&&i===`*`&&a===`*`&&o===`*`&&s===`*`)return{kind:`every-n-minutes`,n:Number(u[1]),raw:t};if(c!==null&&i===`*`&&a===`*`&&o===`*`&&s===`*`)return{kind:`hourly`,minute:c,raw:t};if(c!==null&&l!==null&&a===`*`&&o===`*`&&s===`*`)return{kind:`daily`,hour:l,minute:c,raw:t};let d=Dt(s);if(c!==null&&l!==null&&a===`*`&&o===`*`&&d!==null)return{kind:`weekly`,weekday:d%7,hour:l,minute:c,raw:t};let f=Dt(a);return c!==null&&l!==null&&f!==null&&o===`*`&&s===`*`?{kind:`monthly`,day:f,hour:l,minute:c,raw:t}:{kind:`custom`,raw:t}}var kt=e=>String(e).padStart(2,`0`),At=e=>new Date(e.getFullYear(),e.getMonth(),e.getDate()).getTime();function jt(e,t=new Date){if(!e)return{kind:`none`};let n=new Date(e);if(Number.isNaN(n.getTime()))return{kind:`none`};let r=`${kt(n.getHours())}:${kt(n.getMinutes())}`,i=Math.round((At(n)-At(t))/864e5);return i<0?{kind:`date`,date:`${n.getMonth()+1}-${kt(n.getDate())}`,time:r}:i===0?{kind:`today`,time:r}:i===1?{kind:`tomorrow`,time:r}:i<7?{kind:`weekday`,weekday:n.getDay(),time:r}:{kind:`date`,date:`${n.getMonth()+1}-${kt(n.getDate())}`,time:r}}function Mt(e){switch(e){case`ok`:return`ok`;case`error`:case`timed-out`:return`error`;case`skipped-busy`:case`missed`:case`cancelled`:return`skipped`;default:return`pending`}}function Nt(e){let t=Number(e);if(!Number.isFinite(t)||t<0)return``;if(t<1e3)return`<1s`;let n=Math.round(t/1e3);if(n<60)return`${n}s`;let r=Math.floor(n/60);return r<60?`${r}m${kt(n%60)}s`:`${Math.floor(r/60)}h${kt(r%60)}m`}function Pt(e){let t=Math.min(59,Math.max(0,Math.floor(e.minute))),n=Math.min(23,Math.max(0,Math.floor(e.hour))),r=(Math.floor(e.weekday)%7+7)%7;switch(e.freq){case`minutes`:return`*/${Math.min(59,Math.max(1,Math.floor(e.everyMinutes??30)))} * * * *`;case`hourly`:return`${t} * * * *`;case`daily`:return`${t} ${n} * * *`;case`weekly`:return`${t} ${n} * * ${r}`;case`custom`:return String(e.custom||``).trim()}}w(),l(),B(),A();var Ft={class:`schedule-panel`},It={class:`schedule-toolbar`},Lt={class:`schedule-summary`},Rt={key:0,class:`schedule-error`},zt={key:1,class:`schedule-loading`},Bt={key:2,class:`schedule-empty`},Vt={class:`schedule-empty-title`},Ht={class:`schedule-empty-desc`},Ut={key:3,class:`schedule-list`},Wt={class:`schedule-card-body`},Gt={class:`schedule-card-head`},Kt={class:`schedule-name`},qt={key:0,class:`schedule-running`},Jt=[`aria-checked`,`aria-label`,`onClick`],Yt={class:`schedule-card-sub`},Xt={class:`schedule-desc`},Zt=[`onClick`],Qt={class:`schedule-card-side`},$t={class:`schedule-actions`},en=[`disabled`,`onClick`],tn=[`disabled`,`onClick`],nn=[`onClick`],rn=[`onClick`],an={class:`sch-form`},on={class:`sch-field`},sn={class:`sch-field-label`},cn=[`placeholder`],ln={class:`sch-field`},un={class:`sch-field-label`},dn={class:`sch-freq-row`},fn=[`value`],pn={class:`sch-inline-label`},mn=[`value`],hn={class:`sch-inline-label`},gn=[`value`],_n=[`value`],vn=[`value`],yn={class:`sch-inline-label`},bn=[`value`],xn={class:`sch-inline-label`},Sn=[`placeholder`],Cn={class:`sch-hint`},wn={class:`sch-field`},Tn={class:`sch-field-label`},En=[`placeholder`],Dn={class:`sch-field`},On={class:`sch-field-label`},kn=[`placeholder`],An={class:`sch-field`},jn={class:`sch-field-label`},Mn={class:`sch-radio-row`},Nn={class:`sch-radio`},Pn={class:`sch-radio`},Fn={class:`sch-radio`},In={key:0,class:`sch-form-error`},Ln={class:`sch-form-footer`},Rn=[`disabled`],zn={class:`sch-confirm-text`},Bn={class:`sch-form-footer`},Vn=Z(_({__name:`SchedulePanel`,emits:[`open-session`],setup(t,{emit:r}){let i=r,l=oe(),u=J([]),d=J(!0),f=J(``),p=J({}),g=null,_=null;async function v(){try{u.value=await bt(),f.value=``}catch(e){f.value=e?.message||String(e)}finally{d.value=!1}}function y(){_===null&&(_=window.setTimeout(()=>{_=null,v()},150))}T(async()=>{await v(),g=Et(e=>{[`tasks_changed`,`task_started`,`task_finished`,`hello`].includes(e.type)&&y()})}),m(()=>{g?.(),_!==null&&window.clearTimeout(_)});let b=s(()=>{let e=u.value.filter(e=>e.enabled).length,t=u.value.length-e;return u.value.length?X(`@SCHED:{on} 个启用 · {off} 个停用`,{on:e,off:t}):``}),C=[`@SCHED:周日`,`@SCHED:周一`,`@SCHED:周二`,`@SCHED:周三`,`@SCHED:周四`,`@SCHED:周五`,`@SCHED:周六`];function w(e){let t=Ot(e.schedule);switch(t.kind){case`every-minute`:return X(`@SCHED:每分钟`);case`every-n-minutes`:return X(`@SCHED:每 {n} 分钟`,{n:t.n});case`hourly`:return X(`@SCHED:每小时第 {minute} 分钟`,{minute:t.minute});case`daily`:return X(`@SCHED:每天 {time}`,{time:`${String(t.hour).padStart(2,`0`)}:${String(t.minute).padStart(2,`0`)}`});case`weekly`:return X(`@SCHED:每周 {weekday} {time}`,{weekday:X(C[t.weekday]),time:`${String(t.hour).padStart(2,`0`)}:${String(t.minute).padStart(2,`0`)}`});case`monthly`:return X(`@SCHED:每月 {day} 日 {time}`,{day:t.day,time:`${String(t.hour).padStart(2,`0`)}:${String(t.minute).padStart(2,`0`)}`});default:return t.raw}}function ee(e){if(!e.enabled)return X(`@SCHED:已停用`);if(e.running)return X(`@SCHED:运行中...`);let t=jt(e.nextRunAt);switch(t.kind){case`none`:return``;case`today`:return X(`@SCHED:下次 今天 {time}`,{time:t.time});case`tomorrow`:return X(`@SCHED:下次 明天 {time}`,{time:t.time});case`weekday`:return X(`@SCHED:下次 {weekday} {time}`,{weekday:X(C[t.weekday]),time:t.time});case`date`:return X(`@SCHED:下次 {date} {time}`,{date:t.date,time:t.time})}}function E(e){let t=e.lastRun;if(!t)return X(`@SCHED:还没执行过`);switch(t.status){case`ok`:return X(`@SCHED:成功`);case`error`:return X(`@SCHED:失败`);case`timed-out`:return X(`@SCHED:超时中止`);case`skipped-busy`:return X(`@SCHED:已跳过(会话忙)`);case`missed`:return X(`@SCHED:已错过(未运行)`);case`cancelled`:return X(`@SCHED:已停止`);default:return t.status}}function D(e){let t=e.lastRun;if(!t)return X(`@SCHED:还没执行过`);let n=Nt(t.durationMs),r=X(`@SCHED:上次 {status}`,{status:E(e)});return n?`${r} · ${n}`:r}function k(e){return e.lastRun?`is-${Mt(e.lastRun.status)}`:`is-muted`}async function te(e,t){if(!p.value[e.id]){p.value={...p.value,[e.id]:!0};try{await t(),await v()}catch(e){P.error(e?.message||String(e))}finally{let t={...p.value};delete t[e.id],p.value=t}}}function A(e){return te(e,()=>St(e.id,{enabled:!e.enabled}))}function M(e){return te(e,()=>wt(e.id))}function ne(e){return te(e,()=>Tt(e.id))}let I=J(!1),R=J(null);function B(e){R.value=e,I.value=!0}async function re(){let e=R.value;if(e)try{await Ct(e.id),I.value=!1,await v()}catch(e){P.error(e?.message||String(e))}}let V=J(!1),H=J(``),U=J(``),W=J(!1),G=J({name:``,freq:`daily`,everyMinutes:30,minute:0,hour:9,weekday:1,custom:``,cwd:``,prompt:``,onMissed:`run`,enabled:!0}),ie=s(()=>[{value:`minutes`,label:X(`@SCHED:每 N 分钟`)},{value:`hourly`,label:X(`@SCHED:每小时`)},{value:`daily`,label:X(`@SCHED:每天`)},{value:`weekly`,label:X(`@SCHED:每周`)},{value:`custom`,label:X(`@SCHED:自定义 cron`)}]),Y=s(()=>Pt({freq:G.value.freq,everyMinutes:G.value.everyMinutes,minute:G.value.minute,hour:G.value.hour,weekday:G.value.weekday,custom:G.value.custom}));function ae(){G.value={name:``,freq:`daily`,everyMinutes:30,minute:0,hour:9,weekday:1,custom:``,cwd:l.currentDirectory||``,prompt:``,onMissed:`run`,enabled:!0},U.value=``}function Z(){H.value=``,ae(),V.value=!0}function Q(e){H.value=e.id;let t=Ot(e.schedule),n={name:e.name,freq:`custom`,everyMinutes:30,minute:0,hour:9,weekday:1,custom:e.schedule,cwd:e.cwd,prompt:e.prompt,onMissed:e.onMissed===`skip`?`skip`:`run`,enabled:e.enabled};switch(t.kind){case`every-n-minutes`:n.freq=`minutes`,n.everyMinutes=t.n;break;case`hourly`:n.freq=`hourly`,n.minute=t.minute;break;case`daily`:n.freq=`daily`,n.minute=t.minute,n.hour=t.hour;break;case`weekly`:n.freq=`weekly`,n.minute=t.minute,n.hour=t.hour,n.weekday=t.weekday;break;default:n.freq=`custom`}G.value=n,U.value=``,V.value=!0}async function ce(){let e=G.value;if(!e.name.trim()){U.value=X(`@SCHED:任务名不能为空`);return}if(!e.prompt.trim()){U.value=X(`@SCHED:提示词不能为空`);return}let t=Y.value;if(!t){U.value=X(`@SCHED:cron 表达式不能为空`);return}let n={name:e.name.trim(),schedule:t,cwd:e.cwd.trim(),prompt:e.prompt.trim(),enabled:e.enabled,onMissed:e.onMissed};W.value=!0;try{H.value?await St(H.value,n):await xt(n),V.value=!1,await v()}catch(e){U.value=e?.message||String(e)}finally{W.value=!1}}return(t,r)=>(x(),n(`div`,Ft,[a(`div`,It,[a(`span`,Lt,e(b.value),1),a(`button`,{type:`button`,class:`sch-btn sch-btn-primary`,onClick:Z},e(o(X)(`@SCHED:新建任务`)),1)]),f.value?(x(),n(`div`,Rt,e(o(X)(`@SCHED:操作失败:{error}`,{error:f.value})),1)):F(``,!0),d.value?(x(),n(`div`,zt,e(o(X)(`@SCHED:加载中...`)),1)):u.value.length?(x(),n(`div`,Ut,[(x(!0),n(S,null,j(u.value,t=>(x(),n(`article`,{key:t.id,class:h([`schedule-card`,{"is-disabled":!t.enabled,"is-running":!!t.running}])},[a(`div`,Wt,[a(`div`,Gt,[a(`span`,Kt,e(t.name),1),t.running?(x(),n(`span`,qt,e(o(X)(`@SCHED:运行中`)),1)):F(``,!0),a(`button`,{type:`button`,class:h([`sch-switch`,{on:t.enabled}]),role:`switch`,"aria-checked":t.enabled,"aria-label":t.enabled?o(X)(`@SCHED:停用`):o(X)(`@SCHED:启用`),onClick:e=>A(t)},[...r[17]||=[a(`span`,{class:`sch-switch-knob`},null,-1)]],10,Jt)]),a(`div`,Yt,[a(`span`,Xt,e(w(t)),1),r[18]||=a(`span`,{class:`schedule-sep`},`·`,-1),a(`span`,{class:h([`schedule-last`,k(t)])},e(D(t)),3),t.sessionId?(x(),n(`button`,{key:0,type:`button`,class:`sch-link`,onClick:e=>i(`open-session`,t.sessionId)},e(o(X)(`@SCHED:查看会话`)),9,Zt)):F(``,!0)])]),a(`div`,Qt,[a(`div`,{class:h([`schedule-next`,{"is-muted":!t.enabled}])},e(ee(t)),3),a(`div`,$t,[t.running?(x(),n(`button`,{key:0,type:`button`,class:`sch-btn`,disabled:!!p.value[t.id],onClick:e=>ne(t)},e(o(X)(`@SCHED:停止`)),9,en)):(x(),n(`button`,{key:1,type:`button`,class:`sch-btn`,disabled:!!p.value[t.id],onClick:e=>M(t)},e(o(X)(`@SCHED:运行`)),9,tn)),a(`button`,{type:`button`,class:`sch-btn`,onClick:e=>Q(t)},e(o(X)(`@SCHED:编辑`)),9,nn),a(`button`,{type:`button`,class:`sch-btn sch-btn-danger`,onClick:e=>B(t)},e(o(X)(`@SCHED:删除`)),9,rn)])])],2))),128))])):(x(),n(`div`,Bt,[a(`p`,Vt,e(o(X)(`@SCHED:还没有定时任务`)),1),a(`p`,Ht,e(o(X)(`@SCHED:让 g ai 在指定时间自动做事:定时拉代码、定时巡检、定时汇总。也可以在对话里直接说「每天 9 点帮我…」,让 g ai 来创建。`)),1)])),c(se,{modelValue:V.value,"onUpdate:modelValue":r[14]||=e=>V.value=e,title:H.value?o(X)(`@SCHED:编辑任务`):o(X)(`@SCHED:新建任务`),"close-on-click-modal":!1,"append-to-body":!0,size:`medium`,width:`560px`,"z-index":3e6,"custom-class":`schedule-dialog`},{default:L(()=>[a(`div`,an,[a(`label`,on,[a(`span`,sn,e(o(X)(`@SCHED:任务名`)),1),K(a(`input`,{"onUpdate:modelValue":r[0]||=e=>G.value.name=e,class:`sch-input`,type:`text`,placeholder:o(X)(`@SCHED:如:每日拉代码`)},null,8,cn),[[q,G.value.name]])]),a(`div`,ln,[a(`span`,un,e(o(X)(`@SCHED:执行计划`)),1),a(`div`,dn,[K(a(`select`,{"onUpdate:modelValue":r[1]||=e=>G.value.freq=e,class:`sch-input sch-select`},[(x(!0),n(S,null,j(ie.value,t=>(x(),n(`option`,{key:t.value,value:t.value},e(t.label),9,fn))),128))],512),[[O,G.value.freq]]),G.value.freq===`minutes`?(x(),n(S,{key:0},[a(`span`,pn,e(o(X)(`@SCHED:每`)),1),K(a(`select`,{"onUpdate:modelValue":r[2]||=e=>G.value.everyMinutes=e,class:`sch-input sch-select sch-select-sm`},[(x(),n(S,null,j([5,10,15,20,30,60],t=>a(`option`,{key:t,value:t},e(t),9,mn)),64))],512),[[O,G.value.everyMinutes,void 0,{number:!0}]]),a(`span`,hn,e(o(X)(`@SCHED:分钟`)),1)],64)):G.value.freq===`daily`||G.value.freq===`weekly`?(x(),n(S,{key:1},[G.value.freq===`weekly`?K((x(),n(`select`,{key:0,"onUpdate:modelValue":r[3]||=e=>G.value.weekday=e,class:`sch-input sch-select sch-select-sm`},[(x(),n(S,null,j(C,(t,n)=>a(`option`,{key:n,value:n},e(o(X)(t)),9,gn)),64))],512)),[[O,G.value.weekday,void 0,{number:!0}]]):F(``,!0),K(a(`select`,{"onUpdate:modelValue":r[4]||=e=>G.value.hour=e,class:`sch-input sch-select sch-select-sm`},[(x(),n(S,null,j(24,t=>a(`option`,{key:t-1,value:t-1},e(String(t-1).padStart(2,`0`)),9,_n)),64))],512),[[O,G.value.hour,void 0,{number:!0}]]),r[19]||=a(`span`,{class:`sch-inline-label`},`:`,-1),K(a(`select`,{"onUpdate:modelValue":r[5]||=e=>G.value.minute=e,class:`sch-input sch-select sch-select-sm`},[(x(),n(S,null,j(60,t=>a(`option`,{key:t-1,value:t-1},e(String(t-1).padStart(2,`0`)),9,vn)),64))],512),[[O,G.value.minute,void 0,{number:!0}]])],64)):G.value.freq===`hourly`?(x(),n(S,{key:2},[a(`span`,yn,e(o(X)(`@SCHED:第`)),1),K(a(`select`,{"onUpdate:modelValue":r[6]||=e=>G.value.minute=e,class:`sch-input sch-select sch-select-sm`},[(x(),n(S,null,j(60,t=>a(`option`,{key:t-1,value:t-1},e(String(t-1).padStart(2,`0`)),9,bn)),64))],512),[[O,G.value.minute,void 0,{number:!0}]]),a(`span`,xn,e(o(X)(`@SCHED:分钟`)),1)],64)):K((x(),n(`input`,{key:3,"onUpdate:modelValue":r[7]||=e=>G.value.custom=e,class:`sch-input sch-input-cron`,type:`text`,spellcheck:`false`,placeholder:o(X)(`@SCHED:如:0 9 * * 1-5`)},null,8,Sn)),[[q,G.value.custom]])]),a(`span`,Cn,e(o(X)(`@SCHED:cron:{cron}(分 时 日 月 周,本地时间)`,{cron:Y.value||`—`})),1)]),a(`label`,wn,[a(`span`,Tn,e(o(X)(`@SCHED:项目目录`)),1),K(a(`input`,{"onUpdate:modelValue":r[8]||=e=>G.value.cwd=e,class:`sch-input`,type:`text`,spellcheck:`false`,placeholder:o(X)(`@SCHED:任务在该目录下执行(默认当前项目)`)},null,8,En),[[q,G.value.cwd]])]),a(`label`,Dn,[a(`span`,On,e(o(X)(`@SCHED:提示词`)),1),K(a(`textarea`,{"onUpdate:modelValue":r[9]||=e=>G.value.prompt=e,class:`sch-input sch-textarea`,rows:`4`,placeholder:o(X)(`@SCHED:到点后发给 g ai 的完整指令,例如:检查所有仓库远端更新,有变更就 pull;写成一次自足的请求(未来那一轮没有现在的上下文)`)},null,8,kn),[[q,G.value.prompt]])]),a(`div`,An,[a(`span`,jn,e(o(X)(`@SCHED:错过补偿`)),1),a(`div`,Mn,[a(`label`,Nn,[K(a(`input`,{"onUpdate:modelValue":r[10]||=e=>G.value.onMissed=e,type:`radio`,value:`run`},null,512),[[N,G.value.onMissed]]),a(`span`,null,e(o(X)(`@SCHED:补跑一次(g ui 重新运行后)`)),1)]),a(`label`,Pn,[K(a(`input`,{"onUpdate:modelValue":r[11]||=e=>G.value.onMissed=e,type:`radio`,value:`skip`},null,512),[[N,G.value.onMissed]]),a(`span`,null,e(o(X)(`@SCHED:跳过`)),1)]),a(`label`,Fn,[K(a(`input`,{"onUpdate:modelValue":r[12]||=e=>G.value.enabled=e,type:`checkbox`},null,512),[[z,G.value.enabled]]),a(`span`,null,e(o(X)(`@SCHED:创建后启用`)),1)])])]),U.value?(x(),n(`p`,In,e(U.value),1)):F(``,!0)]),a(`div`,Ln,[a(`button`,{type:`button`,class:`sch-btn`,onClick:r[13]||=e=>V.value=!1},e(o(X)(`@SCHED:取消`)),1),a(`button`,{type:`button`,class:`sch-btn sch-btn-primary`,disabled:W.value,onClick:ce},e(W.value?o(X)(`@SCHED:保存中...`):o(X)(`@SCHED:保存`)),9,Rn)])]),_:1},8,[`modelValue`,`title`]),c(se,{modelValue:I.value,"onUpdate:modelValue":r[16]||=e=>I.value=e,title:o(X)(`@SCHED:删除任务`),"close-on-click-modal":!1,"append-to-body":!0,size:`small`,width:`400px`,"z-index":3e6,"custom-class":`schedule-dialog-confirm`},{default:L(()=>[a(`p`,zn,e(o(X)(`@SCHED:确定删除「{name}」吗?已产生的会话会保留,但任务不再执行。`,{name:R.value?.name||``})),1),a(`div`,Bn,[a(`button`,{type:`button`,class:`sch-btn`,onClick:r[15]||=e=>I.value=!1},e(o(X)(`@SCHED:取消`)),1),a(`button`,{type:`button`,class:`sch-btn sch-btn-danger`,onClick:re},e(o(X)(`@SCHED:删除`)),1)])]),_:1},8,[`modelValue`,`title`])]))}}),[[`__scopeId`,`data-v-75be84e5`]]);w(),B(),l(),A();var Hn={class:`aps`},Un={class:`aps__scroll`},Wn={class:`aps__head`},Gn={class:`aps__title`},Kn={class:`aps__intro`},qn={class:`aps__card aps__card--gai`},Jn={class:`aps__card-head`},Yn={class:`aps__card-title`},Xn={class:`aps__count`},Zn={class:`aps__hint`},Qn=[`placeholder`],$n={class:`aps__foot`},er={key:0,class:`aps__saved`},tr=[`disabled`],nr={class:`aps__card aps__card--dispatch`},rr={class:`aps__card-head`},ir={class:`aps__card-title`},ar={class:`aps__hint`},or={class:`aps__field`},sr={class:`aps__card-head`},cr={class:`aps__label`,for:`aps-global`},lr={class:`aps__count`},ur=[`placeholder`],dr={class:`aps__field`},fr={class:`aps__card-head`},pr={class:`aps__label`,for:`aps-project`},mr={key:0,class:`aps__count`},hr=[`disabled`,`placeholder`],gr={class:`aps__hint`},_r={class:`aps__foot`},vr={key:0,class:`aps__saved`},yr={key:1,class:`aps__saved`},br=[`disabled`],xr=4e3,Sr=Z(_({__name:`AgentPromptSettings`,setup(t){let r=oe(),{defaultPrompt:i,projectPrompts:c,loadOrchestrator:l,saveDefaultPrompt:u,saveProjectPrompt:d}=we(),f=J(``),p=J(!1),m=J(!1),h=s(()=>r.agentDefaultPrompt||``),g=s(()=>f.value.trim()!==h.value.trim());async function _(){if(!p.value&&g.value){p.value=!0;try{await r.saveAiSettings({agentDefaultPrompt:f.value})&&(f.value=h.value,m.value=!0,P.success(X(`@AGENT:已保存 g ai 默认提示词`)))}finally{p.value=!1}}}let v=s(()=>r.currentDirectory||``),y=s(()=>ce(v.value)||v.value),b=s(()=>{let e=Q(v.value);return e&&c.value?.[e]?.prompt||``}),S=J(``),C=J(``),w=J(!1),ee=J(!1),E=J(!1),D=s(()=>S.value.trim()!==(i.value||``).trim()||!!v.value&&C.value.trim()!==b.value.trim());function O(){S.value=i.value||``,C.value=b.value}T(async()=>{f.value=h.value,O();let e=await l(!0);E.value=!e,e&&O()});async function k(){if(!w.value&&D.value){w.value=!0;try{let e=!0,t=S.value.trim();t!==(i.value||``).trim()&&(e=await u(t));let n=C.value.trim();e&&v.value&&n!==b.value.trim()&&(e=await d(v.value,n)),e&&(O(),ee.value=!0)}finally{w.value=!1}}}return(t,r)=>(x(),n(`div`,Hn,[a(`div`,Un,[a(`header`,Wn,[a(`h3`,Gn,e(o(X)(`@AGENT:提示词设置`)),1),a(`p`,Kn,e(o(X)(`@AGENT:这里配的两块提示词,和 g ai 对话时每一轮都会自动带上。改完下一次发消息就生效,不用新开会话。`)),1)]),a(`section`,qn,[a(`div`,Jn,[a(`h4`,Yn,e(o(X)(`@AGENT:g ai 智能体的默认提示词`)),1),a(`span`,Xn,e(f.value.length)+` / `+e(xr),1)]),a(`p`,Zn,e(o(X)(`@AGENT:只作用于 g ai 自己:每次对话都会带上(定时任务也一样)。派发出去的任务读不到这一段。`)),1),K(a(`textarea`,{id:`aps-gai`,"onUpdate:modelValue":r[0]||=e=>f.value=e,class:`aps__area`,rows:`6`,maxlength:xr,placeholder:o(X)(`@AGENT:例如:回答用中文;改完代码先跑一遍验证再汇报;不要动 dist 目录`)},null,8,Qn),[[q,f.value]]),a(`div`,$n,[m.value&&!g.value?(x(),n(`span`,er,e(o(X)(`@AGENT:已保存`)),1)):F(``,!0),r[3]||=a(`span`,{class:`aps__spacer`},null,-1),a(`button`,{type:`button`,class:`aps__btn aps__btn--primary`,disabled:p.value||!g.value,onClick:_},e(p.value?o(X)(`@AGENT:保存中…`):o(X)(`@AGENT:保存`)),9,tr)])]),a(`section`,nr,[a(`div`,rr,[a(`h4`,ir,e(o(X)(`@AGENT:派发任务的提示词`)),1)]),a(`p`,ar,e(o(X)(`@AGENT:与工作台「预设提示词」是同一份设置,在哪边改都一样。派发任务时附加在指令之前,和 g ai 对话时也会带上。`)),1),a(`div`,or,[a(`div`,sr,[a(`label`,cr,e(o(X)(`@AGENT:全局提示词`)),1),a(`span`,lr,e(S.value.length)+` / `+e(xr),1)]),K(a(`textarea`,{id:`aps-global`,"onUpdate:modelValue":r[1]||=e=>S.value=e,class:`aps__area`,rows:`5`,maxlength:xr,placeholder:o(X)(`@AGENT:对所有项目生效。例如:回答用中文;改完代码必须跑一遍测试;不要动 dist 目录`)},null,8,ur),[[q,S.value]])]),a(`div`,dr,[a(`div`,fr,[a(`label`,pr,e(v.value?o(X)(`@AGENT:「{name}」的项目提示词`,{name:y.value}):o(X)(`@AGENT:项目提示词`)),1),v.value?(x(),n(`span`,mr,e(C.value.length)+` / `+e(xr),1)):F(``,!0)]),K(a(`textarea`,{id:`aps-project`,"onUpdate:modelValue":r[2]||=e=>C.value=e,class:`aps__area`,rows:`5`,maxlength:xr,disabled:!v.value,placeholder:v.value?o(X)(`@AGENT:只在这个项目派发/对话时附加。例如:包管理器用 pnpm;改动集中在 src/ui 下`):o(X)(`@AGENT:当前没有打开项目,项目级提示词暂时不能设置`)},null,8,hr),[[q,C.value]]),a(`p`,gr,e(v.value?o(X)(`@AGENT:项目提示词追加在全局提示词之后(不覆盖全局),在「{name}」里派发或对话时一起带上`,{name:y.value}):o(X)(`@AGENT:先在左上角切到一个项目,才能设置它的提示词`)),1)]),a(`div`,_r,[ee.value&&!D.value?(x(),n(`span`,vr,e(o(X)(`@AGENT:已保存`)),1)):E.value?(x(),n(`span`,yr,e(o(X)(`@AGENT:读取设置失败,请稍后重试`)),1)):F(``,!0),r[4]||=a(`span`,{class:`aps__spacer`},null,-1),a(`button`,{type:`button`,class:`aps__btn aps__btn--primary`,disabled:w.value||!D.value,onClick:k},e(w.value?o(X)(`@AGENT:保存中…`):o(X)(`@AGENT:保存`)),9,br)])])])]))}}),[[`__scopeId`,`data-v-ae77c09c`]]);w(),B(),l();var Cr={class:`agent-chat-area`},wr={class:`agent-tabs`,role:`tablist`},Tr=[`aria-selected`,`onClick`],Er={class:`agent-tab-body`},Dr={key:0,class:`agent-chat-pane`},Or={key:0,class:`agent-list-page`},kr={key:0,class:`agent-page-bar`},Ar=[`title`,`aria-label`],jr={class:`agent-page-title`},Mr={key:0,class:`chat-loading`},Nr=Z(_({__name:`AgentView`,setup(i){let l=oe(),d=J(null),{narrow:f}=xe(d),m=J(`chat`),_=J(`chat`),v=s(()=>_.value===`mcp`?`mcp`:`skill`),b=s(()=>[{id:`chat`,label:X(`@AGENT:对话`),icon:M},{id:`schedule`,label:X(`@AGENT:定时任务`),icon:t},{id:`skill`,label:X(`@AGENT:Skill 广场`),icon:C},{id:`mcp`,label:X(`@AGENT:MCP 广场`),icon:W},{id:`settings`,label:X(`@AGENT:设置`),icon:g}]),{sessions:w,sessionsLoading:ee,currentSessionId:T,messages:D,displayMessages:O,isStreaming:k,sessionLoading:te,loadSessions:A,loadSession:N,deleteSession:P,renameSession:ne,newSession:I,sendMessage:R,retryTurn:z,questionPanel:B,answeringQuestion:re,answerQuestion:V,isSessionGenerating:G,currentEngine:K,pendingEngine:q,isEngineLocked:ie,pickEngine:Z,stop:se,inputContextUsage:Q,queuedMessages:ce,queuePaused:we,removeQueuedMessage:Te,flushQueued:Ee}=be(),De=s(()=>ie.value?K.value:q.value);function Oe(e){ie.value||Z(e)}let ke=s(()=>{let e=l.theme;return e===`dark`||e===`auto`&&window.matchMedia(`(prefers-color-scheme: dark)`).matches?`dark`:`light`}),Ae=s(()=>de(w.value,G)),je=ue(),Me=s(()=>Ae.value.find(e=>e.id===T.value)?.title||X(`@AGENT:对话`)),Ne={"--welcome-avatar":`url("${ye}")`},Pe=s(()=>le(l.agentPresetPrompts));async function Fe(e){await R(e.text,e.files),await u(),Be()}async function Ie(e){await R(e.prompt),await u(),Be()}let Le=ge(),Re=J(null),ze=ve();function Be(e=!0){Re.value?.scrollToBottom(e)}U(()=>D.value.length,()=>{u(()=>Be(!1))});function Ve(e){N(e),m.value=`chat`}function He(e){e&&(_.value=`chat`,Ve(e))}function Ue(){I(),m.value=`chat`}let We=J(280),Ge=J(!1);function Ke(e){Ge.value=!0;let t=e.clientX,n=We.value,r=e=>{let r=e.clientX-t,i=Math.max(200,Math.min(500,n+r));We.value=i},i=()=>{Ge.value=!1,document.removeEventListener(`mousemove`,r),document.removeEventListener(`mouseup`,i)};document.addEventListener(`mousemove`,r),document.addEventListener(`mouseup`,i)}return U(f,e=>{e||(m.value=`chat`)}),U(()=>[l.currentDirectory,k.value],async([e,t],n)=>{let r=!n||e!==n[0],i=!!n&&n[1]===!0&&!t;(r||i)&&await A(),T.value&&!k.value&&!w.value.some(e=>e.sessionId===T.value)&&I()},{immediate:!0}),(t,i)=>(x(),n(`div`,{ref_key:`rootRef`,ref:d,class:`agent-view`},[_.value===`chat`&&!o(f)?(x(),n(S,{key:0},[a(`aside`,{class:`agent-sidebar`,style:E({width:We.value+`px`})},[c(o(ae),{class:`agent-conversations`,items:Ae.value,"active-id":o(T),loading:o(ee),labels:o(je),onSelect:Ve,onNew:Ue,onRename:o(ne),onDelete:o(P)},null,8,[`items`,`active-id`,`loading`,`labels`,`onRename`,`onDelete`])],4),a(`div`,{class:h([`sidebar-resizer`,{active:Ge.value}]),onMousedown:Ke},null,34)],64)):F(``,!0),a(`main`,Cr,[a(`nav`,wr,[(x(!0),n(S,null,j(b.value,t=>(x(),n(`button`,{key:t.id,type:`button`,class:h([`agent-tab`,{active:_.value===t.id}]),role:`tab`,"aria-selected":_.value===t.id,onClick:e=>_.value=t.id},[c(o(p),null,{default:L(()=>[(x(),y(H(t.icon)))]),_:2},1024),a(`span`,null,e(t.label),1)],10,Tr))),128)),_.value===`chat`?(x(),y(Se,{key:0,class:`agent-engine`,engine:De.value,locked:o(ie),onSelect:Oe},null,8,[`engine`,`locked`])):F(``,!0),_.value===`chat`?(x(),y(Ce,{key:1,class:`agent-copy`,messages:o(D),title:Me.value,engine:o(me)(De.value)},null,8,[`messages`,`title`,`engine`])):F(``,!0)]),a(`div`,Er,[_.value===`chat`?(x(),n(`div`,Dr,[o(f)&&m.value===`list`?(x(),n(`div`,Or,[c(o(ae),{class:`agent-conversations`,items:Ae.value,"active-id":o(T),loading:o(ee),labels:o(je),onSelect:Ve,onNew:Ue,onRename:o(ne),onDelete:o(P)},null,8,[`items`,`active-id`,`loading`,`labels`,`onRename`,`onDelete`])])):(x(),n(S,{key:1},[o(f)?(x(),n(`div`,kr,[a(`button`,{type:`button`,class:`agent-page-back`,title:o(X)(`@AGENT:返回会话列表`),"aria-label":o(X)(`@AGENT:返回会话列表`),onClick:i[0]||=e=>m.value=`list`},[...i[1]||=[a(`svg`,{viewBox:`0 0 24 24`,width:`14`,height:`14`,fill:`none`,stroke:`currentColor`,"stroke-width":`2`,"stroke-linecap":`round`,"stroke-linejoin":`round`},[a(`line`,{x1:`19`,y1:`12`,x2:`5`,y2:`12`}),a(`polyline`,{points:`12 19 5 12 12 5`})],-1)]],8,Ar),a(`span`,jr,e(Me.value),1)])):F(``,!0),a(`div`,{class:`agent-chat-host`,style:Ne},[o(te)?(x(),n(`div`,Mr,[c(o(p),{class:`is-loading`,size:32},{default:L(()=>[c(o(r))]),_:1}),a(`span`,null,e(o(X)(`@AGENT:加载会话中...`)),1)])):(x(),y(o(Y),{key:1,ref_key:`chatContainerRef`,ref:Re,messages:o(O),"preset-questions":Pe.value,"welcome-title":o(X)(`@AGENT:智能体助手`),"welcome-description":o(X)(`@AGENT:我可以帮你阅读代码、执行命令、修改文件。选择下方话题或直接输入你的问题。`),"assistant-name":o(he),"assistant-avatar":o(ye),theme:ke.value,generating:o(k),"allow-queue":!0,queued:o(ce),"queue-paused":o(we),"queue-labels":o(ze),"upload-config":{accept:o(pe)},"context-usage":o(Q),placeholder:o(k)?o(X)(`@AGENT:生成中,发送后会排队,等本轮跑完自动接上…`):o(X)(`@AGENT:输入消息,Enter 发送`),question:o(B),"question-submitting":o(re),"question-labels":o(Le),"plan-config":{labels:{title:o(X)(`@AGENT:计划`),raw:o(X)(`@AGENT:原始参数`)}},"message-rail-config":o(fe),"message-meta-config":o(_e),onSend:Fe,onSelect:Ie,onStop:o(se),onUnqueue:o(Te),onFlushQueued:o(Ee),onAnswer:o(V),onRetry:o(z)},null,8,[`messages`,`preset-questions`,`welcome-title`,`welcome-description`,`assistant-name`,`assistant-avatar`,`theme`,`generating`,`queued`,`queue-paused`,`queue-labels`,`upload-config`,`context-usage`,`placeholder`,`question`,`question-submitting`,`question-labels`,`plan-config`,`message-rail-config`,`message-meta-config`,`onStop`,`onUnqueue`,`onFlushQueued`,`onAnswer`,`onRetry`]))])],64))])):_.value===`schedule`?(x(),y(Vn,{key:1,onOpenSession:He})):_.value===`skill`||_.value===`mcp`?(x(),y(yt,{key:2,type:v.value},null,8,[`type`])):(x(),y(Sr,{key:3}))])])],512))}}),[[`__scopeId`,`data-v-19c12ea4`]]);export{Nr as default};
@@ -1,10 +0,0 @@
1
- import"./rolldown-runtime-C0FnF6B9.js";import{En as e,Vn as t,i as n,mr as r,r as i,xr as a,yr as o}from"./element-plus-J45pKUrE.js";import{c as s,o as c,s as l,t as u}from"./vendor-B3NyhlYR.js";import{n as d}from"./_plugin-vue_export-helper-Csn085FF.js";import{c as f,s as p,t as m}from"./configStore-DOaPZ6Mq.js";import{_ as h,n as g,p as _,r as v,t as y,v as b}from"./index-C7Y9odvZ.js";function x(e,t=200){let n=typeof e==`string`?e:``;if(!n.trim())return``;let r=n.split(`
2
- `).map(e=>e.trim()).filter(Boolean),i=(r.length?r[r.length-1]:``).replace(/\s+/g,` `);return i.length>t?`${i.slice(0,t-1)}…`:i}function S(e){return d(e===`done`?`@AGENT:对话已完成`:`@AGENT:对话出错`)}function C(){let e={page:!1,browser:!1,sound:!1};try{let t=m();e.page=!!t.notifyPageOnTaskDone,e.browser=!!t.notifyBrowserOnTaskDone,e.sound=!!t.notifySoundOnTaskDone}catch{}return e}function w(){return C().sound?v():!1}function T(e){let t=C();if(!y(t))return!1;let r=String(e.title||``).trim()||d(`@AGENT:无标题`),i=x(e.detail),a=e.tag||`zen-gitsync-agent`,o=i?`${r}\n${i}`:r;return t.sound&&g(e.kind),b(t)&&h({title:S(e.kind),body:o,tag:a})||!t.page||e.alreadyToast||(e.kind===`done`?n.success(d(`@AGENT:对话完成:{name}`,{name:r})):n.error(d(`@AGENT:对话出错:{name}`,{name:r}))),!0}var E=`g ai`,D=`g-ai`,O=[{id:`gai`,name:E},...p.map(e=>({id:e.id,name:e.name}))],k=`zen-gitsync-agent-engine`;function A(e){return e===`gai`||f(e)}function j(e){return O.find(t=>t.id===e)?.name||`g ai`}function M(e){return f(e)}function ee(){try{let e=localStorage.getItem(k);if(A(e))return e}catch{}return`gai`}function te(e){try{localStorage.setItem(k,e)}catch{}}var N=[`png`,`jpg`,`jpeg`,`gif`,`webp`,`bmp`,`svg`],P=/!\[([^\]]*)\]\(\s*(?:<([^<>\n]+)>|([^()\s]+))(\s+["'][^"']*["'])?\s*\)/g,ne=/^\s*(`{3,}|~{3,})/,re=/\.([a-z0-9]+)$/;function F(e){let t=e.trim().toLowerCase().match(re);return!!t&&N.includes(t[1])}function I(e){let t=String(e||``).trim();if(!t)return!1;if(/^[a-zA-Z]:[\\/]/.test(t))return F(t);let n=t.match(/^([a-z][a-z0-9+.-]+):/i);return n&&n[1].toLowerCase()!==`file`||t.startsWith(`//`)||t.startsWith(`/`)?!1:F(t)}function L(e,t){return`/api/workbench/jobs/${encodeURIComponent(e)}/image?path=${encodeURIComponent(t)}`}function R(e,t){return`/api/agent/sessions/${encodeURIComponent(e)}/image?path=${encodeURIComponent(t)}`}function z(e,t){return e.includes(`![`)?e.replace(P,(e,n,r,i,a)=>{let o=(r??i??``).trim();return I(o)?`![${n}](${t(o)}${a||``})`:e}):e}function B(e,t){let n=typeof e==`string`?e:``;if(!n||!t||!n.includes(`![`))return n;let r=n.split(`
3
- `),i=null,a=[];for(let e of r){let n=e.match(ne);if(n){let t=n[1][0];i===null?i=t:i===t&&(i=null),a.push(e);continue}a.push(i===null?z(e,t):e)}return a.join(`
4
- `)}function V(e,t){return B(e,t?e=>L(t,e):null)}function ie(e,t){return B(e,t?e=>R(t,e):null)}t(),r();var H=[`image/*`,`.pdf`,`.txt`,`.md`,`.json`,`.csv`,`.log`,`.yml`,`.yaml`,`.xml`,`.toml`,`.ini`,`.html`,`.css`,`.js`,`.ts`,`.tsx`,`.vue`,`.py`,`.java`,`.go`,`.rs`,`.sql`,`.sh`].join(`,`),U=65536,W=`local-`,ae=0;function oe(e){if(!e||!Array.isArray(e.messages))return[];let t=[],n=e.messages.length,r=new Map;for(let t of e.turnTimings||[])typeof t?.turnIndex==`number`&&Number.isFinite(t?.durationMs)&&r.set(t.turnIndex,t);let i=-1;for(let a=0;a<n;a++){let o=e.messages[a];if(o.role!==`system`){if(o.role===`user`){i+=1;let e=``,n;if(typeof o.content==`string`)e=o.content;else if(Array.isArray(o.content)){e=o.content.filter(e=>e?.type===`text`).map(e=>e.text||``).join(` `);let t=o.content.filter(e=>e?.type===`image_url`&&typeof e.image_url?.url==`string`).map((e,t)=>({id:`att-${a}-${t}`,name:`image`,size:0,type:q(e.image_url?.url||``)||`image/*`,preview:e.image_url?.url}));t.length>0&&(n=t)}(e||n)&&t.push({id:`msg-${a}`,role:`user`,content:e,attachments:n,status:`done`,createdAt:Date.now()})}else if(o.role===`assistant`){let o=`msg-${a}`,s=``,l=[],u=a;for(;u<n;){let t=e.messages[u];if(t.role!==`assistant`&&t.role!==`tool`)break;if(t.role===`assistant`){if(typeof t.content==`string`&&(s+=t.content),t.tool_calls&&t.tool_calls.length>0)for(let e of t.tool_calls)l.push({id:e.id||e.function?.name||c(),name:e.function?.name||``,arguments:e.function?.arguments||``,argsPreview:G(e.function?.name||``,e.function?.arguments||``),status:`done`,result:``})}else{let e=t.tool_call_id||t.name||``,n=l.find(t=>t.id===e);if(n){let e;e=typeof t.content==`string`?t.content:Array.isArray(t.content)&&t.content.filter(e=>e?.type===`text`).map(e=>e.text||``).join(`
5
- `)||`(non-text result)`,e.length>U&&(e=`…(前文已截断)\n${e.slice(-65536)}`),n.result=e}}u++}a=u-1,s.length>U&&(s=`…(前文已截断)\n${s.slice(-65536)}`);let d=!!s,f=l.length>0;if(d||f){let e=r.get(i),n=e?.finishedAt?Date.parse(e.finishedAt):NaN;t.push({id:o,role:`assistant`,content:s,toolCalls:f?l:void 0,status:`done`,createdAt:Number.isFinite(n)&&e?n-e.durationMs:Date.now(),finishedAt:Number.isFinite(n)?n:void 0,meta:e?{durationMs:e.durationMs}:void 0})}}}}return t}function G(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||``);case`update_plan`:{let e=s(t,`update_plan`);if(!e)return``;let{total:r,done:i}=u(e),a=String(n.explanation||``).replace(/\s+/g,` `).trim();return[`${i}/${r}`,a].filter(Boolean).join(` — `).slice(0,200)}default:return JSON.stringify(n).slice(0,200)}}catch{return t.slice(0,200)}}function K(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 q(e){let t=/^data:([^;,]+)/.exec(e);return t?t[1]:``}function J(){let t=m(),r=_(),s=++ae,u=a([]),f=a(!1),p=a(ee());function h(e){A(e)&&(p.value=e,te(e))}let g=o(new Map),v=a(null),y=a(!1),b=0,x=0,S=new Set;function C(e){return{key:e,sessionId:e.startsWith(W)?null:e,title:``,messages:[],isStreaming:!1,abortController:null,nonce:0,pendingQuestion:null,answeringQuestion:!1,contextUsage:null,queue:[],queuePaused:!1}}function E(e){let t=g.get(e);return t||=(g.set(e,C(e)),g.get(e)),t}let D=e(()=>v.value?g.get(v.value)??null:null),O=e(()=>D.value?.messages??[]),k=e(()=>{let e=O.value,t=D.value?.sessionId??null;if(!t)return e;let n=!1,r=e.map(e=>{if(!e.content||!e.content.includes(`![`))return e;let r=ie(e.content,t);return r===e.content?e:(n=!0,{...e,content:r})});return n?r:e}),j=e(()=>D.value?.isStreaming??!1),M=e(()=>D.value?.contextUsage??null),N=e(()=>{let e=M.value;return e?{ratio:Math.min(Math.max(e.tokenRatio,e.messageRatio),1),current:e.tokens,total:e.maxTokens,unit:`K`,suffix:`上下文已使用`,detail:[`${e.messages} / ${e.maxMessages} 条消息`,typeof e.actualInputTokens==`number`&&e.actualInputTokens>0?`实测 ${e.actualInputTokens.toLocaleString()} token`:`估算 ${Math.round(e.estTokens).toLocaleString()} token`,e.droppedMessages>0?`会话共 ${e.transcriptMessages} 条,本次只带入 ${e.messages} 条(其余已摘成梗概)`:``].filter(Boolean).join(`
6
- `)}:null}),P=e(()=>{let e=u.value.find(e=>e.sessionId===v.value);return A(e?.engine)?e.engine:p.value}),ne=e(()=>u.value.some(e=>e.sessionId===v.value)),re=e(()=>D.value?.pendingQuestion??null),F=e(()=>D.value?.answeringQuestion??!1),I=e(()=>D.value?.pendingQuestion??null),L=e(()=>D.value?.queuePaused??!1),R=e(()=>(D.value?.queue??[]).map(e=>({id:e.id,text:e.text,attachmentNames:e.files.map(e=>e.file.name)})));function z(e){let t=D.value;if(!t)return;let n=t.queue.findIndex(t=>t.id===e);n<0||(t.queue.splice(n,1),t.queue.length===0&&(t.queuePaused=!1))}function B(e){if(e.isStreaming)return;let t=e.queue.shift();t&&Q(t.text,t.files,{...t.options,targetKey:e.key,background:!0})}function V(){let e=D.value;e&&!e.isStreaming&&e.queue.length!==0&&(e.queuePaused=!1,B(e))}function H(e){return!!g.get(e)?.isStreaming}function G(e){let n=[...e];for(let e of g.values()){if(!e.sessionId)continue;let r=n.findIndex(t=>t.sessionId===e.sessionId);if(r!==-1){S.delete(e.sessionId),e.isStreaming&&(n[r]={...n[r],isGenerating:!0});continue}if(!e.isStreaming&&!S.has(e.sessionId))continue;let i=new Date().toISOString();n.unshift({sessionId:e.sessionId,title:e.title||d(`@AGENT:无标题`),source:`web`,cwd:t.currentDirectory||``,model:``,engine:p.value,createdAt:i,updatedAt:i,messageCount:e.messages.filter(e=>e.role===`user`).length||1,size:0,isGenerating:e.isStreaming})}return n}async function q(){let e=++b,r=t.currentDirectory||``;if(!r){u.value=[],f.value=!1;return}f.value=!0;try{let t=`/api/agent/sessions?cwd=${encodeURIComponent(r)}`,i=await fetch(t).then(e=>e.json());if(e!==b)return;if(!i.success){n.error(i.error||d(`@AGENT:加载会话列表失败`));return}let a=Array.isArray(i.sessions)?i.sessions:[];u.value=G(a)}catch(t){if(e!==b)return;n.error(d(`@AGENT:加载会话列表失败`)+`: `+(t?.message||t))}finally{e===b&&(f.value=!1)}}function J(e,n){let r=new Date().toISOString(),i=u.value.find(t=>t.sessionId===e);if(i){i.isGenerating=!0,i.updatedAt=r;return}u.value=[{sessionId:e,title:n||d(`@AGENT:无标题`),source:`web`,cwd:t.currentDirectory||``,model:``,engine:p.value,createdAt:r,updatedAt:r,messageCount:1,size:0,isGenerating:!0},...u.value]}function Y(e){let t=u.value.find(t=>t.sessionId===e);t&&(t.isGenerating=!1)}async function X(e){if(g.get(e)?.isStreaming){v.value=e;return}y.value=!0,v.value=e;try{let t=await fetch(`/api/agent/sessions/${encodeURIComponent(e)}`).then(e=>e.json());if(!t.success){n.error(t.error||d(`@AGENT:加载会话失败`));return}let r=E(e);r.sessionId=e,r.messages=oe(t.session),t.session?.title&&(r.title=t.session.title)}catch(e){n.error(d(`@AGENT:加载会话失败`)+`: `+(e?.message||e))}finally{y.value=!1}}async function Z(e){try{await i.confirm(d(`@AGENT:确认删除该会话`),d(`@AGENT:删除后无法恢复`),{type:`warning`})}catch{return}let t=g.get(e);if(t?.abortController)try{t.abortController.abort()}catch{}g.delete(e);try{let t=await fetch(`/api/agent/sessions/${encodeURIComponent(e)}`,{method:`DELETE`}).then(e=>e.json());if(!t.success){n.error(t.error||d(`@AGENT:删除失败`));return}u.value=u.value.filter(t=>t.sessionId!==e),v.value===e&&(v.value=null),n.success(d(`@AGENT:已删除`))}catch(e){n.error(d(`@AGENT:删除失败`)+`: `+(e?.message||e))}}async function se(e,t){try{let r=await fetch(`/api/agent/sessions/${encodeURIComponent(e)}`,{method:`PUT`,headers:{"Content-Type":`application/json`},body:JSON.stringify({title:t})}).then(e=>e.json());if(!r.success){n.error(r.error||d(`@AGENT:重命名失败`));return}let i=u.value.find(t=>t.sessionId===e);i&&(i.title=t);let a=g.get(e);a&&(a.title=t),n.success(d(`@AGENT:已重命名`))}catch(e){n.error(d(`@AGENT:重命名失败`)+`: `+(e?.message||e))}}function ce(){v.value=null}async function Q(e,i=[],a={}){let l=i.filter(e=>e?.file?.type?.startsWith(`image/`)),u=i.filter(e=>!e?.file?.type?.startsWith(`image/`)),f=[],p=0;for(let e of u){let t=e.file.size||0;if(!(t>10485760)){if(f.length>=10||p+t>20971520)break;p+=t,f.push(e)}}let m=u.filter(e=>!f.includes(e));m.length>0&&n.warning(`${d(`@AGENT:以下附件超过大小或数量上限,已忽略:`)}${m.map(e=>e.file.name).join(`、`)}`);let h=a.targetKey||v.value||`${W}${Date.now()}-${++x}`,g=E(h);if(!e.trim()&&l.length===0&&f.length===0)return;if(g.isStreaming){g.queue.push({id:c(),text:e,files:[...l,...f],options:a});return}let _=(await Promise.allSettled(l.map(e=>K(e.file)))).map(e=>e.status===`fulfilled`?e.value:``).filter(e=>e.startsWith(`data:image/`)),y=(await Promise.allSettled(f.map(async e=>({name:e.file.name||`file`,dataUrl:await K(e.file)})))).map(e=>e.status===`fulfilled`?e.value:null).filter(e=>!!e&&typeof e.dataUrl==`string`&&e.dataUrl.startsWith(`data:`));a.background||(v.value=g.key),g.nonce+=1;let b=g.nonce;g.abortController=new AbortController;let S=g.abortController;g.pendingQuestion=null,g.answeringQuestion=!1;let C={id:c(),role:`user`,content:e,status:`done`,createdAt:Date.now()},w=[...l,...f];w.length>0&&(C.attachments=w.map(e=>({id:e.id,name:e.file.name||`image`,size:e.file.size||0,type:e.file.type||``,preview:e.preview}))),g.messages.push(C);let T=o({id:c(),role:`assistant`,content:``,status:`pending`,createdAt:Date.now()});g.messages.push(T),g.isStreaming=!0,g.lastSendOptions=a;let D=`${s}:${h}:${b}`;r.begin(D),await $(g,b,S,T,D,{sessionId:g.sessionId||``,userMessage:e,cwd:t.currentDirectory||``,engine:a.engine??P.value,..._.length>0?{images:_}:{},...y.length>0?{attachments:y}:{},...a.openFilePath?{openFilePath:a.openFilePath}:{},...a.dirStatus?.length?{dirStatus:a.dirStatus}:{},...a.dirSummary?{dirSummary:a.dirSummary}:{},...a.allowDispatch?{allowDispatch:!0,dispatchExecutor:a.dispatchExecutor||``,dispatchUseDefaultPrompt:a.dispatchUseDefaultPrompt!==!1}:{}})}async function $(e,t,i,a,s,u){let f=String(u.userMessage||``),p=[],m=e.sessionId,h=!1,_=null;try{let r=await fetch(`/api/agent/chat`,{method:`POST`,headers:{"Content-Type":`application/json`,Accept:`text/event-stream`},body:JSON.stringify(u),signal:i.signal});if(t!==e.nonce)return;if(!r.ok||!r.body){let e=await r.text().catch(()=>``);throw Error(e||`HTTP ${r.status}`)}let s=r.body.getReader(),h=new TextDecoder(`utf-8`),y=``;for(;;){let{value:r,done:i}=await s.read();if(t!==e.nonce)return;if(i)break;y+=h.decode(r,{stream:!0});let u=y.split(`
7
- `);y=u.pop()??``;for(let t of u){let r=t.trim();if(!r.startsWith(`data:`))continue;let i=r.slice(5).trim();if(!i)continue;let s;try{s=JSON.parse(i)}catch{continue}switch(s.type){case`context`:s.usage&&(e.contextUsage={...e.contextUsage||{},...s.usage});break;case`meta`:if(s.sessionId){let t=String(s.sessionId);if(m=t,e.sessionId!==t){let n=e.key;e.sessionId=t,e.key=t,n!==t&&(g.delete(n),g.set(t,e),v.value===n&&(v.value=t))}let n=String(s.title||``).trim()||f.trim().split(`
8
- `)[0].trim().slice(0,40)||d(`@AGENT:无标题`);e.title||=n,J(t,n)}break;case`attempt`:_={content:(a.content||``).length,reasoning:(a.reasoning||``).length,tools:a.toolCalls?.length??0};break;case`retry`:_&&(a.content=(a.content||``).slice(0,_.content),a.reasoning&&=a.reasoning.slice(0,_.reasoning),a.toolCalls&&a.toolCalls.length>_.tools&&(a.toolCalls.length=_.tools,p=[...a.toolCalls])),a.status=`pending`,a.error=``,a.finishedAt=void 0,a.reasoningStatus===`streaming`&&(a.reasoningStatus=`done`),n.info(d(`@AGENT:连接中断,正在自动重试({attempt}/{max}):{reason}`,{attempt:Number(s.attempt)||0,max:Number(s.maxRetries)||0,reason:String(s.reason||``)}));break;case`thinking`:a.reasoning||(a.reasoning=``,a.reasoningStatus=`streaming`),typeof a.reasoningStartedAt!=`number`&&(a.reasoningStartedAt=Date.now()),a.reasoningEndedAt=Date.now(),a.reasoning+=String(s.delta||``),a.status=`streaming`;break;case`content`:a.status===`pending`&&(a.status=`streaming`);{let e=String(s.delta||``);a.content+=e;let t=l(a.content);t.reasoning&&(a.reasoning||(a.reasoning=``,a.reasoningStatus=`streaming`),a.reasoning=t.reasoning,a.content=t.content)}break;case`tool_call_start`:{let e=o({id:s.toolCallId||c(),name:s.name||``,argsPreview:s.argsPreview||``,arguments:s.arguments||s.argsPreview||``,status:`running`,result:``});p.push(e),a.toolCalls||=[],a.toolCalls.push(e),a.status===`pending`&&(a.status=`streaming`);break}case`tool_output`:{let e=p.find(e=>e.id===s.toolCallId);if(e){let t=`${e.result||``}${String(s.chunk||``)}`;e.result=t.length>U?`…(前文已截断)\n${t.slice(-65536)}`:t}break}case`tool_result`:{let t=p.find(e=>e.id===s.toolCallId);t&&(t.result=String(s.result||``),t.status=`done`,t.name===`ask_user`&&(e.pendingQuestion=null));break}case`ask_user`:e.pendingQuestion={interactionId:String(s.interactionId||``),question:String(s.question||``),options:Array.isArray(s.options)?s.options.map(e=>String(e)):[],allowFreeText:s.allowFreeText!==!1,multiple:s.multiple===!0},w();break;case`done`:{let e=s.content||a.content,t=l(e);t.reasoning&&!a.reasoning&&(a.reasoning=t.reasoning),a.content=t.content,a.status=`done`,a.reasoningStatus===`streaming`&&(a.reasoningStatus=`done`);break}case`turn_done`:{let e=Number(s.durationMs);if(!Number.isFinite(e)||e<0||a.meta?.durationMs!==void 0)break;a.finishedAt=Date.now(),a.meta={...a.meta||{},durationMs:e};break}case`error`:a.status=`error`,a.error=String(s.error||d(`@AGENT:未知错误`)),a.reasoningStatus===`streaming`&&(a.reasoningStatus=`done`)}}}if(t!==e.nonce)return;a.status===`pending`&&(a.status=`done`)}catch(r){if(t!==e.nonce)return;r?.name===`AbortError`||i.signal.aborted?(h=!0,a.content=(a.content||``)+`
9
-
10
- [`+d(`@AGENT:已停止`)+`]`,a.status=`done`,a.reasoningStatus===`streaming`&&(a.reasoningStatus=`done`),a.meta?.durationMs===void 0&&(a.finishedAt=Date.now(),a.meta={...a.meta||{},durationMs:a.finishedAt-(a.createdAt||a.finishedAt)})):(a.status=`error`,a.error=r?.message||String(r),n.error(a.error||d(`@AGENT:对话失败`)))}finally{let n=!!e.pendingQuestion,i=a.status===`error`?`error`:`done`;r.end(s),t===e.nonce&&(e.isStreaming=!1,e.pendingQuestion=null,e.answeringQuestion=!1,e.abortController=null,!h&&!n&&T({kind:i,title:e.title,detail:i===`error`&&a.error||a.content,tag:`zen-gitsync-agent-${m||e.key}`,alreadyToast:i===`error`}),e.queue.length>0&&(h||a.status===`error`?e.queuePaused=!0:n||B(e))),m&&(h&&S.add(m),Y(m)),q().catch(()=>{})}}async function le(e){let i=D.value;if(!i||i.isStreaming)return!1;let a=[...i.messages].reverse().find(e=>e.role===`assistant`),o=(e?.id?i.messages.find(t=>t.id===e.id):null)||a;if(!o||o.role!==`assistant`)return!1;if(a&&o.id!==a.id)return n.warning(d(`@AGENT:只能重试最后一轮`)),!1;if(!i.sessionId)return n.warning(d(`@AGENT:这条会话还没在服务端建立,请重新发送消息`)),!1;let c=u.value.find(e=>e.sessionId===i.sessionId)?.engine||P.value;if(c!==`gai`)return n.warning(d(`@AGENT:该会话由外部 CLI 引擎运行,不支持重试上一轮,请重新发送`)),!1;o.content=``,o.reasoning=void 0,o.reasoningStatus=void 0,o.reasoningStartedAt=void 0,o.reasoningEndedAt=void 0,o.error=``,o.status=`pending`,o.finishedAt=void 0,o.meta&&={...o.meta,durationMs:void 0},i.nonce+=1;let l=i.nonce;i.abortController=new AbortController;let f=i.abortController;i.pendingQuestion=null,i.answeringQuestion=!1,i.isStreaming=!0;let p=`${s}:${i.key}:${l}`;return r.begin(p),await $(i,l,f,o,p,{sessionId:i.sessionId||``,resume:!0,cwd:t.currentDirectory||``,engine:c,...i.lastSendOptions?.openFilePath?{openFilePath:i.lastSendOptions.openFilePath}:{},...i.lastSendOptions?.dirStatus?.length?{dirStatus:i.lastSendOptions.dirStatus}:{},...i.lastSendOptions?.dirSummary?{dirSummary:i.lastSendOptions.dirSummary}:{},...i.lastSendOptions?.allowDispatch?{allowDispatch:!0,dispatchExecutor:i.lastSendOptions.dispatchExecutor||``,dispatchUseDefaultPrompt:i.lastSendOptions.dispatchUseDefaultPrompt!==!1}:{}}),!0}async function ue(e){let t=D.value,r=t?.pendingQuestion,i=t?.sessionId,a=(Array.isArray(e)?e:[e]).map(e=>String(e??``).trim()).filter(Boolean);if(!t||!r||!i||!a.length||t.answeringQuestion)return!1;t.answeringQuestion=!0;try{let e=await fetch(`/api/agent/respond`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({sessionId:i,interactionId:r.interactionId,answer:r.multiple?a:a[0]})}).then(e=>e.json());if(!e.success)throw Error(e.error||d(`@AGENT:回答提交失败`));return t.pendingQuestion=null,!0}catch(e){return n.error(e?.message||d(`@AGENT:回答提交失败`)),!1}finally{t.answeringQuestion=!1}}function de(){let e=D.value;e?.abortController&&(e.abortController.abort(),e.abortController=null)}return{sessions:u,sessionsLoading:f,currentSessionId:v,messages:O,displayMessages:k,isStreaming:j,sessionLoading:y,pendingQuestion:re,questionPanel:I,answeringQuestion:F,isSessionGenerating:H,contextUsage:M,inputContextUsage:N,queuedMessages:R,queuePaused:L,removeQueuedMessage:z,flushQueued:V,currentEngine:P,pendingEngine:p,isEngineLocked:ne,pickEngine:h,loadSessions:q,loadSession:X,deleteSession:Z,renameSession:se,newSession:ce,sendMessage:Q,retryTurn:le,answerQuestion:ue,stop:de}}var Y=`data:image/svg+xml,%3csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2032%2032'%20fill='none'%3e%3crect%20x='2'%20y='6'%20width='27'%20height='23'%20rx='6'%20fill='%235364E8'/%3e%3cpath%20d='M9.419%2012.581a1.3%201.3%200%200%200-1.838%201.838L11.162%2018l-3.581%203.581a1.3%201.3%200%200%200%201.838%201.838l4.5-4.5a1.3%201.3%200%200%200%200-1.838Z'%20fill='%23FFFFFF'/%3e%3crect%20x='15.7'%20y='21.2'%20width='7.6'%20height='2.6'%20rx='1.3'%20fill='%23FFFFFF'/%3e%3cpath%20d='M25%20.4%2027.115%204.885%2031.6%207l-4.485%202.115L25%2013.6l-2.115-4.485L18.4%207l4.485-2.115Z'%20fill='%23FFFFFF'/%3e%3cpath%20d='M25%202.5%2026.22%205.78%2029.5%207l-3.28%201.22L25%2011.5l-1.22-3.28L20.5%207l3.28-1.22Z'%20fill='%2339D7B5'/%3e%3c/svg%3e`;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?d(`@AGENT:今天`):`${e}${d(`@AGENT:天前`)}`}return`${t.getFullYear()}-${i(t.getMonth()+1)}-${i(t.getDate())}`}catch{return e}}function Z(e,t){return e.map(e=>({id:e.sessionId,title:e.title||d(`@AGENT:无标题`),meta:`${X(e.updatedAt)} · ${e.messageCount??0} ${d(`@AGENT:条`)}`,generatingText:e.isGenerating||t(e.sessionId)?d(`@AGENT:正在生成中...`):``,badge:e.source===`cli`?`CLI`:``,searchText:e.model}))}function se(){return{newConversation:d(`@AGENT:新建会话`),searchPlaceholder:d(`@AGENT:搜索会话...`),empty:d(`@AGENT:暂无会话`),emptyHint:d(`@AGENT:点击上方按钮开始对话`),noResult:d(`@AGENT:未找到匹配的会话`),loading:d(`@AGENT:加载会话中...`),rename:d(`@AGENT:重命名`),delete:d(`@AGENT:删除`),untitled:d(`@AGENT:无标题`)}}var ce=`g ai`,Q=Y,$={enable:!0},le={enable:!0,items:[`duration`],visibility:`always`};function ue(){return{title:d(`@AGENT:等待你的回答`),placeholder:d(`@AGENT:输入回答`),submit:d(`@AGENT:提交回答`),answered:d(`@AGENT:已回答`),expand:d(`@AGENT:展开完整问答`),collapse:d(`@AGENT:收起完整问答`)}}function de(){return{title:d(`@AGENT:排队中`),hint:d(`@AGENT:本轮结束后依次发送`),pausedHint:d(`@AGENT:已暂停,点「立即发送」继续`),send:d(`@AGENT:加入队列`),flush:d(`@AGENT:立即发送`),remove:d(`@AGENT:移出队列`)}}export{se as a,Z as c,V as d,O as f,M as h,$ as i,H as l,j as m,ce as n,ue as o,D as p,le as r,de as s,Q as t,J as u};