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.
- package/README.md +2 -2
- package/package.json +1 -1
- package/src/cli/ai/tools.js +152 -1
- package/src/cli/ai/tools.test.js +70 -1
- package/src/ui/public/assets/{AgentView-CV_8sYX6.css → AgentView-BnEgu3NT.css} +1 -1
- package/src/ui/public/assets/AgentView-DQQe_ivW.js +1 -0
- package/src/ui/public/assets/{AppVersionBadge-C4OhcUi8.js → AppVersionBadge-D7PiBP0p.js} +1 -1
- package/src/ui/public/assets/{BranchSelector-CrLieQyJ.js → BranchSelector-BzHoMBOc.js} +1 -1
- package/src/ui/public/assets/{CommitForm-KGQisnPQ.js → CommitForm-CNTjLYTR.js} +1 -1
- package/src/ui/public/assets/{CopySessionButton-y5Rzmact.js → CopySessionButton-Dy5t8Mjy.js} +1 -1
- package/src/ui/public/assets/{EditorView-CkZb2kw5.js → EditorView-CwcdA0Ei.js} +1 -1
- package/src/ui/public/assets/{FlowOrchestrationWorkspace-BMQSVm3V.js → FlowOrchestrationWorkspace-CJHpEBCw.js} +1 -1
- package/src/ui/public/assets/{LogList-BxH6QNlK.js → LogList-KUePBjAt.js} +1 -1
- package/src/ui/public/assets/{MindmapView-D9_qjJsR.js → MindmapView-CwdvsuEK.js} +1 -1
- package/src/ui/public/assets/{MonitorView-z_fsnE8Y.js → MonitorView-CjEnnrTL.js} +1 -1
- package/src/ui/public/assets/{ProjectStartupButton-CFB_JpYG.js → ProjectStartupButton-B36lRb6-.js} +1 -1
- package/src/ui/public/assets/{RecentDirectoriesChat-BYI8lkjQ.js → RecentDirectoriesChat-DNiji9Pr.js} +1 -1
- package/src/ui/public/assets/{RemoteManagerDialog-DXDcN8e7.js → RemoteManagerDialog-Dj_GpA-c.js} +1 -1
- package/src/ui/public/assets/{RemoteRepoCard-C_TYGsXi.js → RemoteRepoCard-C8u9M6dn.js} +1 -1
- package/src/ui/public/assets/{SourceMapView-D6cSweDt.js → SourceMapView-eng0B9U2.js} +1 -1
- package/src/ui/public/assets/{WorkbenchView-D4UDurhF.js → WorkbenchView-CZO18THH.js} +1 -1
- package/src/ui/public/assets/agentConversations-De3wKTsN.js +10 -0
- package/src/ui/public/assets/{index-C7Y9odvZ.js → index-DQ82h1aq.js} +5 -5
- package/src/ui/public/assets/{useOrchestrator-C236G5P5.js → useOrchestrator-BjC7oHpt.js} +1 -1
- package/src/ui/public/index.html +1 -1
- package/src/ui/server/routes/git/clone.js +5 -13
- package/src/ui/server/routes/workbench/agentChat.js +5 -2
- package/src/ui/server/routes/workbench/agentRoutes.js +17 -0
- package/src/ui/server/routes/workbench/index.js +16 -4
- package/src/ui/server/routes/workbench/scheduler.js +3 -0
- package/src/utils/gitRepoName.js +33 -0
- package/src/ui/public/assets/AgentView-DxmnqJxE.js +0 -1
- 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-
|
|
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};
|
package/src/ui/public/index.html
CHANGED
|
@@ -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-
|
|
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
|
-
|
|
45
|
-
|
|
46
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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(`}${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};
|