zen-gitsync 2.16.10 → 2.16.12
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 +17 -16
- package/package.json +1 -1
- package/scripts/release.js +3 -3
- package/src/cli/ai/modelSetup.js +197 -14
- package/src/cli/ai/sessionStore.js +97 -97
- package/src/cli/ai/termui.js +92 -0
- package/src/cli/ai/termui.test.js +131 -0
- package/src/cli/customCommand.exec.test.js +52 -13
- package/src/ui/public/assets/AgentView-B_SeSMYO.js +4 -0
- package/src/ui/public/assets/AppVersionBadge-BeXH_zPw.js +2 -0
- package/src/ui/public/assets/BranchSelector-DiKVTd6_.js +1 -0
- package/src/ui/public/assets/CommitForm-bj3k-DPA.js +6 -0
- package/src/ui/public/assets/EditorView-B9Px9HM-.js +0 -0
- package/src/ui/public/assets/FlowExecutionViewer-B5j4P2AL.js +1 -0
- package/src/ui/public/assets/FlowOrchestrationWorkspace-CvpUR_GE.js +21 -0
- package/src/ui/public/assets/LogList-CRf4Qp6G.js +15 -0
- package/src/ui/public/assets/MindmapView-F9BzvQzm.js +2 -0
- package/src/ui/public/assets/MonitorView-Cp74zQIe.js +1 -0
- package/src/ui/public/assets/ProjectStartupButton-CAJ6NfgE.js +1 -0
- package/src/ui/public/assets/RemoteRepoCard-DbxZKwZQ.js +5 -0
- package/src/ui/public/assets/SourceMapView-SLERMi2h.js +3 -0
- package/src/ui/public/assets/UserInputNode-BJdehl9K.js +1 -0
- package/src/ui/public/assets/WorkbenchView-Ds2-DJ0d.js +28 -0
- package/src/ui/public/assets/element-plus-C0loJL0J.js +32 -0
- package/src/ui/public/assets/element-plus-CXfbWXaJ.css +1 -0
- package/src/ui/public/assets/{flow-mindmap-DnyDhwJv.js → flow-mindmap-CGn6wqsF.js} +1 -1
- package/src/ui/public/assets/index-BEPT2LNX.js +82 -0
- package/src/ui/public/assets/index-Fbjp0DKn.css +1 -0
- package/src/ui/public/assets/{monaco-Dje8Rg13.js → monaco-DPQ3OaiL.js} +2 -2
- package/src/ui/public/assets/socket-io-B9UuzwTN.js +1 -0
- package/src/ui/public/assets/{ts.worker-Dth06zuC.js → ts.worker-METxwbDZ.js} +1 -16
- package/src/ui/public/assets/{vendor-DVvq7qtS.css → vendor-C2ZpZPB4.css} +1 -1
- package/src/ui/public/assets/{vendor-exjCs1jx.js → vendor-pbWglt5U.js} +26 -67
- package/src/ui/public/assets/vue-flow-DRwHh4gM.js +39 -0
- package/src/ui/public/index.html +9 -15
- package/src/ui/server/index.js +4 -0
- package/src/ui/server/routes/workbench/agentChat.js +14 -3
- package/src/ui/server/routes/workbench/agentRoutes.js +218 -212
- package/src/ui/server/routes/workbench/agentSessionStore.js +173 -173
- package/src/ui/public/assets/AgentView-CioAzh-a.js +0 -4
- package/src/ui/public/assets/AppVersionBadge-CZ3UbiAu.js +0 -2
- package/src/ui/public/assets/BranchSelector-Kwcj7e0Z.js +0 -1
- package/src/ui/public/assets/CommitForm-DueeSB7T.js +0 -6
- package/src/ui/public/assets/CommonDialog-ChSKsEz2.css +0 -1
- package/src/ui/public/assets/CommonDialog-Tlk0Fa7g.js +0 -1
- package/src/ui/public/assets/EditorView-B2gm2OW1.js +0 -0
- package/src/ui/public/assets/FlowExecutionViewer-CFpiqZ2C.js +0 -1
- package/src/ui/public/assets/FlowOrchestrationWorkspace-BRUlRQwp.js +0 -21
- package/src/ui/public/assets/LogList-Do3C4BmA.js +0 -15
- package/src/ui/public/assets/MindmapView-C1pPUu8W.js +0 -2
- package/src/ui/public/assets/MonitorView-C2EyggDk.js +0 -1
- package/src/ui/public/assets/ProjectStartupButton-D7mgEsmf.js +0 -1
- package/src/ui/public/assets/RemoteRepoCard-D582mbhK.js +0 -5
- package/src/ui/public/assets/SourceMapView-gQRnN0Vj.js +0 -3
- package/src/ui/public/assets/SvgIcon-CDNsk4-Q.css +0 -1
- package/src/ui/public/assets/SvgIcon-Diox29ks.js +0 -1
- package/src/ui/public/assets/UserInputNode-CYxFuwuS.js +0 -1
- package/src/ui/public/assets/WorkbenchView-CbWSllXy.js +0 -28
- package/src/ui/public/assets/_plugin-vue_export-helper-B9cwfrdH.js +0 -15
- package/src/ui/public/assets/configStore-B8X980y1.js +0 -1
- package/src/ui/public/assets/element-plus-BId3Dnij.js +0 -25
- package/src/ui/public/assets/element-plus-D3Dn7nX0.css +0 -1
- package/src/ui/public/assets/index--onqtBRQ.css +0 -1
- package/src/ui/public/assets/index-DvrM8frM.js +0 -68
- package/src/ui/public/assets/socket-io-CGezBd--.js +0 -1
- package/src/ui/public/assets/vue-flow-Dj_X_Vr1.js +0 -39
- /package/src/ui/public/assets/{dagre-BCXBo6I9.js → dagre-CePNlbK4.js} +0 -0
package/src/cli/ai/termui.js
CHANGED
|
@@ -193,6 +193,96 @@ export function parseKeyForSlashHint(key) {
|
|
|
193
193
|
return null
|
|
194
194
|
}
|
|
195
195
|
|
|
196
|
+
// ──────────────────────────────────────────────────
|
|
197
|
+
// 交互式可选列表(供 modelSetup 等一次性向导使用:上下键切换 + Enter 提交)
|
|
198
|
+
// ──────────────────────────────────────────────────
|
|
199
|
+
//
|
|
200
|
+
// 与 renderSlashHintBody 的差异:
|
|
201
|
+
// - 必须支持 Enter 提交(parseKeyForSlashHint 把它当 'submit',但那个由 readline 默认接管;
|
|
202
|
+
// 可选列表场景下 wizard 自己消费 Enter,不能丢给 readline)
|
|
203
|
+
// - 多支持直接按数字 1..9/0 跳到指定项(给经常用键盘的用户省一趟 ↑↓)
|
|
204
|
+
// - Ctrl+C 在可选列表场景下与 Esc 等价(都视作取消)
|
|
205
|
+
//
|
|
206
|
+
// 渲染/解析都做成纯函数,wizard 内部(modelSetup.selectFromList)负责:
|
|
207
|
+
// - 调用 renderSelectableListBody 把列表写到屏幕
|
|
208
|
+
// - 在 rl.input 上挂 keypress 监听,把 readline 默认行为(历史浏览)回滚掉
|
|
209
|
+
// - 每次 selectedIndex 变化时,重绘列表(用 ANSI 把光标上移、清行、再写)
|
|
210
|
+
|
|
211
|
+
/**
|
|
212
|
+
* 渲染可选项列表 body(纯函数,便于单测)。
|
|
213
|
+
*
|
|
214
|
+
* - 标准项:` [k]. label`(未选中)
|
|
215
|
+
* - 选中项:`▶ [k]. label`(整行反白,含前缀空格,跟下方其它行起点对齐)
|
|
216
|
+
* - 额外项:编号 0,dim 灰;选中时整行反白(与普通选中项视觉一致)
|
|
217
|
+
*
|
|
218
|
+
* @param {Array<{label: string, value: any}>} items
|
|
219
|
+
* @param {number} [selectedIndex=0] - 选中项下标;范围 [0, items.length+extra)
|
|
220
|
+
* 越界回退为 0(默认选第一项,避免空数组报错)
|
|
221
|
+
* @param {string|null} [extraOptionLabel=null] - 额外项(如"自定义" / "手动输入")
|
|
222
|
+
* @returns {string} body 字符串(不含末尾换行 — 由调用方控制)
|
|
223
|
+
*/
|
|
224
|
+
export function renderSelectableListBody(items, selectedIndex = 0, extraOptionLabel = null) {
|
|
225
|
+
const safeItems = Array.isArray(items) ? items : []
|
|
226
|
+
const extraActive = !!extraOptionLabel
|
|
227
|
+
const totalLen = safeItems.length + (extraActive ? 1 : 0)
|
|
228
|
+
// selectedIndex 越界时静默回退为 0(首次调用时通常如此)
|
|
229
|
+
if (!Number.isInteger(selectedIndex) || selectedIndex < 0 || selectedIndex >= totalLen) {
|
|
230
|
+
selectedIndex = 0
|
|
231
|
+
}
|
|
232
|
+
const rows = []
|
|
233
|
+
for (let i = 0; i < safeItems.length; i++) {
|
|
234
|
+
const num = String(i + 1).padStart(2)
|
|
235
|
+
const label = safeItems[i].label
|
|
236
|
+
if (i === selectedIndex) {
|
|
237
|
+
// 整行反白(含 ' ' 缩进) — 起点与未选中行严格对齐,不留左侧白边
|
|
238
|
+
rows.push(chalk.inverse(` ${num}. ${label}`))
|
|
239
|
+
} else {
|
|
240
|
+
rows.push(` ${chalk.cyan(num)}. ${label}`)
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
if (extraActive) {
|
|
244
|
+
const extraIdx = safeItems.length
|
|
245
|
+
if (extraIdx === selectedIndex) {
|
|
246
|
+
// extra 选中时也整行反白,这样高亮跨度统一(虽然 label 是 dim,但反白让它可读)
|
|
247
|
+
rows.push(chalk.inverse(` ${chalk.dim('0')}. ${extraOptionLabel}`))
|
|
248
|
+
} else {
|
|
249
|
+
rows.push(` ${chalk.dim('0')}. ${chalk.dim(extraOptionLabel)}`)
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
return rows.join('\n')
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
/**
|
|
256
|
+
* 解析 readline keypress 事件,识别"可选列表"专用键。
|
|
257
|
+
* 返回动作字符串(消费方据此改 selectedIndex 或提交);
|
|
258
|
+
* 不识别的键返回 null(让 readline 正常处理 — 但消费方应恢复 line buffer
|
|
259
|
+
* 防止方向键的历史浏览把当前输入覆盖)。
|
|
260
|
+
*
|
|
261
|
+
* - ↑ / Shift+Tab → 'prev'
|
|
262
|
+
* - ↓ → 'next'
|
|
263
|
+
* - Enter → 'confirm'
|
|
264
|
+
* - Esc / Ctrl+C → 'cancel'
|
|
265
|
+
* - 数字 0..9 → 'jump:N'(1-based;0 = extra option,需消费方映射)
|
|
266
|
+
*
|
|
267
|
+
* 与 parseKeyForSlashHint 的差别:
|
|
268
|
+
* - 这里 Enter 直接是 'confirm'——wizard 不会让 readline 默认提交(否则进 line 事件
|
|
269
|
+
* 走 REPL 的命令分发,体验错乱);Esc / Ctrl+C 都是 'cancel';不支持 Tab 补全
|
|
270
|
+
* (列表项不是命令片段,不需要补全语义)
|
|
271
|
+
*/
|
|
272
|
+
export function parseKeyForSelectableList(key) {
|
|
273
|
+
if (!key) return null
|
|
274
|
+
const name = key.name
|
|
275
|
+
if (name === 'up') return 'prev'
|
|
276
|
+
if (name === 'tab') return key.shift ? 'prev' : 'next'
|
|
277
|
+
if (name === 'down') return 'next'
|
|
278
|
+
if (name === 'return' || name === 'enter') return 'confirm'
|
|
279
|
+
if (name === 'escape') return 'cancel'
|
|
280
|
+
if (key.ctrl && name === 'c') return 'cancel'
|
|
281
|
+
// 数字键 0..9:readline keypress 事件的 key.name 会是该字符
|
|
282
|
+
if (typeof name === 'string' && /^[0-9]$/.test(name)) return `jump:${name}`
|
|
283
|
+
return null
|
|
284
|
+
}
|
|
285
|
+
|
|
196
286
|
/** 盒式帮助面板 */
|
|
197
287
|
export function printHelpPanel(title, lines) {
|
|
198
288
|
const body = [chalk.bold(title), ...lines].join('\n')
|
|
@@ -536,6 +626,8 @@ export default {
|
|
|
536
626
|
filterSlashCommands,
|
|
537
627
|
renderSlashHintBody,
|
|
538
628
|
parseKeyForSlashHint,
|
|
629
|
+
renderSelectableListBody,
|
|
630
|
+
parseKeyForSelectableList,
|
|
539
631
|
drawInputTop,
|
|
540
632
|
drawInputBottom,
|
|
541
633
|
inputBottomBorder,
|
|
@@ -23,6 +23,7 @@ import {
|
|
|
23
23
|
createAssistantWriter, printToolHeader, printToolResult,
|
|
24
24
|
formatDuration,
|
|
25
25
|
filterSlashCommands, renderSlashHintBody, parseKeyForSlashHint, SLASH_COMMANDS,
|
|
26
|
+
renderSelectableListBody, parseKeyForSelectableList,
|
|
26
27
|
} from './termui.js'
|
|
27
28
|
|
|
28
29
|
// 测试在非 TTY 环境下跑,chalk 默认 level=0(全部降级为纯文本),会让
|
|
@@ -382,3 +383,133 @@ test('parseKeyForSlashHint: 普通字符 / null key 返回 null(消费方透传
|
|
|
382
383
|
assert.equal(parseKeyForSlashHint({ name: 'backspace' }), null)
|
|
383
384
|
assert.equal(parseKeyForSlashHint(undefined), null)
|
|
384
385
|
})
|
|
386
|
+
|
|
387
|
+
// ── 可选项列表(供 /addmodel 等交互式列表选择)──
|
|
388
|
+
|
|
389
|
+
test('renderSelectableListBody: 默认选中第一项(整行反白,起点与未选中行对齐)', () => {
|
|
390
|
+
const items = [
|
|
391
|
+
{ label: 'OpenAI', value: 'openai' },
|
|
392
|
+
{ label: 'Anthropic (Claude)', value: 'anthropic' },
|
|
393
|
+
{ label: 'DeepSeek', value: 'deepseek' },
|
|
394
|
+
]
|
|
395
|
+
const body = renderSelectableListBody(items, 0)
|
|
396
|
+
const lines = stripAnsi(body).split('\n')
|
|
397
|
+
assert.equal(lines.length, 3)
|
|
398
|
+
// 每行视觉对齐到"缩进 + 数字 + . "结构(padStart(2) 让 1-9 编号前面再补 1 空格)
|
|
399
|
+
// → " 1." / " 2." / " 3." 都是"3 个字符前导:空格+空格+空格+数字+点+空格"+ label
|
|
400
|
+
// 选中行(反白)也用同样的" "前缀,不能因为反白就丢掉缩进(否则反白块起点会偏左)
|
|
401
|
+
for (const l of lines) {
|
|
402
|
+
assert.match(l, /^ +\d+\. /, `每行应以"缩进 + 标号 + . "开头: ${JSON.stringify(l)}`)
|
|
403
|
+
}
|
|
404
|
+
// 进一步:每行的"前导列宽"(即 'padStart(2) 后的数字 + . ' 之前的所有字符)长度一致,
|
|
405
|
+
// 才能保证反白块的左缘跟未选中行的左缘对齐(这是 renderSlashHintBody 同款设计)
|
|
406
|
+
const indentCols = lines.map(l => l.indexOf('.') + 1) // 标号结束列
|
|
407
|
+
assert.ok(indentCols.every(c => c === indentCols[0]),
|
|
408
|
+
`每行标号结束列应一致(选中行不能比未选中行更长/更短): ${JSON.stringify(indentCols)}`)
|
|
409
|
+
assert.ok(lines[0].includes('OpenAI'))
|
|
410
|
+
assert.ok(lines[1].includes('Anthropic (Claude)'))
|
|
411
|
+
assert.ok(lines[2].includes('DeepSeek'))
|
|
412
|
+
// raw 中:选中行含 inverse(\x1b[7m),未选中行不含
|
|
413
|
+
const rawLines = body.split('\n')
|
|
414
|
+
assert.match(rawLines[0], /\x1b\[7m/, '选中行首行应含 inverse')
|
|
415
|
+
assert.ok(!rawLines[1].includes('\x1b[7m'), '未选中行不应含 inverse')
|
|
416
|
+
assert.ok(!rawLines[2].includes('\x1b\[7m'), '未选中行不应含 inverse')
|
|
417
|
+
})
|
|
418
|
+
|
|
419
|
+
test('renderSelectableListBody: selectedIndex 切换,反白行随之改变', () => {
|
|
420
|
+
const items = [
|
|
421
|
+
{ label: 'A', value: 'a' },
|
|
422
|
+
{ label: 'B', value: 'b' },
|
|
423
|
+
{ label: 'C', value: 'c' },
|
|
424
|
+
]
|
|
425
|
+
// 选中中间
|
|
426
|
+
const sel = renderSelectableListBody(items, 1)
|
|
427
|
+
const rawLines = sel.split('\n')
|
|
428
|
+
assert.ok(!rawLines[0].includes('\x1b[7m'), '首行 A 不应被反白')
|
|
429
|
+
assert.match(rawLines[1], /\x1b\[7m/, '中间行 B 应被反白')
|
|
430
|
+
assert.ok(!rawLines[2].includes('\x1b[7m'), '末行 C 不应被反白')
|
|
431
|
+
})
|
|
432
|
+
|
|
433
|
+
test('renderSelectableListBody: selectedIndex 越界(<0 或 >=total)静默回退为 0', () => {
|
|
434
|
+
const items = [{ label: 'X', value: 'x' }, { label: 'Y', value: 'y' }]
|
|
435
|
+
// 负数
|
|
436
|
+
assert.match(
|
|
437
|
+
renderSelectableListBody(items, -1).split('\n')[0],
|
|
438
|
+
/\x1b\[7m/,
|
|
439
|
+
'负索引应回退为 0,首行反白',
|
|
440
|
+
)
|
|
441
|
+
// 超出范围
|
|
442
|
+
assert.match(
|
|
443
|
+
renderSelectableListBody(items, 99).split('\n')[0],
|
|
444
|
+
/\x1b\[7m/,
|
|
445
|
+
'超出范围应回退为 0,首行反白',
|
|
446
|
+
)
|
|
447
|
+
// 非整数
|
|
448
|
+
assert.match(
|
|
449
|
+
renderSelectableListBody(items, 1.5).split('\n')[0],
|
|
450
|
+
/\x1b\[7m/,
|
|
451
|
+
'非整数应回退为 0,首行反白',
|
|
452
|
+
)
|
|
453
|
+
})
|
|
454
|
+
|
|
455
|
+
test('renderSelectableListBody: extraOptionLabel 出现且选中时也是整行反白', () => {
|
|
456
|
+
const items = [{ label: 'A', value: 'a' }]
|
|
457
|
+
// 选中 extra(items.length = 1)
|
|
458
|
+
const sel = renderSelectableListBody(items, 1, 'Custom')
|
|
459
|
+
const lines = stripAnsi(sel).split('\n')
|
|
460
|
+
assert.equal(lines.length, 2)
|
|
461
|
+
assert.ok(lines[0].includes('A'))
|
|
462
|
+
assert.ok(lines[1].includes('0'), 'extra 应显示 0 号')
|
|
463
|
+
assert.ok(lines[1].includes('Custom'))
|
|
464
|
+
// raw 中 extra 是反白行
|
|
465
|
+
assert.match(sel.split('\n')[1], /\x1b\[7m/, 'extra 项选中时也应反白')
|
|
466
|
+
})
|
|
467
|
+
|
|
468
|
+
test('renderSelectableListBody: extraOptionLabel 未选中时是 dim 灰,无反白', () => {
|
|
469
|
+
const items = [{ label: 'A', value: 'a' }]
|
|
470
|
+
const sel = renderSelectableListBody(items, 0, 'Custom')
|
|
471
|
+
// standard 行反白,extra 行不反白
|
|
472
|
+
const rawLines = sel.split('\n')
|
|
473
|
+
assert.match(rawLines[0], /\x1b\[7m/, '标准行应反白')
|
|
474
|
+
assert.ok(!rawLines[1].includes('\x1b[7m'), 'extra 行未选中时不应反白')
|
|
475
|
+
// dim 灰用 \x1b[2m 或 grayscale 序列,宽松断言含 \x1b
|
|
476
|
+
assert.match(rawLines[1], /\x1b\[/, 'extra 行应用 dim 着色')
|
|
477
|
+
})
|
|
478
|
+
|
|
479
|
+
test('renderSelectableListBody: 空 items + 无 extra → 返回空串(无渲染)', () => {
|
|
480
|
+
assert.equal(renderSelectableListBody([], 0), '')
|
|
481
|
+
assert.equal(renderSelectableListBody([], 0, undefined), '')
|
|
482
|
+
assert.equal(renderSelectableListBody(undefined, 0), '')
|
|
483
|
+
})
|
|
484
|
+
|
|
485
|
+
test('parseKeyForSelectableList: ↑↓/Enter/Esc/Ctrl+C 返回动作', () => {
|
|
486
|
+
assert.equal(parseKeyForSelectableList({ name: 'up' }), 'prev')
|
|
487
|
+
assert.equal(parseKeyForSelectableList({ name: 'down' }), 'next')
|
|
488
|
+
assert.equal(parseKeyForSelectableList({ name: 'return' }), 'confirm')
|
|
489
|
+
assert.equal(parseKeyForSelectableList({ name: 'enter' }), 'confirm')
|
|
490
|
+
assert.equal(parseKeyForSelectableList({ name: 'escape' }), 'cancel')
|
|
491
|
+
// Ctrl+C 也视作取消
|
|
492
|
+
assert.equal(parseKeyForSelectableList({ name: 'c', ctrl: true }), 'cancel')
|
|
493
|
+
})
|
|
494
|
+
|
|
495
|
+
test('parseKeyForSelectableList: Tab 视作 next,Shift+Tab 视作 prev(同 slash hint)', () => {
|
|
496
|
+
assert.equal(parseKeyForSelectableList({ name: 'tab' }), 'next')
|
|
497
|
+
assert.equal(parseKeyForSelectableList({ name: 'tab', shift: true }), 'prev')
|
|
498
|
+
})
|
|
499
|
+
|
|
500
|
+
test('parseKeyForSelectableList: 数字键 0..9 返回 jump:N(数字直跳)', () => {
|
|
501
|
+
assert.equal(parseKeyForSelectableList({ name: '1' }), 'jump:1')
|
|
502
|
+
assert.equal(parseKeyForSelectableList({ name: '5' }), 'jump:5')
|
|
503
|
+
assert.equal(parseKeyForSelectableList({ name: '9' }), 'jump:9')
|
|
504
|
+
assert.equal(parseKeyForSelectableList({ name: '0' }), 'jump:0')
|
|
505
|
+
})
|
|
506
|
+
|
|
507
|
+
test('parseKeyForSelectableList: 其他字符 / null / undefined 返回 null(透传给 readline)', () => {
|
|
508
|
+
assert.equal(parseKeyForSelectableList(null), null)
|
|
509
|
+
assert.equal(parseKeyForSelectableList(undefined), null)
|
|
510
|
+
assert.equal(parseKeyForSelectableList({ name: 'a' }), null)
|
|
511
|
+
assert.equal(parseKeyForSelectableList({ name: 'space' }), null)
|
|
512
|
+
assert.equal(parseKeyForSelectableList({ name: 'backspace' }), null)
|
|
513
|
+
// Ctrl+(非 c) 不视作取消
|
|
514
|
+
assert.equal(parseKeyForSelectableList({ name: 'd', ctrl: true }), null)
|
|
515
|
+
})
|
|
@@ -19,7 +19,9 @@
|
|
|
19
19
|
// (`node -e "..."` 跨平台) 触发 runCustomCommand 内部 callback,
|
|
20
20
|
// 验证 stdout/stderr/error 三条打印分支都生效。
|
|
21
21
|
//
|
|
22
|
-
// 测试间用 `
|
|
22
|
+
// 测试间用 `waitForContent()` 轮询等待真实子进程的 exec 回调跑完。
|
|
23
|
+
// 早期版本用固定 setTimeout(200),但在 Windows + node --test 并行执行下
|
|
24
|
+
// 子进程回调经常晚于 200ms 到达,导致 flaky 失败。
|
|
23
25
|
import { test, afterEach } from 'node:test'
|
|
24
26
|
import assert from 'node:assert/strict'
|
|
25
27
|
import { runCustomCommand } from './customCommand.js'
|
|
@@ -46,9 +48,37 @@ afterEach(() => {
|
|
|
46
48
|
_resetForTests()
|
|
47
49
|
})
|
|
48
50
|
|
|
49
|
-
/**
|
|
50
|
-
|
|
51
|
-
|
|
51
|
+
/**
|
|
52
|
+
* 等异步 exec 回调跑完的辅助函数。
|
|
53
|
+
* 轮询检测目标数组中出现匹配内容,最多等 3 秒。
|
|
54
|
+
* 比固定 setTimeout 更可靠,避免 Windows 上 exec 回调时序不稳定导致的 flaky。
|
|
55
|
+
*
|
|
56
|
+
* @param {() => boolean} predicate - 检测是否完成的断言函数
|
|
57
|
+
* @param {number} timeout - 最大等待毫秒数
|
|
58
|
+
* @param {number} interval - 轮询间隔毫秒数
|
|
59
|
+
* @returns {Promise<void>}
|
|
60
|
+
*/
|
|
61
|
+
function waitFor(predicate, timeout = 3000, interval = 50) {
|
|
62
|
+
return new Promise((resolve, reject) => {
|
|
63
|
+
const start = Date.now()
|
|
64
|
+
function check() {
|
|
65
|
+
try {
|
|
66
|
+
if (predicate()) return resolve()
|
|
67
|
+
} catch (e) {
|
|
68
|
+
// predicate 可能抛 AssertionError,先记录但不立即失败
|
|
69
|
+
}
|
|
70
|
+
if (Date.now() - start >= timeout) {
|
|
71
|
+
return reject(new Error(`waitFor() 超时(${timeout}ms): 条件未满足`))
|
|
72
|
+
}
|
|
73
|
+
setTimeout(check, interval)
|
|
74
|
+
}
|
|
75
|
+
check()
|
|
76
|
+
})
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/** 超时兜底:无论结果如何,在指定时间后 resolve(用于断言"不应出现"的场景) */
|
|
80
|
+
function settle(timeout = 500) {
|
|
81
|
+
return new Promise((r) => setTimeout(r, timeout))
|
|
52
82
|
}
|
|
53
83
|
|
|
54
84
|
// ========== 行为契约 ==========
|
|
@@ -56,7 +86,8 @@ function settle() {
|
|
|
56
86
|
test('runCustomCommand: silent=true 不打印 [自定义命令执行] 头标', async () => {
|
|
57
87
|
captureConsole()
|
|
58
88
|
runCustomCommand('node -e "console.log(1)"', { silent: true })
|
|
59
|
-
|
|
89
|
+
// 等足够久确保 exec 回调已执行(断言"不应出现"的场景)
|
|
90
|
+
await settle(500)
|
|
60
91
|
assert.equal(
|
|
61
92
|
logs.some((m) => /\[自定义命令执行\]/.test(m)),
|
|
62
93
|
false,
|
|
@@ -66,8 +97,9 @@ test('runCustomCommand: silent=true 不打印 [自定义命令执行] 头标', a
|
|
|
66
97
|
|
|
67
98
|
test('runCustomCommand: 非 silent 打印 [自定义命令执行] 头标 + 命令', async () => {
|
|
68
99
|
captureConsole()
|
|
100
|
+
// 非 silent 模式头标是同步打印的,但 stdout 是异步的
|
|
69
101
|
runCustomCommand('node -e "console.log(1)"')
|
|
70
|
-
await
|
|
102
|
+
await waitFor(() => logs.some((m) => /\[自定义命令执行\]/.test(m)))
|
|
71
103
|
assert.ok(
|
|
72
104
|
logs.some((m) => /\[自定义命令执行\]/.test(m)),
|
|
73
105
|
'非 silent 应打印 [自定义命令执行] 头标'
|
|
@@ -81,7 +113,7 @@ test('runCustomCommand: 非 silent 打印 [自定义命令执行] 头标 + 命
|
|
|
81
113
|
test('runCustomCommand: stdout 有内容时打印 [自定义命令输出] + 内容', async () => {
|
|
82
114
|
captureConsole()
|
|
83
115
|
runCustomCommand('node -e "console.log(\'hello-from-stdout\')"', { silent: true })
|
|
84
|
-
await
|
|
116
|
+
await waitFor(() => logs.some((m) => /hello-from-stdout/.test(m)))
|
|
85
117
|
assert.ok(
|
|
86
118
|
logs.some((m) => /\[自定义命令输出\]/.test(m)),
|
|
87
119
|
'应打印 [自定义命令输出] 头标'
|
|
@@ -98,7 +130,7 @@ test('runCustomCommand: stderr 有内容时打印 [自定义命令错误输出]
|
|
|
98
130
|
'node -e "console.error(\'warning-msg\')"',
|
|
99
131
|
{ silent: true }
|
|
100
132
|
)
|
|
101
|
-
await
|
|
133
|
+
await waitFor(() => errs.some((m) => /warning-msg/.test(m)))
|
|
102
134
|
assert.ok(
|
|
103
135
|
errs.some((m) => /\[自定义命令错误输出\]/.test(m)),
|
|
104
136
|
'应打印 [自定义命令错误输出] 头标'
|
|
@@ -112,7 +144,7 @@ test('runCustomCommand: stderr 有内容时打印 [自定义命令错误输出]
|
|
|
112
144
|
test('runCustomCommand: 进程非 0 退出时打印 [自定义命令错误]', async () => {
|
|
113
145
|
captureConsole()
|
|
114
146
|
runCustomCommand('node -e "process.exit(1)"', { silent: true })
|
|
115
|
-
await
|
|
147
|
+
await waitFor(() => errs.some((m) => /\[自定义命令错误\]/.test(m)))
|
|
116
148
|
assert.ok(
|
|
117
149
|
errs.some((m) => /\[自定义命令错误\]/.test(m)),
|
|
118
150
|
'非 0 退出应打印 [自定义命令错误] 头标'
|
|
@@ -123,7 +155,8 @@ test('runCustomCommand: 进程非 0 退出时打印 [自定义命令错误]', as
|
|
|
123
155
|
test('runCustomCommand: 成功 + 无输出时不打印 [自定义命令输出/错误]', async () => {
|
|
124
156
|
captureConsole()
|
|
125
157
|
runCustomCommand('node -e ""', { silent: true })
|
|
126
|
-
|
|
158
|
+
// 等足够久确保 exec 回调已执行(无输出的情况无法用 waitFor 检测内容)
|
|
159
|
+
await settle(1000)
|
|
127
160
|
assert.equal(logs.some((m) => /\[自定义命令输出\]/.test(m)), false)
|
|
128
161
|
assert.equal(errs.some((m) => /\[自定义命令错误\]/.test(m)), false)
|
|
129
162
|
assert.equal(errs.some((m) => /\[自定义命令错误输出\]/.test(m)), false)
|
|
@@ -135,7 +168,10 @@ test('runCustomCommand: 同时有 stdout 和 stderr 时两条都打印', async (
|
|
|
135
168
|
'node -e "console.log(\'OUT-MARKER-XYZ\'); console.error(\'ERR-MARKER-XYZ\')"',
|
|
136
169
|
{ silent: true }
|
|
137
170
|
)
|
|
138
|
-
await
|
|
171
|
+
await waitFor(() =>
|
|
172
|
+
logs.some((m) => /OUT-MARKER-XYZ/.test(m)) &&
|
|
173
|
+
errs.some((m) => /ERR-MARKER-XYZ/.test(m))
|
|
174
|
+
)
|
|
139
175
|
assert.ok(logs.some((m) => /OUT-MARKER-XYZ/.test(m)), 'stdout 应被打印到 console.log')
|
|
140
176
|
assert.ok(errs.some((m) => /ERR-MARKER-XYZ/.test(m)), 'stderr 应被打印到 console.error')
|
|
141
177
|
})
|
|
@@ -153,13 +189,16 @@ test('runCustomCommand: 跟踪 child 到 activeChildren(SIGINT 兜底)', async (
|
|
|
153
189
|
// 且 SIGINT 路径下用户主动 kill 才走 killAllTrackedChildren,
|
|
154
190
|
// 主动 exit 的 child 由 trackChild 的 once('exit') 自动从集合移除,
|
|
155
191
|
// 已在 cleanup.test.js#trackChild 单独覆盖)
|
|
156
|
-
await settle()
|
|
192
|
+
await settle(1000)
|
|
157
193
|
})
|
|
158
194
|
|
|
159
195
|
test('runCustomCommand: 非 silent + stdout 都打印,顺序头标在前', async () => {
|
|
160
196
|
captureConsole()
|
|
161
197
|
runCustomCommand('node -e "console.log(\'payload\')"')
|
|
162
|
-
await
|
|
198
|
+
await waitFor(() =>
|
|
199
|
+
logs.some((m) => /\[自定义命令执行\]/.test(m)) &&
|
|
200
|
+
logs.some((m) => /\[自定义命令输出\]/.test(m))
|
|
201
|
+
)
|
|
163
202
|
const execIdx = logs.findIndex((m) => /\[自定义命令执行\]/.test(m))
|
|
164
203
|
const outIdx = logs.findIndex((m) => /\[自定义命令输出\]/.test(m))
|
|
165
204
|
assert.ok(execIdx >= 0, '应有 [自定义命令执行] 头标')
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import"./rolldown-runtime-BM3Ffeng.js";import{Bt as e,Cn as t,Et as n,G as r,Jn as i,Ln as a,Mn as o,Pt as s,Tn as c,Vn as l,Xn as u,Y as d,Zn as f,_n as p,_r as m,a as h,ar as g,et as _,gr as v,hn as y,ht as b,i as x,ln as S,lt as C,mn as w,mr as T,o as E,on as D,sr as O,tn as k,un as A,vn as j,zn as M}from"./element-plus-C0loJL0J.js";import{i as N,n as P,o as ee}from"./vendor-pbWglt5U.js";import{E as F,T as I,x as L}from"./index-BEPT2LNX.js";var R=64*1024;function z(e){if(!e||!Array.isArray(e.messages))return[];let t=[],n=e.messages.length;for(let r=0;r<n;r++){let i=e.messages[r];if(i.role!==`system`){if(i.role===`user`){let e=``,n;if(typeof i.content==`string`)e=i.content;else if(Array.isArray(i.content)){e=i.content.filter(e=>e?.type===`text`).map(e=>e.text||``).join(` `);let t=i.content.filter(e=>e?.type===`image_url`&&typeof e.image_url?.url==`string`).map((e,t)=>({id:`att-${r}-${t}`,name:`image`,size:0,type:H(e.image_url?.url||``)||`image/*`,preview:e.image_url?.url}));t.length>0&&(n=t)}(e||n)&&t.push({id:`msg-${r}`,role:`user`,content:e,attachments:n,status:`done`,createdAt:Date.now()})}else if(i.role===`assistant`){let a=``;typeof i.content==`string`&&(a=i.content),a.length>R&&(a=`…(前文已截断)\n${a.slice(-R)}`);let o=[];if(i.tool_calls&&i.tool_calls.length>0)for(let e of i.tool_calls)o.push({id:e.id||e.function?.name||N(),name:e.function?.name||``,arguments:e.function?.arguments||``,argsPreview:B(e.function?.name||``,e.function?.arguments||``),status:`done`,result:``});let s=r+1;for(;s<n&&e.messages[s].role===`tool`;){let t=e.messages[s],n=t.tool_call_id||t.name||``,i=o.find(e=>e.id===n);if(i){let e=t.content;typeof e!=`string`&&(e=`(non-text result)`),e.length>R&&(e=`…(前文已截断)\n${e.slice(-R)}`),i.result=e}r=s,s++}let c=!!a,l=o.length>0;(c||l)&&t.push({id:`msg-${r}`,role:`assistant`,content:a||``,toolCalls:l?o:void 0,status:`done`,createdAt:Date.now()})}}}return t}function B(e,t){try{let n=JSON.parse(t);switch(e){case`run_command`:return String(n.command||``).slice(0,200);case`read_file`:case`write_file`:case`edit_file`:return String(n.path||``);case`list_files`:return String(n.path||`.`);case`search_text`:return String(n.pattern||``);default:return JSON.stringify(n).slice(0,200)}}catch{return t.slice(0,200)}}function V(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 H(e){let t=/^data:([^;,]+)/.exec(e);return t?t[1]:``}function U(){let e=O([]),t=O(!1),n=O(null),r=O([]),i=O(!1),a=O(!1),o=null,s=0;async function c(){t.value=!0;try{let t=await fetch(`/api/agent/sessions`).then(e=>e.json());if(!t.success){h.error(t.error||F(`@AGENT:加载会话列表失败`));return}e.value=Array.isArray(t.sessions)?t.sessions:[]}catch(e){h.error(F(`@AGENT:加载会话列表失败`)+`: `+(e?.message||e))}finally{t.value=!1}}async function l(e){a.value=!0,n.value=e;try{let t=await fetch(`/api/agent/sessions/${encodeURIComponent(e)}`).then(e=>e.json());if(!t.success){h.error(t.error||F(`@AGENT:加载会话失败`));return}r.value=z(t.session)}catch(e){h.error(F(`@AGENT:加载会话失败`)+`: `+(e?.message||e))}finally{a.value=!1}}async function u(t){try{await x.confirm(F(`@AGENT:确认删除该会话`),F(`@AGENT:删除后无法恢复`),{type:`warning`})}catch{return}try{let i=await fetch(`/api/agent/sessions/${encodeURIComponent(t)}`,{method:`DELETE`}).then(e=>e.json());if(!i.success){h.error(i.error||F(`@AGENT:删除失败`));return}e.value=e.value.filter(e=>e.sessionId!==t),n.value===t&&(n.value=null,r.value=[]),h.success(F(`@AGENT:已删除`))}catch(e){h.error(F(`@AGENT:删除失败`)+`: `+(e?.message||e))}}async function d(t,n){try{let r=await fetch(`/api/agent/sessions/${encodeURIComponent(t)}`,{method:`PUT`,headers:{"Content-Type":`application/json`},body:JSON.stringify({title:n})}).then(e=>e.json());if(!r.success){h.error(r.error||F(`@AGENT:重命名失败`));return}let i=e.value.find(e=>e.sessionId===t);i&&(i.title=n),h.success(F(`@AGENT:已重命名`))}catch(e){h.error(F(`@AGENT:重命名失败`)+`: `+(e?.message||e))}}function f(){n.value=null,r.value=[]}async function p(e,t=[]){let a=t.filter(e=>e?.file?.type?.startsWith(`image/`));if(a.length<t.length&&h.warning(F(`@AGENT:仅支持发送图片,非图片文件已忽略`)),!e.trim()&&a.length===0||i.value)return;let l=(await Promise.allSettled(a.map(e=>V(e.file)))).map(e=>e.status===`fulfilled`?e.value:``).filter(e=>e.startsWith(`data:image/`)),u=++s;o=new AbortController;let d=o,f={id:N(),role:`user`,content:e,status:`done`,createdAt:Date.now()};a.length>0&&(f.attachments=a.map(e=>({id:e.id,name:e.file.name||`image`,size:e.file.size||0,type:e.file.type||``,preview:e.preview}))),r.value.push(f);let p=g({id:N(),role:`assistant`,content:``,status:`pending`,createdAt:Date.now()});r.value.push(p),i.value=!0;let m=[];try{let t=await fetch(`/api/agent/chat`,{method:`POST`,headers:{"Content-Type":`application/json`,Accept:`text/event-stream`},body:JSON.stringify({sessionId:n.value||``,userMessage:e,...l.length>0?{images:l}:{}}),signal:d.signal});if(u!==s)return;if(!t.ok||!t.body){let e=await t.text().catch(()=>``);throw Error(e||`HTTP ${t.status}`)}let i=t.body.getReader(),a=new TextDecoder(`utf-8`),o=``,f=n.value;for(;;){let{value:e,done:t}=await i.read();if(u!==s)return;if(t)break;o+=a.decode(e,{stream:!0});let c=o.split(`
|
|
2
|
+
`);o=c.pop()??``;for(let e of c){let t=e.trim();if(!t.startsWith(`data:`))continue;let r=t.slice(5).trim();if(!r)continue;let i;try{i=JSON.parse(r)}catch{continue}switch(i.type){case`meta`:i.sessionId&&(f=i.sessionId,n.value=i.sessionId);break;case`thinking`:p.reasoning||(p.reasoning=``,p.reasoningStatus=`streaming`),p.reasoning+=String(i.delta||``),p.status=`streaming`;break;case`content`:p.status===`pending`&&(p.status=`streaming`);{let e=String(i.delta||``);p.content+=e;let t=P(p.content);t.reasoning&&(p.reasoning||(p.reasoning=``,p.reasoningStatus=`streaming`),p.reasoning=t.reasoning,p.content=t.content)}break;case`tool_call_start`:{let e=g({id:i.toolCallId||N(),name:i.name||``,argsPreview:i.argsPreview||``,arguments:i.argsPreview||``,status:`running`,result:``});m.push(e),p.toolCalls||=[],p.toolCalls.push(e),p.status===`pending`&&(p.status=`streaming`);break}case`tool_result`:{let e=m.find(e=>e.id===i.toolCallId);e&&(e.result=String(i.result||``),e.status=`done`);break}case`done`:{let e=P(i.content||p.content);e.reasoning&&!p.reasoning&&(p.reasoning=e.reasoning),p.content=e.content,p.status=`done`,p.reasoningStatus===`streaming`&&(p.reasoningStatus=`done`);break}case`error`:p.status=`error`,p.error=String(i.error||F(`@AGENT:未知错误`)),p.reasoningStatus===`streaming`&&(p.reasoningStatus=`done`);break}}r.value=[...r.value]}if(u!==s)return;p.status===`pending`&&(p.status=`done`),f&&f!==n.value&&(n.value=f),c().catch(()=>{})}catch(e){if(u!==s)return;e?.name===`AbortError`||d.signal.aborted?(p.content=(p.content||``)+`
|
|
3
|
+
|
|
4
|
+
[`+F(`@AGENT:已停止`)+`]`,p.status=`done`,p.reasoningStatus===`streaming`&&(p.reasoningStatus=`done`)):(p.status=`error`,p.error=e?.message||String(e),h.error(p.error||F(`@AGENT:对话失败`)))}finally{u===s&&(i.value=!1,o=null)}}function m(){o&&=(o.abort(),null)}return{sessions:e,sessionsLoading:t,currentSessionId:n,messages:r,isStreaming:i,sessionLoading:a,loadSessions:c,loadSession:l,deleteSession:u,renameSession:d,newSession:f,sendMessage:p,stop:m}}var W=c({__name:`AgentView`,setup(t,{expose:c}){c();let l=L(),{sessions:u,sessionsLoading:f,currentSessionId:p,messages:m,isStreaming:g,sessionLoading:v,loadSessions:y,loadSession:S,deleteSession:T,renameSession:E,newSession:D,sendMessage:k,stop:A}=U(),j=w(()=>{let e=l.theme;return e===`dark`||e===`auto`&&window.matchMedia(`(prefers-color-scheme: dark)`).matches?`dark`:`light`}),M=O(``),N=w(()=>{if(!M.value.trim())return u.value;let e=M.value.toLowerCase();return u.value.filter(t=>(t.title||``).toLowerCase().includes(e)||(t.model||``).toLowerCase().includes(e))}),P=w(()=>[{id:`p1`,label:F(`@AGENT:查看项目结构`),prompt:F(`@AGENT:prompt_p1`)},{id:`p2`,label:F(`@AGENT:分析代码质量`),prompt:F(`@AGENT:prompt_p2`)},{id:`p3`,label:F(`@AGENT:帮我写测试`),prompt:F(`@AGENT:prompt_p3`)},{id:`p4`,label:F(`@AGENT:Git 状态检查`),prompt:F(`@AGENT:prompt_p4`)}]);async function I(e){await k(e.text,e.files),await o(),B()}async function R(e){await k(e.prompt),await o(),B()}let z=O(null);function B(e=!0){z.value?.scrollToBottom(e)}i(()=>m.value.length,()=>{o(()=>B(!1))});function V(e){if(g.value){h.warning(F(`@AGENT:请先停止当前生成`));return}S(e)}function H(){if(g.value){h.warning(F(`@AGENT:请先停止当前生成`));return}D()}function W(e,t){if(t.stopPropagation(),g.value&&p.value===e){h.warning(F(`@AGENT:请先停止当前生成`));return}T(e)}async function G(e,t,n){n.stopPropagation();try{let{value:n}=await x.prompt(F(`@AGENT:请输入新的会话标题`),F(`@AGENT:重命名会话`),{inputValue:t,inputPattern:/.+/,inputErrorMessage:F(`@AGENT:标题不能为空`)});n&&n!==t&&await E(e,n)}catch{}}function K(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<10080*60*1e3){let e=Math.floor(r/(1440*60*1e3));return e===0?F(`@AGENT:今天`):`${e}${F(`@AGENT:天前`)}`}return`${t.getFullYear()}-${i(t.getMonth()+1)}-${i(t.getDate())}`}catch{return e}}let q=O(280),J=O(!1);function Y(e){J.value=!0;let t=e.clientX,n=q.value,r=e=>{let r=e.clientX-t;q.value=Math.max(200,Math.min(500,n+r))},i=()=>{J.value=!1,document.removeEventListener(`mousemove`,r),document.removeEventListener(`mouseup`,i)};document.addEventListener(`mousemove`,r),document.addEventListener(`mouseup`,i)}a(()=>{y()});let X={configStore:l,sessions:u,sessionsLoading:f,currentSessionId:p,messages:m,isStreaming:g,sessionLoading:v,loadSessions:y,loadSession:S,deleteSession:T,renameSession:E,newSession:D,sendMessage:k,stop:A,chatTheme:j,searchQuery:M,filteredSessions:N,presetQuestions:P,onSend:I,onSelectPreset:R,chatContainerRef:z,scrollToBottom:B,selectSession:V,handleNewSession:H,handleDelete:W,handleRename:G,formatDate:K,sidebarWidth:q,isResizing:J,startResize:Y,get $t(){return F},get ElTooltip(){return r},get ElIcon(){return d},get Plus(){return s},get Search(){return e},get Delete(){return C},get Edit(){return b},get ChatLineRound(){return _},get Loading(){return n},get ChatContainer(){return ee}};return Object.defineProperty(X,`__isScriptSetup`,{enumerable:!1,value:!0}),X}}),G={class:`agent-view`},K={class:`sidebar-header`},q={class:`sidebar-search`},J=[`placeholder`],Y={class:`session-list`},X={key:0,class:`empty-state`},Z={class:`empty-text`},Q={key:0,class:`empty-hint`},te=[`onClick`],ne={class:`session-item-main`},$={class:`session-item-title`},re={class:`session-item-meta`},ie={class:`meta-time`},ae={class:`meta-count`},oe={key:0,class:`meta-source cli`},se=[`onClick`],ce=[`onClick`],le={class:`agent-chat-area`},ue={key:0,class:`chat-loading`},de={key:0,class:`stop-button-bar`};function fe(e,n,r,i,a,o){let s=E;return M(),j(`div`,G,[p(` ═══ 左侧:会话列表 ═══ `),y(`aside`,{class:`agent-sidebar`,style:v({width:i.sidebarWidth+`px`})},[p(` 顶部操作栏 `),y(`div`,K,[y(`button`,{class:`new-session-btn`,onClick:i.handleNewSession},[t(i.ElIcon,null,{default:u(()=>[t(i.Plus)]),_:1}),y(`span`,null,m(i.$t(`@AGENT:新建会话`)),1)])]),p(` 搜索框 `),y(`div`,q,[t(i.ElIcon,{class:`search-icon`},{default:u(()=>[t(i.Search)]),_:1}),f(y(`input`,{"onUpdate:modelValue":n[0]||=e=>i.searchQuery=e,placeholder:i.$t(`@AGENT:搜索会话...`),class:`search-input`,type:`text`},null,8,J),[[D,i.searchQuery]])]),p(` 会话列表 `),f((M(),j(`div`,Y,[i.filteredSessions.length===0&&!i.sessionsLoading?(M(),j(`div`,X,[t(i.ElIcon,{size:28,color:`var(--text-tertiary)`},{default:u(()=>[t(i.ChatLineRound)]),_:1}),y(`div`,Z,m(i.searchQuery?i.$t(`@AGENT:未找到匹配的会话`):i.$t(`@AGENT:暂无会话`)),1),i.searchQuery?p(`v-if`,!0):(M(),j(`div`,Q,m(i.$t(`@AGENT:点击上方按钮开始对话`)),1))])):p(`v-if`,!0),(M(!0),j(A,null,l(i.filteredSessions,e=>(M(),j(`div`,{key:e.sessionId,class:T([`session-item`,{active:i.currentSessionId===e.sessionId}]),onClick:t=>i.selectSession(e.sessionId)},[y(`div`,ne,[y(`div`,$,m(e.title||i.$t(`@AGENT:无标题`)),1),y(`div`,re,[y(`span`,ie,m(i.formatDate(e.updatedAt)),1),n[3]||=y(`span`,{class:`meta-dot`},`·`,-1),y(`span`,ae,m(e.messageCount)+` `+m(i.$t(`@AGENT:条`)),1),e.source===`cli`?(M(),j(`span`,oe,`CLI`)):p(`v-if`,!0)])]),y(`div`,{class:`session-item-actions`,onClick:n[1]||=S(()=>{},[`stop`])},[t(i.ElTooltip,{content:i.$t(`@AGENT:重命名`),placement:`top`,"show-after":500},{default:u(()=>[y(`button`,{class:`item-action-btn`,onClick:t=>i.handleRename(e.sessionId,e.title,t)},[t(i.ElIcon,null,{default:u(()=>[t(i.Edit)]),_:1})],8,se)]),_:2},1032,[`content`]),t(i.ElTooltip,{content:i.$t(`@AGENT:删除`),placement:`top`,"show-after":500},{default:u(()=>[y(`button`,{class:`item-action-btn danger`,onClick:t=>i.handleDelete(e.sessionId,t)},[t(i.ElIcon,null,{default:u(()=>[t(i.Delete)]),_:1})],8,ce)]),_:2},1032,[`content`])])],10,te))),128))])),[[s,i.sessionsLoading]])],4),p(` 拖拽分隔条 `),y(`div`,{class:T([`sidebar-resizer`,{active:i.isResizing}]),onMousedown:i.startResize},null,34),p(` ═══ 右侧:对话区域 ═══ `),y(`main`,le,[p(` 加载中 `),i.sessionLoading?(M(),j(`div`,ue,[t(i.ElIcon,{class:`is-loading`,size:32},{default:u(()=>[t(i.Loading)]),_:1}),y(`span`,null,m(i.$t(`@AGENT:加载会话中...`)),1)])):(M(),j(A,{key:1},[p(` ChatContainer `),t(i.ChatContainer,{ref:`chatContainerRef`,messages:i.messages,"preset-questions":i.presetQuestions,"welcome-title":i.$t(`@AGENT:智能体助手`),"welcome-description":i.$t(`@AGENT:我可以帮你阅读代码、执行命令、修改文件。选择下方话题或直接输入你的问题。`),"assistant-name":`g ai`,theme:i.chatTheme,disabled:i.isStreaming,"upload-config":{accept:`image/*`},placeholder:i.isStreaming?i.$t(`@AGENT:正在生成中...`):i.$t(`@AGENT:输入消息,Enter 发送`),onSend:i.onSend,onSelect:i.onSelectPreset},null,8,[`messages`,`preset-questions`,`welcome-title`,`welcome-description`,`theme`,`disabled`,`placeholder`])],2112)),p(` 停止按钮浮层 `),t(k,{name:`fade`},{default:u(()=>[i.isStreaming?(M(),j(`div`,de,[y(`button`,{class:`stop-button`,onClick:n[2]||=(...e)=>i.stop&&i.stop(...e)},[t(i.ElIcon,null,{default:u(()=>[t(i.Loading,{class:`is-loading`})]),_:1}),y(`span`,null,m(i.$t(`@AGENT:停止生成`)),1)])])):p(`v-if`,!0)]),_:1})])])}var pe=I(W,[[`render`,fe],[`__scopeId`,`data-v-bd681ddd`],[`__file`,`C:/workspace/github_workspace/zen-gitsync/src/ui/client/src/views/AgentView.vue`]]);export{pe as default};
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import"./rolldown-runtime-BM3Ffeng.js";import{B as e,Cn as t,D as n,Et as r,Fn as i,G as a,Jn as o,Ln as s,Mn as c,Sn as l,Tn as u,Xn as d,Y as f,_n as p,_r as m,a as h,gn as g,hn as _,i as v,mn as y,mr as b,nt as x,rt as S,sr as C,vn as w,zn as T}from"./element-plus-C0loJL0J.js";import{E,T as D}from"./index-BEPT2LNX.js";async function O(e,t){let n=e.body.getReader(),r=new TextDecoder(`utf-8`),i=``;for(;;){let{done:e,value:a}=await n.read();if(e)break;i+=r.decode(a,{stream:!0});let o=i.split(`
|
|
2
|
+
`);i=o.pop()??``;for(let e of o)e.trim()&&t(e)}i.trim()&&t(i)}async function k(){let e=await fetch(`/api/app-version`);return e.ok?e.json():{success:!1,current:``,latest:null,hasUpdate:!1,error:`HTTP ${e.status}`}}async function A(e){let t=await fetch(`/api/app-upgrade`,{method:`POST`});if(!t.ok){let n=`HTTP ${t.status}`;try{let e=await t.json();e?.error&&(n=e.error)}catch{}e({type:`error`,message:n}),e({type:`done`,code:t.status});return}if(!t.body){e({type:`error`,message:`响应无 body`}),e({type:`done`,code:-1});return}await O(t,t=>{try{e(JSON.parse(t))}catch{}})}async function j(){let e=await fetch(`/api/app-restart`,{method:`POST`});if(!e.ok){let t=`HTTP ${e.status}`;try{let n=await e.json();n?.error&&(t=n.error)}catch{}throw Error(t)}if(!e.body)throw Error(`响应无 body`);return new Promise((t,n)=>{let r=!1,i=e=>{r||(r=!0,e())};O(e,e=>{try{let r=JSON.parse(e);r.type===`ready`&&typeof r.port==`number`&&r.port>0?i(()=>t(r.port)):r.type===`timeout`?i(()=>n(Error(`restart.timeout`))):r.type===`error`&&i(()=>n(Error(r.message||`restart.failed`)))}catch{}}).then(()=>{i(()=>n(Error(`restart.stream-closed`)))}).catch(()=>{})})}var M=u({__name:`UpgradeDialog`,props:{modelValue:{type:Boolean,required:!0},logs:{type:String,required:!0},status:{type:String,required:!0},countdown:{type:Number,required:!1,default:0}},emits:[`update:modelValue`,`retry`,`restart`,`cancel`],setup(e,{expose:t,emit:n}){t();let i=e,a=n,s=C(null);o(()=>i.logs,async()=>{await c(),s.value&&(s.value.scrollTop=s.value.scrollHeight)});function l(){i.status!==`running`&&(i.status===`success`&&i.countdown>0&&a(`cancel`),a(`update:modelValue`,!1))}function u(){a(`retry`)}function d(){a(`restart`)}function f(){a(`cancel`),a(`update:modelValue`,!1)}let p={props:i,emit:a,logEl:s,close:l,onRetry:u,onRestart:d,onLater:f,get Loading(){return r},get CircleCheck(){return x},get CircleClose(){return S},get $t(){return E}};return Object.defineProperty(p,`__isScriptSetup`,{enumerable:!1,value:!0}),p}}),N={key:3},P={key:4},F={key:5},I={key:0,class:`upgrade-hint`},L={key:0,class:`upgrade-countdown`};function R(r,i,a,o,s,c){let u=f,h=e,v=n;return T(),g(v,{"model-value":a.modelValue,"onUpdate:modelValue":i[0]||=e=>o.emit(`update:modelValue`,e),title:o.$t(`@F13B4:升级`),width:`680px`,"close-on-click-modal":!1,"close-on-press-escape":!1,"show-close":a.status!==`running`,"append-to-body":``,onClose:o.close},{footer:d(()=>[a.status===`failed`?(T(),g(h,{key:0,type:`primary`,onClick:o.onRetry},{default:d(()=>[l(m(o.$t(`@F13B4:重试`)),1)]),_:1})):p(`v-if`,!0),a.status===`success`?(T(),g(h,{key:1,type:`primary`,onClick:o.onRestart},{default:d(()=>[l(m(o.$t(`@F13B4:立即重启并刷新`)),1)]),_:1})):p(`v-if`,!0),a.status===`success`?(T(),g(h,{key:2,onClick:o.onLater},{default:d(()=>[l(m(o.$t(`@F13B4:稍后手动重启`)),1)]),_:1})):p(`v-if`,!0),a.status===`running`?(T(),g(h,{key:3,disabled:``},{default:d(()=>[l(m(o.$t(`@F13B4:升级中`))+`... `,1)]),_:1})):p(`v-if`,!0)]),default:d(()=>[_(`div`,{class:b([`upgrade-status`,`is-${a.status}`])},[a.status===`running`?(T(),g(u,{key:0,class:`is-loading`},{default:d(()=>[t(o.Loading)]),_:1})):a.status===`success`?(T(),g(u,{key:1,color:`#67c23a`},{default:d(()=>[t(o.CircleCheck)]),_:1})):(T(),g(u,{key:2,color:`#f56c6c`},{default:d(()=>[t(o.CircleClose)]),_:1})),a.status===`running`?(T(),w(`span`,N,m(o.$t(`@F13B4:升级中`)),1)):a.status===`success`?(T(),w(`span`,P,m(o.$t(`@F13B4:升级完成`)),1)):(T(),w(`span`,F,m(o.$t(`@F13B4:升级失败`)),1))],2),a.status===`success`?(T(),w(`p`,I,[l(m(o.$t(`@F13B4:新版本已全局安装,需要重启服务才能生效`))+` `,1),a.countdown>0?(T(),w(`span`,L,m(o.$t(`@F13B4:{seconds} 秒后自动刷新`,{seconds:a.countdown})),1)):p(`v-if`,!0)])):p(`v-if`,!0),_(`pre`,{ref:`logEl`,class:`upgrade-log`},m(a.logs||o.$t(`@F13B4:等待日志输出`)),513)]),_:1},8,[`model-value`,`title`,`show-close`])}var z=D(M,[[`render`,R],[`__scopeId`,`data-v-bc566bba`],[`__file`,`C:/workspace/github_workspace/zen-gitsync/src/ui/client/src/components/UpgradeDialog.vue`]]),B=`https://github.com/xz333221/zen-gitsync/releases`,V=5,H=`app-version-check`,U=3600*1e3,W=u({__name:`AppVersionBadge`,setup(e,{expose:t}){t();let n=`2.16.12`,r=C(n),a=y(()=>r.value||n),o=C(null),c=C(!1),l=C(``),u=C(`running`),d=C(0),f=null,p=C(!1);function m(){try{let e=sessionStorage.getItem(H);if(!e)return null;let{at:t,data:n}=JSON.parse(e);return Date.now()-t>U?null:n}catch{return null}}function g(e){try{sessionStorage.setItem(H,JSON.stringify({at:Date.now(),data:e}))}catch{}}async function _(e=!1){let t=m();t&&(o.value=t);try{let t=await k();o.value=t,g(t),t.current&&(r.value=t.current),!e&&t.success&&t.hasUpdate&&h({type:`success`,message:E(`@F13B4:发现新版本 {version}`,{version:t.latest??``}),duration:4e3})}catch(t){e||h({type:`warning`,message:E(`@F13B4:检查更新失败 {error}`,{error:t?.message||``})})}}async function b(){if(o.value?.hasUpdate){try{await v.confirm(E(`@F13B4:确定要从 {current} 升级到 {latest} 吗?`,{current:o.value.current,latest:o.value.latest}),E(`@F13B4:升级`),{confirmButtonText:E(`@F13B4:确定升级`),cancelButtonText:E(`@F13B4:取消`),type:`info`})}catch{return}l.value=``,u.value=`running`,c.value=!0,await A(e=>{if(e.type===`done`){if(u.value=e.code===0?`success`:`failed`,e.code===0){try{sessionStorage.removeItem(H)}catch{}o.value?.latest&&(r.value=o.value.latest),x()}}else e.message&&(l.value+=e.message)})}}function x(){S(),d.value=V,f=setInterval(()=>{--d.value,d.value<=0&&(f&&=(clearInterval(f),null),T())},1e3)}function S(){f&&=(clearInterval(f),null),d.value=0}function w(){S()}async function T(){if(S(),!p.value){p.value=!0;try{let e=await j(),{pathname:t,search:n,hash:r}=window.location;window.location.href=`http://localhost:${e}${t}${n}${r}`}catch(e){let t=e?.message||``,n={"restart.timeout":`@F13B4:重启超时`,"restart.stream-closed":`@F13B4:重启失败,请刷新页面重试`,"restart.failed":`@F13B4:重启失败`}[t];h({type:`warning`,message:n?E(n):E(`@F13B4:重启失败 {error}`,{error:t})}),p.value=!1}}}i(()=>{S()}),s(()=>{_(!0)});let D={buildVersion:n,releasesUrl:B,runtimeVersion:r,displayVersion:a,latestInfo:o,upgradeDialogVisible:c,upgradeLogs:l,upgradeStatus:u,AUTO_REFRESH_SECONDS:V,countdown:d,get countdownTimer(){return f},set countdownTimer(e){f=e},restartInFlight:p,CACHE_KEY:H,CACHE_TTL_MS:U,readCache:m,writeCache:g,checkUpdate:_,handleUpgrade:b,startAutoRefreshCountdown:x,cancelAutoRefreshCountdown:S,handleCancelAutoRefresh:w,handleRestart:T,get $t(){return E},UpgradeDialog:z};return Object.defineProperty(D,`__isScriptSetup`,{enumerable:!1,value:!0}),D}}),G={class:`app-version-badge`},K=[`aria-label`],q=[`aria-label`],J=[`title`,`aria-label`],Y={class:`upgrade-btn__label`},X={class:`upgrade-btn__version`};function Z(e,n,r,i,o,s){let c=a;return T(),w(`div`,G,[p(` GitHub 链接 `),t(c,{content:i.$t(`@F13B4:在 GitHub 上查看源码`),placement:`top`,effect:`dark`,"show-after":300},{default:d(()=>[_(`a`,{href:`https://github.com/xz333221/zen-gitsync`,target:`_blank`,rel:`noopener noreferrer`,class:`badge-icon-link`,"aria-label":i.$t(`@F13B4:在 GitHub 上查看源码`)},[...n[1]||=[_(`svg`,{viewBox:`0 0 24 24`,width:`15`,height:`15`,"aria-hidden":`true`,fill:`currentColor`,xmlns:`http://www.w3.org/2000/svg`},[_(`path`,{d:`M12 2C6.477 2 2 6.484 2 12.017c0 4.425 2.865 8.18 6.839 9.504.5.092.682-.217.682-.483 0-.237-.008-.868-.013-1.703-2.782.605-3.369-1.343-3.369-1.343-.454-1.158-1.11-1.466-1.11-1.466-.908-.62.069-.608.069-.608 1.003.07 1.531 1.032 1.531 1.032.892 1.53 2.341 1.088 2.91.832.092-.647.35-1.088.636-1.338-2.22-.253-4.555-1.113-4.555-4.951 0-1.093.39-1.988 1.029-2.688-.103-.253-.446-1.272.098-2.65 0 0 .84-.27 2.75 1.026A9.564 9.564 0 0 1 12 6.844a9.59 9.59 0 0 1 2.504.337c1.909-1.296 2.747-1.027 2.747-1.027.546 1.379.202 2.398.1 2.651.64.7 1.028 1.595 1.028 2.688 0 3.848-2.339 4.695-4.566 4.943.359.309.678.92.678 1.855 0 1.338-.012 2.419-.012 2.747 0 .268.18.58.688.482A10.02 10.02 0 0 0 22 12.017C22 6.484 17.522 2 12 2z`})],-1)]],8,K)]),_:1},8,[`content`]),p(` NPM 链接 `),t(c,{content:i.$t(`@F13B4:在 npm 上查看包`),placement:`top`,effect:`dark`,"show-after":300},{default:d(()=>[_(`a`,{href:`https://www.npmjs.com/package/zen-gitsync`,target:`_blank`,rel:`noopener noreferrer`,class:`badge-icon-link badge-icon-link--npm`,"aria-label":i.$t(`@F13B4:在 npm 上查看包`)},[...n[2]||=[_(`svg`,{viewBox:`0 0 24 24`,width:`15`,height:`15`,"aria-hidden":`true`,fill:`currentColor`,xmlns:`http://www.w3.org/2000/svg`},[_(`path`,{d:`M2 2v20h20V2H2zm17.167 17.167H12.5v-10h-3.333v10H4.833V4.833h14.334v14.334z`})],-1)]],8,q)]),_:1},8,[`content`]),p(` 版本号 `),t(c,{content:i.$t(`@F13B4:查看更新`),placement:`top`,effect:`dark`,"show-after":300},{default:d(()=>[_(`a`,{href:i.releasesUrl,target:`_blank`,rel:`noopener noreferrer`,class:`version-link`},`v`+m(i.displayVersion),1)]),_:1},8,[`content`]),i.latestInfo?.hasUpdate?(T(),w(`button`,{key:0,type:`button`,class:`upgrade-btn`,title:i.$t(`@F13B4:发现新版本 {version},点击升级`,{version:i.latestInfo.latest??``}),"aria-label":i.$t(`@F13B4:发现新版本 {version},点击升级`,{version:i.latestInfo.latest??``}),onClick:i.handleUpgrade},[n[3]||=_(`span`,{class:`upgrade-btn__dot`,"aria-hidden":`true`},null,-1),_(`span`,Y,m(i.$t(`@F13B4:升级`)),1),_(`span`,X,`v`+m(i.latestInfo.latest),1)],8,J)):p(`v-if`,!0),t(i.UpgradeDialog,{modelValue:i.upgradeDialogVisible,"onUpdate:modelValue":n[0]||=e=>i.upgradeDialogVisible=e,logs:i.upgradeLogs,status:i.upgradeStatus,countdown:i.countdown,onRetry:i.handleUpgrade,onRestart:i.handleRestart,onCancel:i.handleCancelAutoRefresh},null,8,[`modelValue`,`logs`,`status`,`countdown`])])}var Q=D(W,[[`render`,Z],[`__scopeId`,`data-v-7e0300ec`],[`__file`,`C:/workspace/github_workspace/zen-gitsync/src/ui/client/src/components/AppVersionBadge.vue`]]);export{Q as default};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import"./rolldown-runtime-BM3Ffeng.js";import{Cn as e,K as t,L as n,Lt as r,Pt as i,R as a,Tn as o,Vn as s,W as c,Xn as l,Y as u,_n as d,_r as f,cn as p,gn as m,hn as h,kt as g,mn as _,mr as v,q as y,r as b,sr as x,tt as S,un as C,vn as w,zn as T}from"./element-plus-C0loJL0J.js";import{C as E,E as D,T as O,b as k,d as A,w as j}from"./index-BEPT2LNX.js";var M=o({__name:`BranchSelector`,emits:[`branchChanged`],setup(e,{expose:t,emit:n}){t();let a=k(),o=n,s=x(!1),c=x(``),l=_(()=>{let e=c.value.trim().toLowerCase();return e?a.allBranches.filter(t=>t.toLowerCase().includes(e)):a.allBranches});async function u(e){if(e===a.currentBranch){s.value=!1;return}s.value=!1,await a.changeBranch(e)&&(o(`branchChanged`),a.refreshLog())}let d=x(!1),f=x(``),p=x(``);function m(){s.value=!1,p.value=a.currentBranch,d.value=!0}async function h(){await a.createBranch(f.value,p.value)&&(d.value=!1,f.value=``,o(`branchChanged`))}let v=x(!1);async function y(){if(!v.value){v.value=!0;try{await Promise.all([a.getCurrentBranch(!0),a.getBranchStatus(!0),a.getAllBranches()]),o(`branchChanged`),a.refreshLog()}finally{v.value=!1}}}let b={gitStore:a,emit:o,branchPopoverVisible:s,branchFilter:c,filteredBranches:l,selectBranch:u,createBranchDialogVisible:d,newBranchName:f,selectedBaseBranch:p,openCreateBranchDialog:m,createNewBranch:h,isRefreshingBranch:v,refreshCurrentBranch:y,get $t(){return D},get Plus(){return i},get Menu(){return g},get Check(){return S},get Refresh(){return r},CommonDialog:A,IconButton:E,SvgIcon:j};return Object.defineProperty(b,`__isScriptSetup`,{enumerable:!1,value:!0}),b}}),N={key:0,class:`branch-info`},P={class:`branch-wrapper`},F={class:`branch-btn`},I={class:`branch-btn-name`},L={class:`branch-btn-caret`},R={class:`branch-popover-inner`},z={class:`branch-search`},B={class:`branch-list`},V=[`onClick`],H={key:1,class:`branch-item-check-placeholder`},U={class:`branch-item-name`},W={key:0,class:`branch-empty`},G={class:`branch-popover-footer`},K={class:`create-branch-content`},q={class:`form-label`},J={class:`form-label`},Y={class:`dialog-footer`},X={class:`footer-actions`},Z=[`disabled`];function Q(r,i,o,g,_,x){let S=u,E=c,D=b,O=y,k=n,A=a,j=t;return g.gitStore.currentBranch?(T(),w(`div`,N,[h(`div`,P,[d(` VSCode 风格分支按钮 + 弹出列表 `),e(D,{visible:g.branchPopoverVisible,"onUpdate:visible":i[1]||=e=>g.branchPopoverVisible=e,placement:`top-start`,width:260,trigger:`click`,"popper-class":`branch-popover`,"show-arrow":!1,onShow:i[2]||=e=>g.branchFilter=``},{reference:l(()=>[h(`button`,F,[e(g.SvgIcon,{"icon-class":`git-branch`,"class-name":`branch-btn-icon`}),h(`span`,I,f(g.gitStore.currentBranch),1),h(`span`,L,[e(S,null,{default:l(()=>[...i[7]||=[h(`svg`,{viewBox:`0 0 1024 1024`,xmlns:`http://www.w3.org/2000/svg`},[h(`path`,{fill:`currentColor`,d:`M831.872 340.864 512 652.672 192.128 340.864a30.592 30.592 0 0 0-42.752 0 29.12 29.12 0 0 0 0 41.6L489.664 714.24a32 32 0 0 0 44.672 0l340.288-331.776a29.12 29.12 0 0 0 0-41.6 30.592 30.592 0 0 0-42.752 0z`})],-1)]]),_:1})])])]),default:l(()=>[h(`div`,R,[d(` 搜索框 `),h(`div`,z,[e(E,{modelValue:g.branchFilter,"onUpdate:modelValue":i[0]||=e=>g.branchFilter=e,placeholder:g.$t(`@F13B4:搜索或签出分支`),size:`small`,clearable:``,autofocus:``},null,8,[`modelValue`,`placeholder`])]),d(` 分支列表 `),h(`div`,B,[(T(!0),w(C,null,s(g.filteredBranches,t=>(T(),w(`div`,{key:t,class:v([`branch-item`,{"is-active":t===g.gitStore.currentBranch}]),onClick:e=>g.selectBranch(t)},[t===g.gitStore.currentBranch?(T(),m(S,{key:0,class:`branch-item-check`},{default:l(()=>[e(g.Check)]),_:1})):(T(),w(`span`,H)),e(g.SvgIcon,{"icon-class":`git-branch`,"class-name":`branch-item-icon`}),h(`span`,U,f(t),1)],10,V))),128)),g.filteredBranches.length===0?(T(),w(`div`,W,f(g.$t(`@F13B4:没有匹配的分支`)),1)):d(`v-if`,!0)]),d(` 底部:创建新分支 `),h(`div`,G,[h(`button`,{class:`branch-create-btn`,onClick:g.openCreateBranchDialog},[e(S,null,{default:l(()=>[e(g.Plus)]),_:1}),h(`span`,null,f(g.$t(`@F13B4:创建新分支`)),1)])])])]),_:1},8,[`visible`]),d(` 刷新按钮 `),e(g.IconButton,{tooltip:g.$t(`@CMDCON:刷新`),onClick:g.refreshCurrentBranch},{default:l(()=>[e(S,{class:v({"is-loading":g.isRefreshingBranch})},{default:l(()=>[e(g.Refresh)]),_:1},8,[`class`])]),_:1},8,[`tooltip`])]),d(` 创建分支对话框 `),e(g.CommonDialog,{modelValue:g.createBranchDialogVisible,"onUpdate:modelValue":i[6]||=e=>g.createBranchDialogVisible=e,title:g.$t(`@F13B4:创建新分支`),size:`small`,"destroy-on-close":!0,"append-to-body":!0,"custom-class":`create-branch-dialog`},{footer:l(()=>[h(`div`,Y,[h(`div`,X,[h(`button`,{type:`button`,class:`dialog-cancel-btn`,onClick:i[5]||=e=>g.createBranchDialogVisible=!1},f(g.$t(`@F13B4:取消`)),1),h(`button`,{type:`button`,class:`dialog-confirm-btn`,onClick:g.createNewBranch,disabled:g.gitStore.isCreatingBranch},[g.gitStore.isCreatingBranch?(T(),m(S,{key:1,class:`is-loading`},{default:l(()=>[...i[8]||=[h(`svg`,{viewBox:`0 0 1024 1024`,xmlns:`http://www.w3.org/2000/svg`},[h(`path`,{fill:`currentColor`,d:`M512 64a32 32 0 0 1 32 32v192a32 32 0 0 1-64 0V96a32 32 0 0 1 32-32zm0 640a32 32 0 0 1 32 32v192a32 32 0 1 1-64 0V736a32 32 0 0 1 32-32zm448-192a32 32 0 0 1-32 32H736a32 32 0 1 1 0-64h192a32 32 0 0 1 32 32zm-640 0a32 32 0 0 1-32 32H96a32 32 0 0 1 0-64h192a32 32 0 0 1 32 32z`})],-1)]]),_:1})):(T(),m(S,{key:0},{default:l(()=>[e(g.Check)]),_:1})),h(`span`,null,f(g.$t(`@F13B4:创建`)),1)],8,Z)])])]),default:l(()=>[h(`div`,K,[e(j,{model:{newBranchName:g.newBranchName,selectedBaseBranch:g.selectedBaseBranch},"label-position":`top`},{default:l(()=>[e(O,null,{label:l(()=>[h(`div`,q,[e(S,{class:`label-icon`},{default:l(()=>[e(g.Plus)]),_:1}),h(`span`,null,f(g.$t(`@F13B4:新分支名称`)),1)])]),default:l(()=>[e(E,{modelValue:g.newBranchName,"onUpdate:modelValue":i[3]||=e=>g.newBranchName=e,placeholder:g.$t(`@F13B4:请输入新分支名称`),class:`modern-input`,size:`large`,onKeyup:p(g.createNewBranch,[`enter`])},null,8,[`modelValue`,`placeholder`])]),_:1}),e(O,null,{label:l(()=>[h(`div`,J,[e(S,{class:`label-icon`},{default:l(()=>[e(g.Menu)]),_:1}),h(`span`,null,f(g.$t(`@F13B4:基于分支`)),1)])]),default:l(()=>[e(A,{modelValue:g.selectedBaseBranch,"onUpdate:modelValue":i[4]||=e=>g.selectedBaseBranch=e,placeholder:g.$t(`@F13B4:选择基础分支`),class:`modern-select`,size:`large`,style:{width:`100%`}},{default:l(()=>[(T(!0),w(C,null,s(g.gitStore.allBranches,e=>(T(),m(k,{key:e,label:e,value:e},null,8,[`label`,`value`]))),128))]),_:1},8,[`modelValue`,`placeholder`])]),_:1})]),_:1},8,[`model`])])]),_:1},8,[`modelValue`,`title`])])):d(`v-if`,!0)}var $=O(M,[[`render`,Q],[`__scopeId`,`data-v-9548a76f`],[`__file`,`C:/workspace/github_workspace/zen-gitsync/src/ui/client/src/components/BranchSelector.vue`]]);export{$ as default};
|