dsh-browser-view 0.4.0 → 0.7.0
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 +14 -10
- package/lib/client.js +1 -1
- package/lib/index.js +7787 -5190
- package/lib/types/browser/adapters/antd.d.ts +14 -0
- package/lib/types/browser/adapters/archetypes.d.ts +93 -0
- package/lib/types/browser/adapters/dom.d.ts +6 -0
- package/lib/types/browser/adapters/element.d.ts +5 -0
- package/lib/types/browser/adapters/engine.d.ts +51 -0
- package/lib/types/browser/adapters/generic.d.ts +5 -0
- package/lib/types/browser/adapters/index.d.ts +10 -0
- package/lib/types/browser/adapters/modules/drag.d.ts +3 -0
- package/lib/types/browser/adapters/modules/editor.d.ts +3 -0
- package/lib/types/browser/adapters/modules/hierarchy.d.ts +3 -0
- package/lib/types/browser/adapters/modules/temporal.d.ts +3 -0
- package/lib/types/browser/adapters/modules/transfer.d.ts +3 -0
- package/lib/types/browser/adapters/modules/virtual.d.ts +4 -0
- package/lib/types/browser/adapters/quiescence.d.ts +3 -0
- package/lib/types/browser/adapters/registry.d.ts +64 -0
- package/lib/types/browser/adapters/select.d.ts +15 -0
- package/lib/types/browser/adapters/types.d.ts +134 -0
- package/lib/types/browser/codegen/playwright.d.ts +10 -0
- package/lib/types/browser/definitions/collaboration.d.ts +4 -0
- package/lib/types/browser/definitions/doctor.d.ts +4 -0
- package/lib/types/browser/definitions/extract.d.ts +4 -0
- package/lib/types/browser/definitions/inspection.d.ts +4 -0
- package/lib/types/browser/definitions/interaction.d.ts +4 -0
- package/lib/types/browser/definitions/navigation.d.ts +4 -0
- package/lib/types/browser/definitions/recorder.d.ts +4 -0
- package/lib/types/browser/definitions/testing.d.ts +4 -0
- package/lib/types/browser/policy/engine.d.ts +26 -0
- package/lib/types/browser/policy/types.d.ts +36 -0
- package/lib/types/browser/primitives/dialog.d.ts +12 -0
- package/lib/types/browser/primitives/dom.d.ts +43 -0
- package/lib/types/browser/primitives/drag.d.ts +3 -0
- package/lib/types/browser/primitives/editor.d.ts +3 -0
- package/lib/types/browser/primitives/form.d.ts +7 -0
- package/lib/types/browser/primitives/hierarchy.d.ts +3 -0
- package/lib/types/browser/primitives/index.d.ts +12 -0
- package/lib/types/browser/primitives/select.d.ts +7 -0
- package/lib/types/browser/primitives/temporal.d.ts +3 -0
- package/lib/types/browser/primitives/transfer.d.ts +3 -0
- package/lib/types/browser/primitives/types.d.ts +48 -0
- package/lib/types/browser/primitives/virtual.d.ts +4 -0
- package/lib/types/browser/reports.d.ts +0 -2
- package/lib/types/browser/session/cache.d.ts +103 -0
- package/lib/types/browser/session/collaboration.d.ts +53 -0
- package/lib/types/browser/session/recorder.d.ts +62 -0
- package/lib/types/browser/session/screencast.d.ts +37 -0
- package/lib/types/browser/session/screenshot.d.ts +17 -0
- package/lib/types/browser/session/semantic.d.ts +94 -0
- package/lib/types/browser/session/target.d.ts +16 -0
- package/lib/types/browser/session/tracer.d.ts +56 -0
- package/lib/types/browser/session.d.ts +7 -140
- package/lib/types/browser/stealth/keyboard.d.ts +13 -0
- package/lib/types/browser/stealth/mouse.d.ts +28 -0
- package/lib/types/browser/tools/collaboration.d.ts +73 -0
- package/lib/types/browser/tools/common.d.ts +67 -0
- package/lib/types/browser/tools/doctor.d.ts +31 -0
- package/lib/types/browser/tools/extract.d.ts +92 -0
- package/lib/types/browser/tools/inspection.d.ts +93 -0
- package/lib/types/browser/tools/interaction.d.ts +148 -0
- package/lib/types/browser/tools/navigation.d.ts +126 -0
- package/lib/types/browser/tools/recorder.d.ts +236 -0
- package/lib/types/browser/tools/testing.d.ts +94 -0
- package/lib/types/browser/tools.d.ts +9 -861
- package/lib/types/browser/types.d.ts +70 -1
- package/lib/types/browser/walker.d.ts +3 -0
- package/lib/types/client/api.d.ts +24 -0
- package/lib/types/client/components/ConfirmCard.d.ts +20 -0
- package/lib/types/client/components/FloatingOverlay.d.ts +10 -0
- package/lib/types/client/components/FloatingPanel.d.ts +40 -0
- package/lib/types/client/components/InspectionModal.d.ts +51 -0
- package/lib/types/client/components/SettingsSection.d.ts +5 -0
- package/lib/types/client/components/styles.d.ts +18 -0
- package/lib/types/client/hooks/useBrowserStatus.d.ts +11 -0
- package/lib/types/client/hooks/useConfirmPolling.d.ts +6 -0
- package/lib/types/client/hooks/usePickPolling.d.ts +5 -0
- package/lib/types/client/hooks/useRecordings.d.ts +9 -0
- package/lib/types/client/index.d.ts +7 -10
- package/lib/types/client/theme.d.ts +7 -0
- package/lib/types/client/types.d.ts +74 -0
- package/lib/types/lib/config.d.ts +0 -2
- package/lib/types/lib/http.d.ts +0 -2
- package/lib/types/lib/types.d.ts +1 -0
- package/package.json +13 -3
- package/lib/types/embed.d.ts +0 -7
package/README.md
CHANGED
|
@@ -4,9 +4,9 @@ DSH 插件:共享 Playwright 浏览器自动化 + 原生界面实时画面面板
|
|
|
4
4
|
|
|
5
5
|
| 模块 | 做什么 |
|
|
6
6
|
| --- | --- |
|
|
7
|
-
| 🧭 **浏览器自动化** | 共享 Playwright 浏览器:多标签、多 profile、隔离 context、下载/上传、Cookie
|
|
8
|
-
| 🖥️ **实时画面** | 注入 DSH 界面右下角悬浮面板:浏览器状态 + 实时缩略图,点开大屏模态框(2 秒轮询画面 + 访问历史);**双向协作**——agent 等待人工操作/敏感审批时显示交互横幅、执行点击/输入前目标元素琥珀色高亮预告(confirmMode:auto 时敏感动作由宿主层强制拦截弹审批,agent 无法绕过),「最近回归」行与报告模态可一键重跑(agent 忙碌自动置灰) |
|
|
9
|
-
| ✅ **回归测试闭环** | 录制回放 + 选择器自愈 + 参数化/数据驱动 + 失败自动重试(`retryFailed`)+ 视觉回归 + 运行历史/报告导出 + 面板一键重跑(`/runs/rerun`,agent 忙碌置灰) |
|
|
7
|
+
| 🧭 **浏览器自动化** | 共享 Playwright 浏览器:多标签、多 profile、隔离 context、下载/上传、Cookie、what 意图语义定位(`browser_click { what: "登录" }` 一次调用替代快照→查找→点击三轮,零命中返回相近候选 + SoM 看图兜底)、SoM 标徽点击(`mark: N`)、open Shadow DOM 组合树穿透、SPA 路由后 ref 软失效重锚定、点击效果验证(`effect: true`,点了没动静自动换候选)、跨 Frame/IFrame 穿透定位、视口感知动态快照(`viewportOnly`)、多模态 SoM 视口标徽(`som: true`)、批量表单智能填充(`browser_form_fill`)、增量快照(历史版本环形缓存)、抽取字段自动建议(action:suggest),38 个 `browser_*` 工具 |
|
|
8
|
+
| 🖥️ **实时画面** | 注入 DSH 界面右下角悬浮面板:浏览器状态 + 实时缩略图,点开大屏模态框(2 秒轮询画面 + 访问历史);**双向协作**——agent 等待人工操作/敏感审批时显示交互横幅、执行点击/输入前目标元素琥珀色高亮预告(confirmMode:auto 时敏感动作由宿主层强制拦截弹审批,agent 无法绕过),**面板点选教学**(browser_pick_element:疑难元素用户在大图上点一下,直接拿到稳定 selector+指纹+ref),「最近回归」行与报告模态可一键重跑(agent 忙碌自动置灰) |
|
|
9
|
+
| ✅ **回归测试闭环** | 录制回放 + 选择器自愈 + 参数化/数据驱动 + 失败自动重试(`retryFailed`)+ 视觉回归 + 运行历史/报告导出 + **一键导出原生 Playwright 规范代码(`action: "export"`)** + 面板一键重跑(`/runs/rerun`,agent 忙碌置灰) |
|
|
10
10
|
|
|
11
11
|
设计原则:能做的一次性操作交给 agent 用 bash 完成,插件只做 bash 做不到的常驻浏览器自动化。唯一第三方运行时依赖是 `playwright-core`(复用系统已装的 Edge/Chrome,无需下载 Chromium),不依赖任何 `@deepseek-ai` 运行时包。
|
|
12
12
|
|
|
@@ -50,10 +50,12 @@ dsh plugin --profile web add dsh-browser-view
|
|
|
50
50
|
sensitivePatterns: [提交, 删除, 支付] # auto 模式敏感文本模式(子串匹配 role/name/text/id/testid/tag)
|
|
51
51
|
sensitiveTools: [browser_click] # auto 模式参与判定的工具(默认只拦 click;type 误报率高,需拦时显式加入)
|
|
52
52
|
confirmInReplay: true # replay/batch 是否同样走 auto 审批闸(false = 回放不弹审批,风险自担)
|
|
53
|
-
|
|
53
|
+
somFallback: true # what 语义定位零命中时自动附 SoM 标徽截图(多模态看图后 click { mark: N })
|
|
54
|
+
refReanchor: true # SPA 路由后 ref 软失效重锚定(false = 导航即清空的旧行为)
|
|
55
|
+
toolset: all # all(默认全量 38 个)| core(高频核心集 25 个,降 systemPrompt 常驻 token)
|
|
54
56
|
```
|
|
55
57
|
|
|
56
|
-
**工具集裁剪(toolset)**:默认 `all` 注册全部工具。日常浏览/操作/人机协作为主的会话可设 `toolset: core`——只注册
|
|
58
|
+
**工具集裁剪(toolset)**:默认 `all` 注册全部工具。日常浏览/操作/人机协作为主的会话可设 `toolset: core`——只注册 25 个高频核心工具(打开/快照/查找/点击/输入/等待/断言/网络/标签/下载上传/登录等待/人工接管/审批/点选教学/诊断),`browser_record / replay / report / extract / form / profile / context / cookies` 等低频工具不注册、不占 systemPrompt 常驻 token(低频工具的录制管理界面不受影响,已有录制仍可回放,只是 agent 会话内无这些工具)。需要做回归测试或数据抓取时把配置改回 `all` 并重启 DSH 即可。
|
|
57
59
|
|
|
58
60
|
## 浏览器工具
|
|
59
61
|
|
|
@@ -64,20 +66,22 @@ dsh plugin --profile web add dsh-browser-view
|
|
|
64
66
|
| `browser_snapshot` | 页面快照:`mode: "text"`(默认)返回压缩后的文本/链接/输入框;`mode: "aria"` 返回可访问性树,可交互元素带 `[ref=eN]` 短引用;`scope`(CSS 选择器)限定提取区域(text/aria 都生效);`since`(上次返回的 contentVersion)增量重读——未变返回 `unchanged`,变了只返回变化行(`diff` + `changedFrom`/`removed`),翻页后重读 token 降一个量级 |
|
|
65
67
|
| `browser_find` | 语义元素定位:按名称/id/data-testid 查找可交互元素,只返回命中 ref + ancestors 区域链(大页面定位单目标比全量 aria 快照省 95%+ token);`exact` 精确匹配、`scope` 限定容器;多命中全返回,零命中附相近候选 |
|
|
66
68
|
| `browser_elements` | 可交互元素结构化清单(input/button/select/链接 + 关联 label + 现成 CSS 选择器;有展开下拉时附可见选项) |
|
|
67
|
-
| `browser_click` / `browser_type` / `browser_press` | 点击 / 输入(可清空、可回车提交)/ 按键;`selector`(CSS)
|
|
68
|
-
| `browser_select` | 下拉选择原语:原生 `<select>` 与 antd / element-plus / ARIA listbox 通用,selector/ref + option 文本一步完成;找不到选项时报错并列出可见选项 |
|
|
69
|
+
| `browser_click` / `browser_type` / `browser_press` | 点击 / 输入(可清空、可回车提交)/ 按键;`selector`(CSS)、`ref`(aria 快照)、`what`(意图语义定位,页内打分匹配并自动注册 ref,零命中返回相近候选)、`mark`(SoM 标徽编号)四选一;click 另有 `effect: true` 点击效果验证(DOM/URL/网络动静摘要,what 多候选首击无动静自动换选);自动穿透跨域子 Frame 与 open Shadow DOM |
|
|
70
|
+
| `browser_select` | 下拉选择原语:原生 `<select>` 与 antd / element-plus / ARIA listbox 通用,selector/ref/what + option 文本一步完成;找不到选项时报错并列出可见选项 |
|
|
71
|
+
| `browser_form_fill` | 智能批量表单填写:一次调用自动识别并填充多个表单控件,结合 UI 适配器自动反查 label、处理输入/选择与弹层并支持稳态等待 |
|
|
69
72
|
| `browser_eval` | 在页面上下文执行 JS(结果自动净化成 lossless JSON) |
|
|
70
73
|
| `browser_batch` | 动作批处理:一次调用顺序执行多个步骤 `[{tool, args}]`(点击→等待→输入→提交类小序列减少往返;禁止嵌套;可录制可回放) |
|
|
71
|
-
| `browser_screenshot` | 截图存为 PNG(自动清理,见下);`baseline: "<名>"`
|
|
74
|
+
| `browser_screenshot` | 截图存为 PNG(自动清理,见下);`baseline: "<名>"` 存为视觉回归基线;`som: true` 启用多模态 Set-of-Marks 视口标徽,在交互元素上绘制数字徽章并返回映射表供大模型精准看图定位 |
|
|
72
75
|
| `browser_wait` / `browser_back` / `browser_reload` | 等待 / 后退 / 刷新 |
|
|
73
76
|
| `browser_wait_for_login` | 等待人工登录完成(配 `headless: false` 使用,见下) |
|
|
74
77
|
| `browser_pause_for_human` | 人工接管等待:agent 把控制权暂时交还给用户(验证码/二次确认/人工复核),instruction 显示在实时画面面板;`successSelector` / `successUrl` 指定完成条件,都不给则 URL/页面内容变化即视为完成;轮询 2 秒,超时返回 `completed: false` 不抛错 |
|
|
75
78
|
| `browser_confirm` | 敏感操作审批:提交/删除/支付类动作前调用,审批请求推送到实时画面面板等待用户点「允许/拒绝」;允许返回 `decision: "allowed"`,拒绝/超时(fail-closed)抛错,live 与 replay/batch 统一按失败处理 |
|
|
79
|
+
| `browser_pick_element` | 面板点选教学:调用后实时画面大图显示十字光标,用户点一下目标元素,返回稳定 selector + 自愈兼容指纹 + 可直接使用的 ref;定位失败 2 次后改走人工指路比继续猜选择器更高效 |
|
|
76
80
|
| `browser_wait_for` | 通用显式等待(元素状态 / URL / 文本 / 数量 / eval,超时抛错) |
|
|
77
81
|
| `browser_assert` | 结构化断言(失败自动截图存证据目录并报错);`visual: { baseline }` 做视觉回归断言(见下) |
|
|
78
82
|
| `browser_network` | 接口记录查询:list / failed(4xx/5xx)/ wait(命中返回 waitMs,超时附最近请求摘要)/ stats(按 host 聚合计数/失败数/均耗时/状态码分布)/ clear,含请求/响应体(截断) |
|
|
79
83
|
| `browser_extract` | 规则化结构化抽取:fields 定义 CSS 字段(支持嵌套/multiple),`next` 自动翻页聚合,导出 json / csv / jsonl / markdown 落盘工作区;`action: "suggest"` 自动推断字段(表格首行/列表卡片 → 单元格文本/链接 href/图片 src),返回建议 fields + 首行样本,微调后直接交给抽取模式(往返 3-4 次降到 2 次);推断不出规律结构返回原因与容器概览,不猜 |
|
|
80
|
-
| `browser_record` | 操作录制:start / stop / save(list/delete 管理;save 支持 `stripReads` 剔除只读步骤、`vars` 把指定步骤字段抽成 `{{占位符}}`;selector 步骤自动附带元素指纹供回放自愈;**录制期间用户在浏览器中的手动输入/点击/选择也会进录制**,标记 `source: "human"`) |
|
|
84
|
+
| `browser_record` | 操作录制:start / stop / save(list/delete 管理;save 支持 `stripReads` 剔除只读步骤、`vars` 把指定步骤字段抽成 `{{占位符}}`;selector 步骤自动附带元素指纹供回放自愈;**录制期间用户在浏览器中的手动输入/点击/选择也会进录制**,标记 `source: "human"`);`action: "export"` 可将录制序列一键编译转译为原生 Playwright TypeScript 测试代码(`format: "playwright"`) |
|
|
81
85
|
| `browser_replay` | 回放录制或步骤序列(回归测试,遇错可停);`vars` 注入占位符,`data` / `dataFile`(CSV)逐行数据驱动;选择器失效自动按指纹自愈;`retryFailed: N` 失败步骤自动重试 N 次(500ms×n 退避,重试耗尽才停),返回 `retries: { attempted, recovered }` |
|
|
82
86
|
| `browser_report` | 回归报告:list / show / export(运行历史自动记录,export 聚合为 Markdown / 自包含 HTML 落盘) |
|
|
83
87
|
| `browser_status` / `browser_close` | 状态 / 关闭会话 |
|
|
@@ -132,7 +136,7 @@ browser_screenshot # 证据
|
|
|
132
136
|
- button "登录" [ref=e3]
|
|
133
137
|
```
|
|
134
138
|
|
|
135
|
-
后续 `browser_click { ref: "e3" }`、`browser_type { ref: "e2", text }`、`browser_select { ref, option }`、`browser_press { ref, key }` 直接用 ref 代替 CSS 选择器——比手写选择器更稳、比文本快照更省 token。ref 解析时会校验元素的 role/name 仍一致(防漂移误点),不一致自动降级 `getByRole
|
|
139
|
+
后续 `browser_click { ref: "e3" }`、`browser_type { ref: "e2", text }`、`browser_select { ref, option }`、`browser_press { ref, key }` 直接用 ref 代替 CSS 选择器——比手写选择器更稳、比文本快照更省 token。ref 解析时会校验元素的 role/name 仍一致(防漂移误点),不一致自动降级 `getByRole`,再失灵按快照时的视口坐标兜底(`elementFromPoint` + 相似校验)。SPA 客户端路由切换后默认走**软失效重锚定**(按 role+name 指纹把旧 ref 重映射到新 DOM,免整轮快照;`refReanchor: false` 回退导航即失效);整页跳转仍报错提示重取。读正文仍用默认 `mode: "text"`;多模态场景 `browser_screenshot { som: true }` 后可直接 `browser_click { mark: N }` 点标徽。
|
|
136
140
|
|
|
137
141
|
**动作批处理**:固定小序列用 `browser_batch` 一次往返执行:
|
|
138
142
|
|
package/lib/client.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
window.__ModuleLoader__.load({id:`dsh-browser-view`,factory:e=>{var t={exports:{}},n=t.exports;Object.defineProperty(n,Symbol.toStringTag,{value:`Module`});let r=e("react"),i={primary:`#1f2937`,secondary:`#4b5563`,tertiary:`#6b7280`,border:`#d8dde3`,hoverBg:`#f1f4f7`,danger:`#dc2626`},a={primary:`#f3f4f6`,secondary:`#cbd5e1`,tertiary:`#94a3b8`,border:`#3f4a58`,hoverBg:`#2a3240`,danger:`#f87171`};function o(){let[e,t]=(0,r.useState)(()=>typeof document<`u`&&document.body?.getAttribute(`data-ds-dark-theme`)!==null);return(0,r.useEffect)(()=>{if(typeof document>`u`)return;let e=new MutationObserver(()=>t(document.body?.getAttribute(`data-ds-dark-theme`)!==null));return e.observe(document.body,{attributes:!0,attributeFilter:[`data-ds-dark-theme`]}),()=>e.disconnect()},[]),e}function s(e){let t=new Date(e);return`${(`0`+t.getHours()).slice(-2)}:${(`0`+t.getMinutes()).slice(-2)}`}function c(e){return{row:{display:`flex`,alignItems:`center`,gap:`8px`,minWidth:0},label:{flex:1,minWidth:0,overflow:`hidden`,textOverflow:`ellipsis`,whiteSpace:`nowrap`,fontSize:`13px`,color:e.primary,cursor:`pointer`},meta:{color:e.tertiary,fontSize:`12px`,whiteSpace:`nowrap`},btn:{height:`24px`,padding:`0 10px`,border:`1px solid ${e.border}`,borderRadius:`6px`,background:`transparent`,color:e.secondary,font:`inherit`,fontSize:`12px`,cursor:`pointer`},delBtn:{height:`24px`,padding:`0 10px`,border:`1px solid ${e.border}`,borderRadius:`6px`,background:`transparent`,color:e.danger,font:`inherit`,fontSize:`12px`,cursor:`pointer`},itemBox:{display:`flex`,flexDirection:`column`,gap:`6px`,border:`1px solid ${e.border}`,borderRadius:`8px`,padding:`8px 10px`},stepsBox:{display:`flex`,flexDirection:`column`,gap:`2px`,borderTop:`1px solid ${e.border}`,paddingTop:`6px`},stepLine:{display:`flex`,gap:`8px`,fontSize:`13px`,lineHeight:`1.7`,color:e.secondary,whiteSpace:`nowrap`,overflow:`hidden`,textOverflow:`ellipsis`},toolName:{color:e.primary,flex:`none`,fontWeight:500},stepArgs:{flex:1,minWidth:0,overflow:`hidden`,textOverflow:`ellipsis`,color:e.secondary},empty:{color:e.tertiary,fontSize:`12px`,textAlign:`center`,padding:`12px 0`},root:{display:`flex`,flexDirection:`column`,gap:`8px`,maxWidth:`720px`},heading:{color:e.tertiary,fontSize:`12px`,lineHeight:`1.6`}}}function l(){let e=o(),t=e?a:i,[n,c]=(0,r.useState)(`/browser`),[l,u]=(0,r.useState)(!1),[d,f]=(0,r.useState)(!1),[p,m]=(0,r.useState)(null),[h,g]=(0,r.useState)([]),[_,v]=(0,r.useState)([]),[y,b]=(0,r.useState)(Date.now()),[x,S]=(0,r.useState)(null),[C,w]=(0,r.useState)(!1),[T,E]=(0,r.useState)(``),[D,O]=(0,r.useState)(null),[k,A]=(0,r.useState)(!1);(0,r.useEffect)(()=>{let e=!0;return fetch(`/__dsh-browser-view__/config`,{cache:`no-store`}).then(e=>e.ok?e.json():Promise.reject(Error(`HTTP ${e.status}`))).then(t=>{e&&typeof t.basePath==`string`&&t.basePath&&c(t.basePath.replace(/\/+$/,``))}).catch(()=>{}),()=>{e=!1}},[]),(0,r.useEffect)(()=>{let e=!0,t=()=>{fetch(`${n}/status`,{cache:`no-store`}).then(e=>e.ok?e.json():null).then(t=>{e&&(m(t),t?.open&&b(Date.now()))}).catch(()=>{e&&m(null)}),fetch(`${n}/log`,{cache:`no-store`}).then(e=>e.ok?e.json():null).then(t=>{e&&t&&Array.isArray(t.calls)&&g(t.calls.slice(0,8))}).catch(()=>{}),fetch(`${n}/runs/latest`,{cache:`no-store`}).then(e=>e.ok?e.json():null).then(t=>{e&&(S(t?.run??null),w(t?.busy===!0))}).catch(()=>{})};t();let r=setInterval(t,3e3);return()=>{e=!1,clearInterval(r)}},[n]);let j=()=>{let e=x;if(!e||C)return;let t=e.source.replace(/\(已从磁盘重载\)$/,``);if(!t||[`steps`,`recording`,`recent-log`].includes(t)){E(`该来源不是已保存录制,无法一键重跑`);return}E(`重跑中…`),w(!0),fetch(`${n}/runs/rerun`,{method:`POST`,headers:{"content-type":`application/json`},body:JSON.stringify({source:t,retryOf:e.runId})}).then(async e=>{let t=await e.json().catch(()=>null);if(!e.ok)throw Error(t?.error??`HTTP ${e.status}`);return t}).then(()=>E(`重跑完成,报告稍后刷新`)).catch(e=>{w(!1),E(e instanceof Error?e.message:String(e))})};(0,r.useEffect)(()=>{let e=!0,t=0,r,i=()=>{fetch(`${n}/confirm`,{cache:`no-store`}).then(n=>{if(!e)return null;if(!n.ok)throw Error(`HTTP ${n.status}`);return t=0,n.json()}).then(t=>{e&&O(t?.confirm??null)}).catch(()=>{}).finally(()=>{e&&(t++,r=setTimeout(i,t>=5?15e3:1e3))})};return i(),()=>{e=!1,r!==void 0&&clearTimeout(r)}},[n]);let M=e=>{let t=D?.id;t&&(O(null),fetch(`${n}/confirm`,{method:`POST`,headers:{"content-type":`application/json`},body:JSON.stringify({id:t,decision:e})}).catch(()=>{}))};(0,r.useEffect)(()=>{if(!d)return;let e=!0,t=()=>{fetch(`${n}/history`,{cache:`no-store`}).then(e=>e.ok?e.json():null).then(t=>{e&&t&&Array.isArray(t.history)&&v(t.history)}).catch(()=>{}),b(Date.now())};t();let r=setInterval(t,2e3);return()=>{e=!1,clearInterval(r)}},[d,n]),(0,r.useEffect)(()=>{if(!d)return;let e=e=>{e.key===`Escape`&&f(!1)};return document.addEventListener(`keydown`,e),()=>document.removeEventListener(`keydown`,e)},[d]);let N=`${n}/screenshot?v=${y}`;return(0,r.createElement)(`div`,{id:`dsh-browser-client-overlay`,style:{position:`fixed`,inset:0,pointerEvents:`none`,zIndex:2147483e3}},(0,r.createElement)(`button`,{type:`button`,title:`浏览器自动化与实时画面`,onClick:()=>u(e=>!e),style:{position:`fixed`,right:`16px`,bottom:`16px`,width:`42px`,height:`42px`,borderRadius:`999px`,border:`1px solid ${t.border}`,background:e?`#1e2430`:`#ffffff`,color:t.primary,cursor:`pointer`,display:`flex`,alignItems:`center`,justifyContent:`center`,fontSize:`18px`,boxShadow:`0 4px 16px rgba(0, 0, 0, 0.25)`,pointerEvents:`auto`,userSelect:`none`}},`🌐`),l&&(0,r.createElement)(`div`,{style:{position:`fixed`,right:`16px`,bottom:`66px`,width:`320px`,maxHeight:`72vh`,overflowY:`auto`,overflowX:`hidden`,display:`flex`,flexDirection:`column`,gap:`8px`,border:`1px solid ${t.border}`,borderRadius:`12px`,background:e?`#181e29`:`#ffffff`,boxShadow:`0 8px 32px rgba(0, 0, 0, 0.3)`,padding:`12px`,pointerEvents:`auto`}},(0,r.createElement)(`div`,{style:{display:`flex`,alignItems:`center`,gap:`8px`,padding:`4px 0`}},(0,r.createElement)(`span`,{style:{width:`8px`,height:`8px`,borderRadius:`999px`,flex:`none`,background:p?.open?`#10b981`:`#ef4444`}}),(0,r.createElement)(`span`,{style:{flex:1,minWidth:0,color:t.primary,fontSize:`13px`,fontWeight:600,whiteSpace:`nowrap`,overflow:`hidden`,textOverflow:`ellipsis`}},`浏览器实时画面`),(0,r.createElement)(`span`,{style:{color:t.secondary,fontSize:`12px`,whiteSpace:`nowrap`,overflow:`hidden`,textOverflow:`ellipsis`,maxWidth:`160px`}},p===null?`未启用`:p.open?`${p.tabs??1} 标签 · ${(p.url||``).slice(0,20)}`:`未打开`)),D?(0,r.createElement)(`div`,{style:{padding:`6px 8px`,borderRadius:`8px`,border:`1px solid #ef4444`,background:e?`rgba(239, 68, 68, 0.12)`:`rgba(239, 68, 68, 0.07)`,color:e?`#fca5a5`:`#b91c1c`,fontSize:`12px`,lineHeight:`1.5`},title:`Agent 请求执行敏感操作,请审批`},(0,r.createElement)(`div`,{style:{display:`flex`,alignItems:`center`,gap:`6px`}},(0,r.createElement)(`span`,{style:{flex:`none`}},`⚠`),(0,r.createElement)(`span`,{style:{flex:1,minWidth:0,wordBreak:`break-all`,fontWeight:600}},`敏感操作待审批`)),(0,r.createElement)(`div`,{style:{marginTop:`4px`,wordBreak:`break-all`}},D.reason,D.tool?` (${D.tool})`:``),(0,r.createElement)(`div`,{style:{display:`flex`,gap:`8px`,marginTop:`6px`}},(0,r.createElement)(`button`,{onClick:()=>M(`allowed`),style:{flex:1,padding:`4px 0`,borderRadius:`6px`,border:`none`,cursor:`pointer`,background:`#16a34a`,color:`#fff`,fontSize:`12px`,fontWeight:600}},`允许`),(0,r.createElement)(`button`,{onClick:()=>M(`denied`),style:{flex:1,padding:`4px 0`,borderRadius:`6px`,border:`none`,cursor:`pointer`,background:`#dc2626`,color:`#fff`,fontSize:`12px`,fontWeight:600}},`拒绝`))):null,p?.pause?(0,r.createElement)(`div`,{style:{display:`flex`,alignItems:`center`,gap:`6px`,padding:`6px 8px`,borderRadius:`8px`,border:`1px solid #f59e0b`,background:e?`rgba(245, 158, 11, 0.12)`:`rgba(245, 158, 11, 0.08)`,color:e?`#fbbf24`:`#b45309`,fontSize:`12px`,lineHeight:`1.5`},title:`Agent 正在等待人工操作,请在浏览器窗口中完成`},(0,r.createElement)(`span`,{style:{flex:`none`}},`⏸`),(0,r.createElement)(`span`,{style:{flex:1,minWidth:0,wordBreak:`break-all`}},`等待人工操作: ${p.pause.instruction}`)):null,p?.open?(0,r.createElement)(`img`,{src:N,alt:`实时画面`,title:`点击放大查看实时大屏与访问历史`,onClick:()=>f(!0),style:{width:`100%`,maxHeight:`160px`,objectFit:`cover`,borderRadius:`8px`,border:`1px solid ${t.border}`,cursor:`pointer`,background:e?`#10141c`:`#f8fafc`}}):(0,r.createElement)(`div`,{style:{color:t.tertiary,fontSize:`11px`,lineHeight:`1.5`,padding:`8px`,background:e?`#121620`:`#f8fafc`,borderRadius:`6px`}},`浏览器尚未启动。在对话中让 Agent 调用 browser_open 即可呈现画面。`),h.length>0&&(0,r.createElement)(`div`,{style:{display:`flex`,flexDirection:`column`,gap:`3px`,borderTop:`1px solid ${t.border}`,paddingTop:`6px`,marginTop:`2px`}},(0,r.createElement)(`div`,{style:{color:t.tertiary,fontSize:`11px`,fontWeight:500,marginBottom:`2px`}},`最近操作 (${h.length} 条)`),h.map((e,n)=>(0,r.createElement)(`div`,{key:n,style:{display:`flex`,alignItems:`center`,gap:`6px`,fontSize:`12px`,color:t.secondary,whiteSpace:`nowrap`,overflow:`hidden`,textOverflow:`ellipsis`}},(0,r.createElement)(`span`,{style:{flex:`none`,color:e.ok?`#10b981`:`#ef4444`,fontWeight:600}},e.ok?`✓`:`✗`),(0,r.createElement)(`span`,{style:{color:t.tertiary,fontSize:`11px`,flex:`none`}},s(e.ts)),(0,r.createElement)(`span`,{style:{flex:1,minWidth:0,overflow:`hidden`,textOverflow:`ellipsis`},title:`${e.tool}${e.error?`: ${e.error}`:``}`},`${e.tool}${e.error?`: ${e.error}`:``}`)))),x!==null&&(0,r.createElement)(`div`,{style:{display:`flex`,alignItems:`center`,gap:`6px`,borderTop:`1px solid ${t.border}`,paddingTop:`6px`,marginTop:`2px`,fontSize:`12px`,color:t.secondary,whiteSpace:`nowrap`,overflow:`hidden`,textOverflow:`ellipsis`,cursor:`pointer`},title:`runId=${x.runId} · 点击查看报告`,onClick:()=>A(!0)},(0,r.createElement)(`span`,{style:{flex:`none`,color:t.tertiary,fontSize:`11px`}},`最近回归`),(0,r.createElement)(`span`,{style:{flex:`none`,fontWeight:600,color:x.failed===0?`#10b981`:`#ef4444`}},x.failed===0?`✓`:`✗`),(0,r.createElement)(`span`,{style:{overflow:`hidden`,textOverflow:`ellipsis`}},`${x.source}${x.row===void 0?``:` 行${x.row}`} ${x.passed}/${x.total}${x.healedCount>0?` · 自愈${x.healedCount}`:``}${x.retries!==void 0&&x.retries.recovered>0?` · 重试挽回${x.retries.recovered}`:``} · ${new Date(x.ts).toLocaleTimeString(`zh-CN`,{hour12:!1})}`),T!==``&&(0,r.createElement)(`span`,{style:{flex:`none`,color:t.tertiary,fontSize:`11px`}},T),(0,r.createElement)(`button`,{type:`button`,title:C?`agent 忙碌,稍后可重跑`:`重跑 ${x.source}(结果进运行历史,标 retryOf)`,disabled:C,onClick:e=>{e.stopPropagation(),j()},style:{flex:`none`,height:`20px`,padding:`0 8px`,border:`1px solid ${t.border}`,borderRadius:`6px`,background:`transparent`,color:C?t.tertiary:t.secondary,fontSize:`11px`,cursor:C?`not-allowed`:`pointer`,opacity:C?.5:1}},C?`重跑(忙碌)`:`↻ 重跑`))),d&&(0,r.createElement)(`div`,{onClick:e=>{e.target===e.currentTarget&&f(!1)},style:{position:`fixed`,inset:0,zIndex:2147483001,display:`flex`,alignItems:`center`,justifyContent:`center`,padding:`24px`,background:`rgba(0, 0, 0, 0.65)`,pointerEvents:`auto`}},(0,r.createElement)(`div`,{style:{width:`min(1100px, 94vw)`,maxHeight:`90vh`,display:`flex`,flexDirection:`column`,gap:`10px`,border:`1px solid ${t.border}`,borderRadius:`12px`,background:e?`#181e29`:`#ffffff`,padding:`16px`,boxShadow:`0 16px 64px rgba(0, 0, 0, 0.4)`}},(0,r.createElement)(`div`,{style:{display:`flex`,alignItems:`center`,gap:`8px`}},(0,r.createElement)(`span`,{style:{flex:1,minWidth:0,overflow:`hidden`,textOverflow:`ellipsis`,whiteSpace:`nowrap`,color:t.primary,fontSize:`14px`,fontWeight:600}},p?.open?`${p.title||``} (${p.url||``})`:`浏览器实时大屏`),(0,r.createElement)(`button`,{type:`button`,onClick:()=>f(!1),style:{width:`28px`,height:`28px`,border:`1px solid ${t.border}`,borderRadius:`6px`,background:`transparent`,color:t.secondary,cursor:`pointer`,display:`flex`,alignItems:`center`,justifyContent:`center`,fontSize:`14px`}},`✕`)),p?.open?(0,r.createElement)(`img`,{src:N,alt:`浏览器大图`,style:{width:`100%`,maxHeight:`55vh`,objectFit:`contain`,borderRadius:`8px`,border:`1px solid ${t.border}`,background:e?`#10141c`:`#f8fafc`}}):(0,r.createElement)(`div`,{style:{color:t.tertiary,fontSize:`13px`,textAlign:`center`,padding:`32px 0`}},`浏览器尚未打开`),_.length>0&&(0,r.createElement)(`div`,{style:{display:`flex`,flexDirection:`column`,gap:`4px`,maxHeight:`22vh`,overflowY:`auto`,borderTop:`1px solid ${t.border}`,paddingTop:`8px`}},(0,r.createElement)(`div`,{style:{color:t.tertiary,fontSize:`12px`,fontWeight:500}},`访问历史 (${_.length} 条,点击在新标签打开)`),_.map((e,n)=>(0,r.createElement)(`a`,{key:n,href:e.url,target:`_blank`,rel:`noopener noreferrer`,style:{display:`flex`,gap:`8px`,alignItems:`center`,color:t.secondary,fontSize:`12px`,textDecoration:`none`,borderRadius:`6px`,padding:`4px 6px`,whiteSpace:`nowrap`,overflow:`hidden`,textOverflow:`ellipsis`}},(0,r.createElement)(`span`,{style:{color:t.tertiary,flex:`none`}},s(e.ts)),(0,r.createElement)(`span`,{style:{overflow:`hidden`,textOverflow:`ellipsis`}},e.title||e.url)))))),k&&(0,r.createElement)(`div`,{onClick:e=>{e.target===e.currentTarget&&A(!1)},style:{position:`fixed`,inset:0,zIndex:2147483002,display:`flex`,alignItems:`center`,justifyContent:`center`,padding:`24px`,background:`rgba(0, 0, 0, 0.65)`,pointerEvents:`auto`}},(0,r.createElement)(`div`,{style:{width:`min(1000px, 94vw)`,height:`90vh`,display:`flex`,flexDirection:`column`,gap:`10px`,border:`1px solid ${t.border}`,borderRadius:`12px`,background:e?`#181e29`:`#ffffff`,padding:`16px`,boxShadow:`0 16px 64px rgba(0, 0, 0, 0.4)`}},(0,r.createElement)(`div`,{style:{display:`flex`,alignItems:`center`,gap:`8px`}},(0,r.createElement)(`span`,{style:{flex:1,color:t.primary,fontSize:`14px`,fontWeight:600}},`回归报告${x===null?``:` — ${x.source}`}(运行趋势 / 失败明细 / 自愈清单)`),x!==null&&(0,r.createElement)(`button`,{type:`button`,disabled:C,title:C?`agent 忙碌,稍后可重跑`:`重跑最近一次运行`,onClick:()=>j(),style:{height:`28px`,padding:`0 10px`,border:`1px solid ${t.border}`,borderRadius:`6px`,background:`transparent`,color:C?t.tertiary:t.secondary,fontSize:`12px`,cursor:C?`not-allowed`:`pointer`,opacity:C?.5:1}},C?`↻ 重跑(忙碌)`:`↻ 重跑`),(0,r.createElement)(`button`,{type:`button`,onClick:()=>A(!1),style:{width:`28px`,height:`28px`,border:`1px solid ${t.border}`,borderRadius:`6px`,background:`transparent`,color:t.secondary,cursor:`pointer`}},`✕`)),(0,r.createElement)(`iframe`,{src:`${n}/runs/report`,title:`回归报告`,style:{flex:1,width:`100%`,border:`1px solid ${t.border}`,borderRadius:`8px`,background:`#fff`}}))))}function u(e){let t=o(),n=t?a:i,s=c(n),[l,u]=(0,r.useState)(`/browser`),[d,f]=(0,r.useState)(null),[p,m]=(0,r.useState)(``),[h,g]=(0,r.useState)({});(0,r.useEffect)(()=>{let e=!0;return fetch(`/__dsh-browser-view__/config`,{cache:`no-store`}).then(e=>e.ok?e.json():Promise.reject(Error(`HTTP ${e.status}`))).then(t=>{e&&typeof t.basePath==`string`&&t.basePath&&u(t.basePath.replace(/\/+$/,``))}).catch(()=>{}),()=>{e=!1}},[]),(0,r.useEffect)(()=>{let e=!0;return f(null),m(``),fetch(`${l}/recordings`,{cache:`no-store`}).then(e=>e.ok?e.json():Promise.reject(Error(`HTTP ${e.status}`))).then(t=>{e&&f(t.recordings??[])}).catch(t=>{e&&m(t instanceof Error?t.message:String(t))}),()=>{e=!1}},[l]);let _=e=>{g(t=>{let n=t[e];if(n!==void 0&&n!==`loading`){let n={...t};return delete n[e],n}return fetch(`${l}/recordings/detail?name=${encodeURIComponent(e)}`,{cache:`no-store`}).then(e=>e.ok?e.json():Promise.reject(Error(`HTTP ${e.status}`))).then(t=>g(n=>({...n,[e]:t}))).catch(()=>g(t=>({...t,[e]:`failed`}))),{...t,[e]:`loading`}})},v=e=>{fetch(`${l}/recordings`,{method:`POST`,headers:{"content-type":`application/json`},body:JSON.stringify({name:e})}).then(e=>e.ok?e.json():Promise.reject(Error(`HTTP ${e.status}`))).then(()=>{f(t=>t===null?t:t.filter(t=>t.name!==e)),g(t=>{let n={...t};return delete n[e],n})}).catch(()=>{})};return(0,r.createElement)(`div`,{style:s.root},(0,r.createElement)(`div`,{style:{display:`flex`,alignItems:`center`,gap:`12px`,paddingBottom:`12px`,marginBottom:`6px`,borderBottom:`1px solid ${n.border}`}},(0,r.createElement)(`div`,{style:{width:`38px`,height:`38px`,borderRadius:`10px`,display:`flex`,alignItems:`center`,justifyContent:`center`,background:t?`#222938`:`#eef2f6`,border:`1px solid ${n.border}`,fontSize:`20px`,flexShrink:0}},`🌐`),(0,r.createElement)(`div`,{style:{display:`flex`,flexDirection:`column`,gap:`2px`}},(0,r.createElement)(`div`,{style:{fontSize:`15px`,fontWeight:600,color:n.primary}},`浏览器自动化与录制`),(0,r.createElement)(`div`,{style:{fontSize:`12px`,color:n.tertiary}},`共享 Playwright 浏览器自动化、测试原语、操作轨迹与回归录制管理`))),(0,r.createElement)(`div`,{style:s.heading},`已保存的操作录制 (agent 在对话中用 browser_record save <name> 创建,存储于 $DSH_HOME/.dsh-browser/recordings)`),p?(0,r.createElement)(`div`,{style:s.empty},`加载失败: ${p}`):d===null?(0,r.createElement)(`div`,{style:s.empty},`加载中…`):d.length===0?(0,r.createElement)(`div`,{style:s.empty},`暂无录制。让 agent 跑完一轮流程后 browser_record save <name> 创建。`):d.map(e=>{let t=h[e.name];return(0,r.createElement)(`div`,{key:e.name,style:s.itemBox},(0,r.createElement)(`div`,{style:s.row},(0,r.createElement)(`span`,{style:s.label,title:`点击展开步骤`,onClick:()=>_(e.name)},e.name),(0,r.createElement)(`span`,{style:s.meta},`${e.steps} 步 · ${new Date(e.savedAt).toLocaleString()}`),(0,r.createElement)(`button`,{style:s.btn,onClick:()=>_(e.name)},t===void 0?`展开`:`收起`),(0,r.createElement)(`button`,{style:s.delBtn,onClick:()=>v(e.name)},`删除`)),t===void 0?null:t===`loading`?(0,r.createElement)(`div`,{style:s.empty},`加载中…`):(0,r.createElement)(`div`,{style:s.stepsBox},t===`failed`?(0,r.createElement)(`div`,{style:s.empty},`加载失败`):t.steps.length===0?(0,r.createElement)(`div`,{style:s.empty},`(空步骤)`):t.steps.map((t,n)=>(0,r.createElement)(`div`,{key:`${e.name}-${n}`,style:s.stepLine,title:`${t.tool} ${JSON.stringify(t.args??{})}`},(0,r.createElement)(`span`,{style:s.meta},`#${n}`),(0,r.createElement)(`span`,{style:s.toolName},t.tool),(0,r.createElement)(`span`,{style:s.stepArgs},JSON.stringify(t.args??{}))))))}),d!==null&&(0,r.createElement)(`div`,{style:s.heading},`提示:agent 在对话中用 browser_record save <name> 创建录制。`))}let d=[`slots`];function f(e){e.slots.inject(`settings.section`,()=>e.slots.register({name:`settings.section`,id:`browser`,order:40,label:`🌐 浏览器`},u)),e.slots.inject(`shell.overlay`,()=>e.slots.register({name:`shell.overlay`,id:`dsh-browser-overlay`,order:100},l))}return n.apply=f,n.inject=d,t.exports}});
|
|
1
|
+
window.__ModuleLoader__.load({id:`dsh-browser-view`,factory:e=>{var t={exports:{}},n=t.exports;Object.defineProperty(n,Symbol.toStringTag,{value:`Module`});let r=e("react"),i=null;async function a(){if(i!==null)return i;try{let e=await fetch(`/__dsh-browser-view__/config`,{cache:`no-store`});if(e.ok){let t=await e.json();if(typeof t?.basePath==`string`&&t.basePath)return i=t.basePath,t.basePath}}catch{}return i=`/browser`,i}async function o(e){try{let t=await fetch(`${e}/status`,{cache:`no-store`});return t.ok?await t.json():null}catch{return null}}async function s(e){try{let t=await fetch(`${e}/history`,{cache:`no-store`});if(!t.ok)return[];let n=await t.json();return Array.isArray(n?.history)?n.history:[]}catch{return[]}}async function c(e){try{let t=await fetch(`${e}/log`,{cache:`no-store`});if(!t.ok)return[];let n=await t.json();return Array.isArray(n?.calls)?n.calls:[]}catch{return[]}}async function l(e){try{let t=await fetch(`${e}/runs/latest`,{cache:`no-store`});if(!t.ok)return{run:null,busy:!1};let n=await t.json();return{run:n?.run??null,busy:n?.busy===!0}}catch{return{run:null,busy:!1}}}async function u(e){try{let t=await fetch(`${e}/confirm`,{cache:`no-store`});if(!t.ok)return null;let n=await t.json();return n?.confirm??n?.pending??null}catch{return null}}async function d(e,t,n){try{return(await fetch(`${e}/confirm`,{method:`POST`,headers:{"content-type":`application/json`},body:JSON.stringify({id:t,decision:n})})).ok}catch{return!1}}async function f(e){try{let t=await fetch(`${e}/pick`,{cache:`no-store`});return t.ok?(await t.json())?.pick??null:null}catch{return null}}async function p(e,t,n,r,i,a){try{return(await fetch(`${e}/pick`,{method:`POST`,headers:{"content-type":`application/json`},body:JSON.stringify({id:t,x:n,y:r,imgW:i,imgH:a})})).ok}catch{return!1}}async function m(e,t,n){try{let r=await fetch(`${e}/runs/rerun`,{method:`POST`,headers:{"content-type":`application/json`},body:JSON.stringify({source:t,...n?{retryOf:n}:{}})});if(!r.ok){let e=await r.text().catch(()=>``);return{ok:!1,status:r.status,error:e}}return{ok:!0}}catch(e){return{ok:!1,error:e instanceof Error?e.message:String(e)}}}async function h(e){try{let t=await fetch(`${e}/recordings`,{cache:`no-store`});if(!t.ok)return[];let n=await t.json();return Array.isArray(n?.recordings)?n.recordings:[]}catch{return[]}}async function g(e,t){try{let n=await fetch(`${e}/recordings/detail?name=${encodeURIComponent(t)}`,{cache:`no-store`});return n.ok?await n.json():null}catch{return null}}async function _(e,t){try{return(await fetch(`${e}/recordings`,{method:`POST`,headers:{"content-type":`application/json`},body:JSON.stringify({name:t})})).ok}catch{return!1}}function v(e){let[t,n]=(0,r.useState)(null),[i,a]=(0,r.useState)([]),[s,u]=(0,r.useState)(Date.now()),[d,f]=(0,r.useState)(null),[p,h]=(0,r.useState)(!1),[g,_]=(0,r.useState)(``);return(0,r.useEffect)(()=>{let t=!0,r=async()=>{let[r,i,s]=await Promise.all([o(e),c(e),l(e)]);t&&(n(r),r?.open&&u(Date.now()),a(i.slice(0,8)),f(s.run),h(s.busy))};r();let i=setInterval(r,3e3);return()=>{t=!1,clearInterval(i)}},[e]),{status:t,ops:i,shotVersion:s,lastRun:d,agentBusy:p,rerunMsg:g,rerunLast:async()=>{let t=d;if(!t||p)return;let n=t.source.replace(/\(已从磁盘重载\)$/,``);if(!n||[`steps`,`recording`,`recent-log`].includes(n)){_(`该来源不是已保存录制,无法一键重跑`);return}_(`重跑中…`),h(!0);let r=await m(e,n,t.runId);r.ok?_(`重跑完成,报告稍后刷新`):(h(!1),_(r.error??`重跑失败`))}}}function y(e){let[t,n]=(0,r.useState)(null);return(0,r.useEffect)(()=>{let t=!0,r=0,i,a=async()=>{try{let i=await u(e);if(!t)return;r=0,n(i)}catch{r++,t&&n(null)}finally{if(!t)return;i=setTimeout(a,r>=3?15e3:1e3)}};return a(),()=>{t=!1,i!==void 0&&clearTimeout(i)}},[e]),{pendingConfirm:t,resolveConfirm:async(t,r)=>{await d(e,t,r)&&n(null)}}}function b(e){let[t,n]=(0,r.useState)(null);return(0,r.useEffect)(()=>{let t=!0,r=0,i,a=async()=>{try{let i=await f(e);if(!t)return;r=0,n(i)}catch{r++,t&&n(null)}finally{if(!t)return;i=setTimeout(a,r>=3?15e3:1e3)}};return a(),()=>{t=!1,i!==void 0&&clearTimeout(i)}},[e]),{pendingPick:t}}let x={primary:`#1f2937`,secondary:`#4b5563`,tertiary:`#6b7280`,border:`#d8dde3`,hoverBg:`#f1f4f7`,danger:`#dc2626`},S={primary:`#f3f4f6`,secondary:`#cbd5e1`,tertiary:`#94a3b8`,border:`#3f4a58`,hoverBg:`#2a3240`,danger:`#f87171`};function C(){let[e,t]=(0,r.useState)(()=>typeof document<`u`&&document.body?.getAttribute(`data-ds-dark-theme`)!==null);return(0,r.useEffect)(()=>{if(typeof document>`u`)return;let e=new MutationObserver(()=>t(document.body?.getAttribute(`data-ds-dark-theme`)!==null));return e.observe(document.body,{attributes:!0,attributeFilter:[`data-ds-dark-theme`]}),()=>e.disconnect()},[]),e}function w(e){let t=new Date(e);return`${(`0`+t.getHours()).slice(-2)}:${(`0`+t.getMinutes()).slice(-2)}`}function T({confirm:e,dark:t,onDecision:n}){return(0,r.createElement)(`div`,{style:{padding:`6px 8px`,borderRadius:`8px`,border:`1px solid #ef4444`,background:t?`rgba(239, 68, 68, 0.12)`:`rgba(239, 68, 68, 0.07)`,color:t?`#fca5a5`:`#b91c1c`,fontSize:`12px`,lineHeight:`1.5`},title:`Agent 请求执行敏感操作,请审批`},(0,r.createElement)(`div`,{style:{display:`flex`,alignItems:`center`,gap:`6px`}},(0,r.createElement)(`span`,{style:{flex:`none`}},`⚠`),(0,r.createElement)(`span`,{style:{flex:1,minWidth:0,wordBreak:`break-all`,fontWeight:600}},`敏感操作待审批`)),(0,r.createElement)(`div`,{style:{marginTop:`4px`,wordBreak:`break-all`}},e.reason,e.tool?` (${e.tool})`:``),(0,r.createElement)(`div`,{style:{display:`flex`,gap:`8px`,marginTop:`6px`}},(0,r.createElement)(`button`,{onClick:()=>n(`allowed`),style:{flex:1,padding:`4px 0`,borderRadius:`6px`,border:`none`,cursor:`pointer`,background:`#16a34a`,color:`#fff`,fontSize:`12px`,fontWeight:600}},`允许`),(0,r.createElement)(`button`,{onClick:()=>n(`denied`),style:{flex:1,padding:`4px 0`,borderRadius:`6px`,border:`none`,cursor:`pointer`,background:`#dc2626`,color:`#fff`,fontSize:`12px`,fontWeight:600}},`拒绝`)))}function E({status:e,ops:t,lastRun:n,agentBusy:i,rerunMsg:a,pendingConfirm:o,pendingPick:s,shotSrc:c,streamSrc:l,dark:u,palette:d,onOpenModal:f,onOpenReport:p,onConfirmDecision:m,onRerunLast:h}){return(0,r.createElement)(`div`,{style:{position:`fixed`,right:`16px`,bottom:`68px`,width:`320px`,maxHeight:`78vh`,overflowY:`auto`,overflowX:`hidden`,display:`flex`,flexDirection:`column`,gap:`8px`,border:`1px solid ${d.border}`,borderRadius:`12px`,background:u?`#181e29`:`#ffffff`,boxShadow:`0 8px 32px rgba(0, 0, 0, 0.3)`,padding:`12px`,pointerEvents:`auto`}},(0,r.createElement)(`div`,{style:{display:`flex`,alignItems:`center`,gap:`8px`,padding:`4px 0`}},(0,r.createElement)(`span`,{style:{width:`8px`,height:`8px`,borderRadius:`999px`,flex:`none`,background:e?.open?`#10b981`:`#ef4444`}}),(0,r.createElement)(`span`,{style:{flex:1,minWidth:0,color:d.primary,fontSize:`13px`,fontWeight:600,whiteSpace:`nowrap`,overflow:`hidden`,textOverflow:`ellipsis`}},`浏览器实时画面`),(0,r.createElement)(`span`,{style:{color:d.secondary,fontSize:`12px`,whiteSpace:`nowrap`,overflow:`hidden`,textOverflow:`ellipsis`,maxWidth:`160px`}},e===null?`未启用`:e.open?`${e.tabs??1} 标签 · ${(e.url||``).slice(0,20)}`:`未打开`)),o?(0,r.createElement)(T,{confirm:o,dark:u,onDecision:m}):null,e?.pause?(0,r.createElement)(`div`,{style:{display:`flex`,alignItems:`center`,gap:`6px`,padding:`6px 8px`,borderRadius:`8px`,border:`1px solid #f59e0b`,background:u?`rgba(245, 158, 11, 0.12)`:`rgba(245, 158, 11, 0.08)`,color:u?`#fbbf24`:`#b45309`,fontSize:`12px`,lineHeight:`1.5`},title:`Agent 正在等待人工操作,请在浏览器窗口中完成`},(0,r.createElement)(`span`,{style:{flex:`none`}},`⏸`),(0,r.createElement)(`span`,{style:{flex:1,minWidth:0,wordBreak:`break-all`}},`等待人工操作: ${e.pause.instruction}`)):null,s?(0,r.createElement)(`div`,{style:{display:`flex`,alignItems:`center`,gap:`6px`,padding:`6px 8px`,borderRadius:`8px`,border:`1px dashed #f59e0b`,background:u?`rgba(245, 158, 11, 0.12)`:`rgba(245, 158, 11, 0.08)`,color:u?`#fbbf24`:`#b45309`,fontSize:`12px`,lineHeight:`1.5`,cursor:`pointer`},title:`点击放大实时画面,在画面上点选目标元素`,onClick:f},(0,r.createElement)(`span`,{style:{flex:`none`}},`🎯`),(0,r.createElement)(`span`,{style:{flex:1,minWidth:0,wordBreak:`break-all`}},`等待点选教学: ${s.instruction}(点此放大画面)`)):null,e?.open?(0,r.createElement)(`img`,{src:l||c,onError:e=>{e.currentTarget.src!==c&&(e.currentTarget.src=c)},alt:`实时画面`,title:`点击放大查看实时大屏与访问历史`,onClick:f,style:{width:`100%`,maxHeight:`160px`,objectFit:`cover`,borderRadius:`8px`,border:`1px solid ${d.border}`,cursor:`pointer`,background:u?`#10141c`:`#f8fafc`}}):(0,r.createElement)(`div`,{style:{color:d.tertiary,fontSize:`11px`,lineHeight:`1.5`,padding:`8px`,background:u?`#121620`:`#f8fafc`,borderRadius:`6px`}},`浏览器尚未启动。在对话中让 Agent 调用 browser_open 即可呈现画面。`),t.length>0&&(0,r.createElement)(`div`,{style:{display:`flex`,flexDirection:`column`,gap:`3px`,borderTop:`1px solid ${d.border}`,paddingTop:`6px`,marginTop:`2px`}},(0,r.createElement)(`div`,{style:{color:d.tertiary,fontSize:`11px`,fontWeight:500,marginBottom:`2px`}},`最近操作 (${t.length} 条)`),t.map((e,t)=>(0,r.createElement)(`div`,{key:t,style:{display:`flex`,alignItems:`center`,gap:`6px`,fontSize:`12px`,color:d.secondary,whiteSpace:`nowrap`,overflow:`hidden`,textOverflow:`ellipsis`}},(0,r.createElement)(`span`,{style:{flex:`none`,color:e.ok?`#10b981`:`#ef4444`,fontWeight:600}},e.ok?`✓`:`✗`),(0,r.createElement)(`span`,{style:{color:d.tertiary,fontSize:`11px`,flex:`none`}},w(e.ts)),(0,r.createElement)(`span`,{style:{flex:1,minWidth:0,overflow:`hidden`,textOverflow:`ellipsis`},title:`${e.tool}${e.error?`: ${e.error}`:``}`},`${e.tool}${e.error?`: ${e.error}`:``}`)))),n!==null&&(0,r.createElement)(`div`,{style:{display:`flex`,alignItems:`center`,gap:`6px`,borderTop:`1px solid ${d.border}`,paddingTop:`6px`,marginTop:`2px`,fontSize:`12px`,color:d.secondary,whiteSpace:`nowrap`,overflow:`hidden`,textOverflow:`ellipsis`,cursor:`pointer`},title:`runId=${n.runId} · 点击查看报告`,onClick:p},(0,r.createElement)(`span`,{style:{flex:`none`,color:d.tertiary,fontSize:`11px`}},`最近回归`),(0,r.createElement)(`span`,{style:{flex:`none`,fontWeight:600,color:n.failed===0?`#10b981`:`#ef4444`}},n.failed===0?`✓`:`✗`),(0,r.createElement)(`span`,{style:{overflow:`hidden`,textOverflow:`ellipsis`}},`${n.source}${n.row===void 0?``:` 行${n.row}`} ${n.passed}/${n.total}${n.healedCount>0?` · 自愈${n.healedCount}`:``}${n.retries!==void 0&&n.retries.recovered>0?` · 重试挽回${n.retries.recovered}`:``} · ${new Date(n.ts).toLocaleTimeString(`zh-CN`,{hour12:!1})}`),a!==``&&(0,r.createElement)(`span`,{style:{flex:`none`,color:d.tertiary,fontSize:`11px`}},a),(0,r.createElement)(`button`,{type:`button`,title:i?`agent 忙碌,稍后可重跑`:`重跑 ${n.source}(结果进运行历史,标 retryOf)`,disabled:i,onClick:e=>{e.stopPropagation(),h()},style:{flex:`none`,height:`20px`,padding:`0 8px`,border:`1px solid ${d.border}`,borderRadius:`6px`,background:`transparent`,color:i?d.tertiary:d.secondary,fontSize:`11px`,cursor:i?`not-allowed`:`pointer`,opacity:i?.5:1}},i?`重跑(忙碌)`:`↻ 重跑`)))}function D({status:e,history:t,shotSrc:n,streamSrc:i,dark:a,palette:o,onClose:s,pendingPick:c,onPick:l}){(0,r.useEffect)(()=>{let e=e=>{e.key===`Escape`&&s()};return document.addEventListener(`keydown`,e),()=>document.removeEventListener(`keydown`,e)},[s]);let u=e=>{if(c==null||l===void 0)return;let t=e.currentTarget,n=t.getBoundingClientRect(),r=t.naturalWidth||n.width,i=t.naturalHeight||n.height;if(r<=0||i<=0)return;let a=Math.min(n.width/r,n.height/i),o=(n.width-r*a)/2,s=(n.height-i*a)/2,u=Math.min(Math.max((e.clientX-n.left-o)/a,0),r),d=Math.min(Math.max((e.clientY-n.top-s)/a,0),i);l(Math.round(u),Math.round(d),Math.round(r),Math.round(i))},d=c!=null;return(0,r.createElement)(`div`,{onClick:e=>{e.target===e.currentTarget&&s()},style:{position:`fixed`,inset:0,zIndex:2147483001,display:`flex`,alignItems:`center`,justifyContent:`center`,padding:`24px`,background:`rgba(0, 0, 0, 0.65)`,pointerEvents:`auto`}},(0,r.createElement)(`div`,{style:{width:`min(1100px, 94vw)`,maxHeight:`90vh`,display:`flex`,flexDirection:`column`,gap:`10px`,border:`1px solid ${o.border}`,borderRadius:`12px`,background:a?`#181e29`:`#ffffff`,padding:`16px`,boxShadow:`0 16px 64px rgba(0, 0, 0, 0.4)`}},(0,r.createElement)(`div`,{style:{display:`flex`,alignItems:`center`,gap:`8px`}},(0,r.createElement)(`span`,{style:{flex:1,minWidth:0,overflow:`hidden`,textOverflow:`ellipsis`,whiteSpace:`nowrap`,color:o.primary,fontSize:`14px`,fontWeight:600}},e?.open?`${e.title||``} (${e.url||``})`:`浏览器实时大屏`),(0,r.createElement)(`button`,{type:`button`,onClick:s,style:{width:`28px`,height:`28px`,border:`1px solid ${o.border}`,borderRadius:`6px`,background:`transparent`,color:o.secondary,cursor:`pointer`,display:`flex`,alignItems:`center`,justifyContent:`center`,fontSize:`14px`}},`✕`)),d?(0,r.createElement)(`div`,{style:{display:`flex`,alignItems:`center`,gap:`6px`,padding:`6px 10px`,borderRadius:`8px`,border:`1px dashed #f59e0b`,background:a?`rgba(245, 158, 11, 0.12)`:`rgba(245, 158, 11, 0.08)`,color:a?`#fbbf24`:`#b45309`,fontSize:`12px`,lineHeight:`1.5`}},(0,r.createElement)(`span`,{style:{flex:`none`}},`🎯`),(0,r.createElement)(`span`,{style:{flex:1,minWidth:0,wordBreak:`break-all`}},`等待点选教学: ${c.instruction}(在下方画面上点击目标元素)`)):null,e?.open?(0,r.createElement)(`img`,{src:i||n,onError:e=>{e.currentTarget.src!==n&&(e.currentTarget.src=n)},alt:`浏览器大图`,...d?{onClick:u}:{},style:{width:`100%`,maxHeight:`55vh`,objectFit:`contain`,borderRadius:`8px`,border:d?`2px dashed #f59e0b`:`1px solid ${o.border}`,background:a?`#10141c`:`#f8fafc`,cursor:d?`crosshair`:`default`}}):(0,r.createElement)(`div`,{style:{color:o.tertiary,fontSize:`13px`,textAlign:`center`,padding:`32px 0`}},`浏览器尚未打开`),t.length>0&&(0,r.createElement)(`div`,{style:{display:`flex`,flexDirection:`column`,gap:`4px`,maxHeight:`22vh`,overflowY:`auto`,borderTop:`1px solid ${o.border}`,paddingTop:`8px`}},(0,r.createElement)(`div`,{style:{color:o.tertiary,fontSize:`12px`,fontWeight:500}},`访问历史 (${t.length} 条,点击在新标签打开)`),t.map((e,t)=>(0,r.createElement)(`a`,{key:t,href:e.url,target:`_blank`,rel:`noopener noreferrer`,style:{display:`flex`,gap:`8px`,alignItems:`center`,color:o.secondary,fontSize:`12px`,textDecoration:`none`,borderRadius:`6px`,padding:`4px 6px`,whiteSpace:`nowrap`,overflow:`hidden`,textOverflow:`ellipsis`}},(0,r.createElement)(`span`,{style:{color:o.tertiary,flex:`none`}},w(e.ts)),(0,r.createElement)(`span`,{style:{overflow:`hidden`,textOverflow:`ellipsis`}},e.title||e.url))))))}function O({base:e,dark:t,palette:n,onClose:i}){return(0,r.useEffect)(()=>{let e=e=>{e.key===`Escape`&&i()};return document.addEventListener(`keydown`,e),()=>document.removeEventListener(`keydown`,e)},[i]),(0,r.createElement)(`div`,{onClick:e=>{e.target===e.currentTarget&&i()},style:{position:`fixed`,inset:0,zIndex:2147483002,display:`flex`,alignItems:`center`,justifyContent:`center`,padding:`24px`,background:`rgba(0, 0, 0, 0.65)`,pointerEvents:`auto`}},(0,r.createElement)(`div`,{style:{width:`min(1000px, 94vw)`,height:`90vh`,display:`flex`,flexDirection:`column`,gap:`10px`,border:`1px solid ${n.border}`,borderRadius:`12px`,background:t?`#181e29`:`#ffffff`,padding:`16px`,boxShadow:`0 16px 64px rgba(0, 0, 0, 0.4)`}},(0,r.createElement)(`div`,{style:{display:`flex`,alignItems:`center`,gap:`8px`}},(0,r.createElement)(`span`,{style:{flex:1,minWidth:0,color:n.primary,fontSize:`14px`,fontWeight:600}},`回归测试报告 (最新运行)`),(0,r.createElement)(`a`,{href:`${e}/runs/report.html`,target:`_blank`,rel:`noopener noreferrer`,style:{color:n.secondary,fontSize:`12px`,textDecoration:`none`,padding:`4px 8px`,border:`1px solid ${n.border}`,borderRadius:`6px`}},`新标签页打开`),(0,r.createElement)(`button`,{type:`button`,onClick:i,style:{width:`28px`,height:`28px`,border:`1px solid ${n.border}`,borderRadius:`6px`,background:`transparent`,color:n.secondary,cursor:`pointer`,display:`flex`,alignItems:`center`,justifyContent:`center`,fontSize:`14px`}},`✕`)),(0,r.createElement)(`iframe`,{src:`${e}/runs/report.html`,title:`回归测试报告`,style:{flex:1,width:`100%`,border:`1px solid ${n.border}`,borderRadius:`8px`,background:`#ffffff`}})))}function k(){let e=C(),t=e?S:x,[n,i]=(0,r.useState)(`/browser`),[o,c]=(0,r.useState)(!1),[l,u]=(0,r.useState)(!1),[d,f]=(0,r.useState)(!1),[m,h]=(0,r.useState)([]);(0,r.useEffect)(()=>{let e=!0;return a().then(t=>{e&&i(t.replace(/\/+$/,``))}),()=>{e=!1}},[]);let{status:g,ops:_,shotVersion:w,lastRun:T,agentBusy:k,rerunMsg:A,rerunLast:j}=v(n),{pendingConfirm:M,resolveConfirm:N}=y(n),{pendingPick:P}=b(n);(0,r.useEffect)(()=>{if(!l)return;let e=!0,t=async()=>{let t=await s(n);e&&h(t)};t();let r=setInterval(t,2e3);return()=>{e=!1,clearInterval(r)}},[l,n]);let F=`${n}/screenshot?v=${w}`,I=`${n}/stream`;return(0,r.createElement)(`div`,{id:`dsh-browser-client-overlay`,style:{position:`fixed`,inset:0,pointerEvents:`none`,zIndex:2147483e3}},(0,r.createElement)(`button`,{type:`button`,title:`浏览器自动化与实时画面`,onClick:()=>c(e=>!e),style:{position:`fixed`,right:`16px`,bottom:`16px`,width:`42px`,height:`42px`,borderRadius:`999px`,border:`1px solid ${t.border}`,background:e?`#1e2430`:`#ffffff`,color:t.primary,cursor:`pointer`,display:`flex`,alignItems:`center`,justifyContent:`center`,fontSize:`18px`,boxShadow:`0 4px 16px rgba(0, 0, 0, 0.2)`,transition:`transform 0.15s ease, background 0.15s ease`,pointerEvents:`auto`}},`🌐`),o&&(0,r.createElement)(E,{status:g,ops:_,lastRun:T,agentBusy:k,rerunMsg:A,pendingConfirm:M,pendingPick:P,shotSrc:F,streamSrc:I,dark:e,palette:t,onOpenModal:()=>u(!0),onOpenReport:()=>f(!0),onConfirmDecision:e=>{M&&N(M.id,e)},onRerunLast:j}),l&&(0,r.createElement)(D,{status:g,history:m,shotSrc:F,streamSrc:I,dark:e,palette:t,onClose:()=>u(!1),pendingPick:P,onPick:(e,t,r,i)=>{P&&p(n,P.id,e,t,r,i)}}),d&&(0,r.createElement)(O,{base:n,dark:e,palette:t,onClose:()=>f(!1)}))}function A(e){let[t,n]=(0,r.useState)(null),[i,a]=(0,r.useState)(``),[o,s]=(0,r.useState)({});return(0,r.useEffect)(()=>{let t=!0;return n(null),a(``),h(e).then(e=>{t&&n(e)}).catch(e=>{t&&a(e instanceof Error?e.message:String(e))}),()=>{t=!1}},[e]),{list:t,error:i,expanded:o,toggleDetail:t=>{s(n=>{let r=n[t];if(r!==void 0&&r!==`loading`){let e={...n};return delete e[t],e}return g(e,t).then(e=>{s(n=>({...n,[t]:e??`failed`}))}).catch(()=>s(e=>({...e,[t]:`failed`}))),{...n,[t]:`loading`}})},remove:async t=>{await _(e,t)&&(n(e=>e===null?e:e.filter(e=>e.name!==t)),s(e=>{let n={...e};return delete n[t],n}))}}}function j(e){return{row:{display:`flex`,alignItems:`center`,gap:`8px`,minWidth:0},label:{flex:1,minWidth:0,overflow:`hidden`,textOverflow:`ellipsis`,whiteSpace:`nowrap`,fontSize:`13px`,color:e.primary,cursor:`pointer`},meta:{color:e.tertiary,fontSize:`12px`,whiteSpace:`nowrap`},btn:{height:`24px`,padding:`0 10px`,border:`1px solid ${e.border}`,borderRadius:`6px`,background:`transparent`,color:e.secondary,font:`inherit`,fontSize:`12px`,cursor:`pointer`},delBtn:{height:`24px`,padding:`0 10px`,border:`1px solid ${e.border}`,borderRadius:`6px`,background:`transparent`,color:e.danger,font:`inherit`,fontSize:`12px`,cursor:`pointer`},itemBox:{display:`flex`,flexDirection:`column`,gap:`6px`,border:`1px solid ${e.border}`,borderRadius:`8px`,padding:`8px 10px`},stepsBox:{display:`flex`,flexDirection:`column`,gap:`2px`,borderTop:`1px solid ${e.border}`,paddingTop:`6px`},stepLine:{display:`flex`,gap:`8px`,fontSize:`13px`,lineHeight:`1.7`,color:e.secondary,whiteSpace:`nowrap`,overflow:`hidden`,textOverflow:`ellipsis`},toolName:{color:e.primary,flex:`none`,fontWeight:500},stepArgs:{flex:1,minWidth:0,overflow:`hidden`,textOverflow:`ellipsis`,color:e.secondary},empty:{color:e.tertiary,fontSize:`12px`,textAlign:`center`,padding:`12px 0`},root:{display:`flex`,flexDirection:`column`,gap:`8px`,maxWidth:`720px`},heading:{color:e.tertiary,fontSize:`12px`,lineHeight:`1.6`}}}function M(e){let t=C(),n=t?S:x,i=j(n),[o,s]=(0,r.useState)(`/browser`);(0,r.useEffect)(()=>{let e=!0;return a().then(t=>{e&&s(t.replace(/\/+$/,``))}),()=>{e=!1}},[]);let{list:c,error:l,expanded:u,toggleDetail:d,remove:f}=A(o);return(0,r.createElement)(`div`,{style:i.root},(0,r.createElement)(`div`,{style:{display:`flex`,alignItems:`center`,gap:`12px`,paddingBottom:`12px`,marginBottom:`6px`,borderBottom:`1px solid ${n.border}`}},(0,r.createElement)(`div`,{style:{width:`36px`,height:`36px`,borderRadius:`8px`,background:t?`rgba(99, 102, 241, 0.15)`:`rgba(99, 102, 241, 0.1)`,border:`1px solid ${t?`rgba(99, 102, 241, 0.3)`:`rgba(99, 102, 241, 0.2)`}`,display:`flex`,alignItems:`center`,justifyContent:`center`,fontSize:`20px`,flex:`none`}},`🌐`),(0,r.createElement)(`div`,{style:{display:`flex`,flexDirection:`column`,gap:`2px`}},(0,r.createElement)(`div`,{style:{fontSize:`15px`,fontWeight:600,color:n.primary}},`浏览器自动化与录制管理`),(0,r.createElement)(`div`,{style:{fontSize:`12px`,color:n.tertiary}},`管理已保存的浏览器回归脚本,查看执行序列与历史数据`))),(0,r.createElement)(`div`,{style:i.heading},`已保存的录制(由 browser_record save 生成,供 browser_replay 一键回放):`),l?(0,r.createElement)(`div`,{style:{...i.empty,color:n.danger}},`加载失败: ${l}`):c===null?(0,r.createElement)(`div`,{style:i.empty},`加载中…`):c.length===0?(0,r.createElement)(`div`,{style:i.empty},`暂无已保存录制。在与 Agent 对话中完成一轮浏览器操作后,输入「保存录制为 xxx」即可沉淀为回归用例。`):c.map(e=>{let t=u[e.name],n=t!==void 0&&t!==`loading`;return(0,r.createElement)(`div`,{key:e.name,style:i.itemBox},(0,r.createElement)(`div`,{style:i.row},(0,r.createElement)(`span`,{style:i.label,title:`点击展开 / 折叠步骤详情`,onClick:()=>d(e.name)},(n?`▾ `:`▸ `)+e.name),(0,r.createElement)(`span`,{style:i.meta},`${e.steps} 步 · ${new Date(e.savedAt).toLocaleDateString(`zh-CN`)}`),(0,r.createElement)(`button`,{type:`button`,style:i.btn,onClick:()=>d(e.name)},n?`收起`:`步骤`),(0,r.createElement)(`button`,{type:`button`,style:i.delBtn,onClick:()=>f(e.name)},`删除`)),n&&t!==`failed`&&(0,r.createElement)(`div`,{style:i.stepsBox},t.steps.map((e,t)=>(0,r.createElement)(`div`,{key:t,style:i.stepLine},(0,r.createElement)(`span`,{style:i.meta},`#${t+1}`),(0,r.createElement)(`span`,{style:i.toolName},e.tool),(0,r.createElement)(`span`,{style:i.stepArgs},JSON.stringify(e.args))))))}))}let N=[`slots`];function P(e){e.slots.inject(`settings.section`,()=>e.slots.register({name:`settings.section`,id:`browser`,order:40,label:`🌐 浏览器`},M)),e.slots.inject(`shell.overlay`,()=>e.slots.register({name:`shell.overlay`,id:`dsh-browser-overlay`,order:100},k))}return n.apply=P,n.inject=N,t.exports}});
|
|
2
2
|
//# sourceMappingURL=client.js.map
|