diff --git a/docs/reference/cli.md b/docs/reference/cli.md index 04950d3b..b4052106 100644 --- a/docs/reference/cli.md +++ b/docs/reference/cli.md @@ -22,7 +22,7 @@ UniDesk 的统一 CLI 入口是根目录 `scripts/cli.ts`,运行方式固定 - `codex task ` 通过 Code Queue 私有代理按任务 ID 查询结构化执行摘要;默认只返回有界 prompt/response 预览、执行 Provider、工作目录、最后 assistant message、最近工具调用摘要、attempt、judge、错误、耗时和 trace 翻页提示,适合在新队列任务中引用历史 session 且避免噪声爆炸。 - `codex task --trace --tail|--from-start|--after-seq N|--before-seq N --limit N` 按页拉取 Code Queue 的逻辑 trace;响应会返回 `nextAfterSeq`、`previousBeforeSeq`、`hasMore`、`hasBefore` 和下一页/上一页命令,默认 `--trace` 取最新一页,需要完整 prompt/最后 response 时加 `--full`。 - `codex output --tail|--from-start|--after-seq N|--before-seq N --limit N [--full-text]` 按原始 output seq 分页读取底层记录;当 trace 行提示 `commandOmittedLines`、`bodyOmittedLines` 或 `rawSeqs` 时,用该命令按 seq 补取完整信息,默认仍有单条文本预览上限,显式 `--full-text` 才返回该页全文。 -- Code Queue 多队列 lane 由 `codex` 命令命名空间管理:`queues` 列表、`queue create ` 创建、`move --queue ` 迁移;同一个 queue 内部串行执行,不同 queue 之间并行执行,迁移 queued/retry_wait 任务后会立即调度目标 queue。 +- Code Queue 多队列 lane 由 `codex` 命令命名空间管理:`queues` 列表、`queue create ` 创建、`queue merge --into ` 合并、`move --queue ` 迁移;同一个 queue 内部串行执行,不同 queue 之间并行执行。合并只移动任务归属,必须保留源 queue 记录且不提供删除语义;合并后的目标 queue 按任务原 `queueEnteredAt`/`createdAt` 时间顺序串行。迁移 queued/retry_wait 任务后会立即调度目标 queue。 - `job list` 与 `job status` 查询 `.state/jobs/` 文件系统状态,是异步命令的可观测入口。 - `debug health`、`debug dispatch` 与 `debug task` 走真实内部 core、WebSocket、数据库、provider、系统指标、Docker 状态和 Host SSH 维护桥流程,只用于开发调试,不写入 `TEST.md` 的正式验收步骤。 - `e2e run [--only pattern[,pattern...]] [--skip pattern[,pattern...]]` 使用 publicHost 派生的公开 frontend/provider ingress URL,并通过 Docker 内网验证 core API、PostgreSQL、provider self-connection、系统指标曲线、Docker 状态快照、provider.upgrade 预检和 Playwright 前端页面,是交付前的自动化 E2E 门禁;CLI 默认输出 check 状态摘要,完整诊断写入 `resultPath`,日常迭代应优先用 `--only` / `--skip` 跑最小必要集合。 diff --git a/docs/reference/deployment.md b/docs/reference/deployment.md index 0a213da3..f4fc8b8c 100644 --- a/docs/reference/deployment.md +++ b/docs/reference/deployment.md @@ -43,6 +43,10 @@ frontend 的 Docker 上线顺序为:先运行必要的本地校验,例如 `b 正式流程不得依赖人工 `docker rm` 兜底;手工删除旧容器后若 job、Docker client 或 daemon 在 `up` 前中断,会直接造成 `direct microservice proxy failed`。`server rebuild ` 必须是可观测 job:build-first、Compose lock、no-deps force-recreate、post-up validation、保留 named volume。Code Queue 等长任务服务即使被重建也必须依赖服务自身 restart-recovery 恢复任务,不能用“避免重建”掩盖恢复缺陷。 +## User Service Restart Recovery + +主 server 用户服务和计算节点用户服务都必须按 `docs/reference/microservices.md` 的 Runtime Configuration And Persistence Contract 设计。主 server Compose 内的用户服务通过固定 project、`restart` policy、健康检查、PostgreSQL 权威状态和 `server rebuild ` 的 no-deps force-recreate 恢复;计算节点用户服务通过节点本地 Compose/docker run、host bind mount 或业务数据库持久化、Docker restart policy、节点级 autorecover 脚本和 provider-gateway 私有代理验收恢复。上线说明不能只写“容器已启动”,必须说明 Docker daemon 或机器重启后如何重新进入 ready 状态,以及哪些路径/表保存了登录、队列、token、订阅和业务数据。 + ## Health Criteria 服务跑通的最低标准是:backend-core 内网 `/health` 返回 ok,frontend 公网 `/health` 返回 ok,provider ingress 公网 `/health` 返回 ok,database 在容器内 `pg_isready` 可用,Todo Note 后端 `/api/health` 返回 `storage=postgres`,Code Queue `/health` 返回队列摘要、默认模型和 `queue.storage`,Project Manager `/health` 返回 `storage.primary=postgres` 和项目数量,backend-core `/api/performance` 返回性能指标,`/api/nodes` 中出现 `main-server` provider 且状态为 `online`,`/api/nodes/system-status` 中出现 `main-server` 的 CPU/内存/硬盘采样,`/api/nodes/docker-status` 中出现 `main-server` 的 Docker 快照。交付前还必须运行 `bun scripts/cli.ts e2e run`,并以 `docs/reference/e2e.md` 的门禁作为最终判定。 diff --git a/docs/reference/e2e.md b/docs/reference/e2e.md index 8ce89da0..34722e94 100644 --- a/docs/reference/e2e.md +++ b/docs/reference/e2e.md @@ -35,7 +35,8 @@ Typical targeted commands: - Core API: `docker exec unidesk-backend-core` calls internal `GET /api/overview`, which must report `dbReady: true`, `pgdata.volumeName=unidesk_pgdata_10gb`, a positive PostgreSQL database byte count, and at least one online node; internal `GET /api/performance` must report component request statistics, internal operation statistics, PGDATA usage and Code Queue PostgreSQL storage metadata. - Provider self-connection: internal `GET /api/nodes` must contain `main-server` with `status: online`, `labels.providerGatewayVersion` equal to `src/components/provider-gateway/package.json`, `labels.providerGatewayUpgradePolicy: "always-enabled"`, `labels.providerGatewayRestartPolicyOk: true`, `labels.providerGatewayPidModeOk: true`, and `labels.providerGatewayRuntimeGuardOk: true`; internal `GET /api/nodes/system-status` must contain CPU/memory/disk samples plus a non-empty process resource list sorted by memory by default; internal `GET /api/nodes/docker-status` must contain a Docker snapshot for `main-server`; every running `provider-gateway` container visible in Docker snapshots must report `restartPolicy: "always"` and `pidMode: "host"`; public provider ingress `/health` must return ok. - Provider remote control: internal `/api/dispatch` must successfully complete a real `provider.upgrade` task in `mode: "plan"` so the upgrade path is validated without recreating the running gateway during E2E. -- User services: internal `/api/microservices` must include `todo-note` and `code-queue` on `main-server`, canonical `filebrowser` on `D518`, plus `findjob`, `pipeline`, `met-nonlinear` and `filebrowser-d601` on `D601` with `public=false`; `/api/microservices/todo-note/health` must report `storage=postgres`, `/api/microservices/todo-note/proxy/api/instances` must expose the migrated Todo Note lists, and a temporary Todo Note list create/add/toggle/undo/delete cycle must succeed through the real provider-gateway proxy; `/api/microservices/code-queue/health` must return a Code Queue summary with default model `gpt-5.5`, and `/api/microservices/code-queue/proxy/api/tasks` must return queue state through the same proxy; `/api/microservices/filebrowser/health`, `/api/microservices/filebrowser-d601/health` and `/api/microservices/filebrowser/proxy/` must prove File Browser health and WebUI access through UniDesk proxy; `/api/microservices/findjob/health` and `/api/microservices/findjob/proxy/api/summary` must succeed through the real provider-gateway proxy; `/api/microservices/findjob/proxy/api/jobs?__unideskArrayLimit=jobs:5` must return a bounded preview with `_unidesk.arrayLimits` metadata; `/api/microservices/pipeline/health`, `/api/microservices/pipeline/proxy/api/snapshot?__unideskArrayLimit=registry.components:8,runs:3` and `/api/microservices/pipeline/proxy/api/oa-event-flow/diagnostics` must return Pipeline health, registry/run previews and OA event-flow evidence; `/api/microservices/met-nonlinear/health`, `/api/microservices/met-nonlinear/proxy/api/queue`, `/api/microservices/met-nonlinear/proxy/api/projects?root=projects&limit=500`, `/api/microservices/met-nonlinear/proxy/api/projects?root=ex_projects&limit=500`, `/api/microservices/met-nonlinear/proxy/api/projects/config?path=` and `/api/microservices/met-nonlinear/proxy/api/images` must return the D601 TS backend health, queue/GPU policy, full project tree inputs, structured project detail and ready `met-nonlinear-ml:tf26` image status. +- User services: internal `/api/microservices` must include `todo-note` and `code-queue` on `main-server`, canonical `filebrowser` on `D518`, plus `findjob`, `pipeline`, `met-nonlinear`, `claudeqq` and `filebrowser-d601` on `D601` with `public=false`; `/api/microservices/todo-note/health` must report `storage=postgres`, `/api/microservices/todo-note/proxy/api/instances` must expose the migrated Todo Note lists, and a temporary Todo Note list create/add/toggle/undo/delete cycle must succeed through the real provider-gateway proxy; `/api/microservices/code-queue/health` must return a Code Queue summary with default model `gpt-5.5`, and `/api/microservices/code-queue/proxy/api/tasks` must return queue state through the same proxy; `/api/microservices/filebrowser/health`, `/api/microservices/filebrowser-d601/health` and `/api/microservices/filebrowser/proxy/` must prove File Browser health and WebUI access through UniDesk proxy; `/api/microservices/findjob/health` and `/api/microservices/findjob/proxy/api/summary` must succeed through the real provider-gateway proxy; `/api/microservices/findjob/proxy/api/jobs?__unideskArrayLimit=jobs:5` must return a bounded preview with `_unidesk.arrayLimits` metadata; `/api/microservices/pipeline/health`, `/api/microservices/pipeline/proxy/api/snapshot?__unideskArrayLimit=registry.components:8,runs:3` and `/api/microservices/pipeline/proxy/api/oa-event-flow/diagnostics` must return Pipeline health, registry/run previews and OA event-flow evidence; `/api/microservices/met-nonlinear/health`, `/api/microservices/met-nonlinear/proxy/api/queue`, `/api/microservices/met-nonlinear/proxy/api/projects?root=projects&limit=500`, `/api/microservices/met-nonlinear/proxy/api/projects?root=ex_projects&limit=500`, `/api/microservices/met-nonlinear/proxy/api/projects/config?path=` and `/api/microservices/met-nonlinear/proxy/api/images` must return the D601 TS backend health, queue/GPU policy, full project tree inputs, structured project detail and ready `met-nonlinear-ml:tf26` image status. +- ClaudeQQ availability: `/api/microservices/claudeqq/health` must only pass when `ready=true`, NapCat HTTP and WebSocket are connected, and `napcat.loginState=logged_in`; `/api/microservices/claudeqq/proxy/api/napcat/login` must show the same logged-in account state and `/api/microservices/claudeqq/proxy/api/events/recent` must prove the backend can read the persistent event cache. A QR-code-only or not-logged-in NapCat state must be treated as unhealthy. - Database: the command writes an `unidesk_e2e_markers` row through `docker exec unidesk-database psql`, confirms provider state is stored in PostgreSQL, and checks Todo Note rows exist in `todo_note_instances` using the same named volume. - Pipeline OA event flow: `microservice:pipeline-oa-event-flow` must prove both no-audit and monitor-audit runs are driven by OA events end to end. The event stream must show `node-finished` as a neutral fact with `pipeline:{pipelineId}` and `epoch:{runId}` tags, OA policy as the source of downstream/audit decisions, monitor decisions as OA control events, and runner control-result evidence. E2E must fail if delivery still depends on a legacy detail audit policy flag as policy authority, independent legacy audit-request points, a legacy batch completion gate, direct monitor-to-runner calls, or frontend/CLI writes to Pipeline `.state`. - The same Pipeline OA diagnostics must fail on legacy file-transport residuals. Procedure containers, monitor sessions, UI/Gantt DTO builders and CLI fetches must consume prompt/control/stop/display evidence only from the OA event ledger and normalized HTTP read APIs; `control-prompts.jsonl`, `monitor-prompts.jsonl`, `monitor-control`, `control-events.jsonl`, monitor stop files, `.state/pipeline-runs/{runId}/control/commands/`, `PIPELINE_*_APPEND_FILE`, local JSONL append/read helpers, and monitor `/pipeline-state` mounts are forbidden in runtime source. @@ -44,6 +45,7 @@ Typical targeted commands: - Frontend dense-layout regression gate: whenever a frontend change touches Pipeline 右侧边栏、Trace timeline、详情抽屉、甘特图坐标或其他高信息密度面板, Playwright acceptance must inspect both `总高度` and `横向滚动条`. For Pipeline specifically, the OpenCode Trace session head must carry shared agent/model/session facts and the Trace body must use the same Code Queue `TraceView` styling; Playwright must fail if old `.pipeline-opencode-step`, `.pipeline-opencode-flow`, `.pipeline-step-message-card` or `.pipeline-opencode-part` user-visible styles reappear, if the Trace container introduces an internal horizontal scrollbar, or if `frontend:pipeline-gantt-frontend-y-accuracy` fails to prove the frontend `frontend-y` layout maps ticks, markers and execution bars from timestamps to y coordinates within tolerance. - OpenCode Trace must use Code Queue Trace styling and must not render the deprecated Pipeline continuous step connector; Playwright should fail if `.pipeline-opencode-flow`, `.pipeline-opencode-step` or any equivalent continuous connector/card returns to the user-visible Trace. - User service frontend assertions must wait for real backend data, not only the page skeleton. For Todo Note this means the page must show the migrated lists `CONSTAR`、`大论文`、`找工作`、`小论文`、`事务`, support creating a temporary list and task through the frontend, and delete that temporary list afterwards. The temporary list must be selected again by its unique generated name before deletion so E2E never deletes a migrated source list by accident. For FindJob this means the page must show a numeric `岗位总量`, `HEALTH OK`, and a non-empty `PREVIEW` count such as `40/1463 PREVIEW`; for Pipeline this means the page must show `Pipeline v2 工作台`, `Health OK`, a numeric component count, a non-empty React Flow control graph, `控制图`, `Epoch 甘特图`, and after clicking a Gantt execution line it must show `OpenCode Trace` rendered by the shared Code Queue-style Trace component with messages and tool-call groups; for MET Nonlinear this means the page must show `MET Nonlinear 训练编排`, `Health OK`, `Fork Project`, `加入待启动队列`, `启动队列`, `当前队列`, 最大并发设置、task queue and GPU/image panels, and must not show the removed hard-coded `创建10个10轮任务` frontend entry. The MET Nonlinear project library must render `projects/` and `ex_projects/` as a true path tree with folder Project counts; clicking a project row must open a structured detail panel containing `config.json`, `data/ 训练状态`, `模型参数`, `指标` and a parameter count such as `Total Params`; clicking a completed/current/failed job row must open a structured job detail and both the row and detail must show `epoch/h`. Full MET Nonlinear acceptance is driven by public frontend controls: choose a visible source Project, set batch size, epochs and max concurrency in inputs, fork into `projects/unidesk_forks/`, stage the selected forks, start the queue, and verify completed rows plus automatic `metnl-train-*` container removal; loading placeholders like `--` or empty states are not sufficient for E2E success. +- For ClaudeQQ this means the page must show `Health OK`, `NapCat 容器登录`, `NAPCAT HTTP OK`, `NAPCAT WS OK`, logged-in state such as `已登录 logged_in`, event cache, subscriptions and message push controls. A page that only shows a QR code, stale raw JSON, or a running backend without logged-in NapCat is not acceptable. ## Frontend JSON Rule @@ -53,7 +55,7 @@ Remote update records in the frontend are covered by the same rule: `provider.up Provider operation availability is also covered by the structured rendering rule. `host.ssh` availability must be displayed as badges or equivalent controls derived from capabilities and `hostSsh*` labels, and remote update availability must be displayed from `provider.upgrade` capability plus the `always-enabled` policy; these fields must not require opening raw Provider JSON. -User service pages are covered by the same rule. `Todo Note` must show lists, task tree, filters, reminder input, movement controls, undo/redo and metrics as controls; `Code Queue` must show queue cards, live transcript, model/cwd/max attempt inputs, judge decision, attempt table, append prompt, interrupt and retry controls; `File Browser` must show D518 as the default target, D601 as an alternate target, a screenshot export action, and an embedded upstream WebUI frame served through `/api/microservices//proxy/` with compact file rows that do not let material-icon fallback text cover file metadata; `FindJob` must show metrics, jobs and drafts as cards/tables; `Pipeline` must show component classes, React Flow graph nodes/edges, run cards, Gantt execution lines and OpenCode Trace timelines as controls; `MET Nonlinear` must show queue rows, GPU/image cards, a real path tree for the project library, structured project/job detail panels, project config preview, `data/` training state, model parameter count, metrics, progress bars, ETA, `epoch/h` speed and history diagnostics as controls; the full user-service config, summary, snapshot, jobs preview, drafts and run JSON can only appear after an explicit `查看原始JSON` click. +User service pages are covered by the same rule. `Todo Note` must show lists, task tree, filters, reminder input, movement controls, undo/redo and metrics as controls; `Code Queue` must show queue cards, live transcript, model/cwd/max attempt inputs, judge decision, attempt table, append prompt, interrupt and retry controls; `File Browser` must show D518 as the default target, D601 as an alternate target, a screenshot export action, and an embedded upstream WebUI frame served through `/api/microservices//proxy/` with compact file rows that do not let material-icon fallback text cover file metadata; `FindJob` must show metrics, jobs and drafts as cards/tables; `Pipeline` must show component classes, React Flow graph nodes/edges, run cards, Gantt execution lines and OpenCode Trace timelines as controls; `MET Nonlinear` must show queue rows, GPU/image cards, a real path tree for the project library, structured project/job detail panels, project config preview, `data/` training state, model parameter count, metrics, progress bars, ETA, `epoch/h` speed and history diagnostics as controls; `ClaudeQQ` must show NapCat HTTP/WS/login badges, QR/login panel, event cache, subscriptions and message push controls; the full user-service config, summary, snapshot, jobs preview, drafts and run JSON can only appear after an explicit `查看原始JSON` click. ## Public Boundary Rule @@ -63,6 +65,12 @@ The public frontend URL and provider ingress URL are the only public network int The PostgreSQL data volume is the named Docker volume `unidesk_pgdata_10gb`. CLI server control commands must never use `docker compose down -v`, `docker volume rm`, or any equivalent data-volume removal. To validate persistence, insert a marker row into `unidesk_e2e_markers`, run `bun scripts/cli.ts server start` or a full stop/start cycle, and verify the marker row still exists. +## User Service Restart-Recovery Rule + +Any new user service, service migration, or change to a service's Compose/docker run configuration must prove it can recover after container restart and Docker daemon restart. The delivery evidence must include the service's `config.json` id/provider/container mapping, restart policy, host-bound private port, persistent mounts or PostgreSQL tables, health readiness fields, and at least one post-restart `bun scripts/cli.ts microservice health ` plus a representative `microservice proxy` check through the real provider-gateway path. + +D601 services have an extra gate because Windows, WSL and Docker Desktop are separate supervisors: record the Windows scheduled task or equivalent keepalive, run `docker inspect` to confirm `met-nonlinear-ts`, `claudeqq-backend`, `claudeqq-napcat` and any changed service have non-empty restart policies and host bind mounts for durable state, then verify MET Nonlinear queue/image health and ClaudeQQ logged-in NapCat HTTP/WebSocket state after the restart. A service that only becomes `running` but loses login, queue, token, subscription, data directory or pending work is not restart-recovery complete. + ## Delivery Gate Before claiming delivery, run these checks and keep their JSON output or screenshot path available for review: diff --git a/docs/reference/frontend.md b/docs/reference/frontend.md index ccf2019c..644e505e 100644 --- a/docs/reference/frontend.md +++ b/docs/reference/frontend.md @@ -10,11 +10,21 @@ frontend 应用源码必须使用 TypeScript + React,禁止在 `src/components ## Deployment Contract -任何会影响公网 WebUI 的 frontend 源码、样式或导航变更,都必须在同一任务内完成 Docker 上线;只运行 TypeScript 检查、`Bun.build` 或修改仓库文件不代表公网生效。frontend 容器启动时才从镜像内复制的 `src/components/frontend/src/app.tsx` 及其 TSX imports 构建 `/app.js`,当前 Compose 不对 frontend 源码做宿主机 bind mount,因此运行中的 `unidesk-frontend` 不会自动读取工作区新文件。 +任何会影响公网 WebUI 的 frontend 源码、样式或导航变更,都必须在同一任务内完成 Docker 上线;只运行 TypeScript 检查、`Bun.build` 或修改仓库文件不代表公网生效。 -标准上线命令固定为在仓库根目录执行 `bun scripts/cli.ts server rebuild frontend`。该命令会先构建 `frontend` 镜像,再在固定 Compose project 下通过 `up -d --no-deps --force-recreate frontend` 替换单个容器,并等待健康检查通过;不要用“本地 bundle 校验通过”代替这一步。上线后必须用 `bun scripts/cli.ts job status latest` 或具体 job id 确认 `status=succeeded`,再用 `bun scripts/cli.ts server status`、公网 `http://74.48.78.17:18081/health` 和对应页面/深链接验证真实公网页面已经加载新 bundle。 +**关键规则**:frontend 容器启动时才从镜像内复制的 `src/components/frontend/src/app.tsx` 及其 TSX imports 构建 `/app.js`,运行中的 `unidesk-frontend` 不会自动读取工作区新文件。 -如果用户报告公网仍是旧界面,优先排查两件事:第一,确认最近一次 `server rebuild frontend` 的 job 已成功且 `unidesk-frontend` 容器创建时间晚于代码修改时间;第二,浏览器可能保留旧 `/app.js`,应使用无缓存刷新或重新打开无痕窗口,并可用 `curl -H 'Cache-Control: no-cache' http://74.48.78.17:18081/app.js` 检查新 bundle 标记。涉及右键/中键打开新标签页的导航改动,还必须在公网页面 DOM 中确认左侧主模块和顶部子标签是带 `href` 的 ``,普通左键仍走 SPA 路由。 +**上线流程**: +1. 修改源码/CSS +2. 执行 `bun scripts/cli.ts server rebuild frontend` +3. 用 `bun scripts/cli.ts job status latest` 确认 `status=succeeded` +4. 用 E2E `frontend:layout-overflow` 验证改动已生效 + +禁止用"本地 bundle 校验通过"代替 `server rebuild frontend`;禁止跳过 E2E 验证直接交付。 + +前端修改必须通过 `bun scripts/cli.ts server rebuild frontend` 上线。确认 job status=succeeded 后,用 E2E `frontend:layout-overflow` 验证改动已生效。 + +如果公网仍是旧界面:1. 确认 job 已成功且容器创建时间晚于代码修改;2. 强制刷新或开无痕窗口;3. 用 curl -H "Cache-Control: no-cache" http://74.48.78.17:18081/app.js 查新 bundle。 ## Time Zone Contract @@ -78,10 +88,11 @@ frontend shell 必须把左侧主模块与顶部子标签编译为统一的 URL - `FindJob` 子标签必须把 D601 findjob 后端渲染为 UniDesk React 控件,包括岗位指标、岗位预览、草稿报告和显式原始 JSON 按钮。 - `ClaudeQQ` 子标签必须把 D601 ClaudeQQ 后端渲染为 UniDesk React 控件,包括 NapCat 容器登录二维码、NapCat HTTP/WS 状态、事件缓存、QQ 事件订阅表、订阅创建表单、消息推送表单、主用户私聊账号 `645275593` 标记、最近 QQ 事件、已发送记录和显式原始 JSON 按钮。 - `Baidu Netdisk` 子标签必须把主 server `baidu-netdisk-backend` 后端渲染为 UniDesk React 控件,包括 OAuth 设备码二维码/用户码登录、账号容量、配置工作根文件浏览(当前默认百度网盘根目录 `/`)、staging 目录上传/下载任务、上传/下载自测按钮与 MD5 结果、脱敏安全说明、日志摘要和显式原始 JSON 按钮;不得把 access token、refresh token、dlink 或 staging 文件字节流裸露到浏览器。 - - `Code Queue` 子标签必须把主 server `code-queue-backend` 后端渲染为 UniDesk React 控件,包括多 queue lane、queue 内串行、queue 间并行、任务 ID/复制任务 ID、引用按钮、任务耗时、任务提交/批量提交、引用任务 ID、创建成功提示、清空输入、模型下拉、显式入队份数、默认模型 `gpt-5.5`、MiniMax judge 状态、Codex CLI-like 输出流、attempt 终态、运行中追加 prompt、打断、手动重试和显式原始 JSON 按钮;Codex CLI-like 输出流必须始终保留任务的初始 `Submitted prompt` 和运行中 `Steer prompt`;整个 agent loop 消息流统一命名为专有名词 `Trace`,`Trace` 包含 assistant message、user prompt、system event 和 tool call;Code Queue 与 Pipeline/OpenCode messages 必须共用 `src/components/frontend/src/trace.tsx` 的 Trace 公共组件、统一 Trace item 接口和 codex/opencode port 适配层;连续 read/edit/run 工具调用只是在 Trace 内折叠为可展开工具调用组,汇总格式至少包含 `xx read, xx edit, xx run`,并展示读取文件、编辑文件、运行命令和耗时摘要;最近 3 个工具调用保持展开,工具调用内容不得自动换行且必须在工具调用块内部横向滚动,工具调用组展开后不得再增加额外左侧缩进;message 与 prompt 必须自动换行,普通 message 不显示左侧项目符号缩进且永不折叠;Trace 首屏可以是摘要预览,但终态任务被选中后必须自动在后台加载完整 Trace,手动“加载完整 Trace”也必须从 Code Queue output archive 分页补齐早期 trace,不得把 preview 的 `hasMore=false` 当成完整历史;即使热状态为控制体积裁剪了早期 raw output,也要从结构化 `basePrompt/displayPrompt/promptHistory` 和 archive 合成完整用户输入与 agent trace,并且初始 prompt 默认显示注入前 prompt 而不是引用注入全文;当初始 prompt 含引用注入时,引用内容必须默认折叠,并只在 Trace 的初始消息中提供可展开的“最终传入 Codex 的真实完整 prompt”,不得再渲染独立 Prompt 全量卡片;多轮引用注入必须按上游/最早上下文在前、直接引用在后的顺序排列,每一轮必须有明确 `Reference Round N/M` 分割线和时间范围,不能用固定 6 轮截断引用链;点击队列引用按钮必须自动把该任务 ID 写入提交表单的引用输入框,引用任务 ID 创建新任务时必须自动注入 `bun scripts/cli.ts codex task ` 的提示;连续执行同一 prompt 应通过入队份数一次性生成多条任务,避免快速连点造成操作员误判。 + - `Code Queue` 子标签必须把主 server `code-queue-backend` 后端渲染为 UniDesk React 控件,包括多 queue lane、queue 内串行、queue 间并行、queue 合并(只能合并任务归属、不能删除源 queue,合并后按原 queueEnteredAt/createdAt 时间顺序串行)、任务 ID/复制任务 ID、引用按钮、任务耗时、任务提交/批量提交、引用任务 ID、创建成功提示、清空输入、模型下拉、显式入队份数、默认模型 `gpt-5.5`、MiniMax judge 状态、Codex CLI-like 输出流、attempt 终态、运行中追加 prompt、打断、手动重试和显式原始 JSON 按钮;Codex CLI-like 输出流必须始终保留任务的初始 `Submitted prompt` 和运行中 `Steer prompt`;整个 agent loop 消息流统一命名为专有名词 `Trace`,`Trace` 包含 assistant message、user prompt、system event 和 tool call;Code Queue 与 Pipeline/OpenCode messages 必须共用 `src/components/frontend/src/trace.tsx` 的 Trace 公共组件、统一 Trace item 接口和 codex/opencode port 适配层;连续 read/edit/run 工具调用只是在 Trace 内折叠为可展开工具调用组,汇总格式至少包含 `xx read, xx edit, xx run`,并展示读取文件、编辑文件、运行命令和耗时摘要;最近 3 个工具调用保持展开,工具调用内容不得自动换行且必须在工具调用块内部横向滚动,工具调用组展开后不得再增加额外左侧缩进;message 与 prompt 必须自动换行,普通 message 不显示左侧项目符号缩进且永不折叠;Trace 首屏可以是摘要预览,但终态任务被选中后必须自动在后台加载完整 Trace,手动“加载完整 Trace”也必须从 Code Queue output archive 分页补齐早期 trace,不得把 preview 的 `hasMore=false` 当成完整历史;即使热状态为控制体积裁剪了早期 raw output,也要从结构化 `basePrompt/displayPrompt/promptHistory` 和 archive 合成完整用户输入与 agent trace,并且初始 prompt 默认显示注入前 prompt 而不是引用注入全文;当初始 prompt 含引用注入时,引用内容必须默认折叠,并只在 Trace 的初始消息中提供可展开的“最终传入 Codex 的真实完整 prompt”,不得再渲染独立 Prompt 全量卡片;多轮引用注入必须按上游/最早上下文在前、直接引用在后的顺序排列,每一轮必须有明确 `Reference Round N/M` 分割线和时间范围,不能用固定 6 轮截断引用链;点击队列引用按钮必须自动把该任务 ID 写入提交表单的引用输入框,引用任务 ID 创建新任务时必须自动注入 `bun scripts/cli.ts codex task ` 的提示;连续执行同一 prompt 应通过入队份数一次性生成多条任务,避免快速连点造成操作员误判。 - `Code Queue` 前端改进必须在同一任务内重建并上线公网 frontend,不能只修改源码或本地 bundle;重建 frontend 是无状态 WebUI 替换,不会导致 Code Queue 长期任务失败。已结束未读任务只能在 task card 边角显示类似未读消息的 `codex-unread-badge` 圆点和“标为已读”操作,不得把整张卡片改成红色/琥珀色失败态边框、背景或胶囊标签;状态栏的“结束未读”提示也不得使用失败态红色。 - `Code Queue` 前端必须把 PostgreSQL-backed backend API 作为 task、queue、readAt/未读状态和 attempt 状态的唯一数据来源;不得用 `localStorage`、`sessionStorage` 或 IndexedDB 持久化这些业务状态,也不得在后端标记已读失败时伪造本地成功。前端允许保留 React 内存态、请求 in-flight guard 和本轮页面缓存,但刷新页面或切换设备后的状态必须完全由后端 PostgreSQL 数据恢复。 - - `Code Queue` 的 queue/session 左侧边栏必须提供 task 关键词搜索,并采用顶部对齐和内容高度优先布局:搜索栏、列表、分组和 task card 都不得用居中、space-between、stretch 或隐式等高网格去拉满侧栏高度;item 少时允许下半部分留空,不能把单个 item 拉高来铺满;每个 task card 必须显示 `最近更新: ...前` 这类相对更新时间,便于判断运行中的 Trace 是否卡住;`queued` task card 的状态徽标必须显示排队原因,例如 `QUEUED(PREV TASK)`、`QUEUED(MEM LIMIT)`。提交任务时必须立即锁定 prompt、引用 ID、queue、模型、工作目录、最大尝试和入队份数等输入控件,显示等待状态,并用前端 in-flight guard 阻止重复点击造成重复入队;当解析到多个待入队任务时必须显式要求用户勾选批量确认,防止 `---` 分隔或入队份数误操作导致错误传入多个任务。Trace 面板的主滚动条使用全站细窄现代滚动条;工具调用块内部的横向滚动必须可滚动但隐藏横向滚动条,避免移动端阅读被滚动条占用。公共 `TraceView` 的自动滚动必须采用 follow-tail 语义:只有当前滚动位置在底部附近时才跟随新增输出;用户手动向上滚动后立即暂停自动滚动,异步刷新不得把视图拉回底部,直到用户再次滚动到最底部才恢复自动跟随。 + - `Code Queue` 前后端通信必须采用渐进式披露:首屏只请求 queue/task 轻量摘要、必要的 selected preview 和小体积统计,不得默认拉取完整 transcript、raw output、原始 JSON 或全部历史任务;加载下一页或搜索分页时必须显式传递 `selected=0`、`includeActive=0`、`stats=0` 等价开关,避免每一页重复请求 selected/active/stats;点击/选中 task 后再按需加载 summary、prompt part、trace step、raw output 或完整 Trace。`read`/`mark all read` 应调用专用 mutation 并用后端返回的 patch 更新当前内存态,不能为了隐藏未读圆点而强制刷新完整 overview;请求仍需遵守 PostgreSQL 权威源,失败时不得本地伪造已读。Code Queue 性能问题应优先通过缩小 API 响应、分页/cursor、去重 in-flight 请求、短 TTL 且 mutation 失效的页面缓存和后端 SQL 聚合解决,避免以重写渲染层或把大 JSON 藏在 DOM/React state 中规避慢请求。 + - `Code Queue` 的 queue/session 左侧边栏必须提供 task 关键词搜索,并采用顶部对齐和内容高度优先布局:搜索栏、列表、分组和 task card 都不得用居中、space-between、stretch 或隐式等高网格去拉满侧栏高度;item 少时允许下半部分留空,不能把单个 item 拉高来铺满;每个 task card 必须显示 `最近更新: ...前` 这类相对更新时间,便于判断运行中的 Trace 是否卡住;`queued` task card 的状态徽标必须显示排队原因,例如 `QUEUED(PREV TASK)`、`QUEUED(MEM LIMIT)`。SSE/事件驱动刷新只能更新队列列表与当前选中任务的详情,不得因为其他任务产生 `task-step` 或 `task-updated` 而自动切换当前选中的 task;只有用户点击任务、提交新任务或显式切换 queue 才能改变选中任务。提交任务时必须立即锁定 prompt、引用 ID、queue、模型、工作目录、最大尝试和入队份数等输入控件,显示等待状态,并用前端 in-flight guard 阻止重复点击造成重复入队;当解析到多个待入队任务时必须显式要求用户勾选批量确认,防止 `---` 分隔或入队份数误操作导致错误传入多个任务。Trace 面板的主滚动条使用全站细窄现代滚动条;工具调用块内部的横向滚动必须可滚动但隐藏横向滚动条,避免移动端阅读被滚动条占用。公共 `TraceView` 的自动滚动必须采用 follow-tail 语义:只有当前滚动位置在底部附近时才跟随新增输出;用户手动向上滚动后立即暂停自动滚动,异步刷新不得把视图拉回底部,直到用户再次滚动到最底部才恢复自动跟随。 - 用户服务页面不得 iframe 业务旧前端、Todo Note 原 Vite 前端或 Pipeline 自身 WebUI,不得把用户服务后端端口暴露为浏览器直连 URL,也不得把业务 API 的 JSON 裸铺在页面上。 - `Pipeline` 子标签是 D601 `/home/ubuntu/pipeline` 的 UniDesk host UI。 - Pipeline 仓库自带 WebUI 前端已经废弃;UniDesk frontend 是唯一用户可见的 Pipeline UI。 diff --git a/docs/reference/microservices.md b/docs/reference/microservices.md index a9a87d32..9e6436db 100644 --- a/docs/reference/microservices.md +++ b/docs/reference/microservices.md @@ -22,6 +22,18 @@ UniDesk 用户服务是挂载到 UniDesk 核心服务上的、面向用户使用 - `development.providerId`、`development.sshPassthrough=true` 和 `development.worktreePath`,用于说明开发调试入口必须在计算节点上通过 UniDesk SSH 透传完成。 - `frontend.route` 和 `frontend.integrated=true`,用于说明该业务前端已经整合到 UniDesk React 控制台,而不是继续公开业务自身前端。 +## Runtime Configuration And Persistence Contract + +每个长期运行的用户服务都必须把“登记配置、容器恢复、状态持久化、真实 health”作为同一交付项处理,不能只把容器拉起后登记到 `config.json`: + +- 配置来源:`config.json` 只登记 UniDesk 代理与前端入口,业务运行配置必须保存在目标节点的业务仓库、`.state/`、Docker env-file、Windows 用户目录或主 PostgreSQL 中;不得把 token、登录态、运行日志或节点私钥提交到 UniDesk 仓库。 +- 容器恢复:长驻业务后端必须使用业务仓库自己的 Compose 或显式 `docker run` 固化容器名、镜像、端口、环境变量、healthcheck、`restart` policy 和持久化挂载;`repository.composeService`、`repository.containerName` 与实际 Docker 容器必须一致,便于 `microservice list/status`、Docker 状态页和自动恢复脚本互相校验。 +- 重启策略:provider-gateway 必须使用 `restart: always`;普通用户服务至少使用 `restart: unless-stopped`,如果服务是节点核心依赖或无人值守入口,可以提升为 `always`,但必须说明手动停止后的恢复语义。仅靠 restart policy 只能覆盖 Docker daemon 已重新启动后的容器恢复,不能替代 Windows 登录任务、systemd、Docker Desktop 自启动或 WSL keepalive。 +- 持久化边界:任务、队列、账号会话、订阅、token、未读状态和业务数据不得只存在容器 writable layer 或浏览器本地存储;应写入主 PostgreSQL、业务数据库、Docker named volume 或节点 host bind mount。`.state/` 默认只能放可重建缓存、日志、归档和服务自有小状态;如果某服务把 `.state/` 作为权威状态目录,必须在本节或服务小节明确字段、备份和重启恢复方式。 +- 自恢复入口:计算节点上的服务应有节点本地的幂等 autorecover 脚本,在 Docker ready 后用 `docker inspect`、退出码和业务 HTTP readiness 判断是否需要 `docker compose -f up -d --force-recreate `;该脚本必须从节点本地计划任务、systemd、Docker Desktop 自启动后的 WSL keepalive 或等价守护触发,不依赖正在被恢复的 UniDesk provider-gateway SSH 会话。 +- 真实 health:`/health` 必须证明业务“可用”而不是“进程存在”。需要登录、外部连接、GPU、镜像、数据库或后台 worker 的服务,必须在 health body 中暴露这些依赖状态;依赖未满足时必须返回非 healthy 或 `ok=false`,不能让 `/ops/status/` 把不可发消息、不可训练或不可访问的服务计为可用。 +- 验收记录:新增或迁移用户服务时,交付说明必须记录 Compose/docker run 路径、restart policy、端口绑定、持久化挂载、关键环境变量来源、health readiness 字段、容器重启或 Docker daemon 重启后的恢复验证,以及公网 UniDesk frontend 或 `microservice health/proxy` 的真实链路结果。 + ## Compute-Node Development Convention 主 server 本地开发边界固定为只开发 UniDesk frontend 与必要的 UniDesk 配置/代理登记;非 UniDesk 核心功能的后端、Dockerfile、GPU/训练容器、业务数据迁移和业务调试不得默认占用主 server 有限主机资源。涉及 findjob、pipeline、MET Nonlinear 这类业务功能时,应通过 `bun scripts/cli.ts ssh ...` 或 remote CLI SSH 透传进入计算节点,在计算节点本地业务仓库中开发、构建和调试;开发完成后,只把业务服务以用户服务形式登记到 UniDesk。 @@ -106,15 +118,19 @@ Baidu Netdisk 在 UniDesk 语境中按纯后端服务管理:不得暴露百度 - 更名与灾备恢复:旧版 Codex 队列服务名只允许作为兼容诊断和一次性迁移来源;`code-queue-backend` 容器自身 `/health` 正常但 `microservice health code-queue` 返回 `microservice not found`、或服务目录仍只出现旧服务 ID 时,优先判定为 backend-core 仍加载旧 `MICROSERVICES_JSON`,必须刷新 `.state/docker-compose.env` 并显式重建/重建替换 `backend-core`,随后用 `microservice list` 验证 `id=code-queue`、`nodeBaseUrl=http://code-queue:4222` 和容器摘要。若更名后 `unidesk_code_queue_*` 为空而历史 `unidesk_codex_queue_*` 表仍有队列数据,恢复前必须先停止 `code-queue-backend`,备份 `.state/code-queue` 与当前 `unidesk_code_queue_*` 表,再把历史本地状态目录合并到 `.state/code-queue/`,并用 `docker exec -i unidesk-database psql ...` 这类保持 stdin 的方式把 `unidesk_codex_queue_tasks`、`unidesk_codex_queue_queues` 和 `unidesk_codex_queue_notifications` 迁移到对应 `unidesk_code_queue_*` 表;不得在确认 `/api/tasks`、`/api/queues` 和 output archive 可读前删除历史本地状态目录或旧 PostgreSQL 表。迁移完成后只允许用 `docker compose --env-file .state/docker-compose.env up -d --no-deps code-queue` 或 `server rebuild code-queue` 启动目标服务,禁止在灾备窗口里无意执行会连带重建 database/backend-core 的裸 `up -d code-queue`。 - Codex 认证:容器只从主 server 的 `/root/.codex/config.toml` 同步 Codex provider 配置到 `.state/code-queue/codex-home`,并通过运行时环境透传 `OPENAI_API_KEY`、`CRS_OAI_KEY` 等 provider 所需变量;这些 provider 环境变量必须由 `writeComposeEnv` 写入 `.state/docker-compose.env` 并由 Compose 注入,确保 `server rebuild code-queue` 的外部 Docker job runner、自重建和容器重启后不会丢失认证。新增 provider 的 `env_key` 时必须增加同类运行时透传和 Compose env 持久化,禁止把 Codex 或 MiniMax 密钥写入仓库文件。Code Queue 开发容器必须只读挂载 host 的 root SSH 目录到 `/root/.ssh`(默认 `${UNIDESK_HOST_ROOT_SSH_DIR:-/root/.ssh}`),让容器内 `git push`、`ssh -T git@github.com` 与 host 使用同一套 GitHub SSH key/known_hosts;不得把私钥复制进镜像或仓库。 - Develop-ready 镜像:Code Queue 镜像必须在启动前预装 UniDesk/Pipeline 调试所需工具,至少包含 `codex`、`bun`、`node`、`npm`/`npx`、`git`、`rg`、`curl`、`python3`/`pip3`、`docker`、`docker compose`、`docker-compose`、`jq`、`ssh`、`rsync`、`make`、`gcc`/`g++`、`tar`、`gzip` 和 `unzip`;不得依赖 Codex 任务运行时再 `apt-get install` 这些基础环境。 -- 远程开发容器与任务执行 Provider:Code Queue 必须能通过 live API 拉起 D601 等计算节点上的开发容器,入口为 `POST /api/dev-containers//start`,默认 Provider 为 `D601`。该流程由 Code Queue 调用 UniDesk `ssh ` 维护桥在目标节点创建 `unidesk-codex-dev-`,并在主 server 与开发容器之间建立 `ssh -w` TUN 点对点链路;主 server 负责对开发容器的 TUN 源地址做 NAT/MASQUERADE,开发容器默认路由和 DNS 改走该 TUN,从而让 `ping google.com`、DNS、HTTP(S) 等出网都经主 server 全局代理,而不是依赖 D601 本地网络。提交 Code Queue 任务时必须支持选择执行 Provider:`main-server` 在本机 Code Queue 容器中执行且默认工作目录保持 `/root/unidesk`;其他 Provider 在对应 `unidesk-codex-dev-` 容器中执行,默认工作目录为 `/home/ubuntu`,可按任务覆盖 `cwd`。远程任务启动前必须自动复用或拉起该 Provider 的开发容器、同步 Codex 配置和允许的运行时 provider 环境变量,并通过同一 master TUN/NAT 链路出网。验收必须保留三类日志:容器直连 `google.com` 在建隧道前失败、容器建隧道后 `ping google.com` 成功、主 server 上对应 `UNIDESK-CODEX-DEV-` NAT 链或 `tun` 计数在 ping 前后增长。开发容器代理密钥只生成到 `.state/code-queue/dev-proxy/` 与目标节点用户目录,不得提交到仓库。 +- 远程开发容器与任务执行 Provider:Code Queue 必须能通过 live API 拉起 D601 等计算节点上的开发容器,入口为 `POST /api/dev-containers//start`,默认 Provider 为 `D601`。该流程由 Code Queue 调用 UniDesk `ssh ` 维护桥在目标节点创建 `unidesk-codex-dev-`,并在主 server 与开发容器之间建立 `ssh -w` TUN 点对点链路;主 server 负责对开发容器的 TUN 源地址做 NAT/MASQUERADE,开发容器默认路由和 DNS 改走该 TUN,从而让 `ping google.com`、DNS、HTTP(S) 等出网都经主 server 全局代理,而不是依赖 D601 本地网络。提交 Code Queue 任务时必须支持选择执行 Provider:`main-server` 在本机 Code Queue 容器中执行且默认工作目录保持 `/root/unidesk`;其他 Provider 在对应 `unidesk-codex-dev-` 容器中执行,默认工作目录为 `/home/ubuntu`,可按任务覆盖 `cwd`。远程任务启动前必须自动复用或拉起该 Provider 的开发容器、同步 Codex 配置和允许的运行时 provider 环境变量,并通过同一 master TUN/NAT 链路出网;目标 host 存在 `/mnt` 时,开发容器必须挂载 host `/mnt:/mnt`,确保 D601 这类 WSL 节点的 Windows 盘符路径如 `/mnt/f/Work/ConStart` 在任务容器内可见,避免 agent 因缺少真实工作区而搜索到无关项目。TUN 建立必须幂等处理 stale 状态:启动前清理旧 `tun`、默认路由和旧 tunnel SSH 进程,缺失旧设备不能导致失败,冷启动运行时准备要有有界但足够的 timeout。验收必须保留三类日志:容器直连 `google.com` 在建隧道前失败、容器建隧道后 `ping google.com` 成功、主 server 上对应 `UNIDESK-CODEX-DEV-` NAT 链或 `tun` 计数在 ping 前后增长;涉及 WSL 工作区任务时还必须在开发容器内验证目标 `/mnt/...` 路径可读。开发容器代理密钥只生成到 `.state/code-queue/dev-proxy/` 与目标节点用户目录,不得提交到仓库。 +- 远程 Provider 准备不得阻塞控制面:Code Queue 在请求处理、队列调度、远程开发容器准备、Host SSH/WSL SSH 透传、Codex/OpenCode 启动和日志导出路径中,禁止使用会长时间占用 Bun event loop 的同步子进程调用,例如针对远程 Provider 的 `spawnSync`、`execSync` 或 `execFileSync`。远程命令必须通过异步子进程执行,带显式 timeout、超时 kill、stdout/stderr 上限和任务 output 进度记录;远程准备失败只能让对应任务进入失败或 retry,不能让 `POST /api/tasks`、SSE `/api/events`、`/health`、overview 或前端 direct proxy 等控制面请求等待远程 SSH 结束。凡是改动 D601/远程 Provider 准备、`api/dev-containers/*`、任务入队启动或 `runCodeQueueSsh` 等路径,验收必须在一个远程 SSH/status/start 探针运行期间并发验证容器直连 `/health` 和 `/api/tasks/overview` 仍能在 1s 内返回,证明远程超时不会复发为全站刷新卡死。 +- OpenCode 远程执行:`minimax-m2.7` 走 OpenCode JSON event port 时,本地和远程命令都必须显式执行 `opencode run ...`;远程 Docker exec 不得退化成 `exec run ...`,否则会在目标容器内变成 `bash: exec: run: not found`。OpenCode JSON stream 的终态判定以“当前进程退出码 + 当前 attempt 的最终 assistant response”为准:`exit=0` 且当前 attempt 产生非空最终回复时,即使上游没有发 `step_finish` 事件,也应视为正常 terminal;非零退出、无当前最终回复或传输关闭才进入 retry。每个 attempt 的 `finalResponse` 必须只来自当前 OpenCode/Codex turn,禁止在当前 turn 未产出最终回复时回退复用 task 上一次 `finalResponse`,否则会把旧任务内容误判为本轮完成。 - Codex 控制:服务内部启动 `codex app-server --listen stdio://`,用 JSON-RPC 调用 `thread/start`、`turn/start`、`turn/steer` 和 `turn/interrupt`,并监听 `turn/completed`、assistant delta、reasoning delta、command output delta、file diff delta 等通知生成前端可轮询的 transcript。 - 用户输入持久化:任务初始 prompt 以 `basePrompt/displayPrompt` 作为结构化来源,运行中追加的 `turn/steer` prompt 必须写入 `promptHistory`;transcript 构建时从这些结构化字段合成 `Submitted prompt` 和 `Steer prompt`,不能只依赖有 600 条上限的 raw output,否则长任务输出增长后会丢失关键人工指令。 - 队列语义:`POST /api/tasks` 或 `/api/tasks/batch` 入队,服务始终只运行一个 Codex turn;当前任务真正终止后才推进下一个任务。`GET /api/tasks` 与 `GET /api/tasks/{id}` 返回队列、attempt、judge 和输出;`GET /api/tasks/{id}/summary` 返回按任务 ID 查询的结构化摘要,包括初始 prompt、最后 assistant message、工具调用摘要、attempt、judge、错误和耗时;CLI 入口是 `bun scripts/cli.ts codex task `。`POST /api/tasks/{id}/steer` 向运行中 turn 推入 prompt;`POST /api/tasks/{id}/interrupt` 或 `DELETE /api/tasks/{id}` 打断/取消;`POST /api/tasks/{id}/retry` 手动重试。队列 worker 必须隔离单个 task 的异常,不能因为某个 app-server、judge 异常或 judge 判定 `fail` 让后续 queued 任务停止;`fail` 只把当前任务标为 failed,随后必须继续扫描并推进下一个 queued/retry_wait 任务。当存在 queued/retry_wait 且 worker 空闲时,watchdog 必须自动重新调度。 - 稳定性与重启恢复:Code Queue 的第一目标是长期稳定可用;部署修复或运维排障时不得因为担心容器重启会打断任务而拒绝重启、重建或替换 `code-queue-backend`。容器重启、服务进程重启和镜像替换后,队列、`promptHistory`、running/judging/retry_wait 任务和 active session 元数据必须从 PostgreSQL 恢复,并在已有 `codexThreadId` 可用时用 `thread/resume` 和 continuation prompt 无缝继续当前任务;如果原 app-server turn 已丢失,也必须把当前任务恢复到可 retry/continue 的状态,不能错误推进下一个任务或永久卡住。主 server 侧重建必须走 `server rebuild code-queue`,该 job 受 `.state/locks/server-compose.lock` 串行化约束,并且必须在 build 后执行 no-deps force-recreate 与 post-up health validation;禁止在 job 中先手工 `docker rm` 再依赖后续命令补救,因为中断窗口会让容器消失并触发 frontend `direct microservice proxy failed`。重启后出现 active task 丢失、手动 steer/interrupt 记录丢失、running 任务卡死、误判完成、跳过当前任务、容器消失或阻塞队列,均属于 Code Queue 的 P0 核心缺陷,必须先修复并补充 restart-recovery 验收,不能把“避免重启”作为交付策略。 - 调度与 active run slot:Code Queue 必须把“queue processor 正在等待/退避/轮询”和“实际占用 Codex/OpenCode 子进程运行槽”分开建模;`CODE_QUEUE_MAX_ACTIVE_QUEUES` 只限制真实 active run slot,不能把 retry backoff、等待内存下降或等待前序任务的 `processingQueues` 计入 active slot,否则设置全局 active slot 上限时,一个空等队列会把其他 runnable queue 永久饿死。多个 queue 同时等待 active slot 时必须显式维护 FIFO waiter 队列,避免某个长 retry/backoff 队列刚释放 slot 就立刻重抢,导致更早进入等待的 `retry_wait` 任务长期饥饿;`/health` 必须同时暴露真实 `activeQueueIds`、`activeRunSlotCount`、等待中的 `processingQueueIds` 和 active slot waiters,排障时以 active run slot 与 waiter 顺序判断是否真的有任务在跑、谁应下一个启动。restart-recovery 后的 `retry_wait` 任务若缺失 `codexThreadId`/OpenCode session id,不得无限拒绝 retry;必须用紧凑 recovery prompt 和原始任务摘要重新开一个 agent thread/session,让任务继续推进并在 Trace 中留下 recovery 证据。任何修改 scheduler、retry backoff、queue move、manual retry、shutdown recovery 或内存等待逻辑时,都必须保留“空等 processor 不占 active run slot”、“等待者 FIFO 不饥饿”和“缺失 thread/session 可恢复”的自测或 live 验证。 - 内存优化过程与防回归:主 server 内存预算很小,Code Queue 的内存治理必须按“PostgreSQL 权威源优先、进程热状态最小化、容器硬上限兜底”的顺序设计。长期可复用的优化路径是:先确认任务、queue、readAt、promptHistory、active session 和通知 outbox 均可从 PostgreSQL 恢复;再把历史任务列表、详情、统计、Trace/output 和 `/health` 的只读查询改为 PostgreSQL 直读或聚合查询;随后只把 `queued`、`running`、`judging`、`retry_wait` 等调度必需任务载入 Bun 堆,并在 PostgreSQL 查询侧裁剪 hot `output`/`events`;最后用 dirty-only flush、append-only 输出归档、Codex SQLite 小批量导出、`bun --smol`、`mem_limit=600m`、`memswap_limit=1536m`、`NODE_OPTIONS=--max-old-space-size=768` 和 cgroup memory watchdog 作为运行时防线。PostgreSQL 到进程的单次读取足够快,不能为了减少 SQL 查询把全部历史 `task_json`、Trace、output 或统计摘要常驻内存;任何新增缓存都必须有默认较小的环境变量上限、明确淘汰策略、可从 PostgreSQL 或 append-only 归档重建,且不得影响重启恢复。新增或修改 `/api/tasks`、overview、stats、summary、transcript、output、trace、health、flush、scheduler 和通知路径时,禁止在常规请求中调用会物化全量历史任务 JSON 的代码,禁止启动后无条件重写全量历史 task JSON,禁止用未设上限的 `Map`/数组保存历史 output/event/Trace,`CODE_QUEUE_MAX_ACTIVE_QUEUES=0` 表示不按 queue 数量设置全局排队上限;如显式设置为正数,必须同时说明内存预算并补充内存压测验收。memory watchdog 必须以 cgroup working set 为主要判断,且在 swap 仍有余量时不得提前杀掉唯一 active run;否则 TypeScript/Playwright 这类短时高内存验证会被错误中断并让 retry 队列反复震荡。 -- 完成判定:app-server `turn/completed` 的 `turn.status=completed|interrupted|failed` 只代表 Codex turn 已结束;即使 `completed` 也必须把原始任务、assistant 最终回复、command/file-change 事件、stderr tail 和 current attempt events 组成 execution record 交给 judge 判断是否真的完成。配置了 `UNIDESK_CODE_QUEUE_MINIMAX_API_KEY` 且 MiniMax 可用时,MiniMax `MiniMax-M2.7` 对 `complete|retry|fail` 的判定是权威结果;当且仅当 MiniMax LLM 调用失效(未配置、额度/限流/网络/超时不可用、JSON 去噪与 repair 全部耗尽、或返回超预算反馈且修复耗尽)时,才允许启用非 LLM/fallback 判断。任何字符串匹配、正则、硬编码 safety override、`hardCompletionBlockers`/`retryRequiredReasons`、`recentOutput` 中旧 attempt 的 429/exceeded retry limit 证据、或面向特定任务的保护逻辑,都不得覆盖、降级、提升或重写一次成功的 MiniMax 判定;尤其不能因为 attempt 1 的限流中断仍在历史输出里,就禁止 MiniMax 把 attempt 2 的正常完成判为 `complete`。MiniMax 返回必须先做 JSON 去噪,支持去除 Markdown fence、`json` 标签和从夹杂文本中提取平衡 JSON object;如果去噪后仍无法解析,服务必须把解析错误和上一轮去噪前原始回答反馈给 MiniMax 做 JSON repair 重试,重试次数由 `UNIDESK_CODE_QUEUE_MINIMAX_JUDGE_REPAIR_ATTEMPTS` 控制,默认 `2`,耗尽后才进入 fallback,并在 fallback 原因中保留 MiniMax 失败信息。 -- Judge 权威边界:MiniMax 成功返回可解析、预算内的 judge JSON 后,Code Queue 必须直接采用该 `decision/reason/continuePrompt`,不得再执行本地 post-validation、协议级完成门禁或 safety override;`hardCompletionBlockers`、`retryRequiredReasons` 这类本地门禁字段不得出现在发送给 MiniMax 的 `executionRecord` 中。只有 MiniMax 不可用或修复耗尽进入 fallback 时,才允许基于字符串/正则做保守 retry。 +- 列表/详情延迟优化原则:Code Queue 控制面交互的长期目标是常规历史规模下首屏、`GET /api/tasks/overview`、`POST /api/tasks//read` 和分页加载均在 1s 内完成;性能面板出现十几秒级 `code_queue_direct_proxy` 或 `core_proxy` 慢操作时,必须优先按后端查询形态和前后端通信策略定位,不能把问题归因于 React 渲染后只改 UI。后端优化顺序是:先为 queue、status、updated/created 时间、readAt/terminal unread 和常用筛选条件补齐 PostgreSQL 索引;再用 SQL `COUNT`、`GROUP BY`、条件聚合和分页 ID 查询生成 queue/status/stats/unread 摘要;随后按 ID 轻量加载当前页、selected、active 和 unread priority task,禁止为了列表或已读操作解析完整 Trace、output archive、Codex transcript 或物化全量历史 `task_json`。`read`/`read-all` 这类 mutation 必须是 SQL-only 更新并返回最小 patch/queue 计数,不能触发 overview 全量重算或重载所有任务;启动 warm 只能预热小体积聚合和索引路径,不得把历史任务作为常驻缓存。允许 frontend/backend 代理使用秒级、严格有界、mutation 自动失效的 overview micro-cache 来吸收重复刷新,但 cache 只能作为抖动保护,不能替代数据库索引、聚合查询和分页披露,也不能让 stale readAt/queue/status 状态跨设备可见。 +- Trace/实时输出热路径防回归:Code Queue 的 `appendOutput`、output archive append、`publishTaskEvent`、SSE `/api/events`、任务列表、overview、task meta 和 `/health` 都属于热路径,必须保持 O(1) 或明确小常数上界;这些路径不得同步调用完整 transcript 构建器、`taskFullOutput`、output archive 全量读取、Codex session/log 文件解析、完整 `task_json` 物化或任何会随历史输出长度增长的统计。输出追加时必须增量维护轻量持久化指标,至少包括 `stepCount`、`llmStepCount`、`outputMaxSeq` 或等价字段;列表、overview、meta、SSE 事件和 `/health` 只能读取这些指标或小体积 SQL 聚合。完整 Trace、`trace-summary`、`trace-steps`、`trace-step`、transcript/output 详情允许在显式详情请求中解析归档,但必须分页或有界、使用短 TTL 或容量受限缓存,并在 archive append 后失效。若 frontend 性能面板出现 Code Queue direct proxy 502、`/api/tasks/overview`/trace 接口成批超时,或容器内 `/health` 在 active output 持续追加时也卡住,优先按 Bun event-loop starvation/backpressure 排查,而不是先改 React 渲染;修复必须证明热路径不再随 output/archive 历史线性增长。 +- 完成判定:app-server `turn/completed` 的 `turn.status=completed|interrupted|failed` 只代表 Codex turn 已结束;即使 `completed` 也必须把原始任务、当前 attempt 的 assistant 最终回复、command/file-change 事件、stderr tail 和 current attempt events 组成 execution record 交给 judge 判断是否真的完成。MiniMax judge 之前和之后都必须保留少量协议级硬门禁:明确用户 interrupt 判为 fail;当前 attempt `terminalStatus=failed|null`、传输在终态前关闭、或当前 attempt 最终回复为空时判为 retry;这些门禁只保护“本轮 turn 是否可被验收”的事实,不得发明业务实现要求。协议门禁通过后,配置了 `UNIDESK_CODE_QUEUE_MINIMAX_API_KEY` 且 MiniMax 可用时,MiniMax `MiniMax-M2.7` 对业务是否 `complete|retry|fail` 的判定是权威结果;当且仅当 MiniMax LLM 调用失效(未配置、额度/限流/网络/超时不可用、JSON 去噪与 repair 全部耗尽、或返回超预算反馈且修复耗尽)时,才允许启用非 LLM/fallback 判断。MiniMax 返回必须先做 JSON 去噪,支持去除 Markdown fence、`json` 标签和从夹杂文本中提取平衡 JSON object;如果去噪后仍无法解析,服务必须把解析错误和上一轮去噪前原始回答反馈给 MiniMax 做 JSON repair 重试,重试次数由 `UNIDESK_CODE_QUEUE_MINIMAX_JUDGE_REPAIR_ATTEMPTS` 控制,默认 `2`,耗尽后才进入 fallback,并在 fallback 原因中保留 MiniMax 失败信息。 +- Judge 权威边界:MiniMax 成功返回可解析、预算内的 judge JSON 后,Code Queue 不得用旧 attempt 的 429/exceeded retry limit 证据、历史 output 字符串、面向特定任务的正则或 `hardCompletionBlockers`/`retryRequiredReasons` 覆盖一次协议有效的完成判定;尤其不能因为 attempt 1 的限流中断仍在历史输出里,就禁止 MiniMax 把 attempt 2 的正常完成判为 `complete`。允许的本地 safety override 必须限定为协议事实和系统交付纪律:用户显式打断、当前 attempt 未正常终止、当前 attempt 没有最终 assistant response、最终回复停在并发文件确认而非交付、或 runtime/UI/service 变更承认未部署验证。所有 override 都必须写入 `_safetyOverride`、生成紧凑 continuation prompt,并由自测或 judge probe 覆盖;不得把业务猜测伪装成本地硬门禁。 - Retry/推进语义:`retry` 不是新开一个独立任务或完全新 session;只要已有 `codexThreadId`,服务必须 `thread/resume` 原 thread 并 append 一个继续执行 prompt。continuation/judge feedback prompt 只应携带本轮缺口、恢复原因、验收要求和有界原始任务摘要,禁止重新注入完整引用上下文、历史 transcript 或长 JSON;服务重启恢复类 feedback 尤其必须保持短 prompt,依赖现有 thread 上文继续。超长 prompt 必须在 prompt 合成源头解决:每个 feedback/recovery/judge 生成器都要从结构化字段选择必要信息、去重合并缺口并提供按需查询入口,禁止先合成超长 prompt 再在末端用 substring/safePreview 一刀切硬截断;硬截断会静默丢失验收信息,风险高于长 prompt 本身。若 MiniMax `continuePrompt` 超出预算,必须要求 MiniMax 基于原始 judge 输入重新合成紧凑反馈,repair 耗尽后才可进入 fallback;不得把已生成的长 prompt 截尾后发送给 Codex。若 MiniMax 成功返回了预算内 `continuePrompt`,必须原样使用该反馈,不得再用 71-Freq、`period_sum/mpu_read_num`、`mpu_read_num`、历史限流中断等字符串识别把它覆盖成“简洁原始需求 continuation”。只有 judge 判定 `complete` 后,队列 worker 才把当前任务标为成功并推进下一个 queued/retry_wait 任务。非 LLM/fallback 判定产生的 `retry` 最多累计 `3` 次;达到上限后当前任务必须转为 `failed` 并记录原因,worker 继续推进后续 queued/retry_wait 任务,避免 fallback safety override 或硬编码判断造成无限循环。 - Judge 探针:`GET|POST /api/judge/probe` 使用同一套 judge 逻辑跑内置 synthetic execution records,覆盖正常完成、正常结束但只给计划、未上线/未部署的服务或 WebUI 改动、传输中断和用户打断等样本,返回 `hits`、`total`、`hitRate`、每例 `expected` 与 `decision`;该接口不得回显 MiniMax API key。 - 模型选择:默认 Codex 模型是 `gpt-5.5`,内置模型队列包含 `gpt-5.5`、`gpt-5.4-mini`、`gpt-5.4`;`gpt-5.5` 的默认 reasoning effort 必须是 `xhigh`,可通过 `CODE_QUEUE_MODEL_REASONING_EFFORTS` 追加或覆盖模型级默认值;每个入队任务可通过前端模型下拉菜单或 API 覆盖 `model`、`cwd`、`reasoningEffort` 和 `maxAttempts`,`maxAttempts` 上限为 `99`。Judge 判定 `retry` 或非用户取消类 `fail` 时必须继续已有 `codexThreadId`,不能新建 session;重试间隔使用指数退避,从 `1s` 开始,最大 `10min`。MiniMax 不可用而进入 fallback/non-LLM 判定时,当前 attempt 的 429、Too Many Requests、exceeded retry limit、overloaded、stream disconnected 等服务/限流错误应判定为 `retry`,不能当作完成;MiniMax 可用时,这些内容只能作为当前 attempt 的 factual evidence 提供给 MiniMax,不能通过硬编码覆盖 MiniMax 结果。 @@ -132,6 +148,16 @@ Baidu Netdisk 在 UniDesk 语境中按纯后端服务管理:不得暴露百度 - `met-nonlinear`:MET Nonlinear 训练编排服务,UniDesk frontend 渲染 GPU/镜像、训练队列、Project config 预览、训练进度、ETA 和历史记录。 - `claudeqq`:ClaudeQQ 纯后端 QQ 消息网关,UniDesk frontend 渲染 NapCat 连接、事件订阅、消息推送、最近 QQ 事件和发送记录。 +### D601 Docker Restart Recovery + +D601 是 Windows + WSL Ubuntu + Docker Desktop 节点,Docker Desktop 当前 `LiveRestore=false` 时,机器或 Docker daemon 重启会停止容器,恢复链路必须同时覆盖 Windows 登录、WSL keepalive、Docker daemon ready、provider-gateway 和业务用户服务: + +- Windows 登录任务:计划任务 `UniDesk-D601-Autostart` 在用户 `DESKTOP-1MHOD9I\liang` 登录时运行 `C:\WINDOWS\System32\cmd.exe /c ""C:\Users\liang\AppData\Local\UniDesk\d601-autostart.cmd""`,工作目录为 `C:\Users\liang\AppData\Local\UniDesk`。 +- Windows launcher:`C:\Users\liang\AppData\Local\UniDesk\d601-autostart.cmd` 先启动 `%ProgramFiles%\Docker\Docker\Docker Desktop.exe`,再执行 `C:\Windows\System32\wsl.exe -d Ubuntu -u ubuntu -- /bin/bash -lc "/home/ubuntu/.local/bin/unidesk-d601-autostart task"`;D601 的 WSL distro 名必须写 `Ubuntu`,不能写成未验证的 `Ubuntu-22.04`。 +- WSL keepalive:`/home/ubuntu/.local/bin/unidesk-d601-autostart` 使用 `~/.state/unidesk/d601-autostart.lock` 防重复,启动 WSL `sshd`,等待 `docker info`,把 `unidesk-provider-gateway-D601` 修正为 `restart always` 并启动,然后调用 `/home/ubuntu/.local/bin/unidesk-microservice-autorecover boot`;进入常驻 watchdog 后每 300 秒重复检查 provider-gateway 和用户服务。 +- 用户服务 autorecover:`/home/ubuntu/.local/bin/unidesk-microservice-autorecover` 只在 Docker ready 后运行;它用容器 `State.Running`、`State.ExitCode` 和轻量 HTTP 探针判断是否需要恢复,MET Nonlinear 失败时在 `/home/ubuntu/met_nonlinear` 执行 `docker compose -f docker-compose.unidesk.yml up -d --force-recreate met-nonlinear-ts`,ClaudeQQ/NapCat 失败时在 `/home/ubuntu/.agents/skills/claudeqq` 执行 `docker compose -f docker-compose.unidesk.yml up -d --force-recreate napcat claudeqq`。 +- 验收命令:Docker 恢复后必须同时验证 `docker inspect --format '{{.HostConfig.RestartPolicy.Name}} {{.State.Status}}' met-nonlinear-ts claudeqq-backend claudeqq-napcat`、`bun scripts/cli.ts microservice health met-nonlinear`、`bun scripts/cli.ts microservice health claudeqq` 和公网 frontend 页面;ClaudeQQ 还必须验证 `/api/napcat/login` 中 `state=logged_in`、HTTP connected 和 WebSocket connected。 + ### FindJob On D601 当前 FindJob 作为 `id=findjob` 的用户服务登记在 `config.json`: @@ -171,6 +197,8 @@ Pipeline 的一个 epoch 是同一个 pipeline 从入口到终态完整执行一 - 数据挂载:D601 的 `/mnt/f/BaiduSyncdisk/data` 挂载为训练容器内 `/data/data`,并设置 `MET_DATA_BASE=/data`,让旧配置中的 `data/M50` 解析为 `/data/data/M50`;WSL 本机不安装 TensorFlow 训练环境。 - 代码引用:`https://github.com/pikasTech/met_nonlinear` 与配置中的 `repository.commitId`。 - 部署引用:业务仓库内 `docker-compose.unidesk.yml`、`docker/unidesk/Dockerfile.server`、`docker/unidesk/Dockerfile.ml`、`composeService=met-nonlinear-ts`、`containerName=met-nonlinear-ts`。 +- 运行配置:`docker-compose.unidesk.yml` 中 `met-nonlinear-ts` 必须固定 `container_name: met-nonlinear-ts`、`restart: unless-stopped`、`127.0.0.1:3288:3288`、`extra_hosts: ["host.docker.internal:host-gateway"]`,并把 `/var/run/docker.sock`、`/usr/lib/wsl/lib:ro` 和 `/dev/dxg` 挂入容器,让 TS 编排后端能按需拉起 GPU 训练容器并读取 WSL GPU runtime。 +- 持久化路径:业务源码与状态通过 `/home/ubuntu/met_nonlinear:/workspace/met_nonlinear` 挂载,训练数据通过 `/mnt/f/BaiduSyncdisk/data:/data` 挂载;`MET_STATE_DIR=/workspace/met_nonlinear/.state/unidesk-met` 保存队列和服务状态,`MET_LOG_DIR=/workspace/met_nonlinear/logs/unidesk-met` 保存服务日志,`MET_HOST_ROOT` 与 `MET_HOST_DATA_ROOT` 必须指向对应 host 路径,避免训练容器从容器内路径误反推 host 文件。 - 节点后端:D601 上 `127.0.0.1:3288`,provider-gateway 容器内通过 `http://host.docker.internal:3288` 访问。 - 代理路径:只允许 `/health` 和 `/api/` 前缀;允许 `GET`、`HEAD`、`POST`、`PUT`,用于读取队列/历史、从已有 Project fork 新 Project、保存队列设置、加入待启动队列和启动队列。 - UniDesk 前端:`用户服务 / MET Nonlinear` React 页面采用类似下载器的工作台交互,负责从项目库选择已有 Project、fork 新 Project、加入待启动队列、启动队列、调整最大并发、分标签展示当前队列/已完成/失败诊断/GPU 与镜像,并展示训练进度、ETA、训练速度 `epoch/h`、历史训练记录和显式原始 JSON 按钮。项目库必须按 `projects/`、`ex_projects/` 的真实目录层级渲染文件树,文件夹计数等于子树 Project 数;项目库和任务列表行都必须可点击打开结构化详情,详情以控件展示 `config.json` 与 `data/` 中的训练状态、模型参数量、模型层和指标,不默认展示裸 JSON。 @@ -187,10 +215,12 @@ MET Nonlinear 验收必须通过公网 UniDesk frontend 的交互式 UI 完成 - 开发工作树:`/home/ubuntu/.agents/skills/claudeqq`,后端、Dockerfile、订阅分发和 NapCat 连接调试必须通过 UniDesk SSH 透传在 D601 完成;主 server 本地只允许开发 UniDesk frontend 与代理登记。 - 代码引用:`https://gitee.com/lyon1998/agent_skills` 与配置中的 `repository.commitId`,实际服务目录为仓库内 `claudeqq/`。 - 部署引用:业务目录内 `Dockerfile` 与 `docker-compose.unidesk.yml`,Compose service 为 `claudeqq` 与 `napcat`,容器名分别为 `claudeqq-backend` 与 `claudeqq-napcat`。 +- 运行配置:`docker-compose.unidesk.yml` 必须同时定义 `napcat` 与 `claudeqq` 两个 service,均使用 `restart: unless-stopped`;`napcat` 固定 `ACCOUNT=${CLAUDEQQ_NAPCAT_ACCOUNT:-763382329}`、`WEBUI_PREFIX=/webui` 和本机端口 `127.0.0.1:3000/3001/6099`,`claudeqq` 固定 `127.0.0.1:3290:3290`、`CLAUDEQQ_AUTO_REPLY=false`、`CLAUDEQQ_NAPCAT_HTTP_HOST=napcat`、`CLAUDEQQ_NAPCAT_WS_HOST=napcat`、`CLAUDEQQ_ONLINE_NOTICE_USER_ID=645275593` 和 `CLAUDEQQ_LOGIN_MONITOR_INTERVAL_MS`。 +- 持久化路径:NapCat 登录态必须保存在业务目录下的 `./napcat/qq:/app/.config/QQ`,NapCat 配置和二维码缓存分别保存在 `./napcat/config:/app/napcat/config` 与 `./napcat/cache:/app/napcat/cache`;ClaudeQQ 后端必须挂载 `./config.json:/app/config.json:ro`、`./bot_workspace:/bot_workspace`、`./logs:/app/logs`、`./.state:/app/.state` 和 `./napcat:/napcat:ro`。如果这些 host 目录丢失或改成匿名 volume,Docker 重启后 QQ 登录态和事件/订阅状态会丢失,不得判定为已具备自动登录。 - 节点后端:D601 上 `127.0.0.1:3290`,provider-gateway 容器内通过 `http://host.docker.internal:3290` 访问。 - 代理路径:只允许 `/health`、`/logs` 和 `/api/` 前缀;允许方法为 `GET`、`HEAD`、`POST`、`DELETE`。 - 服务模式:ClaudeQQ 在 UniDesk 中按纯后端运行,默认 `CLAUDEQQ_AUTO_REPLY=false`,只负责 NapCat HTTP/WS 连接、QQ 事件入站记录、HTTP webhook 订阅投递和 `/api/push/text` 消息推送,不把 ClaudeQQ 自身旧 WebUI 作为用户入口。NapCat 必须随同 `docker-compose.unidesk.yml` 容器化部署,D601 只绑定 `127.0.0.1:3000`、`127.0.0.1:3001` 和 `127.0.0.1:6099`,ClaudeQQ 容器通过 Compose 内网 `napcat:3000/3001` 访问。 -- NapCat 登录 API:`GET /api/napcat/login` 和 `GET /api/napcat/status` 返回容器化状态、HTTP/WS 连通性、登录状态和二维码 data URL;`GET /api/napcat/qrcode` 只返回二维码。二维码来源为共享挂载中的 `/napcat/cache/qrcode.png`,由 ClaudeQQ 后端转为 JSON data URL 后经 UniDesk 同源代理给前端展示。 +- NapCat 登录 API:`GET /api/napcat/login` 和 `GET /api/napcat/status` 返回容器化状态、HTTP/WS 连通性、登录状态和二维码 data URL;`GET /api/napcat/qrcode` 只返回二维码。二维码来源为共享挂载中的 `/napcat/cache/qrcode.png`,由 ClaudeQQ 后端转为 JSON data URL 后经 UniDesk 同源代理给前端展示。`/health` 的 healthy 条件必须包含 `ready=true`、NapCat HTTP connected、NapCat WebSocket connected 和 `loginState=logged_in`;仅有二维码、NapCat 容器 running 或后端进程 running 不能算健康。 - 订阅 API:`GET /api/events/recent` 返回最近 QQ 事件,`GET|POST /api/events/subscriptions` 管理 webhook 订阅,`DELETE /api/events/subscriptions/{id}` 删除订阅;订阅回调使用 HTTP POST JSON,并在配置 secret 时携带 `x-claudeqq-signature` HMAC-SHA256。 - 推送 API:`POST /api/push/text` 接受 `userId` 或 `groupId` 与 `message`,由 ClaudeQQ 通过 NapCat HTTP API 发送 QQ 消息;NapCat 不可用时必须快速返回 `status=napcat_offline` 和具体连接错误;当前人工推送验收只允许发给主用户私聊账号 `645275593`,其他用户服务和 main server 应通过 UniDesk 用户服务代理调用,不得直连 D601 公网端口。 - UniDesk 前端:`用户服务 / ClaudeQQ` React 页面负责展示 D601 仓库引用、私有后端映射、NapCat 容器登录二维码、NapCat HTTP/WS 状态、事件缓存、订阅表、订阅创建表单、消息推送表单、主用户私聊账号 `645275593` 标记、最近 QQ 事件和已发送记录;完整原始 JSON 只能通过显式 `查看原始JSON` 打开。 @@ -240,6 +270,7 @@ ClaudeQQ 在 UniDesk 语境中按消息网关后端服务管理:不得直接 - 运行 `bun scripts/cli.ts microservice health todo-note` 与 `bun scripts/cli.ts microservice proxy todo-note /api/instances`,确认真实链路经过 backend-core、WebSocket、main-server provider-gateway 和主 server `todo-note-backend` 后端;输出中必须包含五个迁移清单和 PostgreSQL 存储健康状态。 - 运行 `bun scripts/cli.ts microservice health code-queue` 与 `bun scripts/cli.ts microservice proxy code-queue /api/tasks`,确认真实链路经过 backend-core、WebSocket、main-server provider-gateway 和主 server `code-queue-backend` 后端,并且 `/health` 的 `queue.storage.primary=postgres`、`queue.storage.postgresReady=true`,不得出现 file fallback;`queue.notifications.claudeqq.outbox.storage=postgres` 且暴露 pending/failed/sent 统计。再通过公网 frontend 提交一个 `gpt-5.5` 小任务,确认队列串行推进、输出实时更新、结束后有 judge 判定,且运行中可追加 prompt 或打断。Code Queue 的重启恢复必须作为验收项:运行中任务存在时重启或重建 `code-queue-backend` 后,任务必须从 PostgreSQL 恢复到可继续执行状态,不能丢失 active task、`promptHistory`、后续 queued 任务、readAt/未读状态或已入 outbox 的 ClaudeQQ 通知;ClaudeQQ/NapCat 离线期间结束的任务必须能在 `/api/notifications/claudeqq` 中看到 pending/failed,并在登录恢复后通过 `POST /api/notifications/claudeqq/drain` 发送。Code Queue 服务名、表名前缀或持久化目录发生迁移后,还必须运行 `bun scripts/cli.ts e2e run --only microservice:catalog-code-queue,microservice:code-queue-status,microservice:code-queue-health,microservice:code-queue-tasks`,证明 backend-core catalog、私有代理、PostgreSQL 队列和任务列表都指向 `code-queue`。批量验收必须通过公网 frontend 设置 `入队份数=5` 或使用多段 prompt 分隔,一次性入队 5 条任务,并确认 5 条任务按顺序进入 running/judging/succeeded,而不是只运行第一条。 - Code Queue 内存防回归验收:凡是改动 Code Queue 的持久化、scheduler、输出/Trace、health、列表/详情查询、日志导出或容器运行参数,交付前必须用 `docker compose --env-file .state/docker-compose.env config` 或 `docker inspect code-queue-backend` 确认 memory 硬上限为 `629145600` 字节、memory+swap 上限为 `1610612736` 字节,运行 `docker stats --no-stream code-queue-backend` 确认常驻内存低于 `600MiB` 且 `OOMKilled=false`、`RestartCount` 未异常增长,再运行 `bun scripts/cli.ts microservice health code-queue` 确认 `/health` 通过 PostgreSQL 汇总队列而不是物化全量历史任务,并能看到 active run slot 与 waiter 状态。验收还必须覆盖有历史任务存在时的 `/api/tasks`、单任务详情和 output/transcript 查询,证明热状态裁剪不会丢历史输出、也不会重新把全部历史 `task_json` 缓存在进程内;涉及 TypeScript/frontend 验证的任务应能在该 600M memory + 1536M memswap 预算中完成 `bun run --cwd src/components/frontend check` 这类短时高内存命令,而不是被 memory watchdog 反复 SIGTERM。 +- Code Queue 延迟防回归验收:凡是改动 Code Queue 列表、overview、readAt、Trace/summary 懒加载、实时 output/SSE 事件发布、frontend 请求策略、backend-core 用户服务代理或 frontend direct proxy,交付前必须在有历史任务数据且有 active output 流动的 live 环境验证 `GET /api/tasks/overview`、`POST /api/tasks//read`、选定 task 的 `trace-step` 和前端 `/app/code-queue/` 首屏均低于 1s 目标;可运行 `bun scripts/src/code-queue-perf.ts --json --target-ms 1000` 采集公网 frontend 下的首屏耗时、最慢 API 和 DOM 完成指标,并用 `bun scripts/cli.ts microservice proxy code-queue /api/tasks/overview --raw`、容器直连 `/health` 与 `/api/tasks/overview` curl、性能面板 `/api/performance` 与 `/api/frontend-performance` 失败/慢操作记录、`docker stats --no-stream code-queue-backend` 补充后端耗时、代理 502 和内存/CPU 证据。验收结论必须同时说明是否使用了短 TTL cache、cache 如何被 mutation 或 archive append 失效、数据库索引/聚合是否命中、输出热路径是否只读增量指标,以及分页加载是否跳过 selected/active/stats;不能只展示 cache 命中后的单次快照。 - 运行 `bun scripts/cli.ts microservice health filebrowser`、`bun scripts/cli.ts microservice health filebrowser-d601` 和 `bun scripts/cli.ts microservice proxy filebrowser / --max-body-bytes 2000`,确认 File Browser health 返回 `status=OK`,WebUI HTML 包含 `File Browser`,D518/D601 通过 provider-gateway 访问节点本机 `4251`;随后在公网 frontend 的 `用户服务 / File Browser` 中确认 D518 为默认目标、可导出截图、iframe 紧凑布局不再有巨大 `folder` 标记遮挡文件名,并可浏览 `/mnt/c`。 - 在 D601 上用 `bun scripts/cli.ts ssh D601 ...` 调试业务仓库和容器,确认 `curl http://127.0.0.1:3254/api/health` 可用;不要把调试服务部署到主 server。 - 在 D601 上用 `bun scripts/cli.ts ssh D601 ...` 调试业务仓库和容器,确认 `curl http://127.0.0.1:18082/health` 和 `curl http://127.0.0.1:18082/api/snapshot` 可用;不要把 Pipeline 调试服务部署到主 server。 diff --git a/docs/reference/observability.md b/docs/reference/observability.md index fab30114..ae653112 100644 --- a/docs/reference/observability.md +++ b/docs/reference/observability.md @@ -29,3 +29,9 @@ backend-core 必须把 queued、dispatched、running 视为待处理任务,并 backend-core 必须提供 `/api/performance`,返回滚动窗口内的 HTTP 组件请求统计、最近失败请求、内部操作统计、最近慢操作、进程内存、PGDATA 用量和 Code Queue PostgreSQL 存储摘要。组件统计必须包含请求数、失败数、失败率、平均延迟和 P95,内部操作统计必须包含服务名、操作名、次数、平均延迟和 P95;失败和慢操作记录必须保留时间、状态、耗时、路径或细节,避免只给汇总数字而无法定位。 frontend Bun server 必须提供同源 `/api/frontend-performance`,记录 webui 静态资源、登录/session、API 代理和 frontend->core 代理操作耗时。浏览器中的 `运行总览 / 性能面板` 必须把 frontend 与 backend-core 指标合并展示为 Bwebui 曲线、组件汇总、最近失败请求、内部操作汇总和最近慢操作;完整性能 JSON 只能通过显式 `查看原始JSON` 打开。 + +性能优化必须先用这些指标锁定慢操作名称、路径、耗时和代理层级,再改后端查询或前后端通信策略;不得只凭主观体感改 UI。Code Queue 这类控制面页面出现 `code_queue_direct_proxy`、`core_proxy`、`GET /api/tasks/overview`、`POST /api/tasks//read` 等超过 1s 的慢操作时,应保留优化前后的性能面板证据,并同时记录 live API 耗时、容器内存、`/health` 存储摘要和是否仍通过 PostgreSQL/append-only archive 重建历史数据。短 TTL cache、warmup 或页面内存缓存只能作为重复请求抖动保护,性能证据必须证明数据库索引/聚合、分页和渐进式披露本身已把核心路径降到目标内,不能用长缓存遮蔽慢 SQL 或全量 JSON 物化。 + +当最近失败请求集中出现 frontend `webui_api_proxy` 502,路径为 `/api/code-queue-direct/...` 的 overview、trace 或 summary,且 `code-queue-backend` 容器仍在运行时,必须区分“上游进程不可达”和“上游 event loop 被热路径同步工作饿死”。排障顺序是同时查看 `/api/frontend-performance`、`/api/performance`、容器直连 `/health`/overview/trace-step curl、`docker stats`、容器 `RestartCount`/`OOMKilled` 和 Code Queue 日志;如果容器直连 `/health` 也超时,应优先检查实时 output/SSE 发布、archive 读取、transcript 构建、统计计算和远程 Provider 准备/SSH 子进程是否在 active output 追加或任务入队启动时阻塞 event loop,而不是先调整 frontend 渲染或代理超时。涉及 D601 等远程 Provider 时,还要检查 `runCodeQueueSsh`/开发容器准备是否仍存在同步子进程、无 timeout 的 SSH、无上限 stdout/stderr 或 stale TUN 重建等待;修复后必须在远程准备探针运行期间并发证明容器直连 `/health` 与 `/api/tasks/overview` 仍快速返回。 + +Code Queue task 明明产出最终回复却反复 `retry_wait` 时,应优先用任务详情里的 latest attempt 字段核查 `terminalStatus`、`transportClosedBeforeTerminal`、`appServerExitCode`、`finalResponseChars`、`judge.raw._safetyOverride` 和 attempt output。OpenCode 远程任务中,`opencode completed status=completed exit=0` 加当前 attempt 非空 assistant 输出应对应 `terminalStatus=completed`、`transportClosedBeforeTerminal=false`;如果因为缺少 `step_finish` 事件仍触发 `_safetyOverride=terminal_not_completed`,说明协议终态归一化有回归。相反,当前 attempt 没有最终 assistant response 时即使 tool/read/bash 证据完整,也必须 retry,不能用旧 `task.finalResponse` 或 reasoning/tool evidence 代替可见最终回复。 diff --git a/docs/reference/provider-gateway.md b/docs/reference/provider-gateway.md index f64281fe..75a00c30 100644 --- a/docs/reference/provider-gateway.md +++ b/docs/reference/provider-gateway.md @@ -46,6 +46,8 @@ WSL 本身会在没有前台进程时被 Windows 回收;如果该节点要作 Docker daemon 重启后的恢复验收必须看两个层级。第一层是 Docker 自身:`docker inspect --format '{{.HostConfig.RestartPolicy.Name}} {{.HostConfig.PidMode}} {{.State.Status}}' unidesk-provider-gateway-` 必须返回 `always host running`;D601/D518 这类 Docker Desktop daemon 上还要记录 `docker info --format '{{.Name}} {{.LiveRestoreEnabled}}'`,当前 `LiveRestore=false` 意味着 daemon 重启会停止容器,恢复完全依赖 restart policy,因此不能把容器曾经是 running 当作已具备重启恢复能力。第二层是宿主/WSL 常驻:节点应有 systemd、Windows 计划任务、Docker Desktop 自启动或等价 keepalive 证明 Docker daemon 会随机器/WSL 启动;如果 `systemctl list-unit-files '*unidesk*'` 为空,必须在验收记录中明确该节点暂时只依赖 Docker Desktop daemon 自身,不能声称有 WSL 内 systemd watchdog。provider-gateway 新版本会在启动与 heartbeat 中自检当前容器 restart policy,发现不是 `always` 时通过 Docker socket 尝试 `docker update --restart always ` 并在 labels 中上报 `providerGatewayRestartPolicyOk`、`providerGatewayPidModeOk` 与 `providerGatewayRuntimeGuardOk`;这只是最后一道自愈,不能替代 Compose/systemd 的正确配置。 +D601 的已验证常驻链路是 Windows 登录计划任务 `UniDesk-D601-Autostart` -> `C:\Users\liang\AppData\Local\UniDesk\d601-autostart.cmd` -> `wsl.exe -d Ubuntu -u ubuntu -- /bin/bash -lc "/home/ubuntu/.local/bin/unidesk-d601-autostart task"`。WSL 脚本负责启动 sshd、等待 Docker Desktop daemon、确保 `unidesk-provider-gateway-D601` 为 `restart=always` 且 running,并调用 `/home/ubuntu/.local/bin/unidesk-microservice-autorecover` 恢复 D601 用户服务。后续 WSL 节点可以复用这个模式,但必须把 Windows 用户、distro 名、provider ID、业务 autorecover 脚本和日志目录替换为节点自己的值;该模式只用于节点启动后的守护恢复,provider-gateway 版本升级仍必须走 `provider.upgrade mode=schedule`。 + ## WSL Network And Proxy Bootstrap WSL 节点出网异常时,先把代理设置固化到目标 WSL 用户的 `~/.bashrc`,而不是只在当前 shell 临时 `export`。长期可复用的写法是在每次交互 shell 启动时从 `/etc/resolv.conf` 读取 Windows 宿主在 WSL NAT 中的 nameserver IP,再导出 `http_proxy`、`https_proxy`、`HTTP_PROXY`、`HTTPS_PROXY`、`all_proxy` 和 `ALL_PROXY` 指向 `http://:7890` / `socks5://:7890`,并保留 `no_proxy=localhost,127.0.0.1,::1,host.docker.internal`。不要把某次启动看到的宿主 IP 当成永远不变的常量;动态读取可以避免 WSL 网络重建后代理失效。 diff --git a/scripts/cli.ts b/scripts/cli.ts index c36ccc93..4e9616c0 100644 --- a/scripts/cli.ts +++ b/scripts/cli.ts @@ -46,7 +46,7 @@ function help(): unknown { { command: "schedule upsert-pgdata-backup [--time HH:MM] [--remote-base /SERVER_DATA/UNIDESK_PG_DATA]", description: "Create or update the daily PGDATA physical backup task that uploads monthly rotated archives to Baidu Netdisk." }, { command: "codex task [--trace --tail|--from-start|--after-seq N|--before-seq N --limit N] [--full]", description: "Fetch a compact Code Queue task summary; trace rows are opt-in and paged with next/previous commands to avoid output explosion." }, { command: "codex output [--tail|--from-start|--after-seq N|--before-seq N --limit N] [--full-text]", description: "Fetch paged raw Code Queue output records by seq when a trace row has omitted command/output text." }, - { command: "codex (queues | queue create | move --queue )", description: "List/create Code Queue lanes and move a queued task so each queue runs serially while queues run in parallel." }, + { command: "codex (queues | queue create | queue merge --into | move --queue )", description: "List/create/merge Code Queue lanes and move a queued task; merge preserves task queue time order and keeps source queue records." }, { command: "job list", description: "List async jobs from .state/jobs." }, { command: "job status [--tail-bytes N]", description: "Show job state with bounded stdout/stderr tails." }, { command: "debug health", description: "Probe internal core, nodes, system/Docker status, frontend, provider ingress, and public boundary." }, diff --git a/scripts/src/code-queue.ts b/scripts/src/code-queue.ts index 6d198936..b794781a 100644 --- a/scripts/src/code-queue.ts +++ b/scripts/src/code-queue.ts @@ -561,6 +561,42 @@ function requireQueueId(args: string[], command: string): string { return raw.trim(); } +function optionValue(args: string[], names: string[]): string | undefined { + for (const name of names) { + const index = args.indexOf(name); + if (index === -1) continue; + const raw = args[index + 1]; + if (raw === undefined || raw.trim().length === 0) throw new Error(`${name} requires a non-empty value`); + return raw.trim(); + } + return undefined; +} + +function positionalArgs(args: string[]): string[] { + const positions: string[] = []; + for (let index = 0; index < args.length; index += 1) { + const value = args[index] ?? ""; + if (value.startsWith("--")) { + index += 1; + continue; + } + positions.push(value); + } + return positions; +} + +function requireMergeSourceQueueId(args: string[], command: string): string { + const raw = optionValue(args, ["--source", "--from", "--queue"]) ?? positionalArgs(args)[0]; + if (raw === undefined || raw.trim().length === 0) throw new Error(`${command} requires source queue id, for example: codex queue merge old --into default`); + return raw.trim(); +} + +function requireMergeTargetQueueId(args: string[], command: string): string { + const raw = optionValue(args, ["--into", "--target", "--to"]) ?? positionalArgs(args)[1]; + if (raw === undefined || raw.trim().length === 0) throw new Error(`${command} requires target queue id, for example: codex queue merge old --into default`); + return raw.trim(); +} + function codeQueues(): unknown { return unwrapCodexResponse(coreInternalFetch("/api/microservices/code-queue/proxy/api/queues")); } @@ -569,6 +605,10 @@ function codexCreateQueue(queueId: string): unknown { return unwrapCodexResponse(coreInternalFetch("/api/microservices/code-queue/proxy/api/queues", { method: "POST", body: { queueId } })); } +function codexMergeQueue(sourceQueueId: string, targetQueueId: string): unknown { + return unwrapCodexResponse(coreInternalFetch(`/api/microservices/code-queue/proxy/api/queues/${encodeURIComponent(targetQueueId)}/merge`, { method: "POST", body: { sourceQueueId } })); +} + function codexMoveTask(taskId: string, queueId: string): unknown { return unwrapCodexResponse(coreInternalFetch(`/api/microservices/code-queue/proxy/api/tasks/${encodeURIComponent(taskId)}/move`, { method: "POST", body: { queueId } })); } @@ -588,10 +628,14 @@ export async function runCodeQueueCommand(_config: UniDeskConfig, args: string[] const sub = taskIdArg ?? "list"; if (sub === "list") return codeQueues(); if (sub === "create") return codexCreateQueue(requireQueueId(args.slice(2), "queue create")); + if (sub === "merge") { + const mergeArgs = args.slice(2); + return codexMergeQueue(requireMergeSourceQueueId(mergeArgs, "queue merge"), requireMergeTargetQueueId(mergeArgs, "queue merge")); + } } if (action === "move") { const taskId = requireTaskId(taskIdArg, "codex move"); return codexMoveTask(taskId, requireQueueId(args.slice(2), "codex move")); } - throw new Error("codex command must be one of: task, summary, show, output, queues, queue list, queue create, move"); + throw new Error("codex command must be one of: task, summary, show, output, queues, queue list, queue create, queue merge, move"); } diff --git a/scripts/src/e2e.ts b/scripts/src/e2e.ts index fa1c9b0b..a911e626 100644 --- a/scripts/src/e2e.ts +++ b/scripts/src/e2e.ts @@ -119,6 +119,7 @@ const FRONTEND_CHECK_NAMES = [ "frontend:todo-note-integrated-visible", "frontend:findjob-integrated-visible", "frontend:code-queue-integrated-visible", + "frontend:code-queue-enqueue-await-smoke", "frontend:code-queue-summary-mobile-wrap", "frontend:code-queue-initial-prompt-full-expand", "frontend:code-queue-trace-full-load", @@ -540,6 +541,151 @@ function providerGatewayPackageVersion(): string { } } +function isCodeQueueTaskEnqueueRequest(url: string, method: string): boolean { + try { + const parsed = new URL(url); + return method === "POST" && parsed.pathname === "/api/code-queue-direct/api/tasks"; + } catch { + return false; + } +} + +async function runCodeQueueEnqueueAwaitSmoke(page: Page): Promise { + const marker = `e2e-await-enqueue-${Date.now()}-${Math.random().toString(16).slice(2, 8)}`; + const prompt = [ + `Code Queue await enqueue smoke ${marker}`, + "", + "This task is created by the frontend E2E smoke test to verify that the enqueue submit path awaits the backend response before unlocking the form.", + ].join("\n"); + let delayedPostCount = 0; + const routePattern = "**/api/code-queue-direct/api/tasks**"; + const routeHandler = async (route: any, request: any): Promise => { + if (!isCodeQueueTaskEnqueueRequest(request.url(), request.method())) { + await route.continue(); + return; + } + delayedPostCount += 1; + await new Promise((resolve) => setTimeout(resolve, 900)); + await route.continue(); + }; + + await page.route(routePattern, routeHandler); + try { + await page.getByTestId("code-queue-filter-select").selectOption("__all__").catch(() => undefined); + await page.getByTestId("code-queue-id-select").selectOption("default").catch(() => undefined); + await page.getByTestId("codex-max-attempts-input").fill("1"); + await page.getByTestId("codex-repeat-count-input").fill("1"); + await page.locator('[data-testid="code-queue-task-form"] textarea').fill(prompt); + await page.waitForFunction(() => { + const button = document.querySelector('[data-testid="codex-enqueue-button"]') as HTMLButtonElement | null; + return button !== null && !button.disabled && (button.textContent || "").includes("入队"); + }, undefined, { timeout: 5000 }); + + const requestPromise = page.waitForRequest((request) => isCodeQueueTaskEnqueueRequest(request.url(), request.method()), { timeout: 10000 }); + const responsePromise = page.waitForResponse((response) => isCodeQueueTaskEnqueueRequest(response.url(), response.request().method()), { timeout: 30000 }); + await page.getByTestId("codex-enqueue-button").click(); + const request = await requestPromise; + await page.waitForSelector('[data-testid="codex-submit-wait"]', { timeout: 5000 }); + const duringAwait = await page.evaluate(() => { + const form = document.querySelector('[data-testid="code-queue-task-form"]') as HTMLElement | null; + const wait = document.querySelector('[data-testid="codex-submit-wait"]') as HTMLElement | null; + const button = document.querySelector('[data-testid="codex-enqueue-button"]') as HTMLButtonElement | null; + const textarea = document.querySelector('[data-testid="code-queue-task-form"] textarea') as HTMLTextAreaElement | null; + return { + formBusy: form?.getAttribute("aria-busy") === "true", + waitVisible: Boolean(wait && wait.offsetParent !== null && (wait.textContent || "").includes("正在提交")), + buttonDisabled: Boolean(button?.disabled), + buttonText: button?.textContent || "", + textareaDisabled: Boolean(textarea?.disabled), + }; + }); + const response = await responsePromise; + const responseBody = await response.json().catch((error: unknown) => ({ parseError: error instanceof Error ? error.message : String(error) })); + const taskId = String(responseBody?.tasks?.[0]?.id || ""); + await page.waitForFunction((id) => { + const form = document.querySelector('[data-testid="code-queue-task-form"]') as HTMLElement | null; + const notice = document.querySelector('[data-testid="codex-create-success"]') as HTMLElement | null; + return form?.getAttribute("aria-busy") === "false" && (notice?.textContent || "").includes(String(id)); + }, taskId, { timeout: 30000 }); + const afterAwait = await page.evaluate((id) => { + const form = document.querySelector('[data-testid="code-queue-task-form"]') as HTMLElement | null; + const wait = document.querySelector('[data-testid="codex-submit-wait"]') as HTMLElement | null; + const button = document.querySelector('[data-testid="codex-enqueue-button"]') as HTMLButtonElement | null; + const textarea = document.querySelector('[data-testid="code-queue-task-form"] textarea') as HTMLTextAreaElement | null; + const notice = document.querySelector('[data-testid="codex-create-success"]') as HTMLElement | null; + const card = document.querySelector(`[data-testid="codex-task-${CSS.escape(String(id))}"]`) as HTMLElement | null; + return { + formBusy: form?.getAttribute("aria-busy") === "true", + waitMissing: wait === null, + buttonDisabled: Boolean(button?.disabled), + textareaDisabled: Boolean(textarea?.disabled), + textareaEmpty: (textarea?.value || "") === "", + noticeText: notice?.textContent || "", + cardVisible: Boolean(card && card.offsetParent !== null), + }; + }, taskId); + const storedTask = await page.evaluate(async (id) => { + const response = await fetch(`/api/code-queue-direct/api/tasks/${encodeURIComponent(String(id))}?meta=1`, { credentials: "same-origin" }); + const text = await response.text(); + let body: any = null; + try { body = text ? JSON.parse(text) : null; } catch { body = { text }; } + return { ok: response.ok, status: response.status, body }; + }, taskId); + const interrupt = await page.evaluate(async (id) => { + const response = await fetch(`/api/code-queue-direct/api/tasks/${encodeURIComponent(String(id))}/interrupt`, { + method: "POST", + credentials: "same-origin", + headers: { "content-type": "application/json" }, + body: "{}", + }); + const text = await response.text(); + let body: any = null; + try { body = text ? JSON.parse(text) : null; } catch { body = { text }; } + return { ok: response.ok, status: response.status, body }; + }, taskId); + const requestBody = (() => { + try { + return request.postDataJSON(); + } catch { + return null; + } + })(); + await page.getByTestId("codex-max-attempts-input").fill("99").catch(() => undefined); + return { + checked: true, + marker, + delayedPostCount, + requestBody, + responseStatus: response.status(), + responseOk: response.ok(), + responseBody: { + ok: responseBody?.ok === true, + taskIds: Array.isArray(responseBody?.tasks) ? responseBody.tasks.map((task: any) => String(task?.id || "")).filter(Boolean) : [], + }, + taskId, + duringAwait, + afterAwait, + storedTask: { + ok: storedTask.ok, + status: storedTask.status, + id: String(storedTask.body?.task?.id || ""), + queueId: String(storedTask.body?.task?.queueId || ""), + promptIncludesMarker: String(storedTask.body?.task?.prompt || "").includes(marker), + displayPromptIncludesMarker: String(storedTask.body?.task?.displayPrompt || "").includes(marker), + taskStatus: String(storedTask.body?.task?.status || ""), + }, + interrupt: { + ok: interrupt.ok, + status: interrupt.status, + taskStatus: String(interrupt.body?.task?.status || ""), + error: typeof interrupt.body?.error === "string" ? interrupt.body.error : "", + }, + }; + } finally { + await page.unroute(routePattern, routeHandler).catch(() => undefined); + } +} + function runPsql(config: UniDeskConfig, sql: string): { ok: boolean; stdout: string; stderr: string; exitCode: number | null } { const result = runCommand([ "docker", @@ -1082,6 +1228,7 @@ async function frontendCheck(config: UniDeskConfig, urls: PublicUrls, checks: E2 const needFindJob = wants("frontend:findjob-integrated-visible"); const needCodeQueue = wantsAny([ "frontend:code-queue-integrated-visible", + "frontend:code-queue-enqueue-await-smoke", "frontend:code-queue-summary-mobile-wrap", "frontend:code-queue-initial-prompt-full-expand", "frontend:code-queue-trace-full-load", @@ -1175,6 +1322,7 @@ async function frontendCheck(config: UniDeskConfig, urls: PublicUrls, checks: E2 let codeQueueSummaryMobileMetrics: any = { checked: false, summaryCount: 0, ok: false }; let codeQueuePromptDefaultEmpty = false; let codeQueueSubmitGuard: any = { batchRowVisible: false, disabledBeforeConfirm: false, enabledAfterConfirm: false, waitElementMissingBeforeSubmit: false }; + let codeQueueEnqueueAwaitSmoke: any = { checked: false }; let codeQueueScrollbarMetrics: any = { transcriptThin: false, toolHorizontalHidden: true }; let codexInitialPromptFullMetrics: any = { candidateFound: false }; let codexTraceFullMetrics: any = { candidateFound: false }; @@ -1478,6 +1626,7 @@ async function frontendCheck(config: UniDeskConfig, urls: PublicUrls, checks: E2 codeQueueSubmitQueueControl = await page.evaluate(() => { const select = document.querySelector('[data-testid="code-queue-id-select"]') as HTMLSelectElement | null; const button = document.querySelector('[data-testid="codex-create-queue-button"]') as HTMLButtonElement | null; + const mergeButton = document.querySelector('[data-testid="codex-merge-queue-button"]') as HTMLButtonElement | null; const prompt = document.querySelector('[data-testid="code-queue-task-form"] textarea') as HTMLTextAreaElement | null; const provider = document.querySelector('[data-testid="codex-provider-select"]') as HTMLSelectElement | null; const cwd = document.querySelector('[data-testid="codex-cwd-input"]') as HTMLInputElement | null; @@ -1488,6 +1637,7 @@ async function frontendCheck(config: UniDeskConfig, urls: PublicUrls, checks: E2 tagName: select?.tagName.toLowerCase() || "", optionCount: select?.options.length ?? 0, createButtonVisible: Boolean(button && button.offsetParent !== null), + mergeButtonVisible: Boolean(mergeButton && mergeButton.offsetParent !== null), oldInputMissing: document.querySelector('[data-testid="code-queue-id-input"]') === null, promptDefaultEmpty: (prompt?.value || "") === "", providerValue: provider?.value || "", @@ -1530,6 +1680,9 @@ async function frontendCheck(config: UniDeskConfig, urls: PublicUrls, checks: E2 })), }; await page.locator('[data-testid="codex-clear-input-button"]').click(); + if (wants("frontend:code-queue-enqueue-await-smoke")) { + codeQueueEnqueueAwaitSmoke = await runCodeQueueEnqueueAwaitSmoke(page); + } codeQueueOptions = await page.locator('[data-testid="code-queue-filter-select"] option').evaluateAll((options) => options.map((option) => (option as HTMLOptionElement).textContent || "")); codeQueueSwitchMetrics = await page.locator('[data-testid="code-queue-filter-select"] option').evaluateAll((options) => ({ optionCount: options.length, @@ -1936,6 +2089,7 @@ async function frontendCheck(config: UniDeskConfig, urls: PublicUrls, checks: E2 codeQueueSubmitQueueControl = await page.evaluate(() => { const select = document.querySelector('[data-testid="code-queue-id-select"]') as HTMLSelectElement | null; const button = document.querySelector('[data-testid="codex-create-queue-button"]') as HTMLButtonElement | null; + const mergeButton = document.querySelector('[data-testid="codex-merge-queue-button"]') as HTMLButtonElement | null; const prompt = document.querySelector('[data-testid="code-queue-task-form"] textarea') as HTMLTextAreaElement | null; const provider = document.querySelector('[data-testid="codex-provider-select"]') as HTMLSelectElement | null; const cwd = document.querySelector('[data-testid="codex-cwd-input"]') as HTMLInputElement | null; @@ -1946,6 +2100,7 @@ async function frontendCheck(config: UniDeskConfig, urls: PublicUrls, checks: E2 tagName: select?.tagName.toLowerCase() || "", optionCount: select?.options.length ?? 0, createButtonVisible: Boolean(button && button.offsetParent !== null), + mergeButtonVisible: Boolean(mergeButton && mergeButton.offsetParent !== null), oldInputMissing: document.querySelector('[data-testid="code-queue-id-input"]') === null, promptDefaultEmpty: (prompt?.value || "") === "", providerValue: provider?.value || "", @@ -2428,7 +2583,26 @@ async function frontendCheck(config: UniDeskConfig, urls: PublicUrls, checks: E2 addSelectedCheck(checks, options, "frontend:microservice-catalog-visible", microserviceCatalogTextLower.includes("findjob") && microserviceCatalogTextLower.includes("pipeline") && microserviceCatalogTextLower.includes("todo note") && microserviceCatalogTextLower.includes("met nonlinear") && microserviceCatalogTextLower.includes("claudeqq") && microserviceCatalogTextLower.includes("code queue") && microserviceCatalogText.includes("D601") && microserviceCatalogText.includes(config.providerGateway.id) && microserviceCatalogTextLower.includes("private") && microserviceCatalogText.includes("https://gitee.com/Lyon1998/findjob") && microserviceCatalogText.includes("https://github.com/pikasTech/pipeline") && microserviceCatalogText.includes("https://github.com/pikasTech/met_nonlinear") && microserviceCatalogText.includes("https://gitee.com/lyon1998/agent_skills") && microserviceCatalogText.includes("https://gitee.com/Lyon1998/todo_note") && microserviceCatalogText.includes("https://github.com/pikasTech/unidesk"), { microserviceCatalogPreview: microserviceCatalogText.slice(0, 2000) }); addSelectedCheck(checks, options, "frontend:todo-note-integrated-visible", todoNoteTextLower.includes("todo note 工作台") && todoNoteText.includes("CONSTAR") && todoNoteText.includes("大论文") && todoNoteText.includes("UI E2E smoke task") && todoNoteText.includes("撤销") && todoNoteText.includes("重做") && todoNoteText.includes("全部展开") && todoNoteText.includes("仅 UniDesk frontend 代理访问"), { todoNoteTextPreview: todoNoteText.slice(0, 1400) }); addSelectedCheck(checks, options, "frontend:findjob-integrated-visible", findjobTextLower.includes("findjob 工作台".toLowerCase()) && findjobText.includes("岗位总量") && findjobText.includes("D601") && findjobText.includes("近期岗位") && findjobText.includes("仅 UniDesk frontend 代理访问") && /岗位总量\s+\d+/.test(findjobText) && /health\s+ok/i.test(findjobText) && /[1-9]\d*\/[1-9]\d*\s+preview/i.test(findjobText), { findjobTextPreview: findjobText.slice(0, 1200) }); - addSelectedCheck(checks, options, "frontend:code-queue-integrated-visible", codeQueueTextLower.includes("code queue") && codeQueueText.includes("gpt-5.4-mini") && codeQueueText.includes("gpt-5.4") && codeQueueText.includes("gpt-5.5") && codeQueueText.includes("提交任务") && codeQueueText.includes("执行 Provider") && codeQueueText.includes("入队份数") && codeQueueText.includes("追加 prompt") && codeQueueText.includes("打断") && codeQueueTextLower.includes("查看 queue") && codeQueueText.includes("创建 queue") && codeQueueOptions.some((text) => text.includes("All queues")) && codeQueueTracePlacement.firstChildIsTrace === true && codeQueueTracePlacement.noPageTopStatus === true && codeQueueTracePlacement.filterInsideTracePanel === true && codeQueueTracePlacement.taskSearchVisible === true && codeQueueTracePlacement.traceStatusVisible === true && codeQueueTracePlacement.markAllReadVisible === true && codeQueueGlobalStatus.activeMicroserviceVisible === true && codeQueueSidebarUpdateMetrics.hasRecentUpdateLabel === true && codeQueueHtmlGuard.rootAttrMissing === true && codeQueueHtmlGuard.sourceAttrMissing === true && codeQueueHtmlGuard.sourceNoBasePrompt === true && codeQueueSubmitQueueControl.tagName === "select" && codeQueueSubmitQueueControl.createButtonVisible === true && codeQueueSubmitQueueControl.oldInputMissing === true && codeQueueSubmitQueueControl.providerValue === "main-server" && codeQueueSubmitQueueControl.cwdValue === "/root/unidesk" && Array.isArray(codeQueueSubmitQueueControl.providerOptions) && codeQueueSubmitQueueControl.providerOptions.some((item: any) => item.value === "D601" && String(item.text || "").includes("/home/ubuntu")) && codeQueueSubmitQueueControl.maxAttemptsMax === "99" && codeQueueSubmitQueueControl.maxAttemptsValue === "99" && codeQueueSubmitQueueControl.moveQueueVisible === true && codeQueuePromptDefaultEmpty === true && codeQueueSubmitGuard.batchRowVisible === true && codeQueueSubmitGuard.checkboxVisible === true && codeQueueSubmitGuard.disabledBeforeConfirm === true && codeQueueSubmitGuard.enabledAfterConfirm === true && codeQueueSubmitGuard.waitElementMissingBeforeSubmit === true && codeQueueScrollbarMetrics.transcriptThin === true && codeQueueScrollbarMetrics.toolHorizontalHidden === true && (codeQueueSwitchMetrics.optionCount <= 1 || codeQueueSwitchMetrics.switched === true) && codeQueueTextLower.includes("attempts") && codeQueueText.includes("仅 UniDesk frontend 代理访问") && (codeQueueTaskCount === 0 || codeQueueOutputText.includes("Submitted prompt")), { codeQueueTaskCount, codeQueueOptions, codeQueueSwitchMetrics, codeQueueSubmitQueueControl, codeQueueSubmitGuard, codeQueueScrollbarMetrics, codeQueuePromptDefaultEmpty, codeQueueTracePlacement, codeQueueGlobalStatus, codeQueueSidebarUpdateMetrics, codeQueueHtmlGuard, codeQueueOutputPreview: codeQueueOutputText.slice(0, 900), codeQueueTextPreview: codeQueueText.slice(0, 1400) }); + addSelectedCheck(checks, options, "frontend:code-queue-integrated-visible", codeQueueTextLower.includes("code queue") && codeQueueText.includes("gpt-5.4-mini") && codeQueueText.includes("gpt-5.4") && codeQueueText.includes("gpt-5.5") && codeQueueText.includes("提交任务") && codeQueueText.includes("执行 Provider") && codeQueueText.includes("入队份数") && codeQueueText.includes("追加 prompt") && codeQueueText.includes("打断") && codeQueueTextLower.includes("查看 queue") && codeQueueText.includes("创建 queue") && codeQueueText.includes("合并 queue") && codeQueueOptions.some((text) => text.includes("All queues")) && codeQueueTracePlacement.firstChildIsTrace === true && codeQueueTracePlacement.noPageTopStatus === true && codeQueueTracePlacement.filterInsideTracePanel === true && codeQueueTracePlacement.taskSearchVisible === true && codeQueueTracePlacement.traceStatusVisible === true && codeQueueTracePlacement.markAllReadVisible === true && codeQueueGlobalStatus.activeMicroserviceVisible === true && codeQueueSidebarUpdateMetrics.hasRecentUpdateLabel === true && codeQueueHtmlGuard.rootAttrMissing === true && codeQueueHtmlGuard.sourceAttrMissing === true && codeQueueHtmlGuard.sourceNoBasePrompt === true && codeQueueSubmitQueueControl.tagName === "select" && codeQueueSubmitQueueControl.createButtonVisible === true && codeQueueSubmitQueueControl.mergeButtonVisible === true && codeQueueSubmitQueueControl.oldInputMissing === true && codeQueueSubmitQueueControl.providerValue === "main-server" && codeQueueSubmitQueueControl.cwdValue === "/root/unidesk" && Array.isArray(codeQueueSubmitQueueControl.providerOptions) && codeQueueSubmitQueueControl.providerOptions.some((item: any) => item.value === "D601" && String(item.text || "").includes("/home/ubuntu")) && codeQueueSubmitQueueControl.maxAttemptsMax === "99" && codeQueueSubmitQueueControl.maxAttemptsValue === "99" && codeQueueSubmitQueueControl.moveQueueVisible === true && codeQueuePromptDefaultEmpty === true && codeQueueSubmitGuard.batchRowVisible === true && codeQueueSubmitGuard.checkboxVisible === true && codeQueueSubmitGuard.disabledBeforeConfirm === true && codeQueueSubmitGuard.enabledAfterConfirm === true && codeQueueSubmitGuard.waitElementMissingBeforeSubmit === true && codeQueueScrollbarMetrics.transcriptThin === true && codeQueueScrollbarMetrics.toolHorizontalHidden === true && (codeQueueSwitchMetrics.optionCount <= 1 || codeQueueSwitchMetrics.switched === true) && codeQueueTextLower.includes("attempts") && codeQueueText.includes("仅 UniDesk frontend 代理访问") && (codeQueueTaskCount === 0 || codeQueueOutputText.includes("Submitted prompt")), { codeQueueTaskCount, codeQueueOptions, codeQueueSwitchMetrics, codeQueueSubmitQueueControl, codeQueueSubmitGuard, codeQueueScrollbarMetrics, codeQueuePromptDefaultEmpty, codeQueueTracePlacement, codeQueueGlobalStatus, codeQueueSidebarUpdateMetrics, codeQueueHtmlGuard, codeQueueOutputPreview: codeQueueOutputText.slice(0, 900), codeQueueTextPreview: codeQueueText.slice(0, 1400) }); + addSelectedCheck(checks, options, "frontend:code-queue-enqueue-await-smoke", + codeQueueEnqueueAwaitSmoke.checked === true + && codeQueueEnqueueAwaitSmoke.delayedPostCount === 1 + && codeQueueEnqueueAwaitSmoke.responseOk === true + && codeQueueEnqueueAwaitSmoke.responseStatus === 202 + && /^codex_\d+_[A-Za-z0-9_-]+$/u.test(String(codeQueueEnqueueAwaitSmoke.taskId || "")) + && codeQueueEnqueueAwaitSmoke.duringAwait?.formBusy === true + && codeQueueEnqueueAwaitSmoke.duringAwait?.waitVisible === true + && codeQueueEnqueueAwaitSmoke.duringAwait?.buttonDisabled === true + && codeQueueEnqueueAwaitSmoke.duringAwait?.textareaDisabled === true + && codeQueueEnqueueAwaitSmoke.afterAwait?.formBusy === false + && codeQueueEnqueueAwaitSmoke.afterAwait?.waitMissing === true + && codeQueueEnqueueAwaitSmoke.afterAwait?.textareaEmpty === true + && codeQueueEnqueueAwaitSmoke.storedTask?.ok === true + && codeQueueEnqueueAwaitSmoke.storedTask?.id === codeQueueEnqueueAwaitSmoke.taskId + && codeQueueEnqueueAwaitSmoke.storedTask?.queueId === "default" + && codeQueueEnqueueAwaitSmoke.storedTask?.promptIncludesMarker === true + && (codeQueueEnqueueAwaitSmoke.interrupt?.ok === true || codeQueueEnqueueAwaitSmoke.interrupt?.status === 409), + { codeQueueEnqueueAwaitSmoke }); addSelectedCheck(checks, options, "frontend:code-queue-summary-mobile-wrap", codeQueueSummaryMobileMetrics.checked === true && (codeQueueSummaryMobileMetrics.summaryCount === 0 || codeQueueSummaryMobileMetrics.ok === true), { codeQueueSummaryMobileMetrics }); addSelectedCheck(checks, options, "frontend:code-queue-error-red-markers", codeQueueErrorHighlightMetrics.checked === true && codeQueueErrorHighlightMetrics.candidateFound === true && codeQueueErrorHighlightMetrics.ok === true, { codeQueueErrorHighlightMetrics }); addSelectedCheck(checks, options, "frontend:code-queue-initial-prompt-full-expand", diff --git a/src/components/frontend/public/app.js b/src/components/frontend/public/app.js index 8a5ff871..8bea653f 100644 --- a/src/components/frontend/public/app.js +++ b/src/components/frontend/public/app.js @@ -1,39 +1,39 @@ -(()=>{var LO=Object.create;var{getPrototypeOf:XO,defineProperty:oJ,getOwnPropertyNames:BO}=Object;var YO=Object.prototype.hasOwnProperty;function wO(f){return this[f]}var DO,TO,cf=(f,u,l)=>{var _=f!=null&&typeof f==="object";if(_){var y=u?DO??=new WeakMap:TO??=new WeakMap,$=y.get(f);if($)return $}l=f!=null?LO(XO(f)):{};let r=u||!f||!f.__esModule?oJ(l,"default",{value:f,enumerable:!0}):l;for(let j of BO(f))if(!YO.call(r,j))oJ(r,j,{get:wO.bind(f,j),enumerable:!0});if(_)y.set(f,r);return r};var su=(f,u)=>()=>(u||f((u={exports:{}}).exports,u),u.exports);var ef=((f)=>typeof require<"u"?require:typeof Proxy<"u"?new Proxy(f,{get:(u,l)=>(typeof require<"u"?require:u)[l]}):f)(function(f){if(typeof require<"u")return require.apply(this,arguments);throw Error('Dynamic require of "'+f+'" is not supported')});var AU=su((kf)=>{var N3=Symbol.for("react.element"),MO=Symbol.for("react.portal"),PO=Symbol.for("react.fragment"),nO=Symbol.for("react.strict_mode"),SO=Symbol.for("react.profiler"),CO=Symbol.for("react.provider"),iO=Symbol.for("react.context"),cO=Symbol.for("react.forward_ref"),RO=Symbol.for("react.suspense"),xO=Symbol.for("react.memo"),bO=Symbol.for("react.lazy"),aJ=Symbol.iterator;function vO(f){if(f===null||typeof f!=="object")return null;return f=aJ&&f[aJ]||f["@@iterator"],typeof f==="function"?f:null}var fU={isMounted:function(){return!1},enqueueForceUpdate:function(){},enqueueReplaceState:function(){},enqueueSetState:function(){}},uU=Object.assign,lU={};function by(f,u,l){this.props=f,this.context=u,this.refs=lU,this.updater=l||fU}by.prototype.isReactComponent={};by.prototype.setState=function(f,u){if(typeof f!=="object"&&typeof f!=="function"&&f!=null)throw Error("setState(...): takes an object of state variables to update or a function which returns an object of state variables.");this.updater.enqueueSetState(this,f,u,"setState")};by.prototype.forceUpdate=function(f){this.updater.enqueueForceUpdate(this,f,"forceUpdate")};function _U(){}_U.prototype=by.prototype;function Mr(f,u,l){this.props=f,this.context=u,this.refs=lU,this.updater=l||fU}var Pr=Mr.prototype=new _U;Pr.constructor=Mr;uU(Pr,by.prototype);Pr.isPureReactComponent=!0;var dJ=Array.isArray,yU=Object.prototype.hasOwnProperty,nr={current:null},$U={key:!0,ref:!0,__self:!0,__source:!0};function rU(f,u,l){var _,y={},$=null,r=null;if(u!=null)for(_ in u.ref!==void 0&&(r=u.ref),u.key!==void 0&&($=""+u.key),u)yU.call(u,_)&&!$U.hasOwnProperty(_)&&(y[_]=u[_]);var j=arguments.length-2;if(j===1)y.children=l;else if(1{FU.exports=AU()});var EU=su((z0)=>{function Rr(f,u){var l=f.length;f.push(u);f:for(;0>>1,y=f[_];if(0>>1;_<$;){var r=2*(_+1)-1,j=f[r],A=r+1,J=f[A];if(0>k4(j,l))Ak4(J,j)?(f[_]=J,f[A]=l,_=A):(f[_]=j,f[r]=l,_=r);else if(Ak4(J,l))f[_]=J,f[A]=l,_=A;else break f}}return u}function k4(f,u){var l=f.sortIndex-u.sortIndex;return l!==0?l:f.id-u.id}if(typeof performance==="object"&&typeof performance.now==="function")xr=performance,z0.unstable_now=function(){return xr.now()};else t4=Date,br=t4.now(),z0.unstable_now=function(){return t4.now()-br};var xr,t4,br,tl=[],h1=[],sO=1,Wl=null,Au=3,d4=!1,m_=!1,E3=!1,zU=typeof setTimeout==="function"?setTimeout:null,GU=typeof clearTimeout==="function"?clearTimeout:null,WU=typeof setImmediate<"u"?setImmediate:null;typeof navigator<"u"&&navigator.scheduling!==void 0&&navigator.scheduling.isInputPending!==void 0&&navigator.scheduling.isInputPending.bind(navigator.scheduling);function vr(f){for(var u=wl(h1);u!==null;){if(u.callback===null)a4(h1);else if(u.startTime<=f)a4(h1),u.sortIndex=u.expirationTime,Rr(tl,u);else break;u=wl(h1)}}function Ir(f){if(E3=!1,vr(f),!m_)if(wl(tl)!==null)m_=!0,mr(pr);else{var u=wl(h1);u!==null&&gr(Ir,u.startTime-f)}}function pr(f,u){m_=!1,E3&&(E3=!1,GU(H3),H3=-1),d4=!0;var l=Au;try{vr(u);for(Wl=wl(tl);Wl!==null&&(!(Wl.expirationTime>u)||f&&!ZU());){var _=Wl.callback;if(typeof _==="function"){Wl.callback=null,Au=Wl.priorityLevel;var y=_(Wl.expirationTime<=u);u=z0.unstable_now(),typeof y==="function"?Wl.callback=y:Wl===wl(tl)&&a4(tl),vr(u)}else a4(tl);Wl=wl(tl)}if(Wl!==null)var $=!0;else{var r=wl(h1);r!==null&&gr(Ir,r.startTime-u),$=!1}return $}finally{Wl=null,Au=l,d4=!1}}var e4=!1,s4=null,H3=-1,KU=5,NU=-1;function ZU(){return z0.unstable_now()-NUf||125_?(f.sortIndex=l,Rr(h1,f),wl(tl)===null&&f===wl(h1)&&(E3?(GU(H3),H3=-1):E3=!0,gr(Ir,l-_))):(f.sortIndex=y,Rr(tl,f),m_||d4||(m_=!0,mr(pr))),f};z0.unstable_shouldYield=ZU;z0.unstable_wrapCallback=function(f){var u=Au;return function(){var l=Au;Au=u;try{return f.apply(this,arguments)}finally{Au=l}}}});var OU=su((PC,HU)=>{HU.exports=EU()});var qz=su((ul)=>{var oO=O0(),eu=OU();function zf(f){for(var u="https://reactjs.org/docs/error-decoder.html?invariant="+f,l=1;l"u"||typeof window.document>"u"||typeof window.document.createElement>"u"),z9=Object.prototype.hasOwnProperty,aO=/^[:A-Z_a-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD][:A-Z_a-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD\-.0-9\u00B7\u0300-\u036F\u203F-\u2040]*$/,VU={},qU={};function dO(f){if(z9.call(qU,f))return!0;if(z9.call(VU,f))return!1;if(aO.test(f))return qU[f]=!0;return VU[f]=!0,!1}function eO(f,u,l,_){if(l!==null&&l.type===0)return!1;switch(typeof u){case"function":case"symbol":return!0;case"boolean":if(_)return!1;if(l!==null)return!l.acceptsBooleans;return f=f.toLowerCase().slice(0,5),f!=="data-"&&f!=="aria-";default:return!1}}function fV(f,u,l,_){if(u===null||typeof u>"u"||eO(f,u,l,_))return!0;if(_)return!1;if(l!==null)switch(l.type){case 3:return!u;case 4:return u===!1;case 5:return isNaN(u);case 6:return isNaN(u)||1>u}return!1}function qu(f,u,l,_,y,$,r){this.acceptsBooleans=u===2||u===3||u===4,this.attributeName=_,this.attributeNamespace=y,this.mustUseProperty=l,this.propertyName=f,this.type=u,this.sanitizeURL=$,this.removeEmptyString=r}var _u={};"children dangerouslySetInnerHTML defaultValue defaultChecked innerHTML suppressContentEditableWarning suppressHydrationWarning style".split(" ").forEach(function(f){_u[f]=new qu(f,0,!1,f,null,!1,!1)});[["acceptCharset","accept-charset"],["className","class"],["htmlFor","for"],["httpEquiv","http-equiv"]].forEach(function(f){var u=f[0];_u[u]=new qu(u,1,!1,f[1],null,!1,!1)});["contentEditable","draggable","spellCheck","value"].forEach(function(f){_u[f]=new qu(f,2,!1,f.toLowerCase(),null,!1,!1)});["autoReverse","externalResourcesRequired","focusable","preserveAlpha"].forEach(function(f){_u[f]=new qu(f,2,!1,f,null,!1,!1)});"allowFullScreen async autoFocus autoPlay controls default defer disabled disablePictureInPicture disableRemotePlayback formNoValidate hidden loop noModule noValidate open playsInline readOnly required reversed scoped seamless itemScope".split(" ").forEach(function(f){_u[f]=new qu(f,3,!1,f.toLowerCase(),null,!1,!1)});["checked","multiple","muted","selected"].forEach(function(f){_u[f]=new qu(f,3,!0,f,null,!1,!1)});["capture","download"].forEach(function(f){_u[f]=new qu(f,4,!1,f,null,!1,!1)});["cols","rows","size","span"].forEach(function(f){_u[f]=new qu(f,6,!1,f,null,!1,!1)});["rowSpan","start"].forEach(function(f){_u[f]=new qu(f,5,!1,f.toLowerCase(),null,!1,!1)});var A7=/[\-:]([a-z])/g;function F7(f){return f[1].toUpperCase()}"accent-height alignment-baseline arabic-form baseline-shift cap-height clip-path clip-rule color-interpolation color-interpolation-filters color-profile color-rendering dominant-baseline enable-background fill-opacity fill-rule flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight glyph-name glyph-orientation-horizontal glyph-orientation-vertical horiz-adv-x horiz-origin-x image-rendering letter-spacing lighting-color marker-end marker-mid marker-start overline-position overline-thickness paint-order panose-1 pointer-events rendering-intent shape-rendering stop-color stop-opacity strikethrough-position strikethrough-thickness stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width text-anchor text-decoration text-rendering underline-position underline-thickness unicode-bidi unicode-range units-per-em v-alphabetic v-hanging v-ideographic v-mathematical vector-effect vert-adv-y vert-origin-x vert-origin-y word-spacing writing-mode xmlns:xlink x-height".split(" ").forEach(function(f){var u=f.replace(A7,F7);_u[u]=new qu(u,1,!1,f,null,!1,!1)});"xlink:actuate xlink:arcrole xlink:role xlink:show xlink:title xlink:type".split(" ").forEach(function(f){var u=f.replace(A7,F7);_u[u]=new qu(u,1,!1,f,"http://www.w3.org/1999/xlink",!1,!1)});["xml:base","xml:lang","xml:space"].forEach(function(f){var u=f.replace(A7,F7);_u[u]=new qu(u,1,!1,f,"http://www.w3.org/XML/1998/namespace",!1,!1)});["tabIndex","crossOrigin"].forEach(function(f){_u[f]=new qu(f,1,!1,f.toLowerCase(),null,!1,!1)});_u.xlinkHref=new qu("xlinkHref",1,!1,"xlink:href","http://www.w3.org/1999/xlink",!0,!1);["src","href","action","formAction"].forEach(function(f){_u[f]=new qu(f,1,!1,f.toLowerCase(),null,!0,!0)});function J7(f,u,l,_){var y=_u.hasOwnProperty(u)?_u[u]:null;if(y!==null?y.type!==0:_||!(2j||y[r]!==$[j]){var A=` -`+y[r].replace(" at new "," at ");return f.displayName&&A.includes("")&&(A=A.replace("",f.displayName)),A}while(1<=r&&0<=j);break}}}finally{tr=!1,Error.prepareStackTrace=l}return(f=f?f.displayName||f.name:"")?w3(f):""}function uV(f){switch(f.tag){case 5:return w3(f.type);case 16:return w3("Lazy");case 13:return w3("Suspense");case 19:return w3("SuspenseList");case 0:case 2:case 15:return f=sr(f.type,!1),f;case 11:return f=sr(f.type.render,!1),f;case 1:return f=sr(f.type,!0),f;default:return""}}function Z9(f){if(f==null)return null;if(typeof f==="function")return f.displayName||f.name||null;if(typeof f==="string")return f;switch(f){case py:return"Fragment";case Iy:return"Portal";case G9:return"Profiler";case U7:return"StrictMode";case K9:return"Suspense";case N9:return"SuspenseList"}if(typeof f==="object")switch(f.$$typeof){case wQ:return(f.displayName||"Context")+".Consumer";case YQ:return(f._context.displayName||"Context")+".Provider";case Q7:var u=f.render;return f=f.displayName,f||(f=u.displayName||u.name||"",f=f!==""?"ForwardRef("+f+")":"ForwardRef"),f;case W7:return u=f.displayName||null,u!==null?u:Z9(f.type)||"Memo";case p1:u=f._payload,f=f._init;try{return Z9(f(u))}catch(l){}}return null}function lV(f){var u=f.type;switch(f.tag){case 24:return"Cache";case 9:return(u.displayName||"Context")+".Consumer";case 10:return(u._context.displayName||"Context")+".Provider";case 18:return"DehydratedFragment";case 11:return f=u.render,f=f.displayName||f.name||"",u.displayName||(f!==""?"ForwardRef("+f+")":"ForwardRef");case 7:return"Fragment";case 5:return u;case 4:return"Portal";case 3:return"Root";case 6:return"Text";case 16:return Z9(u);case 8:return u===U7?"StrictMode":"Mode";case 22:return"Offscreen";case 12:return"Profiler";case 21:return"Scope";case 13:return"Suspense";case 19:return"SuspenseList";case 25:return"TracingMarker";case 1:case 0:case 17:case 2:case 14:case 15:if(typeof u==="function")return u.displayName||u.name||null;if(typeof u==="string")return u}return null}function y_(f){switch(typeof f){case"boolean":case"number":case"string":case"undefined":return f;case"object":return f;default:return""}}function TQ(f){var u=f.type;return(f=f.nodeName)&&f.toLowerCase()==="input"&&(u==="checkbox"||u==="radio")}function _V(f){var u=TQ(f)?"checked":"value",l=Object.getOwnPropertyDescriptor(f.constructor.prototype,u),_=""+f[u];if(!f.hasOwnProperty(u)&&typeof l<"u"&&typeof l.get==="function"&&typeof l.set==="function"){var{get:y,set:$}=l;return Object.defineProperty(f,u,{configurable:!0,get:function(){return y.call(this)},set:function(r){_=""+r,$.call(this,r)}}),Object.defineProperty(f,u,{enumerable:l.enumerable}),{getValue:function(){return _},setValue:function(r){_=""+r},stopTracking:function(){f._valueTracker=null,delete f[u]}}}}function u8(f){f._valueTracker||(f._valueTracker=_V(f))}function MQ(f){if(!f)return!1;var u=f._valueTracker;if(!u)return!0;var l=u.getValue(),_="";return f&&(_=TQ(f)?f.checked?"true":"false":f.value),f=_,f!==l?(u.setValue(f),!0):!1}function B8(f){if(f=f||(typeof document<"u"?document:void 0),typeof f>"u")return null;try{return f.activeElement||f.body}catch(u){return f.body}}function E9(f,u){var l=u.checked;return B0({},u,{defaultChecked:void 0,defaultValue:void 0,value:void 0,checked:l!=null?l:f._wrapperState.initialChecked})}function XU(f,u){var l=u.defaultValue==null?"":u.defaultValue,_=u.checked!=null?u.checked:u.defaultChecked;l=y_(u.value!=null?u.value:l),f._wrapperState={initialChecked:_,initialValue:l,controlled:u.type==="checkbox"||u.type==="radio"?u.checked!=null:u.value!=null}}function PQ(f,u){u=u.checked,u!=null&&J7(f,"checked",u,!1)}function H9(f,u){PQ(f,u);var l=y_(u.value),_=u.type;if(l!=null)if(_==="number"){if(l===0&&f.value===""||f.value!=l)f.value=""+l}else f.value!==""+l&&(f.value=""+l);else if(_==="submit"||_==="reset"){f.removeAttribute("value");return}u.hasOwnProperty("value")?O9(f,u.type,l):u.hasOwnProperty("defaultValue")&&O9(f,u.type,y_(u.defaultValue)),u.checked==null&&u.defaultChecked!=null&&(f.defaultChecked=!!u.defaultChecked)}function BU(f,u,l){if(u.hasOwnProperty("value")||u.hasOwnProperty("defaultValue")){var _=u.type;if(!(_!=="submit"&&_!=="reset"||u.value!==void 0&&u.value!==null))return;u=""+f._wrapperState.initialValue,l||u===f.value||(f.value=u),f.defaultValue=u}l=f.name,l!==""&&(f.name=""),f.defaultChecked=!!f._wrapperState.initialChecked,l!==""&&(f.name=l)}function O9(f,u,l){if(u!=="number"||B8(f.ownerDocument)!==f)l==null?f.defaultValue=""+f._wrapperState.initialValue:f.defaultValue!==""+l&&(f.defaultValue=""+l)}var D3=Array.isArray;function u$(f,u,l,_){if(f=f.options,u){u={};for(var y=0;y"+u.valueOf().toString()+"";for(u=l8.firstChild;f.firstChild;)f.removeChild(f.firstChild);for(;u.firstChild;)f.appendChild(u.firstChild)}});function g3(f,u){if(u){var l=f.firstChild;if(l&&l===f.lastChild&&l.nodeType===3){l.nodeValue=u;return}}f.textContent=u}var i3={animationIterationCount:!0,aspectRatio:!0,borderImageOutset:!0,borderImageSlice:!0,borderImageWidth:!0,boxFlex:!0,boxFlexGroup:!0,boxOrdinalGroup:!0,columnCount:!0,columns:!0,flex:!0,flexGrow:!0,flexPositive:!0,flexShrink:!0,flexNegative:!0,flexOrder:!0,gridArea:!0,gridRow:!0,gridRowEnd:!0,gridRowSpan:!0,gridRowStart:!0,gridColumn:!0,gridColumnEnd:!0,gridColumnSpan:!0,gridColumnStart:!0,fontWeight:!0,lineClamp:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,tabSize:!0,widows:!0,zIndex:!0,zoom:!0,fillOpacity:!0,floodOpacity:!0,stopOpacity:!0,strokeDasharray:!0,strokeDashoffset:!0,strokeMiterlimit:!0,strokeOpacity:!0,strokeWidth:!0},yV=["Webkit","ms","Moz","O"];Object.keys(i3).forEach(function(f){yV.forEach(function(u){u=u+f.charAt(0).toUpperCase()+f.substring(1),i3[u]=i3[f]})});function iQ(f,u,l){return u==null||typeof u==="boolean"||u===""?"":l||typeof u!=="number"||u===0||i3.hasOwnProperty(f)&&i3[f]?(""+u).trim():u+"px"}function cQ(f,u){f=f.style;for(var l in u)if(u.hasOwnProperty(l)){var _=l.indexOf("--")===0,y=iQ(l,u[l],_);l==="float"&&(l="cssFloat"),_?f.setProperty(l,y):f[l]=y}}var $V=B0({menuitem:!0},{area:!0,base:!0,br:!0,col:!0,embed:!0,hr:!0,img:!0,input:!0,keygen:!0,link:!0,meta:!0,param:!0,source:!0,track:!0,wbr:!0});function L9(f,u){if(u){if($V[f]&&(u.children!=null||u.dangerouslySetInnerHTML!=null))throw Error(zf(137,f));if(u.dangerouslySetInnerHTML!=null){if(u.children!=null)throw Error(zf(60));if(typeof u.dangerouslySetInnerHTML!=="object"||!("__html"in u.dangerouslySetInnerHTML))throw Error(zf(61))}if(u.style!=null&&typeof u.style!=="object")throw Error(zf(62))}}function X9(f,u){if(f.indexOf("-")===-1)return typeof u.is==="string";switch(f){case"annotation-xml":case"color-profile":case"font-face":case"font-face-src":case"font-face-uri":case"font-face-format":case"font-face-name":case"missing-glyph":return!1;default:return!0}}var B9=null;function z7(f){return f=f.target||f.srcElement||window,f.correspondingUseElement&&(f=f.correspondingUseElement),f.nodeType===3?f.parentNode:f}var Y9=null,l$=null,_$=null;function DU(f){if(f=J6(f)){if(typeof Y9!=="function")throw Error(zf(280));var u=f.stateNode;u&&(u=f2(u),Y9(f.stateNode,f.type,u))}}function RQ(f){l$?_$?_$.push(f):_$=[f]:l$=f}function xQ(){if(l$){var f=l$,u=_$;if(_$=l$=null,DU(f),u)for(f=0;f>>=0,f===0?32:31-(KV(f)/NV|0)|0}var _8=64,y8=4194304;function T3(f){switch(f&-f){case 1:return 1;case 2:return 2;case 4:return 4;case 8:return 8;case 16:return 16;case 32:return 32;case 64:case 128:case 256:case 512:case 1024:case 2048:case 4096:case 8192:case 16384:case 32768:case 65536:case 131072:case 262144:case 524288:case 1048576:case 2097152:return f&4194240;case 4194304:case 8388608:case 16777216:case 33554432:case 67108864:return f&130023424;case 134217728:return 134217728;case 268435456:return 268435456;case 536870912:return 536870912;case 1073741824:return 1073741824;default:return f}}function T8(f,u){var l=f.pendingLanes;if(l===0)return 0;var _=0,y=f.suspendedLanes,$=f.pingedLanes,r=l&268435455;if(r!==0){var j=r&~y;j!==0?_=T3(j):($&=r,$!==0&&(_=T3($)))}else r=l&~y,r!==0?_=T3(r):$!==0&&(_=T3($));if(_===0)return 0;if(u!==0&&u!==_&&(u&y)===0&&(y=_&-_,$=u&-u,y>=$||y===16&&($&4194240)!==0))return u;if((_&4)!==0&&(_|=l&16),u=f.entangledLanes,u!==0)for(f=f.entanglements,u&=_;0l;l++)u.push(f);return u}function A6(f,u,l){f.pendingLanes|=u,u!==536870912&&(f.suspendedLanes=0,f.pingedLanes=0),f=f.eventTimes,u=31-nl(u),f[u]=l}function OV(f,u){var l=f.pendingLanes&~u;f.pendingLanes=u,f.suspendedLanes=0,f.pingedLanes=0,f.expiredLanes&=u,f.mutableReadLanes&=u,f.entangledLanes&=u,u=f.entanglements;var _=f.eventTimes;for(f=f.expirationTimes;0=R3),RU=String.fromCharCode(32),xU=!1;function $W(f,u){switch(f){case"keyup":return sV.indexOf(u.keyCode)!==-1;case"keydown":return u.keyCode!==229;case"keypress":case"mousedown":case"focusout":return!0;default:return!1}}function rW(f){return f=f.detail,typeof f==="object"&&"data"in f?f.data:null}var my=!1;function aV(f,u){switch(f){case"compositionend":return rW(u);case"keypress":if(u.which!==32)return null;return xU=!0,RU;case"textInput":return f=u.data,f===RU&&xU?null:f;default:return null}}function dV(f,u){if(my)return f==="compositionend"||!V7&&$W(f,u)?(f=_W(),K8=E7=t1=null,my=!1,f):null;switch(f){case"paste":return null;case"keypress":if(!(u.ctrlKey||u.altKey||u.metaKey)||u.ctrlKey&&u.altKey){if(u.char&&1=u)return{node:l,offset:u-f};f=_}f:{for(;l;){if(l.nextSibling){l=l.nextSibling;break f}l=l.parentNode}l=void 0}l=hU(l)}}function JW(f,u){return f&&u?f===u?!0:f&&f.nodeType===3?!1:u&&u.nodeType===3?JW(f,u.parentNode):("contains"in f)?f.contains(u):f.compareDocumentPosition?!!(f.compareDocumentPosition(u)&16):!1:!1}function UW(){for(var f=window,u=B8();u instanceof f.HTMLIFrameElement;){try{var l=typeof u.contentWindow.location.href==="string"}catch(_){l=!1}if(l)f=u.contentWindow;else break;u=B8(f.document)}return u}function q7(f){var u=f&&f.nodeName&&f.nodeName.toLowerCase();return u&&(u==="input"&&(f.type==="text"||f.type==="search"||f.type==="tel"||f.type==="url"||f.type==="password")||u==="textarea"||f.contentEditable==="true")}function jq(f){var u=UW(),l=f.focusedElem,_=f.selectionRange;if(u!==l&&l&&l.ownerDocument&&JW(l.ownerDocument.documentElement,l)){if(_!==null&&q7(l)){if(u=_.start,f=_.end,f===void 0&&(f=u),"selectionStart"in l)l.selectionStart=u,l.selectionEnd=Math.min(f,l.value.length);else if(f=(u=l.ownerDocument||document)&&u.defaultView||window,f.getSelection){f=f.getSelection();var y=l.textContent.length,$=Math.min(_.start,y);_=_.end===void 0?$:Math.min(_.end,y),!f.extend&&$>_&&(y=_,_=$,$=y),y=IU(l,$);var r=IU(l,_);y&&r&&(f.rangeCount!==1||f.anchorNode!==y.node||f.anchorOffset!==y.offset||f.focusNode!==r.node||f.focusOffset!==r.offset)&&(u=u.createRange(),u.setStart(y.node,y.offset),f.removeAllRanges(),$>_?(f.addRange(u),f.extend(r.node,r.offset)):(u.setEnd(r.node,r.offset),f.addRange(u)))}}u=[];for(f=l;f=f.parentNode;)f.nodeType===1&&u.push({element:f,left:f.scrollLeft,top:f.scrollTop});typeof l.focus==="function"&&l.focus();for(l=0;l=document.documentMode,gy=null,n9=null,b3=null,S9=!1;function pU(f,u,l){var _=l.window===l?l.document:l.nodeType===9?l:l.ownerDocument;S9||gy==null||gy!==B8(_)||(_=gy,("selectionStart"in _)&&q7(_)?_={start:_.selectionStart,end:_.selectionEnd}:(_=(_.ownerDocument&&_.ownerDocument.defaultView||window).getSelection(),_={anchorNode:_.anchorNode,anchorOffset:_.anchorOffset,focusNode:_.focusNode,focusOffset:_.focusOffset}),b3&&d3(b3,_)||(b3=_,_=n8(n9,"onSelect"),0<_.length&&(u=new H7("onSelect","select",null,u,l),f.push({event:u,listeners:_}),u.target=gy)))}function j8(f,u){var l={};return l[f.toLowerCase()]=u.toLowerCase(),l["Webkit"+f]="webkit"+u,l["Moz"+f]="moz"+u,l}var ky={animationend:j8("Animation","AnimationEnd"),animationiteration:j8("Animation","AnimationIteration"),animationstart:j8("Animation","AnimationStart"),transitionend:j8("Transition","TransitionEnd")},u9={},QW={};q1&&(QW=document.createElement("div").style,("AnimationEvent"in window)||(delete ky.animationend.animation,delete ky.animationiteration.animation,delete ky.animationstart.animation),("TransitionEvent"in window)||delete ky.transitionend.transition);function e8(f){if(u9[f])return u9[f];if(!ky[f])return f;var u=ky[f],l;for(l in u)if(u.hasOwnProperty(l)&&l in QW)return u9[f]=u[l];return f}var WW=e8("animationend"),zW=e8("animationiteration"),GW=e8("animationstart"),KW=e8("transitionend"),NW=new Map,mU="abort auxClick cancel canPlay canPlayThrough click close contextMenu copy cut drag dragEnd dragEnter dragExit dragLeave dragOver dragStart drop durationChange emptied encrypted ended error gotPointerCapture input invalid keyDown keyPress keyUp load loadedData loadedMetadata loadStart lostPointerCapture mouseDown mouseMove mouseOut mouseOver mouseUp paste pause play playing pointerCancel pointerDown pointerMove pointerOut pointerOver pointerUp progress rateChange reset resize seeked seeking stalled submit suspend timeUpdate touchCancel touchEnd touchStart volumeChange scroll toggle touchMove waiting wheel".split(" ");function r_(f,u){NW.set(f,u),$y(u,[f])}for(n3=0;n3sy||(f.current=h9[sy],h9[sy]=null,sy--)}function G0(f,u){sy++,h9[sy]=f.current,f.current=u}var $_={},Qu=j_($_),Su=j_(!1),fy=$_;function A$(f,u){var l=f.type.contextTypes;if(!l)return $_;var _=f.stateNode;if(_&&_.__reactInternalMemoizedUnmaskedChildContext===u)return _.__reactInternalMemoizedMaskedChildContext;var y={},$;for($ in l)y[$]=u[$];return _&&(f=f.stateNode,f.__reactInternalMemoizedUnmaskedChildContext=u,f.__reactInternalMemoizedMaskedChildContext=y),y}function Cu(f){return f=f.childContextTypes,f!==null&&f!==void 0}function C8(){E0(Su),E0(Qu)}function aU(f,u,l){if(Qu.current!==$_)throw Error(zf(168));G0(Qu,u),G0(Su,l)}function HW(f,u,l){var _=f.stateNode;if(u=u.childContextTypes,typeof _.getChildContext!=="function")return l;_=_.getChildContext();for(var y in _)if(!(y in u))throw Error(zf(108,lV(f)||"Unknown",y));return B0({},l,_)}function i8(f){return f=(f=f.stateNode)&&f.__reactInternalMemoizedMergedChildContext||$_,fy=Qu.current,G0(Qu,f),G0(Su,Su.current),!0}function dU(f,u,l){var _=f.stateNode;if(!_)throw Error(zf(169));l?(f=HW(f,u,fy),_.__reactInternalMemoizedMergedChildContext=f,E0(Su),E0(Qu),G0(Qu,f)):E0(Su),G0(Su,l)}var E1=null,u2=!1,$9=!1;function OW(f){E1===null?E1=[f]:E1.push(f)}function Nq(f){u2=!0,OW(f)}function A_(){if(!$9&&E1!==null){$9=!0;var f=0,u=r0;try{var l=E1;for(r0=1;f>=r,y-=r,H1=1<<32-nl(u)+y|l<B?(P=w,w=null):P=w.sibling;var h=W(z,w,N[B],E);if(h===null){w===null&&(w=P);break}f&&w&&h.alternate===null&&u(z,w),Z=$(h,Z,B),Y===null?q=h:Y.sibling=h,Y=h,w=P}if(B===N.length)return l(z,w),V0&&k_(z,B),q;if(w===null){for(;BB?(P=w,w=null):P=w.sibling;var M=W(z,w,h.value,E);if(M===null){w===null&&(w=P);break}f&&w&&M.alternate===null&&u(z,w),Z=$(M,Z,B),Y===null?q=M:Y.sibling=M,Y=M,w=P}if(h.done)return l(z,w),V0&&k_(z,B),q;if(w===null){for(;!h.done;B++,h=N.next())h=Q(z,h.value,E),h!==null&&(Z=$(h,Z,B),Y===null?q=h:Y.sibling=h,Y=h);return V0&&k_(z,B),q}for(w=_(z,w);!h.done;B++,h=N.next())h=G(w,z,B,h.value,E),h!==null&&(f&&h.alternate!==null&&w.delete(h.key===null?B:h.key),Z=$(h,Z,B),Y===null?q=h:Y.sibling=h,Y=h);return f&&w.forEach(function(n){return u(z,n)}),V0&&k_(z,B),q}function O(z,Z,N,E){if(typeof N==="object"&&N!==null&&N.type===py&&N.key===null&&(N=N.props.children),typeof N==="object"&&N!==null){switch(N.$$typeof){case f8:f:{for(var q=N.key,Y=Z;Y!==null;){if(Y.key===q){if(q=N.type,q===py){if(Y.tag===7){l(z,Y.sibling),Z=y(Y,N.props.children),Z.return=z,z=Z;break f}}else if(Y.elementType===q||typeof q==="object"&&q!==null&&q.$$typeof===p1&&uQ(q)===Y.type){l(z,Y.sibling),Z=y(Y,N.props),Z.ref=X3(z,Y,N),Z.return=z,z=Z;break f}l(z,Y);break}else u(z,Y);Y=Y.sibling}N.type===py?(Z=e_(N.props.children,z.mode,E,N.key),Z.return=z,z=Z):(E=X8(N.type,N.key,N.props,null,z.mode,E),E.ref=X3(z,Z,N),E.return=z,z=E)}return r(z);case Iy:f:{for(Y=N.key;Z!==null;){if(Z.key===Y)if(Z.tag===4&&Z.stateNode.containerInfo===N.containerInfo&&Z.stateNode.implementation===N.implementation){l(z,Z.sibling),Z=y(Z,N.children||[]),Z.return=z,z=Z;break f}else{l(z,Z);break}else u(z,Z);Z=Z.sibling}Z=W9(N,z.mode,E),Z.return=z,z=Z}return r(z);case p1:return Y=N._init,O(z,Z,Y(N._payload),E)}if(D3(N))return K(z,Z,N,E);if(O3(N))return H(z,Z,N,E);U8(z,N)}return typeof N==="string"&&N!==""||typeof N==="number"?(N=""+N,Z!==null&&Z.tag===6?(l(z,Z.sibling),Z=y(Z,N),Z.return=z,z=Z):(l(z,Z),Z=Q9(N,z.mode,E),Z.return=z,z=Z),r(z)):l(z,Z)}return O}var J$=XW(!0),BW=XW(!1),x8=j_(null),b8=null,dy=null,Y7=null;function w7(){Y7=dy=b8=null}function D7(f){var u=x8.current;E0(x8),f._currentValue=u}function m9(f,u,l){for(;f!==null;){var _=f.alternate;if((f.childLanes&u)!==u?(f.childLanes|=u,_!==null&&(_.childLanes|=u)):_!==null&&(_.childLanes&u)!==u&&(_.childLanes|=u),f===l)break;f=f.return}}function $$(f,u){b8=f,Y7=dy=null,f=f.dependencies,f!==null&&f.firstContext!==null&&((f.lanes&u)!==0&&(nu=!0),f.firstContext=null)}function Zl(f){var u=f._currentValue;if(Y7!==f)if(f={context:f,memoizedValue:u,next:null},dy===null){if(b8===null)throw Error(zf(308));dy=f,b8.dependencies={lanes:0,firstContext:f}}else dy=dy.next=f;return u}var o_=null;function T7(f){o_===null?o_=[f]:o_.push(f)}function YW(f,u,l,_){var y=u.interleaved;return y===null?(l.next=l,T7(u)):(l.next=y.next,y.next=l),u.interleaved=l,X1(f,_)}function X1(f,u){f.lanes|=u;var l=f.alternate;l!==null&&(l.lanes|=u),l=f;for(f=f.return;f!==null;)f.childLanes|=u,l=f.alternate,l!==null&&(l.childLanes|=u),l=f,f=f.return;return l.tag===3?l.stateNode:null}var m1=!1;function M7(f){f.updateQueue={baseState:f.memoizedState,firstBaseUpdate:null,lastBaseUpdate:null,shared:{pending:null,interleaved:null,lanes:0},effects:null}}function wW(f,u){f=f.updateQueue,u.updateQueue===f&&(u.updateQueue={baseState:f.baseState,firstBaseUpdate:f.firstBaseUpdate,lastBaseUpdate:f.lastBaseUpdate,shared:f.shared,effects:f.effects})}function V1(f,u){return{eventTime:f,lane:u,tag:0,payload:null,callback:null,next:null}}function f_(f,u,l){var _=f.updateQueue;if(_===null)return null;if(_=_.shared,(l0&2)!==0){var y=_.pending;return y===null?u.next=u:(u.next=y.next,y.next=u),_.pending=u,X1(f,l)}return y=_.interleaved,y===null?(u.next=u,T7(_)):(u.next=y.next,y.next=u),_.interleaved=u,X1(f,l)}function E8(f,u,l){if(u=u.updateQueue,u!==null&&(u=u.shared,(l&4194240)!==0)){var _=u.lanes;_&=f.pendingLanes,l|=_,u.lanes=l,K7(f,l)}}function lQ(f,u){var{updateQueue:l,alternate:_}=f;if(_!==null&&(_=_.updateQueue,l===_)){var y=null,$=null;if(l=l.firstBaseUpdate,l!==null){do{var r={eventTime:l.eventTime,lane:l.lane,tag:l.tag,payload:l.payload,callback:l.callback,next:null};$===null?y=$=r:$=$.next=r,l=l.next}while(l!==null);$===null?y=$=u:$=$.next=u}else y=$=u;l={baseState:_.baseState,firstBaseUpdate:y,lastBaseUpdate:$,shared:_.shared,effects:_.effects},f.updateQueue=l;return}f=l.lastBaseUpdate,f===null?l.firstBaseUpdate=u:f.next=u,l.lastBaseUpdate=u}function v8(f,u,l,_){var y=f.updateQueue;m1=!1;var{firstBaseUpdate:$,lastBaseUpdate:r}=y,j=y.shared.pending;if(j!==null){y.shared.pending=null;var A=j,J=A.next;A.next=null,r===null?$=J:r.next=J,r=A;var U=f.alternate;U!==null&&(U=U.updateQueue,j=U.lastBaseUpdate,j!==r&&(j===null?U.firstBaseUpdate=J:j.next=J,U.lastBaseUpdate=A))}if($!==null){var Q=y.baseState;r=0,U=J=A=null,j=$;do{var{lane:W,eventTime:G}=j;if((_&W)===W){U!==null&&(U=U.next={eventTime:G,lane:0,tag:j.tag,payload:j.payload,callback:j.callback,next:null});f:{var K=f,H=j;switch(W=u,G=l,H.tag){case 1:if(K=H.payload,typeof K==="function"){Q=K.call(G,Q,W);break f}Q=K;break f;case 3:K.flags=K.flags&-65537|128;case 0:if(K=H.payload,W=typeof K==="function"?K.call(G,Q,W):K,W===null||W===void 0)break f;Q=B0({},Q,W);break f;case 2:m1=!0}}j.callback!==null&&j.lane!==0&&(f.flags|=64,W=y.effects,W===null?y.effects=[j]:W.push(j))}else G={eventTime:G,lane:W,tag:j.tag,payload:j.payload,callback:j.callback,next:null},U===null?(J=U=G,A=Q):U=U.next=G,r|=W;if(j=j.next,j===null)if(j=y.shared.pending,j===null)break;else W=j,j=W.next,W.next=null,y.lastBaseUpdate=W,y.shared.pending=null}while(1);if(U===null&&(A=Q),y.baseState=A,y.firstBaseUpdate=J,y.lastBaseUpdate=U,u=y.shared.interleaved,u!==null){y=u;do r|=y.lane,y=y.next;while(y!==u)}else $===null&&(y.shared.lanes=0);_y|=r,f.lanes=r,f.memoizedState=Q}}function _Q(f,u,l){if(f=u.effects,u.effects=null,f!==null)for(u=0;ul?l:4,f(!0);var _=j9.transition;j9.transition={};try{f(!1),u()}finally{r0=l,j9.transition=_}}function mW(){return El().memoizedState}function Oq(f,u,l){var _=l_(f);if(l={lane:_,action:l,hasEagerState:!1,eagerState:null,next:null},gW(f))kW(u,l);else if(l=YW(f,u,l,_),l!==null){var y=Vu();Sl(l,f,_,y),tW(l,u,_)}}function Vq(f,u,l){var _=l_(f),y={lane:_,action:l,hasEagerState:!1,eagerState:null,next:null};if(gW(f))kW(u,y);else{var $=f.alternate;if(f.lanes===0&&($===null||$.lanes===0)&&($=u.lastRenderedReducer,$!==null))try{var r=u.lastRenderedState,j=$(r,l);if(y.hasEagerState=!0,y.eagerState=j,Cl(j,r)){var A=u.interleaved;A===null?(y.next=y,T7(u)):(y.next=A.next,A.next=y),u.interleaved=y;return}}catch(J){}finally{}l=YW(f,u,y,_),l!==null&&(y=Vu(),Sl(l,f,_,y),tW(l,u,_))}}function gW(f){var u=f.alternate;return f===X0||u!==null&&u===X0}function kW(f,u){v3=I8=!0;var l=f.pending;l===null?u.next=u:(u.next=l.next,l.next=u),f.pending=u}function tW(f,u,l){if((l&4194240)!==0){var _=u.lanes;_&=f.pendingLanes,l|=_,u.lanes=l,K7(f,l)}}var p8={readContext:Zl,useCallback:Fu,useContext:Fu,useEffect:Fu,useImperativeHandle:Fu,useInsertionEffect:Fu,useLayoutEffect:Fu,useMemo:Fu,useReducer:Fu,useRef:Fu,useState:Fu,useDebugValue:Fu,useDeferredValue:Fu,useTransition:Fu,useMutableSource:Fu,useSyncExternalStore:Fu,useId:Fu,unstable_isNewReconciler:!1},qq={readContext:Zl,useCallback:function(f,u){return ol().memoizedState=[f,u===void 0?null:u],f},useContext:Zl,useEffect:$Q,useImperativeHandle:function(f,u,l){return l=l!==null&&l!==void 0?l.concat([f]):null,O8(4194308,4,bW.bind(null,u,f),l)},useLayoutEffect:function(f,u){return O8(4194308,4,f,u)},useInsertionEffect:function(f,u){return O8(4,2,f,u)},useMemo:function(f,u){var l=ol();return u=u===void 0?null:u,f=f(),l.memoizedState=[f,u],f},useReducer:function(f,u,l){var _=ol();return u=l!==void 0?l(u):u,_.memoizedState=_.baseState=u,f={pending:null,interleaved:null,lanes:0,dispatch:null,lastRenderedReducer:f,lastRenderedState:u},_.queue=f,f=f.dispatch=Oq.bind(null,X0,f),[_.memoizedState,f]},useRef:function(f){var u=ol();return f={current:f},u.memoizedState=f},useState:yQ,useDebugValue:x7,useDeferredValue:function(f){return ol().memoizedState=f},useTransition:function(){var f=yQ(!1),u=f[0];return f=Hq.bind(null,f[1]),ol().memoizedState=f,[u,f]},useMutableSource:function(){},useSyncExternalStore:function(f,u,l){var _=X0,y=ol();if(V0){if(l===void 0)throw Error(zf(407));l=l()}else{if(l=u(),o0===null)throw Error(zf(349));(ly&30)!==0||PW(_,u,l)}y.memoizedState=l;var $={value:l,getSnapshot:u};return y.queue=$,$Q(SW.bind(null,_,$,f),[f]),_.flags|=2048,r6(9,nW.bind(null,_,$,l,u),void 0,null),l},useId:function(){var f=ol(),u=o0.identifierPrefix;if(V0){var l=O1,_=H1;l=(_&~(1<<32-nl(_)-1)).toString(32)+l,u=":"+u+"R"+l,l=y6++,0",f=f.removeChild(f.firstChild)):typeof _.is==="string"?f=r.createElement(l,{is:_.is}):(f=r.createElement(l),l==="select"&&(r=f,_.multiple?r.multiple=!0:_.size&&(r.size=_.size))):f=r.createElementNS(f,l),f[al]=u,f[u6]=_,yz(f,u,!1,!1),u.stateNode=f;f:{switch(r=X9(l,_),l){case"dialog":Z0("cancel",f),Z0("close",f),y=_;break;case"iframe":case"object":case"embed":Z0("load",f),y=_;break;case"video":case"audio":for(y=0;yW$&&(u.flags|=128,_=!0,B3($,!1),u.lanes=4194304)}else{if(!_)if(f=h8(r),f!==null){if(u.flags|=128,_=!0,l=f.updateQueue,l!==null&&(u.updateQueue=l,u.flags|=4),B3($,!0),$.tail===null&&$.tailMode==="hidden"&&!r.alternate&&!V0)return Ju(u),null}else 2*S0()-$.renderingStartTime>W$&&l!==1073741824&&(u.flags|=128,_=!0,B3($,!1),u.lanes=4194304);$.isBackwards?(r.sibling=u.child,u.child=r):(l=$.last,l!==null?l.sibling=r:u.child=r,$.last=r)}if($.tail!==null)return u=$.tail,$.rendering=u,$.tail=u.sibling,$.renderingStartTime=S0(),u.sibling=null,l=L0.current,G0(L0,_?l&1|2:l&1),u;return Ju(u),null;case 22:case 23:return m7(),_=u.memoizedState!==null,f!==null&&f.memoizedState!==null!==_&&(u.flags|=8192),_&&(u.mode&1)!==0?(ou&1073741824)!==0&&(Ju(u),u.subtreeFlags&6&&(u.flags|=8192)):Ju(u),null;case 24:return null;case 25:return null}throw Error(zf(156,u.tag))}function Mq(f,u){switch(X7(u),u.tag){case 1:return Cu(u.type)&&C8(),f=u.flags,f&65536?(u.flags=f&-65537|128,u):null;case 3:return U$(),E0(Su),E0(Qu),S7(),f=u.flags,(f&65536)!==0&&(f&128)===0?(u.flags=f&-65537|128,u):null;case 5:return n7(u),null;case 13:if(E0(L0),f=u.memoizedState,f!==null&&f.dehydrated!==null){if(u.alternate===null)throw Error(zf(340));F$()}return f=u.flags,f&65536?(u.flags=f&-65537|128,u):null;case 19:return E0(L0),null;case 4:return U$(),null;case 10:return D7(u.type._context),null;case 22:case 23:return m7(),null;case 24:return null;default:return null}}var W8=!1,Uu=!1,Pq=typeof WeakSet==="function"?WeakSet:Set,Vf=null;function ey(f,u){var l=f.ref;if(l!==null)if(typeof l==="function")try{l(null)}catch(_){w0(f,u,_)}else l.current=null}function f7(f,u,l){try{l()}catch(_){w0(f,u,_)}}var KQ=!1;function nq(f,u){if(c9=M8,f=UW(),q7(f)){if("selectionStart"in f)var l={start:f.selectionStart,end:f.selectionEnd};else f:{l=(l=f.ownerDocument)&&l.defaultView||window;var _=l.getSelection&&l.getSelection();if(_&&_.rangeCount!==0){l=_.anchorNode;var{anchorOffset:y,focusNode:$}=_;_=_.focusOffset;try{l.nodeType,$.nodeType}catch(E){l=null;break f}var r=0,j=-1,A=-1,J=0,U=0,Q=f,W=null;u:for(;;){for(var G;;){if(Q!==l||y!==0&&Q.nodeType!==3||(j=r+y),Q!==$||_!==0&&Q.nodeType!==3||(A=r+_),Q.nodeType===3&&(r+=Q.nodeValue.length),(G=Q.firstChild)===null)break;W=Q,Q=G}for(;;){if(Q===f)break u;if(W===l&&++J===y&&(j=r),W===$&&++U===_&&(A=r),(G=Q.nextSibling)!==null)break;Q=W,W=Q.parentNode}Q=G}l=j===-1||A===-1?null:{start:j,end:A}}else l=null}l=l||{start:0,end:0}}else l=null;R9={focusedElem:f,selectionRange:l},M8=!1;for(Vf=u;Vf!==null;)if(u=Vf,f=u.child,(u.subtreeFlags&1028)!==0&&f!==null)f.return=u,Vf=f;else for(;Vf!==null;){u=Vf;try{var K=u.alternate;if((u.flags&1024)!==0)switch(u.tag){case 0:case 11:case 15:break;case 1:if(K!==null){var{memoizedProps:H,memoizedState:O}=K,z=u.stateNode,Z=z.getSnapshotBeforeUpdate(u.elementType===u.type?H:Tl(u.type,H),O);z.__reactInternalSnapshotBeforeUpdate=Z}break;case 3:var N=u.stateNode.containerInfo;N.nodeType===1?N.textContent="":N.nodeType===9&&N.documentElement&&N.removeChild(N.documentElement);break;case 5:case 6:case 4:case 17:break;default:throw Error(zf(163))}}catch(E){w0(u,u.return,E)}if(f=u.sibling,f!==null){f.return=u.return,Vf=f;break}Vf=u.return}return K=KQ,KQ=!1,K}function h3(f,u,l){var _=u.updateQueue;if(_=_!==null?_.lastEffect:null,_!==null){var y=_=_.next;do{if((y.tag&f)===f){var $=y.destroy;y.destroy=void 0,$!==void 0&&f7(u,l,$)}y=y.next}while(y!==_)}}function y2(f,u){if(u=u.updateQueue,u=u!==null?u.lastEffect:null,u!==null){var l=u=u.next;do{if((l.tag&f)===f){var _=l.create;l.destroy=_()}l=l.next}while(l!==u)}}function u7(f){var u=f.ref;if(u!==null){var l=f.stateNode;switch(f.tag){case 5:f=l;break;default:f=l}typeof u==="function"?u(f):u.current=f}}function jz(f){var u=f.alternate;u!==null&&(f.alternate=null,jz(u)),f.child=null,f.deletions=null,f.sibling=null,f.tag===5&&(u=f.stateNode,u!==null&&(delete u[al],delete u[u6],delete u[v9],delete u[Gq],delete u[Kq])),f.stateNode=null,f.return=null,f.dependencies=null,f.memoizedProps=null,f.memoizedState=null,f.pendingProps=null,f.stateNode=null,f.updateQueue=null}function Az(f){return f.tag===5||f.tag===3||f.tag===4}function NQ(f){f:for(;;){for(;f.sibling===null;){if(f.return===null||Az(f.return))return null;f=f.return}f.sibling.return=f.return;for(f=f.sibling;f.tag!==5&&f.tag!==6&&f.tag!==18;){if(f.flags&2)continue f;if(f.child===null||f.tag===4)continue f;else f.child.return=f,f=f.child}if(!(f.flags&2))return f.stateNode}}function l7(f,u,l){var _=f.tag;if(_===5||_===6)f=f.stateNode,u?l.nodeType===8?l.parentNode.insertBefore(f,u):l.insertBefore(f,u):(l.nodeType===8?(u=l.parentNode,u.insertBefore(f,l)):(u=l,u.appendChild(f)),l=l._reactRootContainer,l!==null&&l!==void 0||u.onclick!==null||(u.onclick=S8));else if(_!==4&&(f=f.child,f!==null))for(l7(f,u,l),f=f.sibling;f!==null;)l7(f,u,l),f=f.sibling}function _7(f,u,l){var _=f.tag;if(_===5||_===6)f=f.stateNode,u?l.insertBefore(f,u):l.appendChild(f);else if(_!==4&&(f=f.child,f!==null))for(_7(f,u,l),f=f.sibling;f!==null;)_7(f,u,l),f=f.sibling}var uu=null,Ml=!1;function I1(f,u,l){for(l=l.child;l!==null;)Fz(f,u,l),l=l.sibling}function Fz(f,u,l){if(dl&&typeof dl.onCommitFiberUnmount==="function")try{dl.onCommitFiberUnmount(o8,l)}catch(j){}switch(l.tag){case 5:Uu||ey(l,u);case 6:var _=uu,y=Ml;uu=null,I1(f,u,l),uu=_,Ml=y,uu!==null&&(Ml?(f=uu,l=l.stateNode,f.nodeType===8?f.parentNode.removeChild(l):f.removeChild(l)):uu.removeChild(l.stateNode));break;case 18:uu!==null&&(Ml?(f=uu,l=l.stateNode,f.nodeType===8?y9(f.parentNode,l):f.nodeType===1&&y9(f,l),o3(f)):y9(uu,l.stateNode));break;case 4:_=uu,y=Ml,uu=l.stateNode.containerInfo,Ml=!0,I1(f,u,l),uu=_,Ml=y;break;case 0:case 11:case 14:case 15:if(!Uu&&(_=l.updateQueue,_!==null&&(_=_.lastEffect,_!==null))){y=_=_.next;do{var $=y,r=$.destroy;$=$.tag,r!==void 0&&(($&2)!==0?f7(l,u,r):($&4)!==0&&f7(l,u,r)),y=y.next}while(y!==_)}I1(f,u,l);break;case 1:if(!Uu&&(ey(l,u),_=l.stateNode,typeof _.componentWillUnmount==="function"))try{_.props=l.memoizedProps,_.state=l.memoizedState,_.componentWillUnmount()}catch(j){w0(l,u,j)}I1(f,u,l);break;case 21:I1(f,u,l);break;case 22:l.mode&1?(Uu=(_=Uu)||l.memoizedState!==null,I1(f,u,l),Uu=_):I1(f,u,l);break;default:I1(f,u,l)}}function ZQ(f){var u=f.updateQueue;if(u!==null){f.updateQueue=null;var l=f.stateNode;l===null&&(l=f.stateNode=new Pq),u.forEach(function(_){var y=hq.bind(null,f,_);l.has(_)||(l.add(_),_.then(y,y))})}}function Dl(f,u){var l=u.deletions;if(l!==null)for(var _=0;_y&&(y=r),_&=~$}if(_=y,_=S0()-_,_=(120>_?120:480>_?480:1080>_?1080:1920>_?1920:3000>_?3000:4320>_?4320:1960*Cq(_/1960))-_,10<_){f.timeoutHandle=b9(t_.bind(null,f,Pu,Z1),_);break}t_(f,Pu,Z1);break;case 5:t_(f,Pu,Z1);break;default:throw Error(zf(329))}}}return iu(f,S0()),f.callbackNode===l?Qz.bind(null,f):null}function r7(f,u){var l=I3;return f.current.memoizedState.isDehydrated&&(d_(f,u).flags|=256),f=t8(f,u),f!==2&&(u=Pu,Pu=l,u!==null&&j7(u)),f}function j7(f){Pu===null?Pu=f:Pu.push.apply(Pu,f)}function iq(f){for(var u=f;;){if(u.flags&16384){var l=u.updateQueue;if(l!==null&&(l=l.stores,l!==null))for(var _=0;_f?16:f,s1===null)var _=!1;else{if(f=s1,s1=null,k8=0,(l0&6)!==0)throw Error(zf(331));var y=l0;l0|=4;for(Vf=f.current;Vf!==null;){var $=Vf,r=$.child;if((Vf.flags&16)!==0){var j=$.deletions;if(j!==null){for(var A=0;AS0()-I7?d_(f,0):h7|=l),iu(f,u)}function Nz(f,u){u===0&&((f.mode&1)===0?u=1:(u=y8,y8<<=1,(y8&130023424)===0&&(y8=4194304)));var l=Vu();f=X1(f,u),f!==null&&(A6(f,u,l),iu(f,l))}function vq(f){var u=f.memoizedState,l=0;u!==null&&(l=u.retryLane),Nz(f,l)}function hq(f,u){var l=0;switch(f.tag){case 13:var{stateNode:_,memoizedState:y}=f;y!==null&&(l=y.retryLane);break;case 19:_=f.stateNode;break;default:throw Error(zf(314))}_!==null&&_.delete(u),Nz(f,l)}var Zz;Zz=function(f,u,l){if(f!==null)if(f.memoizedProps!==u.pendingProps||Su.current)nu=!0;else{if((f.lanes&l)===0&&(u.flags&128)===0)return nu=!1,Dq(f,u,l);nu=(f.flags&131072)!==0?!0:!1}else nu=!1,V0&&(u.flags&1048576)!==0&&VW(u,R8,u.index);switch(u.lanes=0,u.tag){case 2:var _=u.type;V8(f,u),f=u.pendingProps;var y=A$(u,Qu.current);$$(u,l),y=i7(null,u,_,f,y,l);var $=c7();return u.flags|=1,typeof y==="object"&&y!==null&&typeof y.render==="function"&&y.$$typeof===void 0?(u.tag=1,u.memoizedState=null,u.updateQueue=null,Cu(_)?($=!0,i8(u)):$=!1,u.memoizedState=y.state!==null&&y.state!==void 0?y.state:null,M7(u),y.updater=_2,u.stateNode=y,y._reactInternals=u,k9(u,_,f,l),u=o9(null,u,_,!0,$,l)):(u.tag=0,V0&&$&&L7(u),Ou(null,u,y,l),u=u.child),u;case 16:_=u.elementType;f:{switch(V8(f,u),f=u.pendingProps,y=_._init,_=y(_._payload),u.type=_,y=u.tag=pq(_),f=Tl(_,f),y){case 0:u=s9(null,u,_,f,l);break f;case 1:u=WQ(null,u,_,f,l);break f;case 11:u=UQ(null,u,_,f,l);break f;case 14:u=QQ(null,u,_,Tl(_.type,f),l);break f}throw Error(zf(306,_,""))}return u;case 0:return _=u.type,y=u.pendingProps,y=u.elementType===_?y:Tl(_,y),s9(f,u,_,y,l);case 1:return _=u.type,y=u.pendingProps,y=u.elementType===_?y:Tl(_,y),WQ(f,u,_,y,l);case 3:f:{if(uz(u),f===null)throw Error(zf(387));_=u.pendingProps,$=u.memoizedState,y=$.element,wW(f,u),v8(u,_,null,l);var r=u.memoizedState;if(_=r.element,$.isDehydrated)if($={element:_,isDehydrated:!1,cache:r.cache,pendingSuspenseBoundaries:r.pendingSuspenseBoundaries,transitions:r.transitions},u.updateQueue.baseState=$,u.memoizedState=$,u.flags&256){y=Q$(Error(zf(423)),u),u=zQ(f,u,_,l,y);break f}else if(_!==y){y=Q$(Error(zf(424)),u),u=zQ(f,u,_,l,y);break f}else for(au=e1(u.stateNode.containerInfo.firstChild),du=u,V0=!0,Pl=null,l=BW(u,null,_,l),u.child=l;l;)l.flags=l.flags&-3|4096,l=l.sibling;else{if(F$(),_===y){u=B1(f,u,l);break f}Ou(f,u,_,l)}u=u.child}return u;case 5:return DW(u),f===null&&p9(u),_=u.type,y=u.pendingProps,$=f!==null?f.memoizedProps:null,r=y.children,x9(_,y)?r=null:$!==null&&x9(_,$)&&(u.flags|=32),fz(f,u),Ou(f,u,r,l),u.child;case 6:return f===null&&p9(u),null;case 13:return lz(f,u,l);case 4:return P7(u,u.stateNode.containerInfo),_=u.pendingProps,f===null?u.child=J$(u,null,_,l):Ou(f,u,_,l),u.child;case 11:return _=u.type,y=u.pendingProps,y=u.elementType===_?y:Tl(_,y),UQ(f,u,_,y,l);case 7:return Ou(f,u,u.pendingProps,l),u.child;case 8:return Ou(f,u,u.pendingProps.children,l),u.child;case 12:return Ou(f,u,u.pendingProps.children,l),u.child;case 10:f:{if(_=u.type._context,y=u.pendingProps,$=u.memoizedProps,r=y.value,G0(x8,_._currentValue),_._currentValue=r,$!==null)if(Cl($.value,r)){if($.children===y.children&&!Su.current){u=B1(f,u,l);break f}}else for($=u.child,$!==null&&($.return=u);$!==null;){var j=$.dependencies;if(j!==null){r=$.child;for(var A=j.firstContext;A!==null;){if(A.context===_){if($.tag===1){A=V1(-1,l&-l),A.tag=2;var J=$.updateQueue;if(J!==null){J=J.shared;var U=J.pending;U===null?A.next=A:(A.next=U.next,U.next=A),J.pending=A}}$.lanes|=l,A=$.alternate,A!==null&&(A.lanes|=l),m9($.return,l,u),j.lanes|=l;break}A=A.next}}else if($.tag===10)r=$.type===u.type?null:$.child;else if($.tag===18){if(r=$.return,r===null)throw Error(zf(341));r.lanes|=l,j=r.alternate,j!==null&&(j.lanes|=l),m9(r,l,u),r=$.sibling}else r=$.child;if(r!==null)r.return=$;else for(r=$;r!==null;){if(r===u){r=null;break}if($=r.sibling,$!==null){$.return=r.return,r=$;break}r=r.return}$=r}Ou(f,u,y.children,l),u=u.child}return u;case 9:return y=u.type,_=u.pendingProps.children,$$(u,l),y=Zl(y),_=_(y),u.flags|=1,Ou(f,u,_,l),u.child;case 14:return _=u.type,y=Tl(_,u.pendingProps),y=Tl(_.type,y),QQ(f,u,_,y,l);case 15:return dW(f,u,u.type,u.pendingProps,l);case 17:return _=u.type,y=u.pendingProps,y=u.elementType===_?y:Tl(_,y),V8(f,u),u.tag=1,Cu(_)?(f=!0,i8(u)):f=!1,$$(u,l),sW(u,_,y),k9(u,_,y,l),o9(null,u,_,!0,f,l);case 19:return _z(f,u,l);case 22:return eW(f,u,l)}throw Error(zf(156,u.tag))};function Ez(f,u){return gQ(f,u)}function Iq(f,u,l,_){this.tag=f,this.key=l,this.sibling=this.child=this.return=this.stateNode=this.type=this.elementType=null,this.index=0,this.ref=null,this.pendingProps=u,this.dependencies=this.memoizedState=this.updateQueue=this.memoizedProps=null,this.mode=_,this.subtreeFlags=this.flags=0,this.deletions=null,this.childLanes=this.lanes=0,this.alternate=null}function Kl(f,u,l,_){return new Iq(f,u,l,_)}function k7(f){return f=f.prototype,!(!f||!f.isReactComponent)}function pq(f){if(typeof f==="function")return k7(f)?1:0;if(f!==void 0&&f!==null){if(f=f.$$typeof,f===Q7)return 11;if(f===W7)return 14}return 2}function __(f,u){var l=f.alternate;return l===null?(l=Kl(f.tag,u,f.key,f.mode),l.elementType=f.elementType,l.type=f.type,l.stateNode=f.stateNode,l.alternate=f,f.alternate=l):(l.pendingProps=u,l.type=f.type,l.flags=0,l.subtreeFlags=0,l.deletions=null),l.flags=f.flags&14680064,l.childLanes=f.childLanes,l.lanes=f.lanes,l.child=f.child,l.memoizedProps=f.memoizedProps,l.memoizedState=f.memoizedState,l.updateQueue=f.updateQueue,u=f.dependencies,l.dependencies=u===null?null:{lanes:u.lanes,firstContext:u.firstContext},l.sibling=f.sibling,l.index=f.index,l.ref=f.ref,l}function X8(f,u,l,_,y,$){var r=2;if(_=f,typeof f==="function")k7(f)&&(r=1);else if(typeof f==="string")r=5;else f:switch(f){case py:return e_(l.children,y,$,u);case U7:r=8,y|=8;break;case G9:return f=Kl(12,l,u,y|2),f.elementType=G9,f.lanes=$,f;case K9:return f=Kl(13,l,u,y),f.elementType=K9,f.lanes=$,f;case N9:return f=Kl(19,l,u,y),f.elementType=N9,f.lanes=$,f;case DQ:return r2(l,y,$,u);default:if(typeof f==="object"&&f!==null)switch(f.$$typeof){case YQ:r=10;break f;case wQ:r=9;break f;case Q7:r=11;break f;case W7:r=14;break f;case p1:r=16,_=null;break f}throw Error(zf(130,f==null?f:typeof f,""))}return u=Kl(r,l,u,y),u.elementType=f,u.type=_,u.lanes=$,u}function e_(f,u,l,_){return f=Kl(7,f,_,u),f.lanes=l,f}function r2(f,u,l,_){return f=Kl(22,f,_,u),f.elementType=DQ,f.lanes=l,f.stateNode={isHidden:!1},f}function Q9(f,u,l){return f=Kl(6,f,null,u),f.lanes=l,f}function W9(f,u,l){return u=Kl(4,f.children!==null?f.children:[],f.key,u),u.lanes=l,u.stateNode={containerInfo:f.containerInfo,pendingChildren:null,implementation:f.implementation},u}function mq(f,u,l,_,y){this.tag=u,this.containerInfo=f,this.finishedWork=this.pingCache=this.current=this.pendingChildren=null,this.timeoutHandle=-1,this.callbackNode=this.pendingContext=this.context=null,this.callbackPriority=0,this.eventTimes=ar(0),this.expirationTimes=ar(-1),this.entangledLanes=this.finishedLanes=this.mutableReadLanes=this.expiredLanes=this.pingedLanes=this.suspendedLanes=this.pendingLanes=0,this.entanglements=ar(0),this.identifierPrefix=_,this.onRecoverableError=y,this.mutableSourceEagerHydrationData=null}function t7(f,u,l,_,y,$,r,j,A){return f=new mq(f,u,l,j,A),u===1?(u=1,$===!0&&(u|=8)):u=0,$=Kl(3,null,null,u),f.current=$,$.stateNode=f,$.memoizedState={element:_,isDehydrated:l,cache:null,transitions:null,pendingSuspenseBoundaries:null},M7($),f}function gq(f,u,l){var _=3{function Lz(){if(typeof __REACT_DEVTOOLS_GLOBAL_HOOK__>"u"||typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE!=="function")return;try{__REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE(Lz)}catch(f){console.error(f)}}Lz(),Xz.exports=qz()});var Yz=su((e7)=>{var Bz=d7();e7.createRoot=Bz.createRoot,e7.hydrateRoot=Bz.hydrateRoot;var aq});var KK=su((g2)=>{var pB=O0(),mB=Symbol.for("react.element"),gB=Symbol.for("react.fragment"),kB=Object.prototype.hasOwnProperty,tB=pB.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.ReactCurrentOwner,sB={key:!0,ref:!0,__self:!0,__source:!0};function GK(f,u,l){var _,y={},$=null,r=null;l!==void 0&&($=""+l),u.key!==void 0&&($=""+u.key),u.ref!==void 0&&(r=u.ref);for(_ in u)kB.call(u,_)&&!sB.hasOwnProperty(_)&&(y[_]=u[_]);if(f&&f.defaultProps)for(_ in u=f.defaultProps,u)y[_]===void 0&&(y[_]=u[_]);return{$$typeof:mB,type:f,key:$,ref:r,props:y,_owner:tB.current}}g2.Fragment=gB;g2.jsx=GK;g2.jsxs=GK});var ZK=su((Di,NK)=>{NK.exports=KK()});var sN=su((tN)=>{var s$=O0();function QT(f,u){return f===u&&(f!==0||1/f===1/u)||f!==f&&u!==u}var WT=typeof Object.is==="function"?Object.is:QT,zT=s$.useState,GT=s$.useEffect,KT=s$.useLayoutEffect,NT=s$.useDebugValue;function ZT(f,u){var l=u(),_=zT({inst:{value:l,getSnapshot:u}}),y=_[0].inst,$=_[1];return KT(function(){y.value=l,y.getSnapshot=u,IF(y)&&$({inst:y})},[f,l,u]),GT(function(){return IF(y)&&$({inst:y}),f(function(){IF(y)&&$({inst:y})})},[f]),NT(l),l}function IF(f){var u=f.getSnapshot;f=f.value;try{var l=u();return!WT(f,l)}catch(_){return!0}}function ET(f,u){return u()}var HT=typeof window>"u"||typeof window.document>"u"||typeof window.document.createElement>"u"?ET:ZT;tN.useSyncExternalStore=s$.useSyncExternalStore!==void 0?s$.useSyncExternalStore:HT});var aN=su((Vh,oN)=>{oN.exports=sN()});var eN=su((dN)=>{var x5=O0(),OT=aN();function VT(f,u){return f===u&&(f!==0||1/f===1/u)||f!==f&&u!==u}var qT=typeof Object.is==="function"?Object.is:VT,LT=OT.useSyncExternalStore,XT=x5.useRef,BT=x5.useEffect,YT=x5.useMemo,wT=x5.useDebugValue;dN.useSyncExternalStoreWithSelector=function(f,u,l,_,y){var $=XT(null);if($.current===null){var r={hasValue:!1,value:null};$.current=r}else r=$.current;$=YT(function(){function A(G){if(!J){if(J=!0,U=G,G=_(G),y!==void 0&&r.hasValue){var K=r.value;if(y(K,G))return Q=K}return Q=G}if(K=Q,qT(U,G))return K;var H=_(G);if(y!==void 0&&y(K,H))return U=G,K;return U=G,Q=H}var J=!1,U,Q,W=l===void 0?null:l;return[function(){return A(u())},W===null?void 0:function(){return A(W())}]},[u,l,_,y]);var j=LT(f,$[0],$[1]);return BT(function(){r.hasValue=!0,r.value=j},[j]),wT(j),j}});var uZ=su((Lh,fZ)=>{fZ.exports=eN()});var i_=cf(O0(),1);var g4="北京时间";var gO={timeZone:"Asia/Shanghai",hour12:!1},kO={timeZone:"Asia/Shanghai",hour12:!1},tO=new Intl.DateTimeFormat("en-CA",{timeZone:"Asia/Shanghai",year:"numeric",month:"2-digit",day:"2-digit",hour:"2-digit",minute:"2-digit",hourCycle:"h23"});function Cr(f){if(f===null||f===void 0||f==="")return null;let u=f instanceof Date?f:new Date(f);return Number.isNaN(u.getTime())?null:u}function JU(f){let u=Cr(f);if(!u)return null;return tO.formatToParts(u).reduce((l,_)=>{if(_.type!=="literal")l[_.type]=_.value;return l},{})}function Nf(f){let u=Cr(f);return u?u.toLocaleString("zh-CN",gO):"--"}function W0(f){let u=Cr(f);return u?u.toLocaleTimeString("zh-CN",kO):"--"}function ir(f){let u=JU(f);if(!u)return"";let l=u.hour==="24"?"00":u.hour;return`${u.year}-${u.month}-${u.day}T${l}:${u.minute}`}function UU(f=new Date){let u=JU(f);if(!u)return"";return`${u.year}-${u.month}-${u.day}`}function QU(f){if(!f)return null;let u=/^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2})(?::(\d{2}))?$/.exec(f);if(!u)return null;let[,l,_,y,$,r,j="00"]=u,A=Date.UTC(Number(l),Number(_)-1,Number(y),Number($)-8,Number(r),Number(j)),J=new Date(A),U=ir(J);return Number.isNaN(J.getTime())||U!==`${l}-${_}-${y}T${$}:${r}`?null:J.toISOString()}var wH=cf(Yz(),1);var W2=cf(O0(),1);var wz=cf(O0(),1),Q6=wz.default.createElement;function dq({active:f=!0,label:u="正在加载"}){if(!f)return null;return Q6("span",{className:"loading-spinner-indicator",role:"status","aria-label":u,title:u,"data-testid":"loading-title-indicator"},Q6("span",{className:"loading-spinner-ring","aria-hidden":!0}))}function j0({title:f,children:u,loading:l,level:_=2,className:y="",label:$="正在加载"}){return Q6(_===3?"h3":"h2",{className:`loading-title ${l?"is-loading":""} ${y}`.trim()},Q6("span",{className:"loading-title-text"},u??f),Q6(dq,{active:Boolean(l),label:$}))}class K$ extends Error{unideskRequestError=!0;meta;constructor(f,u){super(f);this.name="UniDeskRequestError",this.meta=u}}function eq(f){return new Promise((u)=>setTimeout(u,f))}function G6(f,u="操作失败"){return f instanceof Error?f.message:String(f||u)}function U2(f,u=500){if(f===null||f===void 0)return"";let l=typeof f==="string"?f:JSON.stringify(f),_=String(l||"").replace(/\s+/gu," ").trim();return _.length>u?`${_.slice(0,u)}...`:_}function fL(f){try{let u=typeof location<"u"&&location.origin?location.origin:"http://localhost";return new URL(f,u).toString()}catch{return f}}function Dz(f){return String(f.method||"GET").toUpperCase()}function uL(f){if(f===null||f===void 0)return!1;if(typeof f!=="object")return!1;if(typeof Blob<"u"&&f instanceof Blob)return!1;if(typeof FormData<"u"&&f instanceof FormData)return!1;if(typeof URLSearchParams<"u"&&f instanceof URLSearchParams)return!1;if(typeof ArrayBuffer<"u"&&f instanceof ArrayBuffer)return!1;return!0}function Tz(f){let u=new Headers(f.headers||{}),l=uL(f.body)?JSON.stringify(f.body):f.body;if(l&&!u.has("content-type")&&typeof l==="string")u.set("content-type","application/json");return{...f,credentials:f.credentials||"same-origin",body:l,headers:u}}function Mz(f){if(f?.error&&typeof f.error==="object"&&typeof f.error.message==="string")return f.error.message;if(typeof f?.error==="string")return f.error;if(typeof f?.message==="string")return f.message;if(typeof f?.detail==="string")return f.detail;return""}function lL(f,u){if(!f||typeof f!=="object"||Array.isArray(f))return!1;return u.some((l)=>l!==!1&&f[l]===!1)}function W6(f,u,l,_,y={}){return{kind:f,method:l,url:fL(u),occurredAt:_.toISOString(),...y}}function z6(f,u){if(!f)return"请求失败";return`HTTP ${f}${u?` ${u}`:""}`}function Pz(f){try{return{body:f?JSON.parse(f):null,parseError:""}}catch(u){return{body:{text:f},parseError:G6(u,"parse failed")}}}async function Mf(f,u={},l=0){let{failureFields:_=["ok"],strictJson:y=!1,retryInvalidJson:$=0,retryDelayMs:r=120,invalidJsonPrefix:j="服务返回了无效 JSON",invalidJsonPreview:A=!1,responsePreviewLength:J=500,...U}=u,Q=Dz(U),W=new Date,G;try{G=await fetch(f,Tz(U))}catch(O){let z=G6(O,"网络请求失败");throw new K$(z,W6("network",f,Q,W,{upstreamMessage:z}))}let K=await G.text(),H=Pz(K);if(H.parseError){if(y&&Q==="GET"&&l<$)return await eq(r),Mf(f,u,l+1);if(y){let O=A?`;响应预览:${U2(K,180)}`:"";throw new K$(`${j}(${K.length} bytes):${H.parseError}${O}`,W6("parse",f,Q,W,{status:G.status,statusText:G.statusText,parseError:H.parseError,responsePreview:U2(K,J)}))}}if(!G.ok||lL(H.body,_)){let O=Mz(H.body),z=O||z6(G.status,G.statusText);throw new K$(z,W6("http",f,Q,W,{status:G.status,statusText:G.statusText,upstreamMessage:O,responsePreview:U2(H.parseError?K:H.body,J)}))}return H.body}async function nz(f,u={}){let l=Dz(u),_=new Date,y;try{y=await fetch(f,Tz(u))}catch(J){let U=G6(J,"网络请求失败");throw new K$(U,W6("network",f,l,_,{upstreamMessage:U}))}if(y.ok)return y.blob();let $=await y.text(),r=Pz($),j=Mz(r.body),A=j||z6(y.status,y.statusText);throw new K$(A,W6("http",f,l,_,{status:y.status,statusText:y.statusText,upstreamMessage:j,responsePreview:U2(r.parseError?$:r.body),parseError:r.parseError||void 0}))}function Sz(f){return Boolean(f&&typeof f==="object"&&f.unideskRequestError===!0&&f.meta)}function _L(f){if(!f)return"";let u=new Date(f);if(Number.isNaN(u.getTime()))return f;return`${Nf(u)} ${g4}`}function fj(f,u="操作失败"){if(Sz(f)){let y=f.meta.kind==="parse"?"响应解析失败":f.meta.kind==="network"?"网络请求失败":f.meta.status&&(f.meta.status<200||f.meta.status>=300)?z6(f.meta.status,f.meta.statusText):"应用请求失败",$=f.meta.status?z6(f.meta.status):"",r=(A)=>!A||A===y||A===$,j=!r(f.message)?f.message:r(f.meta.upstreamMessage)?"":f.meta.upstreamMessage||"";return{title:y,message:j,status:f.meta.status,statusText:f.meta.statusText,method:f.meta.method,url:f.meta.url,occurredAt:_L(f.meta.occurredAt),responsePreview:f.meta.responsePreview,parseError:f.meta.parseError,structured:!0}}let _=G6(f,u).split(/\r?\n/u);return{title:_[0]||u,message:_.slice(1).join(` -`),structured:_.length>1}}function yL(f,u="操作失败"){let l=fj(f,u),_=[l.title];if(l.message)_.push(`原因: ${l.message}`);if(l.method||l.url)_.push(`请求: ${[l.method,l.url].filter(Boolean).join(" ")}`);if(l.status)_.push(`状态: ${z6(l.status,l.statusText)}`);if(l.occurredAt)_.push(`时间: ${l.occurredAt}`);if(l.parseError)_.push(`解析错误: ${l.parseError}`);if(l.responsePreview&&l.responsePreview!==l.message)_.push(`响应预览: ${l.responsePreview}`);return _.filter(Boolean).join(` -`)}function Df(f,u="操作失败"){return Sz(f)?yL(f,u):G6(f,u)}var Cz=cf(O0(),1);var F_=Cz.default.createElement;function K6(f,u){return u?[F_("dt",{key:`${f}-label`},f),F_("dd",{key:f},u)]:null}function A0({error:f,wide:u=!1,fallback:l="操作失败",className:_=""}){if(!f)return null;let y=fj(f,l),$=[K6("请求",[y.method,y.url].filter(Boolean).join(" ")),K6("状态",y.status?`HTTP ${y.status}${y.statusText?` ${y.statusText}`:""}`:""),K6("时间",y.occurredAt),K6("解析错误",y.parseError),K6("响应预览",y.responsePreview)].filter(Boolean);return F_("div",{className:`form-error unidesk-error${u?" wide":""}${_?` ${_}`:""}`,role:"alert","data-testid":"unidesk-error"},F_("div",{className:"unidesk-error-title"},F_("strong",null,y.title),y.status?F_("span",{className:"unidesk-error-code"},`HTTP ${y.status}`):null),y.message?F_("pre",{className:"unidesk-error-message"},y.message):null,$.length>0?F_("dl",{className:"unidesk-error-details"},$):null)}var f1=cf(O0(),1),iz=f1.default.createContext(null);function cz({children:f}){let[u,l]=f1.default.useState([]),[_,y]=f1.default.useState(Date.now()),$=f1.default.useCallback((Q,W)=>{let K={id:`notif_${Date.now()}_${Math.random().toString(36).slice(2,8)}`,type:Q,message:W,timestamp:Date.now()};l((H)=>{let O=[...H,K];if(O.length>50)return O.slice(-50);return O})},[]),r=f1.default.useCallback((Q)=>{l((W)=>W.filter((G)=>G.id!==Q))},[]),j=f1.default.useCallback(()=>{l([]),y(Date.now())},[]),A=f1.default.useMemo(()=>{return u.filter((Q)=>Q.timestamp>_).length},[u,_]),J=A>0,U={notifications:u,addNotification:$,removeNotification:r,clearNotifications:j,unreadCount:A,hasUnread:J};return $L(iz.Provider,{value:U},f)}var $L=f1.default.createElement;function Lu(){let f=f1.default.useContext(iz);if(!f)throw Error("useNotification must be used within NotificationProvider");return f}var b=W2.default.createElement,{useEffect:Q2}=W2.default,N$=W2.default.useState;function Wu(f,u={}){return Mf(f,{failureFields:["ok","success"],...u})}function Xu(f,u){return`${f}/microservices/baidu-netdisk/proxy${u}`}function rL(f){let u=Number(f);return Number.isFinite(u)?u.toLocaleString("zh-CN"):"--"}function J_(f){let u=Number(f);if(!Number.isFinite(u)||u<=0)return"--";let l=["B","KB","MB","GB","TB"],_=u,y=0;while(_>=1024&&y{y?.stopPropagation?.(),l(f,u)}},"查看原始JSON")}function E$({title:f,text:u}){return b("div",{className:"empty-state"},b("strong",null,f),b("span",null,u))}function H$({title:f,text:u,href:l,badge:_,testId:y}){return b("a",{className:"doc-link-card",href:l,target:"_blank",rel:"noreferrer","data-testid":y},b("span",null,_||"DOC"),b("strong",null,f),b("p",null,u),b("code",null,l))}function jL(f){return f?.runtime&&typeof f.runtime==="object"&&!Array.isArray(f.runtime)?f.runtime:{}}function AL(f){return f?.backend&&typeof f.backend==="object"&&!Array.isArray(f.backend)?f.backend:{}}function FL(f){return f?.repository&&typeof f.repository==="object"&&!Array.isArray(f.repository)?f.repository:{}}function JL(f){return Array.isArray(f?.files)?f.files:[]}function UL(f){return Array.isArray(f?.jobs)?f.jobs:[]}function QL(f,u){if(!f||f===u)return u;let l=f.replace(/\/+$/u,""),_=l.slice(0,l.lastIndexOf("/"))||u;return _.lengthI.id==="baidu-netdisk")||null,[y,$]=N$({loading:!1,actionLoading:!1,error:"",message:"",health:null,account:null,files:null,transfers:null,logs:null,selfTest:null,refreshedAt:null}),[r,j]=N$("/"),[A,J]=N$(null),[U,Q]=N$(""),[W,G]=N$({localPath:"sample.txt",remotePath:"/sample.txt"}),[K,H]=N$({fsId:"",localPath:"downloads/"}),{addNotification:O}=Lu(),z=y.health?.baidu?.appRoot||y.account?.rootPath||"/";Q2(()=>{G((I)=>{let ff=new Set(["/sample.txt","/apps/UniDeskBaiduNetdisk/sample.txt"]);if(I.remotePath&&!ff.has(I.remotePath))return I;let yf=uj(z,"sample.txt");return I.remotePath===yf?I:{...I,remotePath:yf}})},[z]);async function Z(I=r){let yf=await Wu(Xu(l,`/api/files?dir=${encodeURIComponent(I||z)}&limit=100`));$((rf)=>({...rf,files:yf}))}async function N(){let I=await Wu(Xu(l,"/api/transfers?limit=80"));$((ff)=>({...ff,transfers:I}))}async function E(){if(!_)return;$((I)=>({...I,loading:!0,error:"",message:""}));try{let I=await Wu(`${l}/microservices/baidu-netdisk/health`),ff=I?.baidu?.appRoot||z,yf=null,rf=null;if(I?.auth?.loggedIn){yf=await Wu(Xu(l,"/api/account?refresh=1"));let Gf=r&&r.startsWith(ff)?r:ff;j(Gf),rf=await Wu(Xu(l,`/api/files?dir=${encodeURIComponent(Gf)}&limit=100`))}else j(ff);let Wf=await Wu(Xu(l,"/api/transfers?limit=80")),Ef=await Wu(Xu(l,"/logs?limit=60"));$((Gf)=>({...Gf,loading:!1,health:I,account:yf?.account||null,files:rf,transfers:Wf,logs:Ef,refreshedAt:new Date}))}catch(I){$((ff)=>({...ff,loading:!1,error:Df(I,"百度网盘服务加载失败")}))}}async function q(){$((I)=>({...I,actionLoading:!0,error:"",message:""}));try{let I=await Wu(Xu(l,"/api/auth/device/start"),{method:"POST",body:{}});J(I.session||null),$((ff)=>({...ff,actionLoading:!1,message:"设备码已生成,请扫码授权"}))}catch(I){$((ff)=>({...ff,actionLoading:!1,error:Df(I,"创建设备码失败")}))}}async function Y(I=!1){if(!A?.id)return;if(I)$((ff)=>({...ff,actionLoading:!0,error:""}));try{let ff=await Wu(Xu(l,`/api/auth/device/status?sessionId=${encodeURIComponent(A.id)}`));if(J(ff.session||null),ff.session?.status==="succeeded")$((yf)=>({...yf,actionLoading:!1,message:"授权成功,正在刷新账号与文件列表"})),await E();else if(I)$((yf)=>({...yf,actionLoading:!1}))}catch(ff){$((yf)=>({...yf,actionLoading:!1,error:Df(ff,"轮询登录状态失败")}))}}async function w(){$((I)=>({...I,actionLoading:!0,error:"",message:""}));try{await Wu(Xu(l,"/api/auth/logout"),{method:"POST",body:{}}),J(null),$((I)=>({...I,actionLoading:!1,account:null,files:null,message:"本地 token 已清除"})),await E()}catch(I){$((ff)=>({...ff,actionLoading:!1,error:Df(I,"退出登录失败")}))}}async function B(I){I.preventDefault();let ff=U.trim();if(!ff)return;$((yf)=>({...yf,actionLoading:!0,error:"",message:""}));try{await Wu(Xu(l,"/api/folders"),{method:"POST",body:{path:uj(r,ff)}}),Q(""),$((yf)=>({...yf,actionLoading:!1,message:"文件夹已创建"})),await Z(r)}catch(yf){$((rf)=>({...rf,actionLoading:!1,error:Df(yf,"创建文件夹失败")}))}}async function P(I){if(!I)return;$((ff)=>({...ff,actionLoading:!0,error:"",message:""}));try{await Wu(Xu(l,"/api/files/manage"),{method:"POST",body:{opera:"delete",filelist:[{path:I}],async:1}}),$((ff)=>({...ff,actionLoading:!1,message:"删除任务已提交"})),await Z(r)}catch(ff){$((yf)=>({...yf,actionLoading:!1,error:Df(ff,"删除失败")}))}}async function h(I){I.preventDefault(),$((ff)=>({...ff,actionLoading:!0,error:"",message:""}));try{await Wu(Xu(l,"/api/transfers/upload-from-path"),{method:"POST",body:W}),$((ff)=>({...ff,actionLoading:!1,message:"上传任务已入队"})),await N()}catch(ff){$((yf)=>({...yf,actionLoading:!1,error:Df(ff,"上传任务创建失败")}))}}async function M(I){I.preventDefault(),$((ff)=>({...ff,actionLoading:!0,error:"",message:""}));try{await Wu(Xu(l,"/api/transfers/download-to-path"),{method:"POST",body:K}),$((ff)=>({...ff,actionLoading:!1,message:"下载任务已入队"})),await N()}catch(ff){$((yf)=>({...yf,actionLoading:!1,error:Df(ff,"下载任务创建失败")}))}}async function n(I,ff){$((yf)=>({...yf,actionLoading:!0,error:"",message:""}));try{await Wu(Xu(l,`/api/transfers/${encodeURIComponent(I)}/${ff}`),{method:"POST",body:{}}),$((yf)=>({...yf,actionLoading:!1,message:ff==="cancel"?"已请求取消任务":"任务已重新入队"})),await N()}catch(yf){$((rf)=>({...rf,actionLoading:!1,error:Df(yf,"任务操作失败")}))}}async function S(){$((I)=>({...I,actionLoading:!0,error:"",message:"正在运行上传/下载自测..."}));try{let I=await Wu(Xu(l,"/api/self-test"),{method:"POST",body:{}});$((ff)=>({...ff,actionLoading:!1,selfTest:I,message:`上传/下载自测通过:${I.remotePath||""}`})),await Z(r),await N()}catch(I){$((ff)=>({...ff,actionLoading:!1,error:Df(I,"上传/下载自测失败")}))}}if(Q2(()=>{if(!_)return;E();return},[_?.id,_?.runtime?.providerStatus]),Q2(()=>{if(!A?.id||A.status!=="pending")return;let I=window.setInterval(()=>void Y(!1),Math.max(5000,Number(A.pollIntervalSeconds||5)*1000));return()=>window.clearInterval(I)},[A?.id,A?.status,A?.pollIntervalSeconds]),Q2(()=>{if(!_)return;let I=window.setInterval(()=>void N(),5000);return()=>window.clearInterval(I)},[_?.id]),!_)return b(E$,{title:"Baidu Netdisk 未登记",text:"请在 config.json 的 microservices 中登记用户服务 id=baidu-netdisk"});let T=jL(_),i=FL(_),C=AL(_),v=y.health||{},X=y.account||v.auth?.account||null,D=v.auth||{},p=JL(y.files),m=UL(y.transfers),s=X?.quota||{},d=Boolean(D.loggedIn||X),a=Boolean(D.configured);return b("div",{className:"baidu-netdisk-page","data-testid":"baidu-netdisk-page"},b(Ay,{title:"Baidu Netdisk 工作台",eyebrow:"Containerized Storage Gateway",loading:y.loading,actions:b("div",{className:"panel-actions"},b("a",{className:"ghost-btn",href:"/docs/issue/baidu-netdisk-env-setup.md",target:"_blank",rel:"noreferrer","data-testid":"baidu-netdisk-config-doc-link"},"配置文档"),b("button",{type:"button",className:"ghost-btn",onClick:E,disabled:y.loading,"data-testid":"baidu-netdisk-refresh"},y.loading?"刷新中":"刷新"),b(w1,{title:"Baidu Netdisk 用户服务",data:_,onOpen:u,testId:"raw-baidu-netdisk-service"}))},b("div",{className:"baidu-netdisk-hero"},b("div",null,b("div",{className:"node-version-line"},b(jy,{status:T.providerStatus==="online"?"online":"warn"},T.providerStatus||"unknown"),b("span",null,_.providerId),b(jy,{status:C.public?"warn":"private"},C.public?"公网暴露":"仅 UniDesk frontend 代理访问")),b("p",{className:"muted paragraph"},_.description)),b("div",{className:"microservice-ref-card"},b("span",null,"Repo"),b("strong",null,i.url||"--"),b("code",null,i.commitId||"--")),b("div",{className:"microservice-ref-card"},b("span",null,"Private Backend"),b("strong",null,`${C.nodeBindHost||"--"}:${C.nodePort||"--"}`),b("code",null,`${i.composeFile||"--"} / ${i.composeService||"--"}`))),b(A0,{error:y.error,wide:!0})),b("div",{className:"metric-grid"},b(Z$,{label:"Health",value:v.ok?"OK":"--",hint:v.storage?.postgres||"postgres",tone:v.ok?"ok":"warn"}),b(Z$,{label:"OAuth",value:a?"已配置":"待配置",hint:a?"client + secret + token key":"需要设置 UNIDESK_BAIDU_NETDISK_*",tone:a?"ok":"warn"}),b(Z$,{label:"Login",value:d?"已登录":"未登录",hint:X?.username||"Device Code QR",tone:d?"ok":"warn"}),b(Z$,{label:"Work Root",value:WL(z),hint:z}),b(Z$,{label:"Quota",value:J_(s.used),hint:s.total?`${s.usedPercent||0}% / ${J_(s.total)}`:"授权后刷新"}),b(Z$,{label:"Transfers",value:rL(m.length),hint:`running ${y.transfers?.counts?.running||0} / failed ${y.transfers?.counts?.failed||0}`})),b("div",{className:"baidu-netdisk-grid"},b(Ay,{title:"配置与文档",eyebrow:"Deployment References",className:"baidu-docs-panel",actions:b("div",{className:"panel-actions inline-actions"},b("a",{className:"ghost-btn",href:"/docs/issue/baidu-netdisk-env-setup.md",target:"_blank",rel:"noreferrer"},"打开环境配置"),b("a",{className:"ghost-btn",href:"/docs/issue/baidu-netdisk-user-service.md",target:"_blank",rel:"noreferrer"},"打开服务方案"))},b("p",{className:"muted paragraph"},a?"OAuth 运行时变量已配置;如需轮换密钥、迁移部署或排查代理边界,可直接打开下面的项目内文档。":"首次使用请先按环境变量配置文档填入百度应用 client id / secret,然后重建 baidu-netdisk 服务并刷新本页。"),b("div",{className:"baidu-doc-grid","data-testid":"baidu-netdisk-doc-links"},b(H$,{title:"环境变量配置",text:"填写 UNIDESK_BAIDU_NETDISK_CLIENT_ID、CLIENT_SECRET、TOKEN_KEY,并执行重建与健康检查。",href:"/docs/issue/baidu-netdisk-env-setup.md",badge:"SETUP",testId:"baidu-netdisk-env-doc-card"}),b(H$,{title:"服务方案与 API",text:"说明 OAuth Device Code、根目录工作区、staging 上传下载任务和后端 API 设计。",href:"/docs/issue/baidu-netdisk-user-service.md",badge:"DESIGN"}),b(H$,{title:"用户服务安全边界",text:"查看 UniDesk microservice 私有代理、允许路径、frontendOnly 和密钥边界规则。",href:"/docs/reference/microservices.md",badge:"REF"}),b(H$,{title:"部署与重建流程",text:"查看 server rebuild、Compose 编排、健康检查和交付验证的长期规则。",href:"/docs/reference/deployment.md",badge:"DEPLOY"}),b(H$,{title:"CLI 验证命令",text:"查看 microservice health/proxy、server rebuild、job status 等命令入口。",href:"/docs/reference/cli.md",badge:"CLI"}),b(H$,{title:"百度设备码模式",text:"打开百度官方 OAuth Device Code 文档,对照扫码登录和轮询参数。",href:"https://pan.baidu.com/union/doc/fl1x114ti",badge:"OFFICIAL"}))),b(Ay,{title:"设备码登录",eyebrow:"OAuth Device Code",className:"baidu-login-panel",loading:y.actionLoading,actions:b("div",{className:"panel-actions inline-actions"},b("button",{type:"button",className:"primary-btn",onClick:q,disabled:y.actionLoading||!a,"data-testid":"baidu-netdisk-start-login"},"生成二维码"),A?.id?b("button",{type:"button",className:"ghost-btn",onClick:()=>Y(!0),disabled:y.actionLoading},"检查状态"):null,d?b("button",{type:"button",className:"ghost-btn",onClick:w,disabled:y.actionLoading},"清除本地登录"):null,b(w1,{title:"Baidu Device Session",data:A||D.latestSession,onOpen:u,testId:"raw-baidu-device-session"}))},b("div",{className:"baidu-login-card","data-testid":"baidu-netdisk-login-card"},b("div",{className:"baidu-qr-frame"},A?.qrcodeUrl?b("img",{src:A.qrcodeUrl,alt:"百度网盘设备码授权二维码","data-testid":"baidu-netdisk-qrcode"}):b(E$,{title:a?"等待二维码":"OAuth 未配置",text:a?"点击生成二维码后使用百度网盘或百度 App 扫码":"设置 client id、secret 和 token key 后重建服务"})),b("div",{className:"claudeqq-login-copy"},b("div",{className:"node-version-line"},b(jy,{status:d?"online":A?.status==="pending"?"warn":"unknown"},d?"已登录":A?.status||"未开始"),b("span",null,A?.secondsRemaining!==void 0?`${A.secondsRemaining}s`:"--"),b("span",null,"scope basic,netdisk")),b("p",{className:"muted paragraph"},d?"access token / refresh token 已加密保存到 PostgreSQL;前端只看到脱敏登录态。":"后端使用百度 OAuth Device Code 轮询换取 token;二维码过期后重新生成即可。"),b("div",{className:"microservice-ref-card"},b("span",null,"User Code"),b("strong",null,A?.userCode||"--"),b("code",null,A?.verificationUrl||"https://openapi.baidu.com/device")),b("div",{className:"microservice-ref-card"},b("span",null,"Expires"),b("strong",null,A?.expiresAt?Nf(A.expiresAt):"--"),b("code",null,A?.error||"no token exposed"))))),b(Ay,{title:"账号与容量",eyebrow:y.refreshedAt?`Updated ${W0(y.refreshedAt)}`:"Account",loading:y.loading,actions:b("div",{className:"panel-actions inline-actions"},b(w1,{title:"Baidu Account",data:X,onOpen:u,testId:"raw-baidu-account"}))},X?b("div",{className:"baidu-account-card"},b("div",{className:"node-version-line"},b(jy,{status:"online"},"connected"),b("span",null,X.baiduUid||"--"),b("span",null,`VIP ${X.vipType??"--"}`)),b("h3",null,X.username||"Baidu Netdisk"),b("p",{className:"muted paragraph"},`工作目录固定在 ${X.rootPath||z};v1 上传/下载只读写容器 staging 目录,不把大文件字节流穿过 UniDesk proxy。`),b("div",{className:"quota-bar"},b("span",{style:{width:`${Math.max(0,Math.min(100,Number(s.usedPercent||0)))}%`}})),b("div",{className:"microservice-ref-card"},b("span",null,"Quota"),b("strong",null,`${J_(s.used)} / ${J_(s.total)}`),b("code",null,`${s.usedPercent||0}% used`))):b(E$,{title:"尚未登录",text:"扫码授权后这里会显示账号、UID、会员状态和容量"})),b(Ay,{title:"文件浏览器",eyebrow:r,className:"baidu-files-panel",loading:y.loading,actions:b("div",{className:"panel-actions inline-actions"},b("button",{type:"button",className:"ghost-btn",onClick:()=>{let I=QL(r,z);j(I),Z(I)},disabled:!d||r===z},"上级"),b("button",{type:"button",className:"ghost-btn",onClick:()=>Z(r),disabled:!d},"刷新文件"),b(w1,{title:"Baidu Files",data:y.files,onOpen:u,testId:"raw-baidu-files"}))},b("form",{className:"baidu-pathbar",onSubmit:(I)=>{I.preventDefault(),Z(r)}},b("input",{value:r,onChange:(I)=>j(I.target.value),disabled:!d}),b("button",{type:"submit",className:"ghost-btn",disabled:!d},"打开路径")),b("form",{className:"baidu-pathbar",onSubmit:B},b("input",{value:U,onChange:(I)=>Q(I.target.value),placeholder:"新文件夹名称",disabled:!d}),b("button",{type:"submit",className:"primary-btn",disabled:!d||!U.trim()},"新建文件夹")),!d?b(E$,{title:"等待授权",text:"登录后通过 /api/files 读取工作目录文件列表"}):p.length===0?b(E$,{title:"目录为空",text:"可以从 staging 目录上传文件或新建文件夹"}):b("div",{className:"table-wrap","data-testid":"baidu-netdisk-file-table"},b("table",null,b("thead",null,b("tr",null,b("th",null,"名称"),b("th",null,"类型"),b("th",null,"大小"),b("th",null,"修改时间"),b("th",null,"fs_id"),b("th",null,"操作"))),b("tbody",null,p.map((I)=>b("tr",{key:I.fsId||I.path},b("td",null,b("strong",null,I.serverFilename||I.path),b("code",null,I.path||"--")),b("td",null,b(jy,{status:I.isDir?"queued":"private"},I.isDir?"DIR":"FILE")),b("td",null,I.isDir?"--":J_(I.size)),b("td",null,I.serverMtime?Nf(I.serverMtime*1000):"--"),b("td",null,b("code",null,I.fsId||"--")),b("td",null,b("div",{className:"inline-actions"},I.isDir?b("button",{type:"button",className:"ghost-btn",onClick:()=>{j(I.path),Z(I.path)}},"打开"):b("button",{type:"button",className:"ghost-btn",onClick:()=>H((ff)=>({...ff,fsId:I.fsId}))},"填入下载"),b("button",{type:"button",className:"ghost-btn",onClick:()=>P(I.path),disabled:y.actionLoading},"删除"))))))))),b(Ay,{title:"传输任务",eyebrow:"staging path jobs",className:"baidu-transfers-panel",loading:y.actionLoading,actions:b("div",{className:"panel-actions inline-actions"},b("button",{type:"button",className:"primary-btn",onClick:S,disabled:!d||y.actionLoading,"data-testid":"baidu-netdisk-self-test"},"运行自测"),b("button",{type:"button",className:"ghost-btn",onClick:N},"刷新任务"),b(w1,{title:"Baidu Transfers",data:y.transfers,onOpen:u,testId:"raw-baidu-transfers"}))},b("div",{className:"baidu-transfer-forms"},b("form",{className:"stack-form",onSubmit:h,"data-testid":"baidu-upload-form"},b("label",null,"容器 staging 文件",b("input",{value:W.localPath,onChange:(I)=>G((ff)=>({...ff,localPath:I.target.value})),placeholder:"sample.txt"})),b("label",null,"百度网盘目标路径",b("input",{value:W.remotePath,onChange:(I)=>G((ff)=>({...ff,remotePath:I.target.value})),placeholder:uj(z,"sample.txt")})),b("button",{type:"submit",className:"primary-btn",disabled:!d||y.actionLoading},"上传 staging 文件")),b("form",{className:"stack-form",onSubmit:M,"data-testid":"baidu-download-form"},b("label",null,"文件 fs_id",b("input",{value:K.fsId,onChange:(I)=>H((ff)=>({...ff,fsId:I.target.value})),placeholder:"从文件表填入"})),b("label",null,"保存到 staging 路径",b("input",{value:K.localPath,onChange:(I)=>H((ff)=>({...ff,localPath:I.target.value})),placeholder:"downloads/"})),b("button",{type:"submit",className:"primary-btn",disabled:!d||!K.fsId||y.actionLoading},"下载到 staging"))),y.selfTest?b("div",{className:"baidu-account-card","data-testid":"baidu-netdisk-self-test-result"},b("div",{className:"node-version-line"},b(jy,{status:y.selfTest.ok?"online":"warn"},y.selfTest.ok?"self-test ok":"self-test"),b("span",null,J_(y.selfTest.sizeBytes))),b("h3",null,y.selfTest.remotePath||"Baidu self-test"),b("div",{className:"microservice-ref-card"},b("span",null,"fs_id"),b("strong",null,y.selfTest.fsId||"--"),b("code",null,y.selfTest.downloadedPath||"--")),b("div",{className:"microservice-ref-card"},b("span",null,"MD5"),b("strong",null,y.selfTest.downloadedMd5||"--"),b("code",null,y.selfTest.expectedMd5||"--")),b(w1,{title:"Baidu Self Test",data:y.selfTest,onOpen:u,testId:"raw-baidu-self-test"})):null,m.length===0?b(E$,{title:"暂无传输任务",text:"上传/下载任务会在后端容器内执行,避免大文件穿过 UniDesk proxy"}):b("div",{className:"table-wrap","data-testid":"baidu-transfer-table"},b("table",null,b("thead",null,b("tr",null,b("th",null,"状态"),b("th",null,"方向"),b("th",null,"路径"),b("th",null,"进度"),b("th",null,"时间"),b("th",null,"操作"))),b("tbody",null,m.map((I)=>b("tr",{key:I.id},b("td",null,b(jy,{status:I.status},I.status)),b("td",null,I.direction),b("td",null,b("strong",null,I.remotePath||I.fsId||"--"),b("code",null,I.localPath||"--"),I.error?b("span",{className:"form-error"},I.error):null),b("td",null,b(zL,{percent:I.progressPercent}),b("span",{className:"muted"},`${J_(I.bytesDone)} / ${J_(I.sizeBytes)}`)),b("td",null,Nf(I.updatedAt)),b("td",null,b("div",{className:"inline-actions"},["queued","running"].includes(I.status)?b("button",{type:"button",className:"ghost-btn",onClick:()=>n(I.id,"cancel")},"取消"):null,["failed","canceled"].includes(I.status)?b("button",{type:"button",className:"ghost-btn",onClick:()=>n(I.id,"retry")},"重试"):null,b(w1,{title:`Transfer ${I.id}`,data:I,onOpen:u}))))))))),b(Ay,{title:"安全与日志",eyebrow:"redacted diagnostics",className:"baidu-wide-panel",loading:y.loading,actions:b("div",{className:"panel-actions inline-actions"},b(w1,{title:"Baidu Health",data:v,onOpen:u,testId:"raw-baidu-health"}),b(w1,{title:"Baidu Logs",data:y.logs,onOpen:u,testId:"raw-baidu-logs"}))},b("div",{className:"policy-grid"},b("article",null,b("b",null,"私有后端"),b("span",null,"4244 只在 Compose 网络 expose,浏览器经 UniDesk 同源代理访问")),b("article",null,b("b",null,"Token 加密"),b("span",null,"access/refresh token 使用 BAIDU_NETDISK_TOKEN_KEY 加密后写入 PostgreSQL")),b("article",null,b("b",null,"无浏览器大文件流"),b("span",null,"上传/下载以容器 staging 目录为边界,避免 proxy 文本通道传输大字节流"))))))}var K2=cf(O0(),1);var t=K2.default.createElement,{useEffect:GL}=K2.default,z2=K2.default.useState,Fy={label:"主用户私聊账号",userId:645275593};function lj(f){let u=Number(f);return Number.isFinite(u)?u.toLocaleString("zh-CN"):"--"}async function D1(f,u={}){return Mf(f,{failureFields:["ok","success"],...u})}function G2({status:f,children:u}){let l=String(f||"unknown").toLowerCase();return t("span",{className:`status-badge ${l}`},u||f||"unknown")}function O$({label:f,value:u,hint:l,tone:_}){return t("article",{className:`metric-card ${_||""}`},t("div",{className:"metric-label"},f),t("div",{className:"metric-value"},u),t("div",{className:"metric-hint"},l))}function V$({title:f,eyebrow:u,actions:l,children:_,className:y,loading:$}){return t("section",{className:`panel ${y||""}`},t("div",{className:"panel-head"},t("div",null,u?t("p",{className:"panel-eyebrow"},u):null,t(j0,{title:f,loading:$})),l?t("div",{className:"panel-actions"},l):null),t("div",{className:"panel-body"},_))}function N6({title:f,data:u,onOpen:l,testId:_}){return t("button",{type:"button",className:"ghost-btn","data-testid":_,onClick:(y)=>{y?.stopPropagation?.(),l(f,u)}},"查看原始JSON")}function Z6({title:f,text:u}){return t("div",{className:"empty-state"},t("strong",null,f),t("span",null,u))}function KL(f){return f?.runtime&&typeof f.runtime==="object"&&!Array.isArray(f.runtime)?f.runtime:{}}function NL(f){return f?.backend&&typeof f.backend==="object"&&!Array.isArray(f.backend)?f.backend:{}}function ZL(f){return f?.repository&&typeof f.repository==="object"&&!Array.isArray(f.repository)?f.repository:{}}function U_(f,u){return`${f}/microservices/claudeqq/proxy${u}`}function EL(f){return Array.isArray(f?.events)?f.events.slice(0,80):[]}function HL(f){return Array.isArray(f?.subscriptions)?f.subscriptions.slice(0,50):[]}function OL(f){return Array.isArray(f?.messages)?f.messages.slice(0,30):[]}function xz(f){let u=f?.text??f?.message??f?.raw?.raw_message;if(typeof u!=="string")return"--";return u.length>180?`${u.slice(0,177)}...`:u}function bz(f){let u=f?.groupId??f?.group_id??(f?.message_type==="group"?f?.target_id:void 0),l=f?.userId??f?.user_id??(f?.message_type==="private"?f?.target_id:void 0);if(u)return`群 ${u}`;if(l)return`私聊 ${l}`;return"--"}function vz({microservices:f,onRaw:u,apiBaseUrl:l="/api"}){let _=f.find((X)=>X.id==="claudeqq")||null,[y,$]=z2({loading:!1,qrLoading:!1,error:"",health:null,status:null,napcatLogin:null,napcatQrcode:null,qrcodeFetched:!1,qrcodeRefreshedAt:null,events:null,subscriptions:null,sent:null,refreshedAt:null}),[r,j]=z2({targetType:"private",targetId:String(Fy.userId),message:""}),[A,J]=z2({name:"unidesk-callback",targetUrl:"",eventTypes:"message",secret:""}),[U,Q]=z2(""),{addNotification:W}=Lu();async function G(){if(!_)return;$((X)=>({...X,loading:!0,error:""}));try{let[X,D,p,m,s]=await Promise.all([D1(`${l}/microservices/claudeqq/health`),D1(U_(l,"/api/server/status")),D1(U_(l,"/api/events/recent?limit=60")),D1(U_(l,"/api/events/subscriptions")),D1(U_(l,"/api/messages/sent?limit=20"))]);if($((d)=>({...d,loading:!1,error:"",health:X,status:D,events:p,subscriptions:m,sent:s,refreshedAt:new Date})),!y.qrcodeFetched)K(!1)}catch(X){$((D)=>({...D,loading:!1,error:Df(X,"ClaudeQQ 加载失败")}))}}async function K(X=!0){if(!_)return;$((D)=>({...D,qrLoading:!0,error:X?"":D.error}));try{let D=await D1(U_(l,"/api/napcat/login")),p=D?.napcat?.qrcode||D?.qrcode||null;$((m)=>({...m,qrLoading:!1,error:"",napcatLogin:D,napcatQrcode:p,qrcodeFetched:!0,qrcodeRefreshedAt:new Date}))}catch(D){$((p)=>({...p,qrLoading:!1,error:X||!p.napcatQrcode?Df(D,"NapCat 二维码加载失败"):p.error}))}}async function H(X){X.preventDefault(),Q("");let D=Number(r.targetId);if(!Number.isFinite(D)||D<=0||r.message.trim().length===0){$((p)=>({...p,error:"请填写 QQ 目标和消息内容"}));return}try{await D1(U_(l,"/api/push/text"),{method:"POST",body:JSON.stringify({userId:r.targetType==="private"?D:void 0,groupId:r.targetType==="group"?D:void 0,message:r.message})});let p="消息推送请求已提交";j((m)=>({...m,targetType:"private",targetId:String(Fy.userId),message:""})),Q(p),W("success",p),await G()}catch(p){$((m)=>({...m,error:Df(p,"发送失败")}))}}async function O(X){if(X.preventDefault(),Q(""),A.targetUrl.trim().length===0){$((D)=>({...D,error:"请填写订阅回调 URL"}));return}try{await D1(U_(l,"/api/events/subscriptions"),{method:"POST",body:JSON.stringify({name:A.name,targetUrl:A.targetUrl,eventTypes:A.eventTypes.split(",").map((p)=>p.trim()).filter(Boolean),secret:A.secret||void 0,enabled:!0})});let D="事件订阅已创建";Q(D),W("success",D),await G()}catch(D){$((p)=>({...p,error:Df(D,"订阅失败")}))}}async function z(X){if(!X)return;Q("");try{await D1(U_(l,`/api/events/subscriptions/${encodeURIComponent(X)}`),{method:"DELETE"});let D="事件订阅已删除";Q(D),W("success",D),await G()}catch(D){$((p)=>({...p,error:Df(D,"删除订阅失败")}))}}if(GL(()=>{if(!_)return;G();return},[_?.id,_?.runtime?.providerStatus]),!_)return t(Z6,{title:"ClaudeQQ 未登记",text:"请在 config.json 的 microservices 中登记用户服务 id=claudeqq"});let Z=KL(_),N=ZL(_),E=NL(_),q=y.health||{},Y=y.status||{},w=y.napcatLogin||{},B=q.napcat||Y.napcat||{},P={...w.napcat||{},...B,qrcode:y.napcatQrcode||{},webui:B.webui||w.napcat?.webui},h=w.login||{},M=y.napcatQrcode||{},n=EL(y.events),S=HL(y.subscriptions),T=OL(y.sent),i=Boolean(P.httpConnected||h.ready),C=String(P.loginState||h.state||(i?"logged_in":"unknown")),v=Boolean(M.available&&M.dataUrl);return t("div",{className:"claudeqq-page","data-testid":"claudeqq-page"},t(V$,{title:"ClaudeQQ 工作台",eyebrow:"D601 QQ Event Gateway",loading:y.loading,actions:t("div",{className:"panel-actions"},t("button",{type:"button",className:"ghost-btn",onClick:G,disabled:y.loading,"data-testid":"claudeqq-refresh-button"},y.loading?"刷新中":"刷新"),t(N6,{title:"ClaudeQQ 用户服务",data:_,onOpen:u,testId:"raw-claudeqq-service"}))},t("div",{className:"findjob-hero"},t("div",null,t("div",{className:"node-version-line"},t(G2,{status:Z.providerStatus==="online"?"online":"warn"},Z.providerStatus||"unknown"),t("span",null,_.providerId),t("span",null,E.public?"公网暴露":"仅 UniDesk frontend 代理访问")),t("p",{className:"muted paragraph"},_.description)),t("div",{className:"microservice-ref-card"},t("span",null,"Repo"),t("strong",null,N.url||"--"),t("code",null,N.commitId||"--")),t("div",{className:"microservice-ref-card"},t("span",null,"D601 Docker"),t("strong",null,`${E.nodeBindHost||"--"}:${E.nodePort||"--"}`),t("code",null,`${N.composeFile||"--"} / ${N.composeService||"--"}`))),t(A0,{error:y.error,wide:!0}),U?t("div",{className:"form-success wide"},U):null),t("div",{className:"metric-grid"},t(O$,{label:"Health",value:q.ok||q.status==="ok"?"OK":"--",hint:"D601 /health",tone:q.ok||q.status==="ok"?"ok":"warn"}),t(O$,{label:"NapCat HTTP",value:P.httpConnected||P.http?.connected?"OK":"离线",hint:`${P.httpHost||q.napcat?.httpHost||"--"}:${P.httpPort||q.napcat?.httpPort||"--"}`}),t(O$,{label:"NapCat WS",value:P.wsConnected||P.ws?.connected?"OK":"离线",hint:`${P.wsHost||q.napcat?.wsHost||"--"}:${P.wsPort||q.napcat?.wsPort||"--"}`}),t(O$,{label:"事件缓存",value:lj(y.events?.count??n.length),hint:"recent QQ events"}),t(O$,{label:"订阅",value:lj(y.subscriptions?.count??S.length),hint:"webhook subscribers"}),t(O$,{label:"已发送",value:lj(y.sent?.count??T.length),hint:"sent message log"})),t("div",{className:"findjob-grid"},t(V$,{title:"NapCat 容器登录",eyebrow:"QR Login",className:"claudeqq-login-panel",loading:y.qrLoading,actions:t("div",{className:"panel-actions inline-actions"},t("button",{type:"button",className:"ghost-btn",onClick:()=>K(!0),disabled:y.qrLoading,"data-testid":"claudeqq-napcat-refresh"},y.qrLoading?"刷新中":"手动刷新二维码"),t(N6,{title:"NapCat Login",data:y.napcatLogin,onOpen:u,testId:"raw-claudeqq-napcat-login"}))},t("div",{className:"claudeqq-login-card","data-testid":"claudeqq-napcat-login"},t("div",{className:"claudeqq-qr-frame"},v?t("img",{src:M.dataUrl,alt:"NapCat QQ 登录二维码","data-testid":"claudeqq-napcat-qrcode"}):t(Z6,{title:"等待二维码",text:"NapCat 容器启动后会把登录二维码写入 cache/qrcode.png"})),t("div",{className:"claudeqq-login-copy"},t("div",{className:"node-version-line"},t(G2,{status:i?"online":v?"warn":"unknown"},i?"已登录":v?"待扫码":"等待二维码"),t("span",null,C),t("span",null,"D601 containerized")),t("p",{className:"muted paragraph"},i?"NapCat 已登录,ClaudeQQ 可通过容器内 HTTP/WS 链路收发 QQ 消息。":"用手机 QQ 扫描二维码授权登录。二维码只在首次加载或手动刷新时更新,D601 的 NapCat 端口仍只绑定 127.0.0.1。"),t("div",{className:"microservice-ref-card"},t("span",null,"NapCat WebUI"),t("strong",null,P.webui?.url||"http://napcat:6099/webui"),t("code",null,"local-only / proxied QR login")),t("div",{className:"microservice-ref-card"},t("span",null,"QR Source"),t("strong",null,M.modifiedAt?Nf(M.modifiedAt):y.qrcodeRefreshedAt?Nf(y.qrcodeRefreshedAt):"--"),t("code",null,M.file||"/napcat/cache/qrcode.png"))))),t(V$,{title:"消息推送",eyebrow:"Push API"},t("div",{className:"microservice-ref-card"},t("span",null,Fy.label),t("strong",null,String(Fy.userId)),t("code",null,"private userId / 默认推送测试目标")),t("form",{className:"stack-form",onSubmit:H,"data-testid":"claudeqq-push-form"},t("label",null,"目标类型",t("select",{value:r.targetType,onChange:(X)=>j((D)=>({...D,targetType:X.target.value}))},t("option",{value:"private"},"私聊 userId"),t("option",{value:"group"},"群 groupId"))),t("label",null,"QQ ID",t("input",{value:r.targetId,onChange:(X)=>j((D)=>({...D,targetId:X.target.value})),placeholder:String(Fy.userId)})),t("label",null,"消息内容",t("textarea",{value:r.message,onChange:(X)=>j((D)=>({...D,message:X.target.value})),rows:4,placeholder:"通过 ClaudeQQ 推送一条 QQ 消息"})),t("button",{type:"submit",className:"primary-btn"},"发送 QQ 消息")),t("p",{className:"muted paragraph"},`主 server 和其他用户服务可通过 UniDesk 同源代理调用 /api/push/text;当前人工推送测试默认使用 ${Fy.label} ${Fy.userId},不需要暴露 D601 后端端口。`)),t(V$,{title:"QQ 事件订阅",eyebrow:"Webhook Subscription",loading:y.loading},t("form",{className:"stack-form",onSubmit:O,"data-testid":"claudeqq-subscription-form"},t("label",null,"订阅名称",t("input",{value:A.name,onChange:(X)=>J((D)=>({...D,name:X.target.value}))})),t("label",null,"回调 URL",t("input",{value:A.targetUrl,onChange:(X)=>J((D)=>({...D,targetUrl:X.target.value})),placeholder:"http://host.docker.internal:18080/..."})),t("label",null,"事件类型",t("input",{value:A.eventTypes,onChange:(X)=>J((D)=>({...D,eventTypes:X.target.value})),placeholder:"message,notice"})),t("label",null,"签名密钥",t("input",{value:A.secret,onChange:(X)=>J((D)=>({...D,secret:X.target.value})),placeholder:"可选,生成 x-claudeqq-signature"})),t("button",{type:"submit",className:"primary-btn"},"创建订阅")),S.length===0?t(Z6,{title:"暂无订阅",text:"可以为 main server 或其他用户服务注册 HTTP webhook"}):t("div",{className:"table-wrap","data-testid":"claudeqq-subscription-table"},t("table",null,t("thead",null,t("tr",null,t("th",null,"名称"),t("th",null,"状态"),t("th",null,"事件"),t("th",null,"回调"),t("th",null,"最近投递"),t("th",null,"操作"))),t("tbody",null,S.map((X)=>t("tr",{key:X.id},t("td",null,t("strong",null,X.name||X.id),t("code",null,X.id||"--")),t("td",null,t(G2,{status:X.enabled?"online":"warn"},X.enabled?"enabled":"disabled")),t("td",null,Array.isArray(X.eventTypes)?X.eventTypes.join(", "):"message"),t("td",null,X.targetUrl||"--"),t("td",null,X.lastDelivery?`${X.lastDelivery.ok?"OK":"FAIL"} ${Nf(X.lastDelivery.at)}`:"--"),t("td",null,t("button",{type:"button",className:"ghost-btn",onClick:()=>z(X.id)},"删除"))))))),t("div",{className:"panel-actions inline-actions"},t(N6,{title:"ClaudeQQ Subscriptions",data:y.subscriptions,onOpen:u,testId:"raw-claudeqq-subscriptions"}))),t(V$,{title:"最近 QQ 事件",eyebrow:y.refreshedAt?`Updated ${W0(y.refreshedAt)}`:"Event Stream",loading:y.loading},n.length===0?t(Z6,{title:"暂无事件",text:"等待 NapCat WebSocket 上报 QQ 消息事件,或通过订阅 API 消费后续事件"}):t("div",{className:"table-wrap","data-testid":"claudeqq-event-list"},t("table",null,t("thead",null,t("tr",null,t("th",null,"时间"),t("th",null,"类型"),t("th",null,"会话"),t("th",null,"消息"),t("th",null,"ID"))),t("tbody",null,n.map((X)=>t("tr",{key:X.id},t("td",null,Nf(X.receivedAt||X.timestamp)),t("td",null,t(G2,{status:X.postType||X.eventType},X.postType||X.eventType||"--")),t("td",null,bz(X)),t("td",null,xz(X)),t("td",null,t("code",null,X.messageId||X.id||"--"))))))),t("div",{className:"panel-actions inline-actions"},t(N6,{title:"ClaudeQQ Events",data:y.events,onOpen:u,testId:"raw-claudeqq-events"}))),t(V$,{title:"已发送消息",eyebrow:`${T.length} Sent`,loading:y.loading},T.length===0?t(Z6,{title:"暂无发送记录",text:"发送日志来自 ClaudeQQ bot_workspace/messages/sent_messages.jsonl"}):t("div",{className:"table-wrap"},t("table",null,t("thead",null,t("tr",null,t("th",null,"时间"),t("th",null,"目标"),t("th",null,"消息"),t("th",null,"结果"))),t("tbody",null,T.map((X,D)=>t("tr",{key:X.id||D},t("td",null,Nf(X.timestamp||X.sentAt||X.createdAt)),t("td",null,bz(X)),t("td",null,xz(X)),t("td",null,X.status||X.messageId||X.message_id||"--")))))),t("div",{className:"panel-actions inline-actions"},t(N6,{title:"ClaudeQQ Sent Messages",data:y.sent,onOpen:u,testId:"raw-claudeqq-sent"})))))}var Y6=cf(O0(),1);var pz=cf(O0(),1),U0=pz.default.createElement;function mz({markdown:f,className:u,testId:l}){let _=String(f??"").trimEnd(),y=["markdown-body",u].filter(Boolean).join(" ");return U0("div",{className:y,"data-testid":l},gz(_,"md"))}function gz(f,u){let l=VL(f).split(` -`),_=[],y=0;while(y\s?/u.test($)){let Q=[];while(y\s?(.*)$/u);if(G!==null){Q.push(G[1]),y+=1;continue}if(W.trim().length===0){Q.push(""),y+=1;continue}break}_.push(U0("blockquote",{key:`${u}-quote-${y}`},gz(Q.join(` -`),`${u}-quote-${y}`)));continue}if(tz(l,y)){let Q=y,W=E6(l[y]??""),G=E6(l[y+1]??"");y+=2;let K=[];while(y0)K.push(E6(l[y]??"")),y+=1;_.push(YL(W,G,K,`${u}-table-${Q}`));continue}let A=Z2($);if(A!==null){let Q=y,W=A.ordered,G=A.start,K=[];while(yXL(O,`${u}-list-${Q}-${z}`))));continue}let J=y,U=[];while(y0&&!LL(l,y))U.push(l[y].trim()),y+=1;if(U.length===0)U.push($.trim()),y+=1;_.push(U0("p",{key:`${u}-p-${J}`},u1(U.join(` -`),`${u}-p-${J}`)))}return _}function VL(f){return String(f||"").replace(/\r\n/gu,` +(()=>{var YK=Object.create;var{getPrototypeOf:DK,defineProperty:oj,getOwnPropertyNames:tK}=Object;var SK=Object.prototype.hasOwnProperty;function PK(u){return this[u]}var MK,mK,Pu=(u,f,l)=>{var r=u!=null&&typeof u==="object";if(r){var y=f?MK??=new WeakMap:mK??=new WeakMap,i=y.get(u);if(i)return i}l=u!=null?YK(DK(u)):{};let _=f||!u||!u.__esModule?oj(l,"default",{value:u,enumerable:!0}):l;for(let n of tK(u))if(!SK.call(_,n))oj(_,n,{get:PK.bind(u,n),enumerable:!0});if(r)y.set(u,_);return _};var ol=(u,f)=>()=>(f||u((f={exports:{}}).exports,f),f.exports);var eu=((u)=>typeof require<"u"?require:typeof Proxy<"u"?new Proxy(u,{get:(f,l)=>(typeof require<"u"?require:f)[l]}):u)(function(u){if(typeof require<"u")return require.apply(this,arguments);throw Error('Dynamic require of "'+u+'" is not supported')});var AF=ol((gu)=>{var W_=Symbol.for("react.element"),pK=Symbol.for("react.portal"),CK=Symbol.for("react.fragment"),xK=Symbol.for("react.strict_mode"),RK=Symbol.for("react.profiler"),hK=Symbol.for("react.provider"),bK=Symbol.for("react.context"),vK=Symbol.for("react.forward_ref"),IK=Symbol.for("react.suspense"),kK=Symbol.for("react.memo"),gK=Symbol.for("react.lazy"),dj=Symbol.iterator;function sK(u){if(u===null||typeof u!=="object")return null;return u=dj&&u[dj]||u["@@iterator"],typeof u==="function"?u:null}var fF={isMounted:function(){return!1},enqueueForceUpdate:function(){},enqueueReplaceState:function(){},enqueueSetState:function(){}},lF=Object.assign,rF={};function py(u,f,l){this.props=u,this.context=f,this.refs=rF,this.updater=l||fF}py.prototype.isReactComponent={};py.prototype.setState=function(u,f){if(typeof u!=="object"&&typeof u!=="function"&&u!=null)throw Error("setState(...): takes an object of state variables to update or a function which returns an object of state variables.");this.updater.enqueueSetState(this,u,f,"setState")};py.prototype.forceUpdate=function(u){this.updater.enqueueForceUpdate(this,u,"forceUpdate")};function yF(){}yF.prototype=py.prototype;function Y8(u,f,l){this.props=u,this.context=f,this.refs=rF,this.updater=l||fF}var D8=Y8.prototype=new yF;D8.constructor=Y8;lF(D8,py.prototype);D8.isPureReactComponent=!0;var ej=Array.isArray,iF=Object.prototype.hasOwnProperty,t8={current:null},_F={key:!0,ref:!0,__self:!0,__source:!0};function nF(u,f,l){var r,y={},i=null,_=null;if(f!=null)for(r in f.ref!==void 0&&(_=f.ref),f.key!==void 0&&(i=""+f.key),f)iF.call(f,r)&&!_F.hasOwnProperty(r)&&(y[r]=f[r]);var n=arguments.length-2;if(n===1)y.children=l;else if(1{jF.exports=AF()});var GF=ol((Wf)=>{function p8(u,f){var l=u.length;u.push(f);u:for(;0>>1,y=u[r];if(0>>1;re$(n,l))$e$(j,n)?(u[r]=j,u[$]=l,r=$):(u[r]=n,u[_]=l,r=_);else if($e$(j,l))u[r]=j,u[$]=l,r=$;else break u}}return f}function e$(u,f){var l=u.sortIndex-f.sortIndex;return l!==0?l:u.id-f.id}if(typeof performance==="object"&&typeof performance.now==="function")C8=performance,Wf.unstable_now=function(){return C8.now()};else u3=Date,x8=u3.now(),Wf.unstable_now=function(){return u3.now()-x8};var C8,u3,x8,kr=[],R0=[],rL=1,Qr=null,jl=3,y3=!1,R1=!1,N_=!1,qF=typeof setTimeout==="function"?setTimeout:null,WF=typeof clearTimeout==="function"?clearTimeout:null,QF=typeof setImmediate<"u"?setImmediate:null;typeof navigator<"u"&&navigator.scheduling!==void 0&&navigator.scheduling.isInputPending!==void 0&&navigator.scheduling.isInputPending.bind(navigator.scheduling);function R8(u){for(var f=Hr(R0);f!==null;){if(f.callback===null)r3(R0);else if(f.startTime<=u)r3(R0),f.sortIndex=f.expirationTime,p8(kr,f);else break;f=Hr(R0)}}function b8(u){if(N_=!1,R8(u),!R1)if(Hr(kr)!==null)R1=!0,I8(v8);else{var f=Hr(R0);f!==null&&k8(b8,f.startTime-u)}}function v8(u,f){R1=!1,N_&&(N_=!1,WF(z_),z_=-1),y3=!0;var l=jl;try{R8(f);for(Qr=Hr(kr);Qr!==null&&(!(Qr.expirationTime>f)||u&&!zF());){var r=Qr.callback;if(typeof r==="function"){Qr.callback=null,jl=Qr.priorityLevel;var y=r(Qr.expirationTime<=f);f=Wf.unstable_now(),typeof y==="function"?Qr.callback=y:Qr===Hr(kr)&&r3(kr),R8(f)}else r3(kr);Qr=Hr(kr)}if(Qr!==null)var i=!0;else{var _=Hr(R0);_!==null&&k8(b8,_.startTime-f),i=!1}return i}finally{Qr=null,jl=l,y3=!1}}var i3=!1,f3=null,z_=-1,cF=5,NF=-1;function zF(){return Wf.unstable_now()-NFu||125r?(u.sortIndex=l,p8(R0,u),Hr(kr)===null&&u===Hr(R0)&&(N_?(WF(z_),z_=-1):N_=!0,k8(b8,l-r))):(u.sortIndex=y,p8(kr,u),R1||y3||(R1=!0,I8(v8))),u};Wf.unstable_shouldYield=zF;Wf.unstable_wrapCallback=function(u){var f=jl;return function(){var l=jl;jl=f;try{return u.apply(this,arguments)}finally{jl=l}}}});var LF=ol((kS,KF)=>{KF.exports=GF()});var EQ=ol((rr)=>{var yL=wf(),fr=LF();function Uu(u){for(var f="https://reactjs.org/docs/error-decoder.html?invariant="+u,l=1;l"u"||typeof window.document>"u"||typeof window.document.createElement>"u"),q2=Object.prototype.hasOwnProperty,iL=/^[:A-Z_a-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD][:A-Z_a-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD\-.0-9\u00B7\u0300-\u036F\u203F-\u2040]*$/,wF={},EF={};function _L(u){if(q2.call(EF,u))return!0;if(q2.call(wF,u))return!1;if(iL.test(u))return EF[u]=!0;return wF[u]=!0,!1}function nL(u,f,l,r){if(l!==null&&l.type===0)return!1;switch(typeof f){case"function":case"symbol":return!0;case"boolean":if(r)return!1;if(l!==null)return!l.acceptsBooleans;return u=u.toLowerCase().slice(0,5),u!=="data-"&&u!=="aria-";default:return!1}}function $L(u,f,l,r){if(f===null||typeof f>"u"||nL(u,f,l,r))return!0;if(r)return!1;if(l!==null)switch(l.type){case 3:return!f;case 4:return f===!1;case 5:return isNaN(f);case 6:return isNaN(f)||1>f}return!1}function Ll(u,f,l,r,y,i,_){this.acceptsBooleans=f===2||f===3||f===4,this.attributeName=r,this.attributeNamespace=y,this.mustUseProperty=l,this.propertyName=u,this.type=f,this.sanitizeURL=i,this.removeEmptyString=_}var il={};"children dangerouslySetInnerHTML defaultValue defaultChecked innerHTML suppressContentEditableWarning suppressHydrationWarning style".split(" ").forEach(function(u){il[u]=new Ll(u,0,!1,u,null,!1,!1)});[["acceptCharset","accept-charset"],["className","class"],["htmlFor","for"],["httpEquiv","http-equiv"]].forEach(function(u){var f=u[0];il[f]=new Ll(f,1,!1,u[1],null,!1,!1)});["contentEditable","draggable","spellCheck","value"].forEach(function(u){il[u]=new Ll(u,2,!1,u.toLowerCase(),null,!1,!1)});["autoReverse","externalResourcesRequired","focusable","preserveAlpha"].forEach(function(u){il[u]=new Ll(u,2,!1,u,null,!1,!1)});"allowFullScreen async autoFocus autoPlay controls default defer disabled disablePictureInPicture disableRemotePlayback formNoValidate hidden loop noModule noValidate open playsInline readOnly required reversed scoped seamless itemScope".split(" ").forEach(function(u){il[u]=new Ll(u,3,!1,u.toLowerCase(),null,!1,!1)});["checked","multiple","muted","selected"].forEach(function(u){il[u]=new Ll(u,3,!0,u,null,!1,!1)});["capture","download"].forEach(function(u){il[u]=new Ll(u,4,!1,u,null,!1,!1)});["cols","rows","size","span"].forEach(function(u){il[u]=new Ll(u,6,!1,u,null,!1,!1)});["rowSpan","start"].forEach(function(u){il[u]=new Ll(u,5,!1,u.toLowerCase(),null,!1,!1)});var A5=/[\-:]([a-z])/g;function j5(u){return u[1].toUpperCase()}"accent-height alignment-baseline arabic-form baseline-shift cap-height clip-path clip-rule color-interpolation color-interpolation-filters color-profile color-rendering dominant-baseline enable-background fill-opacity fill-rule flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight glyph-name glyph-orientation-horizontal glyph-orientation-vertical horiz-adv-x horiz-origin-x image-rendering letter-spacing lighting-color marker-end marker-mid marker-start overline-position overline-thickness paint-order panose-1 pointer-events rendering-intent shape-rendering stop-color stop-opacity strikethrough-position strikethrough-thickness stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width text-anchor text-decoration text-rendering underline-position underline-thickness unicode-bidi unicode-range units-per-em v-alphabetic v-hanging v-ideographic v-mathematical vector-effect vert-adv-y vert-origin-x vert-origin-y word-spacing writing-mode xmlns:xlink x-height".split(" ").forEach(function(u){var f=u.replace(A5,j5);il[f]=new Ll(f,1,!1,u,null,!1,!1)});"xlink:actuate xlink:arcrole xlink:role xlink:show xlink:title xlink:type".split(" ").forEach(function(u){var f=u.replace(A5,j5);il[f]=new Ll(f,1,!1,u,"http://www.w3.org/1999/xlink",!1,!1)});["xml:base","xml:lang","xml:space"].forEach(function(u){var f=u.replace(A5,j5);il[f]=new Ll(f,1,!1,u,"http://www.w3.org/XML/1998/namespace",!1,!1)});["tabIndex","crossOrigin"].forEach(function(u){il[u]=new Ll(u,1,!1,u.toLowerCase(),null,!1,!1)});il.xlinkHref=new Ll("xlinkHref",1,!1,"xlink:href","http://www.w3.org/1999/xlink",!0,!1);["src","href","action","formAction"].forEach(function(u){il[u]=new Ll(u,1,!1,u.toLowerCase(),null,!0,!0)});function F5(u,f,l,r){var y=il.hasOwnProperty(f)?il[f]:null;if(y!==null?y.type!==0:r||!(2n||y[_]!==i[n]){var $=` +`+y[_].replace(" at new "," at ");return u.displayName&&$.includes("")&&($=$.replace("",u.displayName)),$}while(1<=_&&0<=n);break}}}finally{s8=!1,Error.prepareStackTrace=l}return(u=u?u.displayName||u.name:"")?H_(u):""}function AL(u){switch(u.tag){case 5:return H_(u.type);case 16:return H_("Lazy");case 13:return H_("Suspense");case 19:return H_("SuspenseList");case 0:case 2:case 15:return u=a8(u.type,!1),u;case 11:return u=a8(u.type.render,!1),u;case 1:return u=a8(u.type,!0),u;default:return""}}function z2(u){if(u==null)return null;if(typeof u==="function")return u.displayName||u.name||null;if(typeof u==="string")return u;switch(u){case hy:return"Fragment";case Ry:return"Portal";case W2:return"Profiler";case J5:return"StrictMode";case c2:return"Suspense";case N2:return"SuspenseList"}if(typeof u==="object")switch(u.$$typeof){case BJ:return(u.displayName||"Context")+".Consumer";case OJ:return(u._context.displayName||"Context")+".Provider";case U5:var f=u.render;return u=u.displayName,u||(u=f.displayName||f.name||"",u=u!==""?"ForwardRef("+u+")":"ForwardRef"),u;case Q5:return f=u.displayName||null,f!==null?f:z2(u.type)||"Memo";case b0:f=u._payload,u=u._init;try{return z2(u(f))}catch(l){}}return null}function jL(u){var f=u.type;switch(u.tag){case 24:return"Cache";case 9:return(f.displayName||"Context")+".Consumer";case 10:return(f._context.displayName||"Context")+".Provider";case 18:return"DehydratedFragment";case 11:return u=f.render,u=u.displayName||u.name||"",f.displayName||(u!==""?"ForwardRef("+u+")":"ForwardRef");case 7:return"Fragment";case 5:return f;case 4:return"Portal";case 3:return"Root";case 6:return"Text";case 16:return z2(f);case 8:return f===J5?"StrictMode":"Mode";case 22:return"Offscreen";case 12:return"Profiler";case 21:return"Scope";case 13:return"Suspense";case 19:return"SuspenseList";case 25:return"TracingMarker";case 1:case 0:case 17:case 2:case 14:case 15:if(typeof f==="function")return f.displayName||f.name||null;if(typeof f==="string")return f}return null}function y1(u){switch(typeof u){case"boolean":case"number":case"string":case"undefined":return u;case"object":return u;default:return""}}function XJ(u){var f=u.type;return(u=u.nodeName)&&u.toLowerCase()==="input"&&(f==="checkbox"||f==="radio")}function FL(u){var f=XJ(u)?"checked":"value",l=Object.getOwnPropertyDescriptor(u.constructor.prototype,f),r=""+u[f];if(!u.hasOwnProperty(f)&&typeof l<"u"&&typeof l.get==="function"&&typeof l.set==="function"){var{get:y,set:i}=l;return Object.defineProperty(u,f,{configurable:!0,get:function(){return y.call(this)},set:function(_){r=""+_,i.call(this,_)}}),Object.defineProperty(u,f,{enumerable:l.enumerable}),{getValue:function(){return r},setValue:function(_){r=""+_},stopTracking:function(){u._valueTracker=null,delete u[f]}}}}function n3(u){u._valueTracker||(u._valueTracker=FL(u))}function YJ(u){if(!u)return!1;var f=u._valueTracker;if(!f)return!0;var l=f.getValue(),r="";return u&&(r=XJ(u)?u.checked?"true":"false":u.value),u=r,u!==l?(f.setValue(u),!0):!1}function Y3(u){if(u=u||(typeof document<"u"?document:void 0),typeof u>"u")return null;try{return u.activeElement||u.body}catch(f){return u.body}}function G2(u,f){var l=f.checked;return Of({},f,{defaultChecked:void 0,defaultValue:void 0,value:void 0,checked:l!=null?l:u._wrapperState.initialChecked})}function ZF(u,f){var l=f.defaultValue==null?"":f.defaultValue,r=f.checked!=null?f.checked:f.defaultChecked;l=y1(f.value!=null?f.value:l),u._wrapperState={initialChecked:r,initialValue:l,controlled:f.type==="checkbox"||f.type==="radio"?f.checked!=null:f.value!=null}}function DJ(u,f){f=f.checked,f!=null&&F5(u,"checked",f,!1)}function K2(u,f){DJ(u,f);var l=y1(f.value),r=f.type;if(l!=null)if(r==="number"){if(l===0&&u.value===""||u.value!=l)u.value=""+l}else u.value!==""+l&&(u.value=""+l);else if(r==="submit"||r==="reset"){u.removeAttribute("value");return}f.hasOwnProperty("value")?L2(u,f.type,l):f.hasOwnProperty("defaultValue")&&L2(u,f.type,y1(f.defaultValue)),f.checked==null&&f.defaultChecked!=null&&(u.defaultChecked=!!f.defaultChecked)}function HF(u,f,l){if(f.hasOwnProperty("value")||f.hasOwnProperty("defaultValue")){var r=f.type;if(!(r!=="submit"&&r!=="reset"||f.value!==void 0&&f.value!==null))return;f=""+u._wrapperState.initialValue,l||f===u.value||(u.value=f),u.defaultValue=f}l=u.name,l!==""&&(u.name=""),u.defaultChecked=!!u._wrapperState.initialChecked,l!==""&&(u.name=l)}function L2(u,f,l){if(f!=="number"||Y3(u.ownerDocument)!==u)l==null?u.defaultValue=""+u._wrapperState.initialValue:u.defaultValue!==""+l&&(u.defaultValue=""+l)}var O_=Array.isArray;function ui(u,f,l,r){if(u=u.options,f){f={};for(var y=0;y"+f.valueOf().toString()+"";for(f=$3.firstChild;u.firstChild;)u.removeChild(u.firstChild);for(;f.firstChild;)u.appendChild(f.firstChild)}});function v_(u,f){if(f){var l=u.firstChild;if(l&&l===u.lastChild&&l.nodeType===3){l.nodeValue=f;return}}u.textContent=f}var S_={animationIterationCount:!0,aspectRatio:!0,borderImageOutset:!0,borderImageSlice:!0,borderImageWidth:!0,boxFlex:!0,boxFlexGroup:!0,boxOrdinalGroup:!0,columnCount:!0,columns:!0,flex:!0,flexGrow:!0,flexPositive:!0,flexShrink:!0,flexNegative:!0,flexOrder:!0,gridArea:!0,gridRow:!0,gridRowEnd:!0,gridRowSpan:!0,gridRowStart:!0,gridColumn:!0,gridColumnEnd:!0,gridColumnSpan:!0,gridColumnStart:!0,fontWeight:!0,lineClamp:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,tabSize:!0,widows:!0,zIndex:!0,zoom:!0,fillOpacity:!0,floodOpacity:!0,stopOpacity:!0,strokeDasharray:!0,strokeDashoffset:!0,strokeMiterlimit:!0,strokeOpacity:!0,strokeWidth:!0},JL=["Webkit","ms","Moz","O"];Object.keys(S_).forEach(function(u){JL.forEach(function(f){f=f+u.charAt(0).toUpperCase()+u.substring(1),S_[f]=S_[u]})});function MJ(u,f,l){return f==null||typeof f==="boolean"||f===""?"":l||typeof f!=="number"||f===0||S_.hasOwnProperty(u)&&S_[u]?(""+f).trim():f+"px"}function mJ(u,f){u=u.style;for(var l in f)if(f.hasOwnProperty(l)){var r=l.indexOf("--")===0,y=MJ(l,f[l],r);l==="float"&&(l="cssFloat"),r?u.setProperty(l,y):u[l]=y}}var UL=Of({menuitem:!0},{area:!0,base:!0,br:!0,col:!0,embed:!0,hr:!0,img:!0,input:!0,keygen:!0,link:!0,meta:!0,param:!0,source:!0,track:!0,wbr:!0});function T2(u,f){if(f){if(UL[u]&&(f.children!=null||f.dangerouslySetInnerHTML!=null))throw Error(Uu(137,u));if(f.dangerouslySetInnerHTML!=null){if(f.children!=null)throw Error(Uu(60));if(typeof f.dangerouslySetInnerHTML!=="object"||!("__html"in f.dangerouslySetInnerHTML))throw Error(Uu(61))}if(f.style!=null&&typeof f.style!=="object")throw Error(Uu(62))}}function Z2(u,f){if(u.indexOf("-")===-1)return typeof f.is==="string";switch(u){case"annotation-xml":case"color-profile":case"font-face":case"font-face-src":case"font-face-uri":case"font-face-format":case"font-face-name":case"missing-glyph":return!1;default:return!0}}var H2=null;function q5(u){return u=u.target||u.srcElement||window,u.correspondingUseElement&&(u=u.correspondingUseElement),u.nodeType===3?u.parentNode:u}var O2=null,fi=null,li=null;function VF(u){if(u=jn(u)){if(typeof O2!=="function")throw Error(Uu(280));var f=u.stateNode;f&&(f=_6(f),O2(u.stateNode,u.type,f))}}function pJ(u){fi?li?li.push(u):li=[u]:fi=u}function CJ(){if(fi){var u=fi,f=li;if(li=fi=null,VF(u),f)for(u=0;u>>=0,u===0?32:31-(EL(u)/TL|0)|0}var A3=64,j3=4194304;function B_(u){switch(u&-u){case 1:return 1;case 2:return 2;case 4:return 4;case 8:return 8;case 16:return 16;case 32:return 32;case 64:case 128:case 256:case 512:case 1024:case 2048:case 4096:case 8192:case 16384:case 32768:case 65536:case 131072:case 262144:case 524288:case 1048576:case 2097152:return u&4194240;case 4194304:case 8388608:case 16777216:case 33554432:case 67108864:return u&130023424;case 134217728:return 134217728;case 268435456:return 268435456;case 536870912:return 536870912;case 1073741824:return 1073741824;default:return u}}function P3(u,f){var l=u.pendingLanes;if(l===0)return 0;var r=0,y=u.suspendedLanes,i=u.pingedLanes,_=l&268435455;if(_!==0){var n=_&~y;n!==0?r=B_(n):(i&=_,i!==0&&(r=B_(i)))}else _=l&~y,_!==0?r=B_(_):i!==0&&(r=B_(i));if(r===0)return 0;if(f!==0&&f!==r&&(f&y)===0&&(y=r&-r,i=f&-f,y>=i||y===16&&(i&4194240)!==0))return f;if((r&4)!==0&&(r|=l&16),f=u.entangledLanes,f!==0)for(u=u.entanglements,f&=r;0l;l++)f.push(u);return f}function $n(u,f,l){u.pendingLanes|=f,f!==536870912&&(u.suspendedLanes=0,u.pingedLanes=0),u=u.eventTimes,f=31-Yr(f),u[f]=l}function BL(u,f){var l=u.pendingLanes&~f;u.pendingLanes=f,u.suspendedLanes=0,u.pingedLanes=0,u.expiredLanes&=f,u.mutableReadLanes&=f,u.entangledLanes&=f,f=u.entanglements;var r=u.eventTimes;for(u=u.expirationTimes;0=M_),pF=String.fromCharCode(32),CF=!1;function _U(u,f){switch(u){case"keyup":return rw.indexOf(f.keyCode)!==-1;case"keydown":return f.keyCode!==229;case"keypress":case"mousedown":case"focusout":return!0;default:return!1}}function nU(u){return u=u.detail,typeof u==="object"&&"data"in u?u.data:null}var by=!1;function iw(u,f){switch(u){case"compositionend":return nU(f);case"keypress":if(f.which!==32)return null;return CF=!0,pF;case"textInput":return u=f.data,u===pF&&CF?null:u;default:return null}}function _w(u,f){if(by)return u==="compositionend"||!w5&&_U(u,f)?(u=yU(),L3=G5=g0=null,by=!1,u):null;switch(u){case"paste":return null;case"keypress":if(!(f.ctrlKey||f.altKey||f.metaKey)||f.ctrlKey&&f.altKey){if(f.char&&1=f)return{node:l,offset:f-u};u=r}u:{for(;l;){if(l.nextSibling){l=l.nextSibling;break u}l=l.parentNode}l=void 0}l=hF(l)}}function FU(u,f){return u&&f?u===f?!0:u&&u.nodeType===3?!1:f&&f.nodeType===3?FU(u,f.parentNode):("contains"in u)?u.contains(f):u.compareDocumentPosition?!!(u.compareDocumentPosition(f)&16):!1:!1}function JU(){for(var u=window,f=Y3();f instanceof u.HTMLIFrameElement;){try{var l=typeof f.contentWindow.location.href==="string"}catch(r){l=!1}if(l)u=f.contentWindow;else break;f=Y3(u.document)}return f}function E5(u){var f=u&&u.nodeName&&u.nodeName.toLowerCase();return f&&(f==="input"&&(u.type==="text"||u.type==="search"||u.type==="tel"||u.type==="url"||u.type==="password")||f==="textarea"||u.contentEditable==="true")}function qw(u){var f=JU(),l=u.focusedElem,r=u.selectionRange;if(f!==l&&l&&l.ownerDocument&&FU(l.ownerDocument.documentElement,l)){if(r!==null&&E5(l)){if(f=r.start,u=r.end,u===void 0&&(u=f),"selectionStart"in l)l.selectionStart=f,l.selectionEnd=Math.min(u,l.value.length);else if(u=(f=l.ownerDocument||document)&&f.defaultView||window,u.getSelection){u=u.getSelection();var y=l.textContent.length,i=Math.min(r.start,y);r=r.end===void 0?i:Math.min(r.end,y),!u.extend&&i>r&&(y=r,r=i,i=y),y=bF(l,i);var _=bF(l,r);y&&_&&(u.rangeCount!==1||u.anchorNode!==y.node||u.anchorOffset!==y.offset||u.focusNode!==_.node||u.focusOffset!==_.offset)&&(f=f.createRange(),f.setStart(y.node,y.offset),u.removeAllRanges(),i>r?(u.addRange(f),u.extend(_.node,_.offset)):(f.setEnd(_.node,_.offset),u.addRange(f)))}}f=[];for(u=l;u=u.parentNode;)u.nodeType===1&&f.push({element:u,left:u.scrollLeft,top:u.scrollTop});typeof l.focus==="function"&&l.focus();for(l=0;l=document.documentMode,vy=null,t2=null,p_=null,S2=!1;function vF(u,f,l){var r=l.window===l?l.document:l.nodeType===9?l:l.ownerDocument;S2||vy==null||vy!==Y3(r)||(r=vy,("selectionStart"in r)&&E5(r)?r={start:r.selectionStart,end:r.selectionEnd}:(r=(r.ownerDocument&&r.ownerDocument.defaultView||window).getSelection(),r={anchorNode:r.anchorNode,anchorOffset:r.anchorOffset,focusNode:r.focusNode,focusOffset:r.focusOffset}),p_&&o_(p_,r)||(p_=r,r=p3(t2,"onSelect"),0gy||(u.current=h2[gy],h2[gy]=null,gy--)}function cf(u,f){gy++,h2[gy]=u.current,u.current=f}var i1={},Ql=n1(i1),Sl=n1(!1),o1=i1;function ni(u,f){var l=u.type.contextTypes;if(!l)return i1;var r=u.stateNode;if(r&&r.__reactInternalMemoizedUnmaskedChildContext===f)return r.__reactInternalMemoizedMaskedChildContext;var y={},i;for(i in l)y[i]=f[i];return r&&(u=u.stateNode,u.__reactInternalMemoizedUnmaskedChildContext=f,u.__reactInternalMemoizedMaskedChildContext=y),y}function Pl(u){return u=u.childContextTypes,u!==null&&u!==void 0}function x3(){Gf(Sl),Gf(Ql)}function dF(u,f,l){if(Ql.current!==i1)throw Error(Uu(168));cf(Ql,f),cf(Sl,l)}function KU(u,f,l){var r=u.stateNode;if(f=f.childContextTypes,typeof r.getChildContext!=="function")return l;r=r.getChildContext();for(var y in r)if(!(y in f))throw Error(Uu(108,jL(u)||"Unknown",y));return Of({},l,r)}function R3(u){return u=(u=u.stateNode)&&u.__reactInternalMemoizedMergedChildContext||i1,o1=Ql.current,cf(Ql,u),cf(Sl,Sl.current),!0}function eF(u,f,l){var r=u.stateNode;if(!r)throw Error(Uu(169));l?(u=KU(u,f,o1),r.__reactInternalMemoizedMergedChildContext=u,Gf(Sl),Gf(Ql),cf(Ql,u)):Gf(Sl),cf(Sl,l)}var q0=null,n6=!1,_2=!1;function LU(u){q0===null?q0=[u]:q0.push(u)}function Tw(u){n6=!0,LU(u)}function $1(){if(!_2&&q0!==null){_2=!0;var u=0,f=nf;try{var l=q0;for(nf=1;u>=_,y-=_,W0=1<<32-Yr(f)+y|l<T?(X=B,B=null):X=B.sibling;var R=U(Q,B,c[T],z);if(R===null){B===null&&(B=X);break}u&&B&&R.alternate===null&&f(Q,B),N=i(R,N,T),H===null?w=R:H.sibling=R,H=R,B=X}if(T===c.length)return l(Q,B),Ef&&b1(Q,T),w;if(B===null){for(;TT?(X=B,B=null):X=B.sibling;var Y=U(Q,B,R.value,z);if(Y===null){B===null&&(B=X);break}u&&B&&Y.alternate===null&&f(Q,B),N=i(Y,N,T),H===null?w=Y:H.sibling=Y,H=Y,B=X}if(R.done)return l(Q,B),Ef&&b1(Q,T),w;if(B===null){for(;!R.done;T++,R=c.next())R=J(Q,R.value,z),R!==null&&(N=i(R,N,T),H===null?w=R:H.sibling=R,H=R);return Ef&&b1(Q,T),w}for(B=r(Q,B);!R.done;T++,R=c.next())R=q(B,Q,T,R.value,z),R!==null&&(u&&R.alternate!==null&&B.delete(R.key===null?T:R.key),N=i(R,N,T),H===null?w=R:H.sibling=R,H=R);return u&&B.forEach(function(P){return f(Q,P)}),Ef&&b1(Q,T),w}function K(Q,N,c,z){if(typeof c==="object"&&c!==null&&c.type===hy&&c.key===null&&(c=c.props.children),typeof c==="object"&&c!==null){switch(c.$$typeof){case _3:u:{for(var w=c.key,H=N;H!==null;){if(H.key===w){if(w=c.type,w===hy){if(H.tag===7){l(Q,H.sibling),N=y(H,c.props.children),N.return=Q,Q=N;break u}}else if(H.elementType===w||typeof w==="object"&&w!==null&&w.$$typeof===b0&&lJ(w)===H.type){l(Q,H.sibling),N=y(H,c.props),N.ref=E_(Q,H,c),N.return=Q,Q=N;break u}l(Q,H);break}else f(Q,H);H=H.sibling}c.type===hy?(N=a1(c.props.children,Q.mode,z,c.key),N.return=Q,Q=N):(z=X3(c.type,c.key,c.props,null,Q.mode,z),z.ref=E_(Q,N,c),z.return=Q,Q=z)}return _(Q);case Ry:u:{for(H=c.key;N!==null;){if(N.key===H)if(N.tag===4&&N.stateNode.containerInfo===c.containerInfo&&N.stateNode.implementation===c.implementation){l(Q,N.sibling),N=y(N,c.children||[]),N.return=Q,Q=N;break u}else{l(Q,N);break}else f(Q,N);N=N.sibling}N=Q2(c,Q.mode,z),N.return=Q,Q=N}return _(Q);case b0:return H=c._init,K(Q,N,H(c._payload),z)}if(O_(c))return W(Q,N,c,z);if(G_(c))return G(Q,N,c,z);c3(Q,c)}return typeof c==="string"&&c!==""||typeof c==="number"?(c=""+c,N!==null&&N.tag===6?(l(Q,N.sibling),N=y(N,c),N.return=Q,Q=N):(l(Q,N),N=U2(c,Q.mode,z),N.return=Q,Q=N),_(Q)):l(Q,N)}return K}var Ai=ZU(!0),HU=ZU(!1),v3=n1(null),I3=null,oy=null,O5=null;function B5(){O5=oy=I3=null}function V5(u){var f=v3.current;Gf(v3),u._currentValue=f}function I2(u,f,l){for(;u!==null;){var r=u.alternate;if((u.childLanes&f)!==f?(u.childLanes|=f,r!==null&&(r.childLanes|=f)):r!==null&&(r.childLanes&f)!==f&&(r.childLanes|=f),u===l)break;u=u.return}}function yi(u,f){I3=u,O5=oy=null,u=u.dependencies,u!==null&&u.firstContext!==null&&((u.lanes&f)!==0&&(tl=!0),u.firstContext=null)}function zr(u){var f=u._currentValue;if(O5!==u)if(u={context:u,memoizedValue:f,next:null},oy===null){if(I3===null)throw Error(Uu(308));oy=u,I3.dependencies={lanes:0,firstContext:u}}else oy=oy.next=u;return f}var k1=null;function X5(u){k1===null?k1=[u]:k1.push(u)}function OU(u,f,l,r){var y=f.interleaved;return y===null?(l.next=l,X5(f)):(l.next=y.next,y.next=l),f.interleaved=l,K0(u,r)}function K0(u,f){u.lanes|=f;var l=u.alternate;l!==null&&(l.lanes|=f),l=u;for(u=u.return;u!==null;)u.childLanes|=f,l=u.alternate,l!==null&&(l.childLanes|=f),l=u,u=u.return;return l.tag===3?l.stateNode:null}var v0=!1;function Y5(u){u.updateQueue={baseState:u.memoizedState,firstBaseUpdate:null,lastBaseUpdate:null,shared:{pending:null,interleaved:null,lanes:0},effects:null}}function BU(u,f){u=u.updateQueue,f.updateQueue===u&&(f.updateQueue={baseState:u.baseState,firstBaseUpdate:u.firstBaseUpdate,lastBaseUpdate:u.lastBaseUpdate,shared:u.shared,effects:u.effects})}function N0(u,f){return{eventTime:u,lane:f,tag:0,payload:null,callback:null,next:null}}function u1(u,f,l){var r=u.updateQueue;if(r===null)return null;if(r=r.shared,(lf&2)!==0){var y=r.pending;return y===null?f.next=f:(f.next=y.next,y.next=f),r.pending=f,K0(u,l)}return y=r.interleaved,y===null?(f.next=f,X5(r)):(f.next=y.next,y.next=f),r.interleaved=f,K0(u,l)}function T3(u,f,l){if(f=f.updateQueue,f!==null&&(f=f.shared,(l&4194240)!==0)){var r=f.lanes;r&=u.pendingLanes,l|=r,f.lanes=l,c5(u,l)}}function rJ(u,f){var{updateQueue:l,alternate:r}=u;if(r!==null&&(r=r.updateQueue,l===r)){var y=null,i=null;if(l=l.firstBaseUpdate,l!==null){do{var _={eventTime:l.eventTime,lane:l.lane,tag:l.tag,payload:l.payload,callback:l.callback,next:null};i===null?y=i=_:i=i.next=_,l=l.next}while(l!==null);i===null?y=i=f:i=i.next=f}else y=i=f;l={baseState:r.baseState,firstBaseUpdate:y,lastBaseUpdate:i,shared:r.shared,effects:r.effects},u.updateQueue=l;return}u=l.lastBaseUpdate,u===null?l.firstBaseUpdate=f:u.next=f,l.lastBaseUpdate=f}function k3(u,f,l,r){var y=u.updateQueue;v0=!1;var{firstBaseUpdate:i,lastBaseUpdate:_}=y,n=y.shared.pending;if(n!==null){y.shared.pending=null;var $=n,j=$.next;$.next=null,_===null?i=j:_.next=j,_=$;var F=u.alternate;F!==null&&(F=F.updateQueue,n=F.lastBaseUpdate,n!==_&&(n===null?F.firstBaseUpdate=j:n.next=j,F.lastBaseUpdate=$))}if(i!==null){var J=y.baseState;_=0,F=j=$=null,n=i;do{var{lane:U,eventTime:q}=n;if((r&U)===U){F!==null&&(F=F.next={eventTime:q,lane:0,tag:n.tag,payload:n.payload,callback:n.callback,next:null});u:{var W=u,G=n;switch(U=f,q=l,G.tag){case 1:if(W=G.payload,typeof W==="function"){J=W.call(q,J,U);break u}J=W;break u;case 3:W.flags=W.flags&-65537|128;case 0:if(W=G.payload,U=typeof W==="function"?W.call(q,J,U):W,U===null||U===void 0)break u;J=Of({},J,U);break u;case 2:v0=!0}}n.callback!==null&&n.lane!==0&&(u.flags|=64,U=y.effects,U===null?y.effects=[n]:U.push(n))}else q={eventTime:q,lane:U,tag:n.tag,payload:n.payload,callback:n.callback,next:null},F===null?(j=F=q,$=J):F=F.next=q,_|=U;if(n=n.next,n===null)if(n=y.shared.pending,n===null)break;else U=n,n=U.next,U.next=null,y.lastBaseUpdate=U,y.shared.pending=null}while(1);if(F===null&&($=J),y.baseState=$,y.firstBaseUpdate=j,y.lastBaseUpdate=F,f=y.shared.interleaved,f!==null){y=f;do _|=y.lane,y=y.next;while(y!==f)}else i===null&&(y.shared.lanes=0);uy|=_,u.lanes=_,u.memoizedState=J}}function yJ(u,f,l){if(u=f.effects,f.effects=null,u!==null)for(f=0;fl?l:4,u(!0);var r=$2.transition;$2.transition={};try{u(!1),f()}finally{nf=l,$2.transition=r}}function IU(){return Gr().memoizedState}function Bw(u,f,l){var r=l1(u);if(l={lane:r,action:l,hasEagerState:!1,eagerState:null,next:null},kU(u))gU(f,l);else if(l=OU(u,f,l,r),l!==null){var y=Kl();Dr(l,u,r,y),sU(l,f,r)}}function Vw(u,f,l){var r=l1(u),y={lane:r,action:l,hasEagerState:!1,eagerState:null,next:null};if(kU(u))gU(f,y);else{var i=u.alternate;if(u.lanes===0&&(i===null||i.lanes===0)&&(i=f.lastRenderedReducer,i!==null))try{var _=f.lastRenderedState,n=i(_,l);if(y.hasEagerState=!0,y.eagerState=n,tr(n,_)){var $=f.interleaved;$===null?(y.next=y,X5(f)):(y.next=$.next,$.next=y),f.interleaved=y;return}}catch(j){}finally{}l=OU(u,f,y,r),l!==null&&(y=Kl(),Dr(l,u,r,y),sU(l,f,r))}}function kU(u){var f=u.alternate;return u===Hf||f!==null&&f===Hf}function gU(u,f){C_=s3=!0;var l=u.pending;l===null?f.next=f:(f.next=l.next,l.next=f),u.pending=f}function sU(u,f,l){if((l&4194240)!==0){var r=f.lanes;r&=u.pendingLanes,l|=r,f.lanes=l,c5(u,l)}}var a3={readContext:zr,useCallback:Fl,useContext:Fl,useEffect:Fl,useImperativeHandle:Fl,useInsertionEffect:Fl,useLayoutEffect:Fl,useMemo:Fl,useReducer:Fl,useRef:Fl,useState:Fl,useDebugValue:Fl,useDeferredValue:Fl,useTransition:Fl,useMutableSource:Fl,useSyncExternalStore:Fl,useId:Fl,unstable_isNewReconciler:!1},Xw={readContext:zr,useCallback:function(u,f){return sr().memoizedState=[u,f===void 0?null:f],u},useContext:zr,useEffect:_J,useImperativeHandle:function(u,f,l){return l=l!==null&&l!==void 0?l.concat([u]):null,H3(4194308,4,xU.bind(null,f,u),l)},useLayoutEffect:function(u,f){return H3(4194308,4,u,f)},useInsertionEffect:function(u,f){return H3(4,2,u,f)},useMemo:function(u,f){var l=sr();return f=f===void 0?null:f,u=u(),l.memoizedState=[u,f],u},useReducer:function(u,f,l){var r=sr();return f=l!==void 0?l(f):f,r.memoizedState=r.baseState=f,u={pending:null,interleaved:null,lanes:0,dispatch:null,lastRenderedReducer:u,lastRenderedState:f},r.queue=u,u=u.dispatch=Bw.bind(null,Hf,u),[r.memoizedState,u]},useRef:function(u){var f=sr();return u={current:u},f.memoizedState=u},useState:iJ,useDebugValue:C5,useDeferredValue:function(u){return sr().memoizedState=u},useTransition:function(){var u=iJ(!1),f=u[0];return u=Ow.bind(null,u[1]),sr().memoizedState=u,[f,u]},useMutableSource:function(){},useSyncExternalStore:function(u,f,l){var r=Hf,y=sr();if(Ef){if(l===void 0)throw Error(Uu(407));l=l()}else{if(l=f(),df===null)throw Error(Uu(349));(e1&30)!==0||DU(r,f,l)}y.memoizedState=l;var i={value:l,getSnapshot:f};return y.queue=i,_J(SU.bind(null,r,i,u),[u]),r.flags|=2048,_n(9,tU.bind(null,r,i,l,f),void 0,null),l},useId:function(){var u=sr(),f=df.identifierPrefix;if(Ef){var l=c0,r=W0;l=(r&~(1<<32-Yr(r)-1)).toString(32)+l,f=":"+f+"R"+l,l=rn++,0",u=u.removeChild(u.firstChild)):typeof r.is==="string"?u=_.createElement(l,{is:r.is}):(u=_.createElement(l),l==="select"&&(_=u,r.multiple?_.multiple=!0:r.size&&(_.size=r.size))):u=_.createElementNS(u,l),u[ar]=f,u[un]=r,iQ(u,f,!1,!1),f.stateNode=u;u:{switch(_=Z2(l,r),l){case"dialog":zf("cancel",u),zf("close",u),y=r;break;case"iframe":case"object":case"embed":zf("load",u),y=r;break;case"video":case"audio":for(y=0;yJi&&(f.flags|=128,r=!0,T_(i,!1),f.lanes=4194304)}else{if(!r)if(u=g3(_),u!==null){if(f.flags|=128,r=!0,l=u.updateQueue,l!==null&&(f.updateQueue=l,f.flags|=4),T_(i,!0),i.tail===null&&i.tailMode==="hidden"&&!_.alternate&&!Ef)return Jl(f),null}else 2*tf()-i.renderingStartTime>Ji&&l!==1073741824&&(f.flags|=128,r=!0,T_(i,!1),f.lanes=4194304);i.isBackwards?(_.sibling=f.child,f.child=_):(l=i.last,l!==null?l.sibling=_:f.child=_,i.last=_)}if(i.tail!==null)return f=i.tail,i.rendering=f,i.tail=f.sibling,i.renderingStartTime=tf(),f.sibling=null,l=Zf.current,cf(Zf,r?l&1|2:l&1),f;return Jl(f),null;case 22:case 23:return I5(),r=f.memoizedState!==null,u!==null&&u.memoizedState!==null!==r&&(f.flags|=8192),r&&(f.mode&1)!==0?(dl&1073741824)!==0&&(Jl(f),f.subtreeFlags&6&&(f.flags|=8192)):Jl(f),null;case 24:return null;case 25:return null}throw Error(Uu(156,f.tag))}function pw(u,f){switch(Z5(f),f.tag){case 1:return Pl(f.type)&&x3(),u=f.flags,u&65536?(f.flags=u&-65537|128,f):null;case 3:return ji(),Gf(Sl),Gf(Ql),S5(),u=f.flags,(u&65536)!==0&&(u&128)===0?(f.flags=u&-65537|128,f):null;case 5:return t5(f),null;case 13:if(Gf(Zf),u=f.memoizedState,u!==null&&u.dehydrated!==null){if(f.alternate===null)throw Error(Uu(340));$i()}return u=f.flags,u&65536?(f.flags=u&-65537|128,f):null;case 19:return Gf(Zf),null;case 4:return ji(),null;case 10:return V5(f.type._context),null;case 22:case 23:return I5(),null;case 24:return null;default:return null}}var z3=!1,Ul=!1,Cw=typeof WeakSet==="function"?WeakSet:Set,wu=null;function dy(u,f){var l=u.ref;if(l!==null)if(typeof l==="function")try{l(null)}catch(r){Vf(u,f,r)}else l.current=null}function f5(u,f,l){try{l()}catch(r){Vf(u,f,r)}}var cJ=!1;function xw(u,f){if(m2=M3,u=JU(),E5(u)){if("selectionStart"in u)var l={start:u.selectionStart,end:u.selectionEnd};else u:{l=(l=u.ownerDocument)&&l.defaultView||window;var r=l.getSelection&&l.getSelection();if(r&&r.rangeCount!==0){l=r.anchorNode;var{anchorOffset:y,focusNode:i}=r;r=r.focusOffset;try{l.nodeType,i.nodeType}catch(z){l=null;break u}var _=0,n=-1,$=-1,j=0,F=0,J=u,U=null;f:for(;;){for(var q;;){if(J!==l||y!==0&&J.nodeType!==3||(n=_+y),J!==i||r!==0&&J.nodeType!==3||($=_+r),J.nodeType===3&&(_+=J.nodeValue.length),(q=J.firstChild)===null)break;U=J,J=q}for(;;){if(J===u)break f;if(U===l&&++j===y&&(n=_),U===i&&++F===r&&($=_),(q=J.nextSibling)!==null)break;J=U,U=J.parentNode}J=q}l=n===-1||$===-1?null:{start:n,end:$}}else l=null}l=l||{start:0,end:0}}else l=null;p2={focusedElem:u,selectionRange:l},M3=!1;for(wu=f;wu!==null;)if(f=wu,u=f.child,(f.subtreeFlags&1028)!==0&&u!==null)u.return=f,wu=u;else for(;wu!==null;){f=wu;try{var W=f.alternate;if((f.flags&1024)!==0)switch(f.tag){case 0:case 11:case 15:break;case 1:if(W!==null){var{memoizedProps:G,memoizedState:K}=W,Q=f.stateNode,N=Q.getSnapshotBeforeUpdate(f.elementType===f.type?G:Br(f.type,G),K);Q.__reactInternalSnapshotBeforeUpdate=N}break;case 3:var c=f.stateNode.containerInfo;c.nodeType===1?c.textContent="":c.nodeType===9&&c.documentElement&&c.removeChild(c.documentElement);break;case 5:case 6:case 4:case 17:break;default:throw Error(Uu(163))}}catch(z){Vf(f,f.return,z)}if(u=f.sibling,u!==null){u.return=f.return,wu=u;break}wu=f.return}return W=cJ,cJ=!1,W}function x_(u,f,l){var r=f.updateQueue;if(r=r!==null?r.lastEffect:null,r!==null){var y=r=r.next;do{if((y.tag&u)===u){var i=y.destroy;y.destroy=void 0,i!==void 0&&f5(f,l,i)}y=y.next}while(y!==r)}}function j6(u,f){if(f=f.updateQueue,f=f!==null?f.lastEffect:null,f!==null){var l=f=f.next;do{if((l.tag&u)===u){var r=l.create;l.destroy=r()}l=l.next}while(l!==f)}}function l5(u){var f=u.ref;if(f!==null){var l=u.stateNode;switch(u.tag){case 5:u=l;break;default:u=l}typeof f==="function"?f(u):f.current=u}}function $Q(u){var f=u.alternate;f!==null&&(u.alternate=null,$Q(f)),u.child=null,u.deletions=null,u.sibling=null,u.tag===5&&(f=u.stateNode,f!==null&&(delete f[ar],delete f[un],delete f[R2],delete f[ww],delete f[Ew])),u.stateNode=null,u.return=null,u.dependencies=null,u.memoizedProps=null,u.memoizedState=null,u.pendingProps=null,u.stateNode=null,u.updateQueue=null}function AQ(u){return u.tag===5||u.tag===3||u.tag===4}function NJ(u){u:for(;;){for(;u.sibling===null;){if(u.return===null||AQ(u.return))return null;u=u.return}u.sibling.return=u.return;for(u=u.sibling;u.tag!==5&&u.tag!==6&&u.tag!==18;){if(u.flags&2)continue u;if(u.child===null||u.tag===4)continue u;else u.child.return=u,u=u.child}if(!(u.flags&2))return u.stateNode}}function r5(u,f,l){var r=u.tag;if(r===5||r===6)u=u.stateNode,f?l.nodeType===8?l.parentNode.insertBefore(u,f):l.insertBefore(u,f):(l.nodeType===8?(f=l.parentNode,f.insertBefore(u,l)):(f=l,f.appendChild(u)),l=l._reactRootContainer,l!==null&&l!==void 0||f.onclick!==null||(f.onclick=C3));else if(r!==4&&(u=u.child,u!==null))for(r5(u,f,l),u=u.sibling;u!==null;)r5(u,f,l),u=u.sibling}function y5(u,f,l){var r=u.tag;if(r===5||r===6)u=u.stateNode,f?l.insertBefore(u,f):l.appendChild(u);else if(r!==4&&(u=u.child,u!==null))for(y5(u,f,l),u=u.sibling;u!==null;)y5(u,f,l),u=u.sibling}var rl=null,Vr=!1;function h0(u,f,l){for(l=l.child;l!==null;)jQ(u,f,l),l=l.sibling}function jQ(u,f,l){if(or&&typeof or.onCommitFiberUnmount==="function")try{or.onCommitFiberUnmount(l6,l)}catch(n){}switch(l.tag){case 5:Ul||dy(l,f);case 6:var r=rl,y=Vr;rl=null,h0(u,f,l),rl=r,Vr=y,rl!==null&&(Vr?(u=rl,l=l.stateNode,u.nodeType===8?u.parentNode.removeChild(l):u.removeChild(l)):rl.removeChild(l.stateNode));break;case 18:rl!==null&&(Vr?(u=rl,l=l.stateNode,u.nodeType===8?i2(u.parentNode,l):u.nodeType===1&&i2(u,l),s_(u)):i2(rl,l.stateNode));break;case 4:r=rl,y=Vr,rl=l.stateNode.containerInfo,Vr=!0,h0(u,f,l),rl=r,Vr=y;break;case 0:case 11:case 14:case 15:if(!Ul&&(r=l.updateQueue,r!==null&&(r=r.lastEffect,r!==null))){y=r=r.next;do{var i=y,_=i.destroy;i=i.tag,_!==void 0&&((i&2)!==0?f5(l,f,_):(i&4)!==0&&f5(l,f,_)),y=y.next}while(y!==r)}h0(u,f,l);break;case 1:if(!Ul&&(dy(l,f),r=l.stateNode,typeof r.componentWillUnmount==="function"))try{r.props=l.memoizedProps,r.state=l.memoizedState,r.componentWillUnmount()}catch(n){Vf(l,f,n)}h0(u,f,l);break;case 21:h0(u,f,l);break;case 22:l.mode&1?(Ul=(r=Ul)||l.memoizedState!==null,h0(u,f,l),Ul=r):h0(u,f,l);break;default:h0(u,f,l)}}function zJ(u){var f=u.updateQueue;if(f!==null){u.updateQueue=null;var l=u.stateNode;l===null&&(l=u.stateNode=new Cw),f.forEach(function(r){var y=aw.bind(null,u,r);l.has(r)||(l.add(r),r.then(y,y))})}}function Or(u,f){var l=f.deletions;if(l!==null)for(var r=0;ry&&(y=_),r&=~i}if(r=y,r=tf()-r,r=(120>r?120:480>r?480:1080>r?1080:1920>r?1920:3000>r?3000:4320>r?4320:1960*hw(r/1960))-r,10u?16:u,s0===null)var r=!1;else{if(u=s0,s0=null,e3=0,(lf&6)!==0)throw Error(Uu(331));var y=lf;lf|=4;for(wu=u.current;wu!==null;){var i=wu,_=i.child;if((wu.flags&16)!==0){var n=i.deletions;if(n!==null){for(var $=0;$tf()-b5?s1(u,0):h5|=l),Ml(u,f)}function NQ(u,f){f===0&&((u.mode&1)===0?f=1:(f=j3,j3<<=1,(j3&130023424)===0&&(j3=4194304)));var l=Kl();u=K0(u,f),u!==null&&($n(u,f,l),Ml(u,l))}function sw(u){var f=u.memoizedState,l=0;f!==null&&(l=f.retryLane),NQ(u,l)}function aw(u,f){var l=0;switch(u.tag){case 13:var{stateNode:r,memoizedState:y}=u;y!==null&&(l=y.retryLane);break;case 19:r=u.stateNode;break;default:throw Error(Uu(314))}r!==null&&r.delete(f),NQ(u,l)}var zQ;zQ=function(u,f,l){if(u!==null)if(u.memoizedProps!==f.pendingProps||Sl.current)tl=!0;else{if((u.lanes&l)===0&&(f.flags&128)===0)return tl=!1,Mw(u,f,l);tl=(u.flags&131072)!==0?!0:!1}else tl=!1,Ef&&(f.flags&1048576)!==0&&wU(f,b3,f.index);switch(f.lanes=0,f.tag){case 2:var r=f.type;O3(u,f),u=f.pendingProps;var y=ni(f,Ql.current);yi(f,l),y=M5(null,f,r,u,y,l);var i=m5();return f.flags|=1,typeof y==="object"&&y!==null&&typeof y.render==="function"&&y.$$typeof===void 0?(f.tag=1,f.memoizedState=null,f.updateQueue=null,Pl(r)?(i=!0,R3(f)):i=!1,f.memoizedState=y.state!==null&&y.state!==void 0?y.state:null,Y5(f),y.updater=A6,f.stateNode=y,y._reactInternals=f,g2(f,r,u,l),f=o2(null,f,r,!0,i,l)):(f.tag=0,Ef&&i&&T5(f),Gl(null,f,y,l),f=f.child),f;case 16:r=f.elementType;u:{switch(O3(u,f),u=f.pendingProps,y=r._init,r=y(r._payload),f.type=r,y=f.tag=dw(r),u=Br(r,u),y){case 0:f=a2(null,f,r,u,l);break u;case 1:f=QJ(null,f,r,u,l);break u;case 11:f=JJ(null,f,r,u,l);break u;case 14:f=UJ(null,f,r,Br(r.type,u),l);break u}throw Error(Uu(306,r,""))}return f;case 0:return r=f.type,y=f.pendingProps,y=f.elementType===r?y:Br(r,y),a2(u,f,r,y,l);case 1:return r=f.type,y=f.pendingProps,y=f.elementType===r?y:Br(r,y),QJ(u,f,r,y,l);case 3:u:{if(lQ(f),u===null)throw Error(Uu(387));r=f.pendingProps,i=f.memoizedState,y=i.element,BU(u,f),k3(f,r,null,l);var _=f.memoizedState;if(r=_.element,i.isDehydrated)if(i={element:r,isDehydrated:!1,cache:_.cache,pendingSuspenseBoundaries:_.pendingSuspenseBoundaries,transitions:_.transitions},f.updateQueue.baseState=i,f.memoizedState=i,f.flags&256){y=Fi(Error(Uu(423)),f),f=qJ(u,f,r,l,y);break u}else if(r!==y){y=Fi(Error(Uu(424)),f),f=qJ(u,f,r,l,y);break u}else for(el=e0(f.stateNode.containerInfo.firstChild),ur=f,Ef=!0,Xr=null,l=HU(f,null,r,l),f.child=l;l;)l.flags=l.flags&-3|4096,l=l.sibling;else{if($i(),r===y){f=L0(u,f,l);break u}Gl(u,f,r,l)}f=f.child}return f;case 5:return VU(f),u===null&&v2(f),r=f.type,y=f.pendingProps,i=u!==null?u.memoizedProps:null,_=y.children,C2(r,y)?_=null:i!==null&&C2(r,i)&&(f.flags|=32),fQ(u,f),Gl(u,f,_,l),f.child;case 6:return u===null&&v2(f),null;case 13:return rQ(u,f,l);case 4:return D5(f,f.stateNode.containerInfo),r=f.pendingProps,u===null?f.child=Ai(f,null,r,l):Gl(u,f,r,l),f.child;case 11:return r=f.type,y=f.pendingProps,y=f.elementType===r?y:Br(r,y),JJ(u,f,r,y,l);case 7:return Gl(u,f,f.pendingProps,l),f.child;case 8:return Gl(u,f,f.pendingProps.children,l),f.child;case 12:return Gl(u,f,f.pendingProps.children,l),f.child;case 10:u:{if(r=f.type._context,y=f.pendingProps,i=f.memoizedProps,_=y.value,cf(v3,r._currentValue),r._currentValue=_,i!==null)if(tr(i.value,_)){if(i.children===y.children&&!Sl.current){f=L0(u,f,l);break u}}else for(i=f.child,i!==null&&(i.return=f);i!==null;){var n=i.dependencies;if(n!==null){_=i.child;for(var $=n.firstContext;$!==null;){if($.context===r){if(i.tag===1){$=N0(-1,l&-l),$.tag=2;var j=i.updateQueue;if(j!==null){j=j.shared;var F=j.pending;F===null?$.next=$:($.next=F.next,F.next=$),j.pending=$}}i.lanes|=l,$=i.alternate,$!==null&&($.lanes|=l),I2(i.return,l,f),n.lanes|=l;break}$=$.next}}else if(i.tag===10)_=i.type===f.type?null:i.child;else if(i.tag===18){if(_=i.return,_===null)throw Error(Uu(341));_.lanes|=l,n=_.alternate,n!==null&&(n.lanes|=l),I2(_,l,f),_=i.sibling}else _=i.child;if(_!==null)_.return=i;else for(_=i;_!==null;){if(_===f){_=null;break}if(i=_.sibling,i!==null){i.return=_.return,_=i;break}_=_.return}i=_}Gl(u,f,y.children,l),f=f.child}return f;case 9:return y=f.type,r=f.pendingProps.children,yi(f,l),y=zr(y),r=r(y),f.flags|=1,Gl(u,f,r,l),f.child;case 14:return r=f.type,y=Br(r,f.pendingProps),y=Br(r.type,y),UJ(u,f,r,y,l);case 15:return eU(u,f,f.type,f.pendingProps,l);case 17:return r=f.type,y=f.pendingProps,y=f.elementType===r?y:Br(r,y),O3(u,f),f.tag=1,Pl(r)?(u=!0,R3(f)):u=!1,yi(f,l),aU(f,r,y),g2(f,r,y,l),o2(null,f,r,!0,u,l);case 19:return yQ(u,f,l);case 22:return uQ(u,f,l)}throw Error(Uu(156,f.tag))};function GQ(u,f){return kJ(u,f)}function ow(u,f,l,r){this.tag=u,this.key=l,this.sibling=this.child=this.return=this.stateNode=this.type=this.elementType=null,this.index=0,this.ref=null,this.pendingProps=f,this.dependencies=this.memoizedState=this.updateQueue=this.memoizedProps=null,this.mode=r,this.subtreeFlags=this.flags=0,this.deletions=null,this.childLanes=this.lanes=0,this.alternate=null}function cr(u,f,l,r){return new ow(u,f,l,r)}function g5(u){return u=u.prototype,!(!u||!u.isReactComponent)}function dw(u){if(typeof u==="function")return g5(u)?1:0;if(u!==void 0&&u!==null){if(u=u.$$typeof,u===U5)return 11;if(u===Q5)return 14}return 2}function r1(u,f){var l=u.alternate;return l===null?(l=cr(u.tag,f,u.key,u.mode),l.elementType=u.elementType,l.type=u.type,l.stateNode=u.stateNode,l.alternate=u,u.alternate=l):(l.pendingProps=f,l.type=u.type,l.flags=0,l.subtreeFlags=0,l.deletions=null),l.flags=u.flags&14680064,l.childLanes=u.childLanes,l.lanes=u.lanes,l.child=u.child,l.memoizedProps=u.memoizedProps,l.memoizedState=u.memoizedState,l.updateQueue=u.updateQueue,f=u.dependencies,l.dependencies=f===null?null:{lanes:f.lanes,firstContext:f.firstContext},l.sibling=u.sibling,l.index=u.index,l.ref=u.ref,l}function X3(u,f,l,r,y,i){var _=2;if(r=u,typeof u==="function")g5(u)&&(_=1);else if(typeof u==="string")_=5;else u:switch(u){case hy:return a1(l.children,y,i,f);case J5:_=8,y|=8;break;case W2:return u=cr(12,l,f,y|2),u.elementType=W2,u.lanes=i,u;case c2:return u=cr(13,l,f,y),u.elementType=c2,u.lanes=i,u;case N2:return u=cr(19,l,f,y),u.elementType=N2,u.lanes=i,u;case VJ:return J6(l,y,i,f);default:if(typeof u==="object"&&u!==null)switch(u.$$typeof){case OJ:_=10;break u;case BJ:_=9;break u;case U5:_=11;break u;case Q5:_=14;break u;case b0:_=16,r=null;break u}throw Error(Uu(130,u==null?u:typeof u,""))}return f=cr(_,l,f,y),f.elementType=u,f.type=r,f.lanes=i,f}function a1(u,f,l,r){return u=cr(7,u,r,f),u.lanes=l,u}function J6(u,f,l,r){return u=cr(22,u,r,f),u.elementType=VJ,u.lanes=l,u.stateNode={isHidden:!1},u}function U2(u,f,l){return u=cr(6,u,null,f),u.lanes=l,u}function Q2(u,f,l){return f=cr(4,u.children!==null?u.children:[],u.key,f),f.lanes=l,f.stateNode={containerInfo:u.containerInfo,pendingChildren:null,implementation:u.implementation},f}function ew(u,f,l,r,y){this.tag=f,this.containerInfo=u,this.finishedWork=this.pingCache=this.current=this.pendingChildren=null,this.timeoutHandle=-1,this.callbackNode=this.pendingContext=this.context=null,this.callbackPriority=0,this.eventTimes=d8(0),this.expirationTimes=d8(-1),this.entangledLanes=this.finishedLanes=this.mutableReadLanes=this.expiredLanes=this.pingedLanes=this.suspendedLanes=this.pendingLanes=0,this.entanglements=d8(0),this.identifierPrefix=r,this.onRecoverableError=y,this.mutableSourceEagerHydrationData=null}function s5(u,f,l,r,y,i,_,n,$){return u=new ew(u,f,l,n,$),f===1?(f=1,i===!0&&(f|=8)):f=0,i=cr(3,null,null,f),u.current=i,i.stateNode=u,i.memoizedState={element:r,isDehydrated:l,cache:null,transitions:null,pendingSuspenseBoundaries:null},Y5(i),u}function uE(u,f,l){var r=3{function TQ(){if(typeof __REACT_DEVTOOLS_GLOBAL_HOOK__>"u"||typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE!=="function")return;try{__REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE(TQ)}catch(u){console.error(u)}}TQ(),ZQ.exports=EQ()});var OQ=ol((uA)=>{var HQ=e5();uA.createRoot=HQ.createRoot,uA.hydrateRoot=HQ.hydrateRoot;var iE});var NW=ol((g6)=>{var _H=wf(),nH=Symbol.for("react.element"),$H=Symbol.for("react.fragment"),AH=Object.prototype.hasOwnProperty,jH=_H.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.ReactCurrentOwner,FH={key:!0,ref:!0,__self:!0,__source:!0};function cW(u,f,l){var r,y={},i=null,_=null;l!==void 0&&(i=""+l),f.key!==void 0&&(i=""+f.key),f.ref!==void 0&&(_=f.ref);for(r in f)AH.call(f,r)&&!FH.hasOwnProperty(r)&&(y[r]=f[r]);if(u&&u.defaultProps)for(r in f=u.defaultProps,f)y[r]===void 0&&(y[r]=f[r]);return{$$typeof:nH,type:u,key:i,ref:_,props:y,_owner:jH.current}}g6.Fragment=$H;g6.jsx=cW;g6.jsxs=cW});var GW=ol((bP,zW)=>{zW.exports=NW()});var oc=ol((ac)=>{var ki=wf();function OV(u,f){return u===f&&(u!==0||1/u===1/f)||u!==u&&f!==f}var BV=typeof Object.is==="function"?Object.is:OV,VV=ki.useState,XV=ki.useEffect,YV=ki.useLayoutEffect,DV=ki.useDebugValue;function tV(u,f){var l=f(),r=VV({inst:{value:l,getSnapshot:f}}),y=r[0].inst,i=r[1];return YV(function(){y.value=l,y.getSnapshot=f,h7(y)&&i({inst:y})},[u,l,f]),XV(function(){return h7(y)&&i({inst:y}),u(function(){h7(y)&&i({inst:y})})},[u]),DV(l),l}function h7(u){var f=u.getSnapshot;u=u.value;try{var l=f();return!BV(u,l)}catch(r){return!0}}function SV(u,f){return f()}var PV=typeof window>"u"||typeof window.document>"u"||typeof window.document.createElement>"u"?SV:tV;ac.useSyncExternalStore=ki.useSyncExternalStore!==void 0?ki.useSyncExternalStore:PV});var ec=ol((MR,dc)=>{dc.exports=oc()});var fN=ol((uN)=>{var x4=wf(),MV=ec();function mV(u,f){return u===f&&(u!==0||1/u===1/f)||u!==u&&f!==f}var pV=typeof Object.is==="function"?Object.is:mV,CV=MV.useSyncExternalStore,xV=x4.useRef,RV=x4.useEffect,hV=x4.useMemo,bV=x4.useDebugValue;uN.useSyncExternalStoreWithSelector=function(u,f,l,r,y){var i=xV(null);if(i.current===null){var _={hasValue:!1,value:null};i.current=_}else _=i.current;i=hV(function(){function $(q){if(!j){if(j=!0,F=q,q=r(q),y!==void 0&&_.hasValue){var W=_.value;if(y(W,q))return J=W}return J=q}if(W=J,pV(F,q))return W;var G=r(q);if(y!==void 0&&y(W,G))return F=q,W;return F=q,J=G}var j=!1,F,J,U=l===void 0?null:l;return[function(){return $(f())},U===null?void 0:function(){return $(U())}]},[f,l,r,y]);var n=CV(u,i[0],i[1]);return RV(function(){_.hasValue=!0,_.value=n},[n]),bV(n),n}});var rN=ol((pR,lN)=>{lN.exports=fN()});var M1=Pu(wf(),1);var d$="北京时间";var uL={timeZone:"Asia/Shanghai",hour12:!1},fL={timeZone:"Asia/Shanghai",hour12:!1},lL=new Intl.DateTimeFormat("en-CA",{timeZone:"Asia/Shanghai",year:"numeric",month:"2-digit",day:"2-digit",hour:"2-digit",minute:"2-digit",hourCycle:"h23"});function P8(u){if(u===null||u===void 0||u==="")return null;let f=u instanceof Date?u:new Date(u);return Number.isNaN(f.getTime())?null:f}function FF(u){let f=P8(u);if(!f)return null;return lL.formatToParts(f).reduce((l,r)=>{if(r.type!=="literal")l[r.type]=r.value;return l},{})}function Nu(u){let f=P8(u);return f?f.toLocaleString("zh-CN",uL):"--"}function qf(u){let f=P8(u);return f?f.toLocaleTimeString("zh-CN",fL):"--"}function M8(u){let f=FF(u);if(!f)return"";let l=f.hour==="24"?"00":f.hour;return`${f.year}-${f.month}-${f.day}T${l}:${f.minute}`}function JF(u=new Date){let f=FF(u);if(!f)return"";return`${f.year}-${f.month}-${f.day}`}function UF(u){if(!u)return null;let f=/^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2})(?::(\d{2}))?$/.exec(u);if(!f)return null;let[,l,r,y,i,_,n="00"]=f,$=Date.UTC(Number(l),Number(r)-1,Number(y),Number(i)-8,Number(_),Number(n)),j=new Date($),F=M8(j);return Number.isNaN(j.getTime())||F!==`${l}-${r}-${y}T${i}:${_}`?null:j.toISOString()}var VG=Pu(OQ(),1);var z6=Pu(wf(),1);var BQ=Pu(wf(),1),Jn=BQ.default.createElement;function _E({active:u=!0,label:f="正在加载"}){if(!u)return null;return Jn("span",{className:"loading-spinner-indicator",role:"status","aria-label":f,title:f,"data-testid":"loading-title-indicator"},Jn("span",{className:"loading-spinner-ring","aria-hidden":!0}))}function Af({title:u,children:f,loading:l,level:r=2,className:y="",label:i="正在加载"}){return Jn(r===3?"h3":"h2",{className:`loading-title ${l?"is-loading":""} ${y}`.trim()},Jn("span",{className:"loading-title-text"},f??u),Jn(_E,{active:Boolean(l),label:i}))}class qi extends Error{unideskRequestError=!0;meta;constructor(u,f){super(u);this.name="UniDeskRequestError",this.meta=f}}function nE(u){return new Promise((f)=>setTimeout(f,u))}function qn(u,f="操作失败"){return u instanceof Error?u.message:String(u||f)}function c6(u,f=500){if(u===null||u===void 0)return"";let l=typeof u==="string"?u:JSON.stringify(u),r=String(l||"").replace(/\s+/gu," ").trim();return r.length>f?`${r.slice(0,f)}...`:r}function $E(u){try{let f=typeof location<"u"&&location.origin?location.origin:"http://localhost";return new URL(u,f).toString()}catch{return u}}function VQ(u){return String(u.method||"GET").toUpperCase()}function AE(u){if(u===null||u===void 0)return!1;if(typeof u!=="object")return!1;if(typeof Blob<"u"&&u instanceof Blob)return!1;if(typeof FormData<"u"&&u instanceof FormData)return!1;if(typeof URLSearchParams<"u"&&u instanceof URLSearchParams)return!1;if(typeof ArrayBuffer<"u"&&u instanceof ArrayBuffer)return!1;return!0}function XQ(u){let f=new Headers(u.headers||{}),l=AE(u.body)?JSON.stringify(u.body):u.body;if(l&&!f.has("content-type")&&typeof l==="string")f.set("content-type","application/json");return{...u,credentials:u.credentials||"same-origin",body:l,headers:f}}function YQ(u){if(u?.error&&typeof u.error==="object"&&typeof u.error.message==="string")return u.error.message;if(typeof u?.error==="string")return u.error;if(typeof u?.message==="string")return u.message;if(typeof u?.detail==="string")return u.detail;return""}function jE(u,f){if(!u||typeof u!=="object"||Array.isArray(u))return!1;return f.some((l)=>l!==!1&&u[l]===!1)}function Un(u,f,l,r,y={}){return{kind:u,method:l,url:$E(f),occurredAt:r.toISOString(),...y}}function Qn(u,f){if(!u)return"请求失败";return`HTTP ${u}${f?` ${f}`:""}`}function DQ(u){try{return{body:u?JSON.parse(u):null,parseError:""}}catch(f){return{body:{text:u},parseError:qn(f,"parse failed")}}}async function Xu(u,f={},l=0){let{failureFields:r=["ok"],strictJson:y=!1,retryInvalidJson:i=0,retryDelayMs:_=120,invalidJsonPrefix:n="服务返回了无效 JSON",invalidJsonPreview:$=!1,responsePreviewLength:j=500,...F}=f,J=VQ(F),U=new Date,q;try{q=await fetch(u,XQ(F))}catch(K){let Q=qn(K,"网络请求失败");throw new qi(Q,Un("network",u,J,U,{upstreamMessage:Q}))}let W=await q.text(),G=DQ(W);if(G.parseError){if(y&&J==="GET"&&l=300)?Qn(u.meta.status,u.meta.statusText):"应用请求失败",i=u.meta.status?Qn(u.meta.status):"",_=($)=>!$||$===y||$===i,n=!_(u.message)?u.message:_(u.meta.upstreamMessage)?"":u.meta.upstreamMessage||"";return{title:y,message:n,status:u.meta.status,statusText:u.meta.statusText,method:u.meta.method,url:u.meta.url,occurredAt:FE(u.meta.occurredAt),responsePreview:u.meta.responsePreview,parseError:u.meta.parseError,structured:!0}}let r=qn(u,f).split(/\r?\n/u);return{title:r[0]||f,message:r.slice(1).join(` +`),structured:r.length>1}}function JE(u,f="操作失败"){let l=fA(u,f),r=[l.title];if(l.message)r.push(`原因: ${l.message}`);if(l.method||l.url)r.push(`请求: ${[l.method,l.url].filter(Boolean).join(" ")}`);if(l.status)r.push(`状态: ${Qn(l.status,l.statusText)}`);if(l.occurredAt)r.push(`时间: ${l.occurredAt}`);if(l.parseError)r.push(`解析错误: ${l.parseError}`);if(l.responsePreview&&l.responsePreview!==l.message)r.push(`响应预览: ${l.responsePreview}`);return r.filter(Boolean).join(` +`)}function Bu(u,f="操作失败"){return SQ(u)?JE(u,f):qn(u,f)}var PQ=Pu(wf(),1);var A1=PQ.default.createElement;function Wn(u,f){return f?[A1("dt",{key:`${u}-label`},u),A1("dd",{key:u},f)]:null}function jf({error:u,wide:f=!1,fallback:l="操作失败",className:r=""}){if(!u)return null;let y=fA(u,l),i=[Wn("请求",[y.method,y.url].filter(Boolean).join(" ")),Wn("状态",y.status?`HTTP ${y.status}${y.statusText?` ${y.statusText}`:""}`:""),Wn("时间",y.occurredAt),Wn("解析错误",y.parseError),Wn("响应预览",y.responsePreview)].filter(Boolean);return A1("div",{className:`form-error unidesk-error${f?" wide":""}${r?` ${r}`:""}`,role:"alert","data-testid":"unidesk-error"},A1("div",{className:"unidesk-error-title"},A1("strong",null,y.title),y.status?A1("span",{className:"unidesk-error-code"},`HTTP ${y.status}`):null),y.message?A1("pre",{className:"unidesk-error-message"},y.message):null,i.length>0?A1("dl",{className:"unidesk-error-details"},i):null)}var er=Pu(wf(),1),MQ=er.default.createContext(null);function mQ({children:u}){let[f,l]=er.default.useState([]),[r,y]=er.default.useState(Date.now()),i=er.default.useCallback((J,U)=>{let W={id:`notif_${Date.now()}_${Math.random().toString(36).slice(2,8)}`,type:J,message:U,timestamp:Date.now()};l((G)=>{let K=[...G,W];if(K.length>50)return K.slice(-50);return K})},[]),_=er.default.useCallback((J)=>{l((U)=>U.filter((q)=>q.id!==J))},[]),n=er.default.useCallback(()=>{l([]),y(Date.now())},[]),$=er.default.useMemo(()=>{return f.filter((J)=>J.timestamp>r).length},[f,r]),j=$>0,F={notifications:f,addNotification:i,removeNotification:_,clearNotifications:n,unreadCount:$,hasUnread:j};return UE(MQ.Provider,{value:F},u)}var UE=er.default.createElement;function wl(){let u=er.default.useContext(MQ);if(!u)throw Error("useNotification must be used within NotificationProvider");return u}var C=z6.default.createElement,{useEffect:N6}=z6.default,Wi=z6.default.useState;function ql(u,f={}){return Xu(u,{failureFields:["ok","success"],...f})}function El(u,f){return`${u}/microservices/baidu-netdisk/proxy${f}`}function QE(u){let f=Number(u);return Number.isFinite(f)?f.toLocaleString("zh-CN"):"--"}function j1(u){let f=Number(u);if(!Number.isFinite(f)||f<=0)return"--";let l=["B","KB","MB","GB","TB"],r=f,y=0;while(r>=1024&&y{y?.stopPropagation?.(),l(u,f)}},"查看原始JSON")}function Ni({title:u,text:f}){return C("div",{className:"empty-state"},C("strong",null,u),C("span",null,f))}function zi({title:u,text:f,href:l,badge:r,testId:y}){return C("a",{className:"doc-link-card",href:l,target:"_blank",rel:"noreferrer","data-testid":y},C("span",null,r||"DOC"),C("strong",null,u),C("p",null,f),C("code",null,l))}function qE(u){return u?.runtime&&typeof u.runtime==="object"&&!Array.isArray(u.runtime)?u.runtime:{}}function WE(u){return u?.backend&&typeof u.backend==="object"&&!Array.isArray(u.backend)?u.backend:{}}function cE(u){return u?.repository&&typeof u.repository==="object"&&!Array.isArray(u.repository)?u.repository:{}}function NE(u){return Array.isArray(u?.files)?u.files:[]}function zE(u){return Array.isArray(u?.jobs)?u.jobs:[]}function GE(u,f){if(!u||u===f)return f;let l=u.replace(/\/+$/u,""),r=l.slice(0,l.lastIndexOf("/"))||f;return r.lengthx.id==="baidu-netdisk")||null,[y,i]=Wi({loading:!1,actionLoading:!1,error:"",message:"",health:null,account:null,files:null,transfers:null,logs:null,selfTest:null,refreshedAt:null}),[_,n]=Wi("/"),[$,j]=Wi(null),[F,J]=Wi(""),[U,q]=Wi({localPath:"sample.txt",remotePath:"/sample.txt"}),[W,G]=Wi({fsId:"",localPath:"downloads/"}),{addNotification:K}=wl(),Q=y.health?.baidu?.appRoot||y.account?.rootPath||"/";N6(()=>{q((x)=>{let uu=new Set(["/sample.txt","/apps/UniDeskBaiduNetdisk/sample.txt"]);if(x.remotePath&&!uu.has(x.remotePath))return x;let nu=lA(Q,"sample.txt");return x.remotePath===nu?x:{...x,remotePath:nu}})},[Q]);async function N(x=_){let nu=await ql(El(l,`/api/files?dir=${encodeURIComponent(x||Q)}&limit=100`));i(($u)=>({...$u,files:nu}))}async function c(){let x=await ql(El(l,"/api/transfers?limit=80"));i((uu)=>({...uu,transfers:x}))}async function z(){if(!r)return;i((x)=>({...x,loading:!0,error:"",message:""}));try{let x=await ql(`${l}/microservices/baidu-netdisk/health`),uu=x?.baidu?.appRoot||Q,nu=null,$u=null;if(x?.auth?.loggedIn){nu=await ql(El(l,"/api/account?refresh=1"));let Wu=_&&_.startsWith(uu)?_:uu;n(Wu),$u=await ql(El(l,`/api/files?dir=${encodeURIComponent(Wu)}&limit=100`))}else n(uu);let Fu=await ql(El(l,"/api/transfers?limit=80")),Ku=await ql(El(l,"/logs?limit=60"));i((Wu)=>({...Wu,loading:!1,health:x,account:nu?.account||null,files:$u,transfers:Fu,logs:Ku,refreshedAt:new Date}))}catch(x){i((uu)=>({...uu,loading:!1,error:Bu(x,"百度网盘服务加载失败")}))}}async function w(){i((x)=>({...x,actionLoading:!0,error:"",message:""}));try{let x=await ql(El(l,"/api/auth/device/start"),{method:"POST",body:{}});j(x.session||null),i((uu)=>({...uu,actionLoading:!1,message:"设备码已生成,请扫码授权"}))}catch(x){i((uu)=>({...uu,actionLoading:!1,error:Bu(x,"创建设备码失败")}))}}async function H(x=!1){if(!$?.id)return;if(x)i((uu)=>({...uu,actionLoading:!0,error:""}));try{let uu=await ql(El(l,`/api/auth/device/status?sessionId=${encodeURIComponent($.id)}`));if(j(uu.session||null),uu.session?.status==="succeeded")i((nu)=>({...nu,actionLoading:!1,message:"授权成功,正在刷新账号与文件列表"})),await z();else if(x)i((nu)=>({...nu,actionLoading:!1}))}catch(uu){i((nu)=>({...nu,actionLoading:!1,error:Bu(uu,"轮询登录状态失败")}))}}async function B(){i((x)=>({...x,actionLoading:!0,error:"",message:""}));try{await ql(El(l,"/api/auth/logout"),{method:"POST",body:{}}),j(null),i((x)=>({...x,actionLoading:!1,account:null,files:null,message:"本地 token 已清除"})),await z()}catch(x){i((uu)=>({...uu,actionLoading:!1,error:Bu(x,"退出登录失败")}))}}async function T(x){x.preventDefault();let uu=F.trim();if(!uu)return;i((nu)=>({...nu,actionLoading:!0,error:"",message:""}));try{await ql(El(l,"/api/folders"),{method:"POST",body:{path:lA(_,uu)}}),J(""),i((nu)=>({...nu,actionLoading:!1,message:"文件夹已创建"})),await N(_)}catch(nu){i(($u)=>({...$u,actionLoading:!1,error:Bu(nu,"创建文件夹失败")}))}}async function X(x){if(!x)return;i((uu)=>({...uu,actionLoading:!0,error:"",message:""}));try{await ql(El(l,"/api/files/manage"),{method:"POST",body:{opera:"delete",filelist:[{path:x}],async:1}}),i((uu)=>({...uu,actionLoading:!1,message:"删除任务已提交"})),await N(_)}catch(uu){i((nu)=>({...nu,actionLoading:!1,error:Bu(uu,"删除失败")}))}}async function R(x){x.preventDefault(),i((uu)=>({...uu,actionLoading:!0,error:"",message:""}));try{await ql(El(l,"/api/transfers/upload-from-path"),{method:"POST",body:U}),i((uu)=>({...uu,actionLoading:!1,message:"上传任务已入队"})),await c()}catch(uu){i((nu)=>({...nu,actionLoading:!1,error:Bu(uu,"上传任务创建失败")}))}}async function Y(x){x.preventDefault(),i((uu)=>({...uu,actionLoading:!0,error:"",message:""}));try{await ql(El(l,"/api/transfers/download-to-path"),{method:"POST",body:W}),i((uu)=>({...uu,actionLoading:!1,message:"下载任务已入队"})),await c()}catch(uu){i((nu)=>({...nu,actionLoading:!1,error:Bu(uu,"下载任务创建失败")}))}}async function P(x,uu){i((nu)=>({...nu,actionLoading:!0,error:"",message:""}));try{await ql(El(l,`/api/transfers/${encodeURIComponent(x)}/${uu}`),{method:"POST",body:{}}),i((nu)=>({...nu,actionLoading:!1,message:uu==="cancel"?"已请求取消任务":"任务已重新入队"})),await c()}catch(nu){i(($u)=>({...$u,actionLoading:!1,error:Bu(nu,"任务操作失败")}))}}async function t(){i((x)=>({...x,actionLoading:!0,error:"",message:"正在运行上传/下载自测..."}));try{let x=await ql(El(l,"/api/self-test"),{method:"POST",body:{}});i((uu)=>({...uu,actionLoading:!1,selfTest:x,message:`上传/下载自测通过:${x.remotePath||""}`})),await N(_),await c()}catch(x){i((uu)=>({...uu,actionLoading:!1,error:Bu(x,"上传/下载自测失败")}))}}if(N6(()=>{if(!r)return;z();return},[r?.id,r?.runtime?.providerStatus]),N6(()=>{if(!$?.id||$.status!=="pending")return;let x=window.setInterval(()=>void H(!1),Math.max(5000,Number($.pollIntervalSeconds||5)*1000));return()=>window.clearInterval(x)},[$?.id,$?.status,$?.pollIntervalSeconds]),N6(()=>{if(!r)return;let x=window.setInterval(()=>void c(),5000);return()=>window.clearInterval(x)},[r?.id]),!r)return C(Ni,{title:"Baidu Netdisk 未登记",text:"请在 config.json 的 microservices 中登记用户服务 id=baidu-netdisk"});let O=qE(r),M=cE(r),S=WE(r),b=y.health||{},Z=y.account||b.auth?.account||null,D=b.auth||{},I=NE(y.files),k=zE(y.transfers),h=Z?.quota||{},o=Boolean(D.loggedIn||Z),s=Boolean(D.configured);return C("div",{className:"baidu-netdisk-page","data-testid":"baidu-netdisk-page"},C(iy,{title:"Baidu Netdisk 工作台",eyebrow:"Containerized Storage Gateway",loading:y.loading,actions:C("div",{className:"panel-actions"},C("a",{className:"ghost-btn",href:"/docs/issue/baidu-netdisk-env-setup.md",target:"_blank",rel:"noreferrer","data-testid":"baidu-netdisk-config-doc-link"},"配置文档"),C("button",{type:"button",className:"ghost-btn",onClick:z,disabled:y.loading,"data-testid":"baidu-netdisk-refresh"},y.loading?"刷新中":"刷新"),C(E0,{title:"Baidu Netdisk 用户服务",data:r,onOpen:f,testId:"raw-baidu-netdisk-service"}))},C("div",{className:"baidu-netdisk-hero"},C("div",null,C("div",{className:"node-version-line"},C(yy,{status:O.providerStatus==="online"?"online":"warn"},O.providerStatus||"unknown"),C("span",null,r.providerId),C(yy,{status:S.public?"warn":"private"},S.public?"公网暴露":"仅 UniDesk frontend 代理访问")),C("p",{className:"muted paragraph"},r.description)),C("div",{className:"microservice-ref-card"},C("span",null,"Repo"),C("strong",null,M.url||"--"),C("code",null,M.commitId||"--")),C("div",{className:"microservice-ref-card"},C("span",null,"Private Backend"),C("strong",null,`${S.nodeBindHost||"--"}:${S.nodePort||"--"}`),C("code",null,`${M.composeFile||"--"} / ${M.composeService||"--"}`))),C(jf,{error:y.error,wide:!0})),C("div",{className:"metric-grid"},C(ci,{label:"Health",value:b.ok?"OK":"--",hint:b.storage?.postgres||"postgres",tone:b.ok?"ok":"warn"}),C(ci,{label:"OAuth",value:s?"已配置":"待配置",hint:s?"client + secret + token key":"需要设置 UNIDESK_BAIDU_NETDISK_*",tone:s?"ok":"warn"}),C(ci,{label:"Login",value:o?"已登录":"未登录",hint:Z?.username||"Device Code QR",tone:o?"ok":"warn"}),C(ci,{label:"Work Root",value:KE(Q),hint:Q}),C(ci,{label:"Quota",value:j1(h.used),hint:h.total?`${h.usedPercent||0}% / ${j1(h.total)}`:"授权后刷新"}),C(ci,{label:"Transfers",value:QE(k.length),hint:`running ${y.transfers?.counts?.running||0} / failed ${y.transfers?.counts?.failed||0}`})),C(iy,{title:"文件浏览器",eyebrow:_,className:"baidu-files-panel",loading:y.loading,actions:C("div",{className:"panel-actions inline-actions"},C("button",{type:"button",className:"ghost-btn",onClick:()=>{let x=GE(_,Q);n(x),N(x)},disabled:!o||_===Q},"上级"),C("button",{type:"button",className:"ghost-btn",onClick:()=>N(_),disabled:!o},"刷新文件"),C(E0,{title:"Baidu Files",data:y.files,onOpen:f,testId:"raw-baidu-files"}))},C("form",{className:"baidu-pathbar",onSubmit:(x)=>{x.preventDefault(),N(_)}},C("input",{value:_,onChange:(x)=>n(x.target.value),disabled:!o}),C("button",{type:"submit",className:"ghost-btn",disabled:!o},"打开路径")),C("form",{className:"baidu-pathbar",onSubmit:T},C("input",{value:F,onChange:(x)=>J(x.target.value),placeholder:"新文件夹名称",disabled:!o}),C("button",{type:"submit",className:"primary-btn",disabled:!o||!F.trim()},"新建文件夹")),!o?C(Ni,{title:"等待授权",text:"登录后通过 /api/files 读取工作目录文件列表"}):I.length===0?C(Ni,{title:"目录为空",text:"可以从 staging 目录上传文件或新建文件夹"}):C("div",{className:"table-wrap","data-testid":"baidu-netdisk-file-table"},C("table",null,C("thead",null,C("tr",null,C("th",null,"名称"),C("th",null,"类型"),C("th",null,"大小"),C("th",null,"修改时间"),C("th",null,"fs_id"),C("th",null,"操作"))),C("tbody",null,I.map((x)=>C("tr",{key:x.fsId||x.path},C("td",null,C("strong",null,x.serverFilename||x.path),C("code",null,x.path||"--")),C("td",null,C(yy,{status:x.isDir?"queued":"private"},x.isDir?"DIR":"FILE")),C("td",null,x.isDir?"--":j1(x.size)),C("td",null,x.serverMtime?Nu(x.serverMtime*1000):"--"),C("td",null,C("code",null,x.fsId||"--")),C("td",null,C("div",{className:"inline-actions"},x.isDir?C("button",{type:"button",className:"ghost-btn",onClick:()=>{n(x.path),N(x.path)}},"打开"):C("button",{type:"button",className:"ghost-btn",onClick:()=>G((uu)=>({...uu,fsId:x.fsId}))},"填入下载"),C("button",{type:"button",className:"ghost-btn",onClick:()=>X(x.path),disabled:y.actionLoading},"删除"))))))))),C("div",{className:"baidu-netdisk-grid"},C(iy,{title:"配置与文档",eyebrow:"Deployment References",className:"baidu-docs-panel",actions:C("div",{className:"panel-actions inline-actions"},C("a",{className:"ghost-btn",href:"/docs/issue/baidu-netdisk-env-setup.md",target:"_blank",rel:"noreferrer"},"打开环境配置"),C("a",{className:"ghost-btn",href:"/docs/issue/baidu-netdisk-user-service.md",target:"_blank",rel:"noreferrer"},"打开服务方案"))},C("p",{className:"muted paragraph"},s?"OAuth 运行时变量已配置;如需轮换密钥、迁移部署或排查代理边界,可直接打开下面的项目内文档。":"首次使用请先按环境变量配置文档填入百度应用 client id / secret,然后重建 baidu-netdisk 服务并刷新本页。"),C("div",{className:"baidu-doc-grid","data-testid":"baidu-netdisk-doc-links"},C(zi,{title:"环境变量配置",text:"填写 UNIDESK_BAIDU_NETDISK_CLIENT_ID、CLIENT_SECRET、TOKEN_KEY,并执行重建与健康检查。",href:"/docs/issue/baidu-netdisk-env-setup.md",badge:"SETUP",testId:"baidu-netdisk-env-doc-card"}),C(zi,{title:"服务方案与 API",text:"说明 OAuth Device Code、根目录工作区、staging 上传下载任务和后端 API 设计。",href:"/docs/issue/baidu-netdisk-user-service.md",badge:"DESIGN"}),C(zi,{title:"用户服务安全边界",text:"查看 UniDesk microservice 私有代理、允许路径、frontendOnly 和密钥边界规则。",href:"/docs/reference/microservices.md",badge:"REF"}),C(zi,{title:"部署与重建流程",text:"查看 server rebuild、Compose 编排、健康检查和交付验证的长期规则。",href:"/docs/reference/deployment.md",badge:"DEPLOY"}),C(zi,{title:"CLI 验证命令",text:"查看 microservice health/proxy、server rebuild、job status 等命令入口。",href:"/docs/reference/cli.md",badge:"CLI"}),C(zi,{title:"百度设备码模式",text:"打开百度官方 OAuth Device Code 文档,对照扫码登录和轮询参数。",href:"https://pan.baidu.com/union/doc/fl1x114ti",badge:"OFFICIAL"}))),C(iy,{title:"设备码登录",eyebrow:"OAuth Device Code",className:"baidu-login-panel",loading:y.actionLoading,actions:C("div",{className:"panel-actions inline-actions"},C("button",{type:"button",className:"primary-btn",onClick:w,disabled:y.actionLoading||!s,"data-testid":"baidu-netdisk-start-login"},"生成二维码"),$?.id?C("button",{type:"button",className:"ghost-btn",onClick:()=>H(!0),disabled:y.actionLoading},"检查状态"):null,o?C("button",{type:"button",className:"ghost-btn",onClick:B,disabled:y.actionLoading},"清除本地登录"):null,C(E0,{title:"Baidu Device Session",data:$||D.latestSession,onOpen:f,testId:"raw-baidu-device-session"}))},C("div",{className:"baidu-login-card","data-testid":"baidu-netdisk-login-card"},C("div",{className:"baidu-qr-frame"},$?.qrcodeUrl?C("img",{src:$.qrcodeUrl,alt:"百度网盘设备码授权二维码","data-testid":"baidu-netdisk-qrcode"}):C(Ni,{title:s?"等待二维码":"OAuth 未配置",text:s?"点击生成二维码后使用百度网盘或百度 App 扫码":"设置 client id、secret 和 token key 后重建服务"})),C("div",{className:"claudeqq-login-copy"},C("div",{className:"node-version-line"},C(yy,{status:o?"online":$?.status==="pending"?"warn":"unknown"},o?"已登录":$?.status||"未开始"),C("span",null,$?.secondsRemaining!==void 0?`${$.secondsRemaining}s`:"--"),C("span",null,"scope basic,netdisk")),C("p",{className:"muted paragraph"},o?"access token / refresh token 已加密保存到 PostgreSQL;前端只看到脱敏登录态。":"后端使用百度 OAuth Device Code 轮询换取 token;二维码过期后重新生成即可。"),C("div",{className:"microservice-ref-card"},C("span",null,"User Code"),C("strong",null,$?.userCode||"--"),C("code",null,$?.verificationUrl||"https://openapi.baidu.com/device")),C("div",{className:"microservice-ref-card"},C("span",null,"Expires"),C("strong",null,$?.expiresAt?Nu($.expiresAt):"--"),C("code",null,$?.error||"no token exposed"))))),C(iy,{title:"账号与容量",eyebrow:y.refreshedAt?`Updated ${qf(y.refreshedAt)}`:"Account",loading:y.loading,actions:C("div",{className:"panel-actions inline-actions"},C(E0,{title:"Baidu Account",data:Z,onOpen:f,testId:"raw-baidu-account"}))},Z?C("div",{className:"baidu-account-card"},C("div",{className:"node-version-line"},C(yy,{status:"online"},"connected"),C("span",null,Z.baiduUid||"--"),C("span",null,`VIP ${Z.vipType??"--"}`)),C("h3",null,Z.username||"Baidu Netdisk"),C("p",{className:"muted paragraph"},`工作目录固定在 ${Z.rootPath||Q};v1 上传/下载只读写容器 staging 目录,不把大文件字节流穿过 UniDesk proxy。`),C("div",{className:"quota-bar"},C("span",{style:{width:`${Math.max(0,Math.min(100,Number(h.usedPercent||0)))}%`}})),C("div",{className:"microservice-ref-card"},C("span",null,"Quota"),C("strong",null,`${j1(h.used)} / ${j1(h.total)}`),C("code",null,`${h.usedPercent||0}% used`))):C(Ni,{title:"尚未登录",text:"扫码授权后这里会显示账号、UID、会员状态和容量"})),C(iy,{title:"传输任务",eyebrow:"staging path jobs",className:"baidu-transfers-panel",loading:y.actionLoading,actions:C("div",{className:"panel-actions inline-actions"},C("button",{type:"button",className:"primary-btn",onClick:t,disabled:!o||y.actionLoading,"data-testid":"baidu-netdisk-self-test"},"运行自测"),C("button",{type:"button",className:"ghost-btn",onClick:c},"刷新任务"),C(E0,{title:"Baidu Transfers",data:y.transfers,onOpen:f,testId:"raw-baidu-transfers"}))},C("div",{className:"baidu-transfer-forms"},C("form",{className:"stack-form",onSubmit:R,"data-testid":"baidu-upload-form"},C("label",null,"容器 staging 文件",C("input",{value:U.localPath,onChange:(x)=>q((uu)=>({...uu,localPath:x.target.value})),placeholder:"sample.txt"})),C("label",null,"百度网盘目标路径",C("input",{value:U.remotePath,onChange:(x)=>q((uu)=>({...uu,remotePath:x.target.value})),placeholder:lA(Q,"sample.txt")})),C("button",{type:"submit",className:"primary-btn",disabled:!o||y.actionLoading},"上传 staging 文件")),C("form",{className:"stack-form",onSubmit:Y,"data-testid":"baidu-download-form"},C("label",null,"文件 fs_id",C("input",{value:W.fsId,onChange:(x)=>G((uu)=>({...uu,fsId:x.target.value})),placeholder:"从文件表填入"})),C("label",null,"保存到 staging 路径",C("input",{value:W.localPath,onChange:(x)=>G((uu)=>({...uu,localPath:x.target.value})),placeholder:"downloads/"})),C("button",{type:"submit",className:"primary-btn",disabled:!o||!W.fsId||y.actionLoading},"下载到 staging"))),y.selfTest?C("div",{className:"baidu-account-card","data-testid":"baidu-netdisk-self-test-result"},C("div",{className:"node-version-line"},C(yy,{status:y.selfTest.ok?"online":"warn"},y.selfTest.ok?"self-test ok":"self-test"),C("span",null,j1(y.selfTest.sizeBytes))),C("h3",null,y.selfTest.remotePath||"Baidu self-test"),C("div",{className:"microservice-ref-card"},C("span",null,"fs_id"),C("strong",null,y.selfTest.fsId||"--"),C("code",null,y.selfTest.downloadedPath||"--")),C("div",{className:"microservice-ref-card"},C("span",null,"MD5"),C("strong",null,y.selfTest.downloadedMd5||"--"),C("code",null,y.selfTest.expectedMd5||"--")),C(E0,{title:"Baidu Self Test",data:y.selfTest,onOpen:f,testId:"raw-baidu-self-test"})):null,k.length===0?C(Ni,{title:"暂无传输任务",text:"上传/下载任务会在后端容器内执行,避免大文件穿过 UniDesk proxy"}):C("div",{className:"table-wrap","data-testid":"baidu-transfer-table"},C("table",null,C("thead",null,C("tr",null,C("th",null,"状态"),C("th",null,"方向"),C("th",null,"路径"),C("th",null,"进度"),C("th",null,"时间"),C("th",null,"操作"))),C("tbody",null,k.map((x)=>C("tr",{key:x.id},C("td",null,C(yy,{status:x.status},x.status)),C("td",null,x.direction),C("td",null,C("strong",null,x.remotePath||x.fsId||"--"),C("code",null,x.localPath||"--"),x.error?C("span",{className:"form-error"},x.error):null),C("td",null,C(LE,{percent:x.progressPercent}),C("span",{className:"muted"},`${j1(x.bytesDone)} / ${j1(x.sizeBytes)}`)),C("td",null,Nu(x.updatedAt)),C("td",null,C("div",{className:"inline-actions"},["queued","running"].includes(x.status)?C("button",{type:"button",className:"ghost-btn",onClick:()=>P(x.id,"cancel")},"取消"):null,["failed","canceled"].includes(x.status)?C("button",{type:"button",className:"ghost-btn",onClick:()=>P(x.id,"retry")},"重试"):null,C(E0,{title:`Transfer ${x.id}`,data:x,onOpen:f}))))))))),C(iy,{title:"安全与日志",eyebrow:"redacted diagnostics",className:"baidu-wide-panel",loading:y.loading,actions:C("div",{className:"panel-actions inline-actions"},C(E0,{title:"Baidu Health",data:b,onOpen:f,testId:"raw-baidu-health"}),C(E0,{title:"Baidu Logs",data:y.logs,onOpen:f,testId:"raw-baidu-logs"}))},C("div",{className:"policy-grid"},C("article",null,C("b",null,"私有后端"),C("span",null,"4244 只在 Compose 网络 expose,浏览器经 UniDesk 同源代理访问")),C("article",null,C("b",null,"Token 加密"),C("span",null,"access/refresh token 使用 BAIDU_NETDISK_TOKEN_KEY 加密后写入 PostgreSQL")),C("article",null,C("b",null,"无浏览器大文件流"),C("span",null,"上传/下载以容器 staging 目录为边界,避免 proxy 文本通道传输大字节流"))))))}var L6=Pu(wf(),1);var a=L6.default.createElement,{useEffect:wE}=L6.default,G6=L6.default.useState,_y={label:"主用户私聊账号",userId:645275593};function rA(u){let f=Number(u);return Number.isFinite(f)?f.toLocaleString("zh-CN"):"--"}async function F1(u,f={}){return Xu(u,{failureFields:["ok","success"],...f})}async function EE(u){let f=await fetch(u,{credentials:"same-origin"}),l=await f.text();try{return l?JSON.parse(l):{ok:f.ok,status:f.status}}catch{return{ok:f.ok,status:f.status,text:l}}}function K6({status:u,children:f}){let l=String(u||"unknown").toLowerCase();return a("span",{className:`status-badge ${l}`},f||u||"unknown")}function Gi({label:u,value:f,hint:l,tone:r}){return a("article",{className:`metric-card ${r||""}`},a("div",{className:"metric-label"},u),a("div",{className:"metric-value"},f),a("div",{className:"metric-hint"},l))}function Ki({title:u,eyebrow:f,actions:l,children:r,className:y,loading:i}){return a("section",{className:`panel ${y||""}`},a("div",{className:"panel-head"},a("div",null,f?a("p",{className:"panel-eyebrow"},f):null,a(Af,{title:u,loading:i})),l?a("div",{className:"panel-actions"},l):null),a("div",{className:"panel-body"},r))}function cn({title:u,data:f,onOpen:l,testId:r}){return a("button",{type:"button",className:"ghost-btn","data-testid":r,onClick:(y)=>{y?.stopPropagation?.(),l(u,f)}},"查看原始JSON")}function Nn({title:u,text:f}){return a("div",{className:"empty-state"},a("strong",null,u),a("span",null,f))}function TE(u){return u?.runtime&&typeof u.runtime==="object"&&!Array.isArray(u.runtime)?u.runtime:{}}function ZE(u){return u?.backend&&typeof u.backend==="object"&&!Array.isArray(u.backend)?u.backend:{}}function HE(u){return u?.repository&&typeof u.repository==="object"&&!Array.isArray(u.repository)?u.repository:{}}function J1(u,f){return`${u}/microservices/claudeqq/proxy${f}`}function OE(u){return Array.isArray(u?.events)?u.events.slice(0,80):[]}function BE(u){return Array.isArray(u?.subscriptions)?u.subscriptions.slice(0,50):[]}function VE(u){return Array.isArray(u?.messages)?u.messages.slice(0,30):[]}function CQ(u){let f=u?.text??u?.message??u?.raw?.raw_message;if(typeof f!=="string")return"--";return f.length>180?`${f.slice(0,177)}...`:f}function xQ(u){let f=u?.groupId??u?.group_id??(u?.message_type==="group"?u?.target_id:void 0),l=u?.userId??u?.user_id??(u?.message_type==="private"?u?.target_id:void 0);if(f)return`群 ${f}`;if(l)return`私聊 ${l}`;return"--"}function RQ({microservices:u,onRaw:f,apiBaseUrl:l="/api"}){let r=u.find((Z)=>Z.id==="claudeqq")||null,[y,i]=G6({loading:!1,qrLoading:!1,error:"",health:null,status:null,napcatLogin:null,napcatQrcode:null,qrcodeFetched:!1,qrcodeRefreshedAt:null,events:null,subscriptions:null,sent:null,refreshedAt:null}),[_,n]=G6({targetType:"private",targetId:String(_y.userId),message:""}),[$,j]=G6({name:"unidesk-callback",targetUrl:"",eventTypes:"message",secret:""}),[F,J]=G6(""),{addNotification:U}=wl();async function q(){if(!r)return;i((Z)=>({...Z,loading:!0,error:""}));try{let[Z,D,I,k,h]=await Promise.all([EE(`${l}/microservices/claudeqq/health`),F1(J1(l,"/api/server/status")),F1(J1(l,"/api/events/recent?limit=60")),F1(J1(l,"/api/events/subscriptions")),F1(J1(l,"/api/messages/sent?limit=20"))]);if(i((o)=>({...o,loading:!1,error:"",health:Z,status:D,events:I,subscriptions:k,sent:h,refreshedAt:new Date})),!y.qrcodeFetched)W(!1)}catch(Z){i((D)=>({...D,loading:!1,error:Bu(Z,"ClaudeQQ 加载失败")}))}}async function W(Z=!0){if(!r)return;i((D)=>({...D,qrLoading:!0,error:Z?"":D.error}));try{let D=await F1(J1(l,"/api/napcat/login")),I=D?.napcat?.qrcode||D?.qrcode||null;i((k)=>({...k,qrLoading:!1,error:"",napcatLogin:D,napcatQrcode:I,qrcodeFetched:!0,qrcodeRefreshedAt:new Date}))}catch(D){i((I)=>({...I,qrLoading:!1,error:Z||!I.napcatQrcode?Bu(D,"NapCat 二维码加载失败"):I.error}))}}async function G(Z){Z.preventDefault(),J("");let D=Number(_.targetId);if(!Number.isFinite(D)||D<=0||_.message.trim().length===0){i((I)=>({...I,error:"请填写 QQ 目标和消息内容"}));return}try{await F1(J1(l,"/api/push/text"),{method:"POST",body:JSON.stringify({userId:_.targetType==="private"?D:void 0,groupId:_.targetType==="group"?D:void 0,message:_.message})});let I="消息推送请求已提交";n((k)=>({...k,targetType:"private",targetId:String(_y.userId),message:""})),J(I),U("success",I),await q()}catch(I){i((k)=>({...k,error:Bu(I,"发送失败")}))}}async function K(Z){if(Z.preventDefault(),J(""),$.targetUrl.trim().length===0){i((D)=>({...D,error:"请填写订阅回调 URL"}));return}try{await F1(J1(l,"/api/events/subscriptions"),{method:"POST",body:JSON.stringify({name:$.name,targetUrl:$.targetUrl,eventTypes:$.eventTypes.split(",").map((I)=>I.trim()).filter(Boolean),secret:$.secret||void 0,enabled:!0})});let D="事件订阅已创建";J(D),U("success",D),await q()}catch(D){i((I)=>({...I,error:Bu(D,"订阅失败")}))}}async function Q(Z){if(!Z)return;J("");try{await F1(J1(l,`/api/events/subscriptions/${encodeURIComponent(Z)}`),{method:"DELETE"});let D="事件订阅已删除";J(D),U("success",D),await q()}catch(D){i((I)=>({...I,error:Bu(D,"删除订阅失败")}))}}if(wE(()=>{if(!r)return;q();return},[r?.id,r?.runtime?.providerStatus]),!r)return a(Nn,{title:"ClaudeQQ 未登记",text:"请在 config.json 的 microservices 中登记用户服务 id=claudeqq"});let N=TE(r),c=HE(r),z=ZE(r),w=y.health||{},H=y.status||{},B=y.napcatLogin||{},T=w.napcat||H.napcat||{},X={...B.napcat||{},...T,qrcode:y.napcatQrcode||{},webui:T.webui||B.napcat?.webui},R=B.login||{},Y=y.napcatQrcode||{},P=OE(y.events),t=BE(y.subscriptions),O=VE(y.sent),M=Boolean(X.httpConnected||R.ready),S=String(X.loginState||R.state||(M?"logged_in":"unknown")),b=Boolean(Y.available&&Y.dataUrl);return a("div",{className:"claudeqq-page","data-testid":"claudeqq-page"},a(Ki,{title:"ClaudeQQ 工作台",eyebrow:"D601 QQ Event Gateway",loading:y.loading,actions:a("div",{className:"panel-actions"},a("button",{type:"button",className:"ghost-btn",onClick:q,disabled:y.loading,"data-testid":"claudeqq-refresh-button"},y.loading?"刷新中":"刷新"),a(cn,{title:"ClaudeQQ 用户服务",data:r,onOpen:f,testId:"raw-claudeqq-service"}))},a("div",{className:"findjob-hero"},a("div",null,a("div",{className:"node-version-line"},a(K6,{status:N.providerStatus==="online"?"online":"warn"},N.providerStatus||"unknown"),a("span",null,r.providerId),a("span",null,z.public?"公网暴露":"仅 UniDesk frontend 代理访问")),a("p",{className:"muted paragraph"},r.description)),a("div",{className:"microservice-ref-card"},a("span",null,"Repo"),a("strong",null,c.url||"--"),a("code",null,c.commitId||"--")),a("div",{className:"microservice-ref-card"},a("span",null,"D601 Docker"),a("strong",null,`${z.nodeBindHost||"--"}:${z.nodePort||"--"}`),a("code",null,`${c.composeFile||"--"} / ${c.composeService||"--"}`))),a(jf,{error:y.error,wide:!0}),F?a("div",{className:"form-success wide"},F):null),a("div",{className:"metric-grid"},a(Gi,{label:"Health",value:w.ok||w.status==="ok"?"OK":"--",hint:"D601 /health",tone:w.ok||w.status==="ok"?"ok":"warn"}),a(Gi,{label:"NapCat HTTP",value:X.httpConnected||X.http?.connected?"OK":"离线",hint:`${X.httpHost||w.napcat?.httpHost||"--"}:${X.httpPort||w.napcat?.httpPort||"--"}`}),a(Gi,{label:"NapCat WS",value:X.wsConnected||X.ws?.connected?"OK":"离线",hint:`${X.wsHost||w.napcat?.wsHost||"--"}:${X.wsPort||w.napcat?.wsPort||"--"}`}),a(Gi,{label:"事件缓存",value:rA(y.events?.count??P.length),hint:"recent QQ events"}),a(Gi,{label:"订阅",value:rA(y.subscriptions?.count??t.length),hint:"webhook subscribers"}),a(Gi,{label:"已发送",value:rA(y.sent?.count??O.length),hint:"sent message log"})),a("div",{className:"findjob-grid"},a(Ki,{title:"NapCat 容器登录",eyebrow:"QR Login",className:"claudeqq-login-panel",loading:y.qrLoading,actions:a("div",{className:"panel-actions inline-actions"},a("button",{type:"button",className:"ghost-btn",onClick:()=>W(!0),disabled:y.qrLoading,"data-testid":"claudeqq-napcat-refresh"},y.qrLoading?"刷新中":"手动刷新二维码"),a(cn,{title:"NapCat Login",data:y.napcatLogin,onOpen:f,testId:"raw-claudeqq-napcat-login"}))},a("div",{className:"claudeqq-login-card","data-testid":"claudeqq-napcat-login"},a("div",{className:"claudeqq-qr-frame"},b?a("img",{src:Y.dataUrl,alt:"NapCat QQ 登录二维码","data-testid":"claudeqq-napcat-qrcode"}):a(Nn,{title:"等待二维码",text:"NapCat 容器启动后会把登录二维码写入 cache/qrcode.png"})),a("div",{className:"claudeqq-login-copy"},a("div",{className:"node-version-line"},a(K6,{status:M?"online":b?"warn":"unknown"},M?"已登录":b?"待扫码":"等待二维码"),a("span",null,S),a("span",null,"D601 containerized")),a("p",{className:"muted paragraph"},M?"NapCat 已登录,ClaudeQQ 可通过容器内 HTTP/WS 链路收发 QQ 消息。":"用手机 QQ 扫描二维码授权登录。二维码只在首次加载或手动刷新时更新,D601 的 NapCat 端口仍只绑定 127.0.0.1。"),a("div",{className:"microservice-ref-card"},a("span",null,"NapCat WebUI"),a("strong",null,X.webui?.url||"http://napcat:6099/webui"),a("code",null,"local-only / proxied QR login")),a("div",{className:"microservice-ref-card"},a("span",null,"QR Source"),a("strong",null,Y.modifiedAt?Nu(Y.modifiedAt):y.qrcodeRefreshedAt?Nu(y.qrcodeRefreshedAt):"--"),a("code",null,Y.file||"/napcat/cache/qrcode.png"))))),a(Ki,{title:"消息推送",eyebrow:"Push API"},a("div",{className:"microservice-ref-card"},a("span",null,_y.label),a("strong",null,String(_y.userId)),a("code",null,"private userId / 默认推送测试目标")),a("form",{className:"stack-form",onSubmit:G,"data-testid":"claudeqq-push-form"},a("label",null,"目标类型",a("select",{value:_.targetType,onChange:(Z)=>n((D)=>({...D,targetType:Z.target.value}))},a("option",{value:"private"},"私聊 userId"),a("option",{value:"group"},"群 groupId"))),a("label",null,"QQ ID",a("input",{value:_.targetId,onChange:(Z)=>n((D)=>({...D,targetId:Z.target.value})),placeholder:String(_y.userId)})),a("label",null,"消息内容",a("textarea",{value:_.message,onChange:(Z)=>n((D)=>({...D,message:Z.target.value})),rows:4,placeholder:"通过 ClaudeQQ 推送一条 QQ 消息"})),a("button",{type:"submit",className:"primary-btn"},"发送 QQ 消息")),a("p",{className:"muted paragraph"},`主 server 和其他用户服务可通过 UniDesk 同源代理调用 /api/push/text;当前人工推送测试默认使用 ${_y.label} ${_y.userId},不需要暴露 D601 后端端口。`)),a(Ki,{title:"QQ 事件订阅",eyebrow:"Webhook Subscription",loading:y.loading},a("form",{className:"stack-form",onSubmit:K,"data-testid":"claudeqq-subscription-form"},a("label",null,"订阅名称",a("input",{value:$.name,onChange:(Z)=>j((D)=>({...D,name:Z.target.value}))})),a("label",null,"回调 URL",a("input",{value:$.targetUrl,onChange:(Z)=>j((D)=>({...D,targetUrl:Z.target.value})),placeholder:"http://host.docker.internal:18080/..."})),a("label",null,"事件类型",a("input",{value:$.eventTypes,onChange:(Z)=>j((D)=>({...D,eventTypes:Z.target.value})),placeholder:"message,notice"})),a("label",null,"签名密钥",a("input",{value:$.secret,onChange:(Z)=>j((D)=>({...D,secret:Z.target.value})),placeholder:"可选,生成 x-claudeqq-signature"})),a("button",{type:"submit",className:"primary-btn"},"创建订阅")),t.length===0?a(Nn,{title:"暂无订阅",text:"可以为 main server 或其他用户服务注册 HTTP webhook"}):a("div",{className:"table-wrap","data-testid":"claudeqq-subscription-table"},a("table",null,a("thead",null,a("tr",null,a("th",null,"名称"),a("th",null,"状态"),a("th",null,"事件"),a("th",null,"回调"),a("th",null,"最近投递"),a("th",null,"操作"))),a("tbody",null,t.map((Z)=>a("tr",{key:Z.id},a("td",null,a("strong",null,Z.name||Z.id),a("code",null,Z.id||"--")),a("td",null,a(K6,{status:Z.enabled?"online":"warn"},Z.enabled?"enabled":"disabled")),a("td",null,Array.isArray(Z.eventTypes)?Z.eventTypes.join(", "):"message"),a("td",null,Z.targetUrl||"--"),a("td",null,Z.lastDelivery?`${Z.lastDelivery.ok?"OK":"FAIL"} ${Nu(Z.lastDelivery.at)}`:"--"),a("td",null,a("button",{type:"button",className:"ghost-btn",onClick:()=>Q(Z.id)},"删除"))))))),a("div",{className:"panel-actions inline-actions"},a(cn,{title:"ClaudeQQ Subscriptions",data:y.subscriptions,onOpen:f,testId:"raw-claudeqq-subscriptions"}))),a(Ki,{title:"最近 QQ 事件",eyebrow:y.refreshedAt?`Updated ${qf(y.refreshedAt)}`:"Event Stream",loading:y.loading},P.length===0?a(Nn,{title:"暂无事件",text:"等待 NapCat WebSocket 上报 QQ 消息事件,或通过订阅 API 消费后续事件"}):a("div",{className:"table-wrap","data-testid":"claudeqq-event-list"},a("table",null,a("thead",null,a("tr",null,a("th",null,"时间"),a("th",null,"类型"),a("th",null,"会话"),a("th",null,"消息"),a("th",null,"ID"))),a("tbody",null,P.map((Z)=>a("tr",{key:Z.id},a("td",null,Nu(Z.receivedAt||Z.timestamp)),a("td",null,a(K6,{status:Z.postType||Z.eventType},Z.postType||Z.eventType||"--")),a("td",null,xQ(Z)),a("td",null,CQ(Z)),a("td",null,a("code",null,Z.messageId||Z.id||"--"))))))),a("div",{className:"panel-actions inline-actions"},a(cn,{title:"ClaudeQQ Events",data:y.events,onOpen:f,testId:"raw-claudeqq-events"}))),a(Ki,{title:"已发送消息",eyebrow:`${O.length} Sent`,loading:y.loading},O.length===0?a(Nn,{title:"暂无发送记录",text:"发送日志来自 ClaudeQQ bot_workspace/messages/sent_messages.jsonl"}):a("div",{className:"table-wrap"},a("table",null,a("thead",null,a("tr",null,a("th",null,"时间"),a("th",null,"目标"),a("th",null,"消息"),a("th",null,"结果"))),a("tbody",null,O.map((Z,D)=>a("tr",{key:Z.id||D},a("td",null,Nu(Z.timestamp||Z.sentAt||Z.createdAt)),a("td",null,xQ(Z)),a("td",null,CQ(Z)),a("td",null,Z.status||Z.messageId||Z.message_id||"--")))))),a("div",{className:"panel-actions inline-actions"},a(cn,{title:"ClaudeQQ Sent Messages",data:y.sent,onOpen:f,testId:"raw-claudeqq-sent"})))))}var On=Pu(wf(),1);var vQ=Pu(wf(),1),Jf=vQ.default.createElement;function IQ({markdown:u,className:f,testId:l}){let r=String(u??"").trimEnd(),y=["markdown-body",f].filter(Boolean).join(" ");return Jf("div",{className:y,"data-testid":l},kQ(r,"md"))}function kQ(u,f){let l=XE(u).split(` +`),r=[],y=0;while(y\s?/u.test(i)){let J=[];while(y\s?(.*)$/u);if(q!==null){J.push(q[1]),y+=1;continue}if(U.trim().length===0){J.push(""),y+=1;continue}break}r.push(Jf("blockquote",{key:`${f}-quote-${y}`},kQ(J.join(` +`),`${f}-quote-${y}`)));continue}if(sQ(l,y)){let J=y,U=zn(l[y]??""),q=zn(l[y+1]??"");y+=2;let W=[];while(y0)W.push(zn(l[y]??"")),y+=1;r.push(PE(U,q,W,`${f}-table-${J}`));continue}let $=E6(i);if($!==null){let J=y,U=$.ordered,q=$.start,W=[];while(ytE(K,`${f}-list-${J}-${Q}`))));continue}let j=y,F=[];while(y0&&!DE(l,y))F.push(l[y].trim()),y+=1;if(F.length===0)F.push(i.trim()),y+=1;r.push(Jf("p",{key:`${f}-p-${j}`},u0(F.join(` +`),`${f}-p-${j}`)))}return r}function XE(u){return String(u||"").replace(/\r\n/gu,` `).replace(/\r/gu,` -`).trimEnd()}function kz(f){let u=f.match(/^\s*(```+|~~~+)\s*([A-Za-z0-9_-]+)?\s*$/u);if(u===null)return null;let l=u[1];return{marker:l.startsWith("`")?"`":"~",length:l.length,language:u[2]||""}}function qL(f,u){let l=f.trim();return l.length>=u.length&&l.split("").every((_)=>_===u.marker)}function _j(f){return/^(?: {4}|\t)/u.test(f)}function hz(f,u,l){let _=u.trim().length>0?`language-${DL(u)}`:void 0;return U0("pre",{key:l,className:"markdown-code-block"},U0("code",{className:_},f))}function LL(f,u){let l=f[u]??"";if(l.trim().length===0)return!0;return kz(l)!==null||_j(l)||/^(#{1,6})\s+.+$/u.test(l)||/^\s*(?:---+|\*\*\*+|___+)\s*$/u.test(l)||/^\s*>\s?/u.test(l)||tz(f,u)||Z2(l)!==null}function Z2(f){let u=f.match(/^\s{0,3}[-*+]\s+(.+)$/u);if(u!==null)return{ordered:!1,text:u[1]};let l=f.match(/^\s{0,3}(\d+)[.)]\s+(.+)$/u);if(l!==null)return{ordered:!0,start:Number(l[1]),text:l[2]};return null}function XL(f,u){let l=f.match(/^\[([ xX])\]\s+(.+)$/u);if(l!==null){let _=l[1].toLowerCase()==="x";return U0("li",{key:u,className:"task-list-item"},U0("input",{type:"checkbox",checked:_,readOnly:!0,tabIndex:-1}),U0("span",null,u1(l[2],`${u}-task`)))}return U0("li",{key:u},u1(f,u))}function tz(f,u){let l=f[u]??"",_=f[u+1]??"";if(!l.includes("|")||!_.includes("|"))return!1;let y=E6(l),$=E6(_);return y.length>1&&$.length===y.length&&$.every((r)=>/^:?-{3,}:?$/u.test(r.trim()))}function E6(f){let u=f.trim();if(u.startsWith("|"))u=u.slice(1);if(u.endsWith("|"))u=u.slice(0,-1);return u.split("|").map((l)=>l.trim())}function BL(f){let u=f.trim();if(u.startsWith(":")&&u.endsWith(":"))return"center";if(u.endsWith(":"))return"right";if(u.startsWith(":"))return"left";return}function YL(f,u,l,_){let y=u.map(BL);return U0("div",{key:_,className:"markdown-table-wrap"},U0("table",null,U0("thead",null,U0("tr",null,f.map(($,r)=>U0("th",{key:`${_}-h-${r}`,style:y[r]?{textAlign:y[r]}:void 0},u1($,`${_}-h-${r}`))))),U0("tbody",null,l.map(($,r)=>U0("tr",{key:`${_}-r-${r}`},f.map((j,A)=>U0("td",{key:`${_}-r-${r}-${A}`,style:y[A]?{textAlign:y[A]}:void 0},u1($[A]||"",`${_}-r-${r}-${A}`))))))))}function u1(f,u,l={}){let _=[],y=/`([^`\n]+)`|\[([^\]\n]+)\]\(([^)\s]+)(?:\s+"[^"]*")?\)|(https?:\/\/[^\s<>)]+)|\*\*([^*\n]+)\*\*|__([^_\n]+)__|~~([^~\n]+)~~|\*([^*\n]+)\*|_([^_\n]+)_/gu,$=l.linkify!==!1,r=0,j=0;for(let A of f.matchAll(y)){let J=A[0],U=A.index??0;N2(_,f.slice(r,U),`${u}-text-${j}`),r=U+J.length;let Q=`${u}-inline-${j}`;if(j+=1,A[1]!==void 0){_.push(U0("code",{key:Q},A[1]));continue}if(A[2]!==void 0&&A[3]!==void 0){if(!$){N2(_,J,`${Q}-literal`);continue}_.push(Iz(A[2],A[3],Q));continue}if(A[4]!==void 0){if(!$){N2(_,J,`${Q}-literal`);continue}_.push(Iz(A[4],A[4],Q));continue}let W=A[5]??A[6];if(W!==void 0){_.push(U0("strong",{key:Q},u1(W,`${Q}-strong`)));continue}if(A[7]!==void 0){_.push(U0("del",{key:Q},u1(A[7],`${Q}-del`)));continue}let G=A[8]??A[9];if(G!==void 0)_.push(U0("em",{key:Q},u1(G,`${Q}-em`)))}return N2(_,f.slice(r),`${u}-text-tail`),_}function N2(f,u,l){if(u.length===0)return;u.split(` -`).forEach((y,$)=>{if($>0)f.push(U0("br",{key:`${l}-br-${$}`}));if(y.length>0)f.push(y)})}function Iz(f,u,l){let _=wL(u);if(_===null)return U0("span",{key:l},f);let y=/^(?:https?:|mailto:)/iu.test(_);return U0("a",{key:l,href:_,target:y?"_blank":void 0,rel:y?"noreferrer":void 0},u1(f,`${l}-label`,{linkify:!1}))}function wL(f){let u=String(f||"").trim();if(/^(?:https?:|mailto:)/iu.test(u))return u;if(u.startsWith("/")&&!u.startsWith("//"))return u;if(u.startsWith("#"))return u;return null}function DL(f){return String(f||"").toLowerCase().replace(/[^a-z0-9_-]+/gu,"-").replace(/^-+|-+$/gu,"")||"text"}var Fj=cf(O0(),1);var Sf=Fj.default.createElement,{useEffect:TL,useRef:sz}=Fj.default;function ML(f,u){return UG(f.toTrace(u))}function PL(f){let u=Number(f);if(!Number.isFinite(u)||u<0)return"--";let l=Math.floor(u/1000),_=Math.floor(l/3600),y=Math.floor(l%3600/60),$=l%60;if(_>0)return`${_}h ${String(y).padStart(2,"0")}m`;if(y>0)return`${y}m ${String($).padStart(2,"0")}s`;return`${$}s`}function il(f){let u=Number(f);return Number.isFinite(u)&&u>=0?u:null}function L$(f,u=180){let l=String(f||"").replace(/\s+/gu," ").trim();return l.length>u?`${l.slice(0,u-1)}…`:l}function nL(f){if(!f)return 0;return f.split(/\r?\n/u).length}function rj(f){return{ran:"Ran",explored:"Explored",edited:"Edited",toolGroup:"Tool calls",plan:"Plan",message:"Message",system:"System",error:"Error"}[f]||"Message"}function jj(f){let u=Number(f||0);return Number.isFinite(u)&&u>0?`… +${Math.floor(u)} lines`:""}function SL(f){return(Array.isArray(f)?f:[]).reduce((u,l)=>Math.max(u,Number(l?.seq??0)),0)}function oz(f){return["explored","edited","ran"].includes(String(f?.kind||""))}function yG(f){let u={read:0,edit:0,run:0};for(let l of f){let _=String(l?.kind||"");if(_==="explored")u.read+=1;else if(_==="edited")u.edit+=1;else if(_==="ran")u.run+=1}return u}function $G(f){let u=yG(f);return`${u.read} read, ${u.edit} edit, ${u.run} run`}function rG(f){return f.replace(/^['"`([{<]+/u,"").replace(/['"`)\]}>.,;:]+$/u,"").replace(/:\d+(?::\d+)?$/u,"").trim()}function az(f){let l=String(f||"").match(/(?:~|\.{1,2}|\/)?(?:[A-Za-z0-9_.@+-]+\/)+[A-Za-z0-9_.@+-]+|[A-Za-z0-9_.@+-]+\.(?:c|cc|cpp|h|hpp|js|jsx|ts|tsx|json|md|py|sh|toml|ya?ml|txt|log|lock)/gu)||[],_=[];for(let y of l){let $=rG(y);if($.length<2||$.includes("..."))continue;if(/^(http|https|status|method)$/iu.test($))continue;if(!_.includes($))_.push($)}return _}function yj(f,u=4){if(f.length===0)return"--";let l=f.slice(0,u).join(", ");return f.length>u?`${l} +${f.length-u}`:l}function dz(f){let u="";for(let l of f){if(l.length===0)continue;if(u.length>0&&!u.endsWith(` +`).trimEnd()}function gQ(u){let f=u.match(/^\s*(```+|~~~+)\s*([A-Za-z0-9_-]+)?\s*$/u);if(f===null)return null;let l=f[1];return{marker:l.startsWith("`")?"`":"~",length:l.length,language:f[2]||""}}function YE(u,f){let l=u.trim();return l.length>=f.length&&l.split("").every((r)=>r===f.marker)}function yA(u){return/^(?: {4}|\t)/u.test(u)}function hQ(u,f,l){let r=f.trim().length>0?`language-${mE(f)}`:void 0;return Jf("pre",{key:l,className:"markdown-code-block"},Jf("code",{className:r},u))}function DE(u,f){let l=u[f]??"";if(l.trim().length===0)return!0;return gQ(l)!==null||yA(l)||/^(#{1,6})\s+.+$/u.test(l)||/^\s*(?:---+|\*\*\*+|___+)\s*$/u.test(l)||/^\s*>\s?/u.test(l)||sQ(u,f)||E6(l)!==null}function E6(u){let f=u.match(/^\s{0,3}[-*+]\s+(.+)$/u);if(f!==null)return{ordered:!1,text:f[1]};let l=u.match(/^\s{0,3}(\d+)[.)]\s+(.+)$/u);if(l!==null)return{ordered:!0,start:Number(l[1]),text:l[2]};return null}function tE(u,f){let l=u.match(/^\[([ xX])\]\s+(.+)$/u);if(l!==null){let r=l[1].toLowerCase()==="x";return Jf("li",{key:f,className:"task-list-item"},Jf("input",{type:"checkbox",checked:r,readOnly:!0,tabIndex:-1}),Jf("span",null,u0(l[2],`${f}-task`)))}return Jf("li",{key:f},u0(u,f))}function sQ(u,f){let l=u[f]??"",r=u[f+1]??"";if(!l.includes("|")||!r.includes("|"))return!1;let y=zn(l),i=zn(r);return y.length>1&&i.length===y.length&&i.every((_)=>/^:?-{3,}:?$/u.test(_.trim()))}function zn(u){let f=u.trim();if(f.startsWith("|"))f=f.slice(1);if(f.endsWith("|"))f=f.slice(0,-1);return f.split("|").map((l)=>l.trim())}function SE(u){let f=u.trim();if(f.startsWith(":")&&f.endsWith(":"))return"center";if(f.endsWith(":"))return"right";if(f.startsWith(":"))return"left";return}function PE(u,f,l,r){let y=f.map(SE);return Jf("div",{key:r,className:"markdown-table-wrap"},Jf("table",null,Jf("thead",null,Jf("tr",null,u.map((i,_)=>Jf("th",{key:`${r}-h-${_}`,style:y[_]?{textAlign:y[_]}:void 0},u0(i,`${r}-h-${_}`))))),Jf("tbody",null,l.map((i,_)=>Jf("tr",{key:`${r}-r-${_}`},u.map((n,$)=>Jf("td",{key:`${r}-r-${_}-${$}`,style:y[$]?{textAlign:y[$]}:void 0},u0(i[$]||"",`${r}-r-${_}-${$}`))))))))}function u0(u,f,l={}){let r=[],y=/`([^`\n]+)`|\[([^\]\n]+)\]\(([^)\s]+)(?:\s+"[^"]*")?\)|(https?:\/\/[^\s<>)]+)|\*\*([^*\n]+)\*\*|__([^_\n]+)__|~~([^~\n]+)~~|\*([^*\n]+)\*|_([^_\n]+)_/gu,i=l.linkify!==!1,_=0,n=0;for(let $ of u.matchAll(y)){let j=$[0],F=$.index??0;w6(r,u.slice(_,F),`${f}-text-${n}`),_=F+j.length;let J=`${f}-inline-${n}`;if(n+=1,$[1]!==void 0){r.push(Jf("code",{key:J},$[1]));continue}if($[2]!==void 0&&$[3]!==void 0){if(!i){w6(r,j,`${J}-literal`);continue}r.push(bQ($[2],$[3],J));continue}if($[4]!==void 0){if(!i){w6(r,j,`${J}-literal`);continue}r.push(bQ($[4],$[4],J));continue}let U=$[5]??$[6];if(U!==void 0){r.push(Jf("strong",{key:J},u0(U,`${J}-strong`)));continue}if($[7]!==void 0){r.push(Jf("del",{key:J},u0($[7],`${J}-del`)));continue}let q=$[8]??$[9];if(q!==void 0)r.push(Jf("em",{key:J},u0(q,`${J}-em`)))}return w6(r,u.slice(_),`${f}-text-tail`),r}function w6(u,f,l){if(f.length===0)return;f.split(` +`).forEach((y,i)=>{if(i>0)u.push(Jf("br",{key:`${l}-br-${i}`}));if(y.length>0)u.push(y)})}function bQ(u,f,l){let r=ME(f);if(r===null)return Jf("span",{key:l},u);let y=/^(?:https?:|mailto:)/iu.test(r);return Jf("a",{key:l,href:r,target:y?"_blank":void 0,rel:y?"noreferrer":void 0},u0(u,`${l}-label`,{linkify:!1}))}function ME(u){let f=String(u||"").trim();if(/^(?:https?:|mailto:)/iu.test(f))return f;if(f.startsWith("/")&&!f.startsWith("//"))return f;if(f.startsWith("#"))return f;return null}function mE(u){return String(u||"").toLowerCase().replace(/[^a-z0-9_-]+/gu,"-").replace(/^-+|-+$/gu,"")||"text"}var jA=Pu(wf(),1);var Su=jA.default.createElement,{useEffect:pE,useRef:aQ}=jA.default;function CE(u,f){return Jq(u.toTrace(f))}function xE(u){let f=Number(u);if(!Number.isFinite(f)||f<0)return"--";let l=Math.floor(f/1000),r=Math.floor(l/3600),y=Math.floor(l%3600/60),i=l%60;if(r>0)return`${r}h ${String(y).padStart(2,"0")}m`;if(y>0)return`${y}m ${String(i).padStart(2,"0")}s`;return`${i}s`}function Sr(u){let f=Number(u);return Number.isFinite(f)&&f>=0?f:null}function wi(u,f=180){let l=String(u||"").replace(/\s+/gu," ").trim();return l.length>f?`${l.slice(0,f-1)}…`:l}function RE(u){if(!u)return 0;return u.split(/\r?\n/u).length}function nA(u){return{ran:"Ran",explored:"Explored",edited:"Edited",toolGroup:"Tool calls",plan:"Plan",message:"Message",system:"System",error:"Error"}[u]||"Message"}function $A(u){let f=Number(u||0);return Number.isFinite(f)&&f>0?`… +${Math.floor(f)} lines`:""}function hE(u){return(Array.isArray(u)?u:[]).reduce((f,l)=>Math.max(f,Number(l?.seq??0)),0)}function oQ(u){return["explored","edited","ran"].includes(String(u?.kind||""))}function iq(u){let f={read:0,edit:0,run:0};for(let l of u){let r=String(l?.kind||"");if(r==="explored")f.read+=1;else if(r==="edited")f.edit+=1;else if(r==="ran")f.run+=1}return f}function _q(u){let f=iq(u);return`${f.read} read, ${f.edit} edit, ${f.run} run`}function nq(u){return u.replace(/^['"`([{<]+/u,"").replace(/['"`)\]}>.,;:]+$/u,"").replace(/:\d+(?::\d+)?$/u,"").trim()}function dQ(u){let l=String(u||"").match(/(?:~|\.{1,2}|\/)?(?:[A-Za-z0-9_.@+-]+\/)+[A-Za-z0-9_.@+-]+|[A-Za-z0-9_.@+-]+\.(?:c|cc|cpp|h|hpp|js|jsx|ts|tsx|json|md|py|sh|toml|ya?ml|txt|log|lock)/gu)||[],r=[];for(let y of l){let i=nq(y);if(i.length<2||i.includes("..."))continue;if(/^(http|https|status|method)$/iu.test(i))continue;if(!r.includes(i))r.push(i)}return r}function iA(u,f=4){if(u.length===0)return"--";let l=u.slice(0,f).join(", ");return u.length>f?`${l} +${u.length-f}`:l}function eQ(u){let f="";for(let l of u){if(l.length===0)continue;if(f.length>0&&!f.endsWith(` `)&&!l.startsWith(` -`))u+=` -`;u+=l}return u}function jG(f){let u=String(f||"").replace(/\r\n/gu,` +`))f+=` +`;f+=l}return f}function $q(u){let f=String(u||"").replace(/\r\n/gu,` `).replace(/\r/gu,` -`).trimEnd();return u.length>0?u.split(` -`):[]}function Aj(f){let u=String(f.status||"").trim();if(u.length>0)return u;let l=String(f.bodyPreview||"");return/^(item\/[A-Za-z]+(?:\/[A-Za-z]+)?):/u.exec(l)?.[1]||"item/fileChange"}function CL(f){let u=String(f.bodyPreview||"");return/file changes status=([A-Za-z0-9_-]+)/u.exec(u)?.[1]}function iL(f){return/^item\/(?:started|completed): file changes status=/u.test(String(f||"").trim())}function AG(f){if(String(f.kind||"")!=="edited")return!1;let u=String(f.status||""),l=String(f.title||""),_=String(f.bodyPreview||""),y=String(f.commandPreview||"");if(l==="Edited files")return!0;if(/^item\/fileChange\//u.test(u))return!0;if((u==="item/started"||u==="item/completed")&&/file changes status=/u.test(_))return!0;if(/^Success\. Updated the following files:/mu.test(_))return!0;if(/^diff --git /mu.test(_))return!0;return/^([AMDRCU?]{1,2})\s+\S+/mu.test(_)||y.length>0&&H2(_).length>0}function q$(f){return rG(String(f||"").replace(/^[ab]\//u,"").trim())}function Jj(f){let u=/^([AMDRCU?]{1,2})\s+(.+)$/u.exec(f);if(!u)return null;let l=q$(u[2]||"");return l.length>0?{status:u[1]||"M",path:l}:null}function Uj(f){let u=/^\*\*\*\s+(Add|Update|Delete)\s+File:\s+(.+)$/u.exec(f);if(u){let _=u[1]==="Add"?"A":u[1]==="Delete"?"D":"M",y=q$(u[2]||"");return y.length>0?{status:_,path:y}:null}let l=/^\*\*\*\s+Move to:\s+(.+)$/u.exec(f);if(l){let _=q$(l[1]||"");return _.length>0?{status:"R",path:_}:null}return null}function H2(f){let u=[],l=(y,$)=>{let r=q$($);if(r.length===0||r==="/dev/null")return;let j=u.find((A)=>A.path===r);if(j){if(j.status==="M"&&y!=="M")j.status=y;return}u.push({status:y,path:r})},_="";for(let y of jG(f)){let $=Jj(y)||Uj(y);if($!==null){l($.status,$.path),_=$.path;continue}let r=/^diff --git a\/(.+?) b\/(.+)$/u.exec(y);if(r){let Q=r[2]||r[1]||"";l("M",Q),_=q$(Q);continue}let j=/^\+\+\+ b\/(.+)$/u.exec(y);if(j&&j[1]!=="/dev/null"){l("M",j[1]||""),_=q$(j[1]||"");continue}if(/^new file mode /u.exec(y)&&_)l("A",_);if(/^deleted file mode /u.exec(y)&&_)l("D",_);let U=/^rename to (.+)$/u.exec(y);if(U)l("R",U[1]||"")}return u}function cL(f){if(Jj(f)!==null||Uj(f)!==null)return"file";if(/^(diff --git |index |--- |\+\+\+ |\*\*\* Begin Patch|\*\*\* End Patch)/u.test(f))return"meta";if(/^@@ /u.test(f))return"hunk";if(/^\+/u.test(f))return"add";if(/^-/u.test(f))return"del";if(/^(Success\.|No changes|Updated\b|Created\b|Deleted\b|Added\s+\d+\s+lines?|Wrote\s+\d+\s+lines?|Read\s+\d+\s+files?|\.\.\.\[patch content truncated)/iu.test(f))return"note";return"context"}function Qj(f){return jG(f).map((u)=>{let l=Jj(u)||Uj(u);if(l!==null)return{text:u,kind:"file",path:l.path,status:l.status};return{text:u,kind:cL(u)}})}function RL(f){return f.reduce((u,l)=>{if(l.kind==="add")u.added+=1;else if(l.kind==="del")u.removed+=1;return u},{added:0,removed:0})}function ez(f,u){return`${u} ${f} line${f===1?"":"s"}`}function xL(f,u){let l=[];if(f>0)l.push(ez(f,"Added"));if(u>0)l.push(ez(u,"removed"));return l.join(", ")}function bL(f){for(let l=f.length-1;l>=0;l-=1){let _=String(f[l]?.status||"").trim();if(_.length>0)return _}let u=String(f[f.length-1]?.method||"").trim();if(u==="item/fileChange/outputDelta")return"updated";if(u==="item/started")return"started";if(u==="item/completed")return"completed";return u.replace(/^item\//u,"")||"changed"}function vL(f){return`${f} file${f===1?"":"s"}`}function FG(f){let u=f.length>0?f:[],l=dz(u.map((W)=>String(W.bodyPreview||""))),y=dz(u.map((W)=>String(W.bodyPreview||"")).filter((W)=>W.trim().length>0&&!iL(W)))||l,$=H2(y||l),r=u.map((W)=>({method:Aj(W),status:CL(W),at:W.at})),j=Qj(y||l),A=RL(j),J=xL(A.added,A.removed),U=$.length>0?vL($.length):"",Q=J.length>0?`${J}${U?` in ${U}`:""}`:$.length>0?U:L$(y||l||"File changes",72);return{status:bL(r),summary:Q,files:$,stages:r,lines:j,addedLines:A.added,removedLines:A.removed,rawText:l}}function hL(f){let u=f[0],l=f[f.length-1]||u,_=FG(f);return{...u,seq:Number.isFinite(Number(l?.seq))?Number(l?.seq):Number(u?.seq??0),at:l?.at||u?.at,title:_.files.length>0?`Edited ${_.summary}`:"Edited files",status:_.status,commandPreview:"",commandOmittedLines:void 0,bodyPreview:_.rawText,bodyOmittedLines:f.reduce((y,$)=>y+Number($.bodyOmittedLines||0),0)||void 0,rawSeqs:f.flatMap((y)=>Array.isArray(y?.rawSeqs)?y.rawSeqs:[y?.seq]).filter((y)=>y!==void 0),editObservation:_}}function IL(f){let u=Array.isArray(f)?f:[],l=[],_=[],y=()=>{if(_.length===0)return;l.push(hL(_)),_=[]};for(let $ of u){if(AG($)){if(Aj($)==="item/started"&&_.length>0)y();if(_.push($),Aj($)==="item/completed")y();continue}y(),l.push($)}return y(),l}function JG(f){let u=[],l=[],_=[],y=(J,U)=>{for(let Q of U)if(!J.includes(Q))J.push(Q)};for(let J of f){let U=String(J?.kind||""),Q=[J?.commandPreview,J?.bodyPreview,J?.title].map((W)=>String(W||"")).join(` -`);if(U==="explored")y(u,az(Q));else if(U==="edited")y(l,az(Q));else if(U==="ran"){let W=String(J?.commandPreview||J?.title||"").trim();if(W.length>0&&!_.includes(W))_.push(L$(W,90))}}let $=f.map((J)=>Date.parse(String(J?.at||""))).filter((J)=>Number.isFinite(J)),r=$.length>=2?Math.max(0,Math.max(...$)-Math.min(...$)):0,j=f.reduce((J,U)=>J+(il(U?.durationMs)??il(U?.elapsedMs)??0),0),A=r>0?r:j;return{readFiles:u,editedFiles:l,runCommands:_,durationLabel:PL(A)}}function pL(f,u=3){let l=Array.isArray(f)?f:[],_=[],y=[],$=Math.max(0,u),r=new Set;for(let A=l.length-1;A>=0&&$>0;A-=1){let J=l[A];if(!oz(J))continue;r.add(J),$-=1}let j=()=>{if(y.length>=2){let A=yG(y);_.push({seq:Number(y[0]?.seq??0),at:y[0]?.at||y.at(-1)?.at,kind:"toolGroup",title:$G(y),status:`${y.length} calls`,items:y,counts:A,digest:JG(y),rawSeqs:y.flatMap((J)=>Array.isArray(J?.rawSeqs)?J.rawSeqs:[J?.seq]).filter((J)=>J!==void 0)})}else _.push(...y);y=[]};for(let A of l){if(oz(A)&&!r.has(A)){y.push(A);continue}j(),_.push(A)}return j(),_}function UG(f){return(Array.isArray(f)?f:[]).map((u,l)=>({...u,seq:Number.isFinite(Number(u?.seq))?Number(u.seq):l+1,kind:String(u?.kind||"message"),at:u?.at===void 0?void 0:String(u.at),durationMs:il(u?.durationMs)??void 0,title:u?.title===void 0?void 0:String(u.title),status:u?.status===void 0?void 0:String(u.status)}))}function H6(f){let u=il(f?.state?.time?.start)??il(f?.time?.start),l=il(f?.state?.time?.end)??il(f?.time?.end);return il(f?.durationMs)??il(f?.elapsedMs)??il(f?.timing?.durationMs)??il(f?.metadata?.durationMs)??(u!==null&&l!==null&&l>=u?l-u:null)??void 0}function O6(f,u){return f?.createdAt||f?.updatedAt||f?.completedAt||u||void 0}function $j(f,u){return f?.id||f?.messageId||u}function mL(f,u=1200){if(typeof f==="string")return f;if(f===void 0||f===null)return"";try{return L$(JSON.stringify(f),u)}catch{return L$(String(f),u)}}function QG(f,u,l){if(typeof f?.metadata?.diff==="string"&&f.metadata.diff.length>0)return f.metadata.diff;if(typeof f?.metadata?.filediff?.patch==="string"&&f.metadata.filediff.patch.length>0)return f.metadata.filediff.patch;if(typeof f?.output==="string"&&f.output.length>0)return f.output;if(typeof f?.result==="string"&&f.result.length>0)return f.result;if(typeof u?.output==="string"&&u.output.length>0)return u.output;if(typeof l?.output==="string"&&l.output.length>0)return l.output;if(typeof f?.metadata?.output==="string"&&f.metadata.output.length>0)return f.metadata.output;return""}function E2(f,u){if(!f||typeof f!=="object"||Array.isArray(f))return"";for(let l of u){let _=f[l];if(typeof _==="string"&&_.length>0)return _;if(_!==void 0&&_!==null&&typeof _!=="object")return String(_)}return""}function fG(f,u){if(!f||typeof f!=="object"||Array.isArray(f))return null;for(let l of u){let _=Number(f[l]);if(Number.isFinite(_))return _}return null}function WG(f,u){let l=u?.input&&typeof u.input==="object"&&!Array.isArray(u.input)?u.input:f?.input&&typeof f.input==="object"&&!Array.isArray(f.input)?f.input:{},_=E2(l,["command","cmd","script"]);if(_.length>0)return _;if(typeof f?.command==="string"&&f.command.length>0)return f.command;if(typeof u?.command==="string"&&u.command.length>0)return u.command;let y=String(f?.tool||f?.title||"tool"),$=E2(l,["filePath","filepath","path"])||E2(f,["filePath","filepath","path"]),r=E2(l,["pattern","query"]),j=fG(l,["offset"]),A=fG(l,["limit"]),J=[y];if(r.length>0)J.push(r);if($.length>0)J.push($);if(j!==null)J.push(`offset=${j}`);if(A!==null)J.push(`limit=${A}`);return J.length>1?J.join(" "):y}function gL(f,u){let l=f?.part&&typeof f.part==="object"&&!Array.isArray(f.part)?f.part:{},_=String(f?.type||f?.event||f?.name||l?.type||"").toLowerCase(),y=String(l?.type||"").toLowerCase(),$=f?.at||f?.timestamp||l?.updatedAt||l?.createdAt,r=Number.isFinite(Number(f?.seq))?Number(f.seq):u;if(_==="step_start"||_==="step-start"||y==="step-start")return null;if(_==="step_finish"||_==="step-finish"||y==="step-finish")return null;if(y==="tool"||/tool|bash|command/iu.test(`${_} ${y}`)){let A=l?.state&&typeof l.state==="object"&&!Array.isArray(l.state)?l.state:{},J=WG(l,A),U=QG(A,l,f),Q=zG(J,String(l?.tool||l?.title||"")),W=Q==="edited"?{status:String(A?.status||l?.status||f?.status||""),summary:L$(U||J,72),files:H2(U),stages:[],lines:Qj(U),addedLines:0,removedLines:0,rawText:U}:void 0;return{seq:r,at:O6(l,$),kind:Q,title:String(A?.title||l?.title||A?.metadata?.description||l?.tool||"OpenCode tool"),status:String(A?.status||l?.status||f?.status||""),commandPreview:J,bodyPreview:U,durationMs:H6(l),rawSeqs:[l?.id||l?.callID||f?.sessionID||r],editObservation:W}}let j=mL(l?.text??l?.content??l?.delta??f?.text??f?.content??f?.delta,3000).trim();if(j.length>0)return{seq:r,at:O6(l,$),kind:y==="reasoning"?"message":/error|failed/iu.test(`${_} ${y}`)?"error":"message",title:y==="reasoning"?"Reasoning":/error|failed/iu.test(`${_} ${y}`)?"OpenCode error":"Assistant message",status:`opencode/${_||y||"event"}`,bodyPreview:j,durationMs:H6(l),rawSeqs:[l?.id||f?.sessionID||r]};return null}function zG(f,u){let l=`${u} ${f}`.toLowerCase();if(/\b(read|grep|glob|list|ls|find|search|view|cat|sed|rg|head|tail|wc|file)\b/iu.test(l))return"explored";if(/\b(edit|write|patch|apply|update|create|delete|apply_patch|git apply|cat >|tee .*<<|sed -i|python3? .*write_text|mkdir|rm |touch )\b/iu.test(l))return"edited";return"ran"}function kL(f){let u=[],l=1;for(let _ of Array.isArray(f)?f:[]){if(_?.kind&&_?.title){let j=String(_?.status||"");if(j==="opencode/step-start"||j==="opencode/step-finish")continue;u.push({..._,seq:Number.isFinite(Number(_?.seq))?Number(_.seq):l++});continue}let y=_?.createdAt||_?.updatedAt||_?.completedAt,$=String(_?.role||"assistant").toLowerCase(),r=Array.isArray(_?.parts)?_.parts:[];if(r.length===0){if(_?.part&&(_?.sessionID||String(_?.type||"").startsWith("step_")||String(_?.type||"").includes("tool"))){let j=gL(_,l);if(j!==null)u.push(j),l=Math.max(l+1,Number(j.seq)+1)}else if(_?.textPreview)u.push({seq:l++,at:y,kind:"message",title:`${$||"assistant"} message`,status:$,bodyPreview:String(_.textPreview),rawSeqs:[_?.messageId||l]});continue}for(let j of r){let A=String(j?.type||"").toLowerCase();if(A==="step-start"||A==="step-finish")continue;if(A==="text"||A==="reasoning"){let U=String(j?.textPreview||_?.textPreview||"").trim();if(U.length===0)continue;u.push({seq:l++,at:O6(j,y),kind:"message",title:A==="reasoning"?"Reasoning":$==="user"?"User message":$==="system"?"System message":"Assistant message",status:A==="reasoning"?"reasoning":$,bodyPreview:U,durationMs:H6(j),rawSeqs:[$j(j,l)]});continue}if(A==="tool"){let U=j?.state&&typeof j.state==="object"&&!Array.isArray(j.state)?j.state:{},Q=WG(j,U),W=QG(U,j,{}),G=zG(Q,String(j?.tool||j?.title||"")),K=G==="edited"?{status:String(U?.status||j?.status||""),summary:L$(W||Q,72),files:H2(W),stages:[],lines:Qj(W),addedLines:0,removedLines:0,rawText:W}:void 0;u.push({seq:l++,at:O6(j,y),kind:G,title:String(j?.title||j?.tool||"tool"),status:String(j?.status||""),commandPreview:Q,bodyPreview:W,durationMs:H6(j),rawSeqs:[$j(j,l)],editObservation:K});continue}let J=String(j?.textPreview||j?.title||A||"").trim();if(J)u.push({seq:l++,at:O6(j,y),kind:"system",title:A||"part",bodyPreview:J,status:String(j?.status||""),durationMs:H6(j),rawSeqs:[$j(j,l)]})}}return u}var GG={source:"opencode",toTrace:kL};function tL(f){return String(f||"unknown").toLowerCase().replace(/[^a-z0-9_-]+/gu,"-")||"unknown"}function uG(f){let u=String(f||"M").toUpperCase();if(u.startsWith("A")||u==="??")return"added";if(u.startsWith("D"))return"deleted";if(u.startsWith("R"))return"renamed";return"modified"}function sL(f){if(f==="item/fileChange/outputDelta")return"delta";return f.replace(/^item\//u,"")}function oL(f,u){if(f.kind==="file"){let y=String(f.status||"M");return Sf("div",{key:`${u}-${f.text}`,className:`codex-edit-diff-line file ${uG(y)}`},Sf("span",{className:`codex-edit-file-status ${uG(y)}`},y),Sf("code",null,f.path||f.text.replace(/^([AMDRCU?]{1,2})\s+/u,"")))}let l=f.kind==="add"||f.kind==="del"?f.text.slice(0,1):f.kind==="hunk"?"@@":f.kind==="note"?"ok":"",_=f.kind==="add"||f.kind==="del"?f.text.slice(1):f.text;return Sf("div",{key:`${u}-${f.text}`,className:`codex-edit-diff-line ${f.kind}`},Sf("span",{className:"codex-edit-diff-sign"},l),Sf("code",null,_||" "))}function aL(f,u){let l=f.lines.length>0?f.lines:f.files.map((y)=>({text:`${y.status} ${y.path}`,kind:"file",path:y.path,status:y.status})),_=Number(f.addedLines||0)+Number(f.removedLines||0)>0;return Sf("div",{className:"codex-edit-observation","data-testid":"codex-edit-observation"},Sf("div",{className:"codex-edit-observation-head"},Sf("span",{className:"codex-edit-window-controls","aria-hidden":"true"},Sf("i",null),Sf("i",null),Sf("i",null)),Sf("strong",null,_?"git diff":"git diff --stat"),Sf("code",null,f.summary||"File changes")),f.stages.length>0?Sf("div",{className:"codex-edit-stage-strip"},f.stages.map((y,$)=>Sf("span",{key:`${y.method}-${$}`,className:`codex-edit-stage ${tL(y.status||y.method)}`},Sf("b",null,sL(y.method)),y.status?Sf("em",null,y.status):null))):null,l.length>0?Sf("div",{className:"codex-edit-diff",role:"list"},l.map(oL)):null,u?Sf("div",{className:"codex-edit-omitted"},`${u} (查看原始JSON获取完整记录)`):null)}function lG(f,u,l){let _=jj(l);return Sf("div",{className:`codex-transcript-stream ${f}`,"data-testid":`codex-trace-${f}`},Sf("span",{className:"codex-transcript-stream-label"},f),Sf("pre",{className:"codex-transcript-body"},u,_?` -${_} (查看原始JSON获取完整记录)`:""))}function KG(f,u=!1){let l=String(f.kind||"message"),_=["ran","explored","edited"].includes(l),y=jj(f.commandOmittedLines),$=jj(f.bodyOmittedLines),r=String(f.commandPreview||(_?f.title||"":"")),j=String(f.stdoutPreview||""),A=String(f.stderrPreview||""),J=j.length>0||A.length>0,U=Boolean(f.foldedReferencePrompt)&&String(f.fullPrompt||"").length>0,Q=l==="edited"&&(f.editObservation!==void 0||AG(f))?f.editObservation||FG([f]):null;return Sf("article",{key:`${f.seq}-${l}`,className:`codex-transcript-item ${l} ${u?"nested":""}`},Sf("div",{className:"codex-transcript-main"},Sf("div",{className:"codex-transcript-title"},Sf("span",{className:"codex-output-channel"},rj(l)),_&&Q===null?null:Sf("strong",null,Q!==null?"File changes":String(f.title||rj(l))),f.status?Sf("code",null,String(Q?.status||f.status)):null,Sf("time",null,Nf(f.at))),r&&Q===null?Sf("pre",{className:"codex-transcript-command"},r,y?` -${y}`:""):null,Q!==null?aL(Q,$):J?Sf("div",{className:"codex-transcript-streams"},j.length>0?lG("stdout",j,f.stdoutOmittedLines):null,A.length>0?lG("stderr",A,f.stderrOmittedLines):null):f.bodyPreview?Sf("pre",{className:"codex-transcript-body"},String(f.bodyPreview),$?` -${$} (查看原始JSON获取完整记录)`:""):null,U?Sf("details",{className:"codex-initial-prompt-full","data-testid":"codex-initial-prompt-full"},Sf("summary",null,Sf("span",null,"引用注入已折叠,点击查看最终传入 Codex 的完整 prompt"),Sf("code",null,`${f.fullPromptLines||nL(String(f.fullPrompt||""))} lines / ${f.fullPromptChars||String(f.fullPrompt||"").length} chars`)),Sf("pre",{className:"codex-transcript-body codex-transcript-full-prompt","data-testid":"codex-initial-prompt-full-text"},String(f.fullPrompt||""))):null))}function dL(f){let u=Array.isArray(f.items)?f.items:[],l=f.digest&&typeof f.digest==="object"?f.digest:JG(u);return Sf("article",{key:`${f.seq}-toolGroup`,className:"codex-transcript-item toolGroup"},Sf("div",{className:"codex-transcript-main"},Sf("details",{className:"codex-tool-group","data-testid":"codex-tool-group"},Sf("summary",null,Sf("div",{className:"codex-tool-group-head"},Sf("span",{className:"codex-output-channel"},rj("toolGroup")),Sf("strong",null,String(f.title||$G(u))),Sf("code",null,String(f.status||`${u.length} calls`)),Sf("time",null,Nf(f.at)))),Sf("div",{className:"codex-tool-group-digest"},Sf("span",null,`read: ${yj(Array.isArray(l.readFiles)?l.readFiles:[])}`),Sf("span",null,`edit: ${yj(Array.isArray(l.editedFiles)?l.editedFiles:[])}`),Sf("span",null,`run: ${yj(Array.isArray(l.runCommands)?l.runCommands:[],2)}`),Sf("span",null,`duration: ${l.durationLabel||"--"}`)),Sf("div",{className:"codex-tool-group-items"},u.map((_)=>KG(_,!0))))))}var eL=16;function _G(f){return f.scrollHeight-f.scrollTop-f.clientHeight<=eL}function O2({items:f,input:u,port:l,autoScroll:_=!1,loading:y=!1,hasDetail:$=!0,emptyText:r="等待 Trace 输出...",loadingText:j="正在加载完整 Trace...",testId:A="trace-output",className:J="codex-transcript",keepRecentToolCalls:U=3,collapseTools:Q=!0}){let W=sz(null),G=sz(!0),K=IL(l?ML(l,u):UG(f)),H=Q?pL(K,U):K,O=SL(K);TL(()=>{let N=W.current;if(!_||!N)return;if(!G.current&&!_G(N))return;N.scrollTop=N.scrollHeight,G.current=!0},[_,K.length,O]);let Z={className:J,ref:W,onScroll:(N)=>{let E=N.currentTarget;G.current=_G(E)},"data-testid":A};if(y&&!$)return Sf("div",Z,Sf("div",{className:"codex-output-empty"},j));return Sf("div",Z,H.length===0?Sf("div",{className:"codex-output-empty"},r):H.map((N)=>String(N.kind||"")==="toolGroup"?dL(N):KG(N)))}var L=Y6.default.createElement,{useEffect:W_,useMemo:NG,useRef:m0}=Y6.default,tf=Y6.default.useState,fX=120,Zj=24,MG=48,uX=1200;function ZG(){return typeof document>"u"||document.visibilityState!=="hidden"}function ll(f,u="操作失败"){return Df(f,u)}function Rl(f){let u=Number(f);if(!Number.isFinite(u)||u<0)return"--";let l=Math.floor(u/1000),_=Math.floor(l/3600),y=Math.floor(l%3600/60),$=l%60;if(_>0)return`${_}h ${String(y).padStart(2,"0")}m`;if(y>0)return`${y}m ${String($).padStart(2,"0")}s`;return`${$}s`}function D$(f){if(f===null||f===void 0||f==="")return null;let u=f instanceof Date?f.getTime():new Date(f).getTime();return Number.isFinite(u)?u:null}function PG(f,u=Date.now()){let l=D$(f);if(l===null)return"--";let _=Math.max(0,Math.floor((u-l)/1000));if(_<1)return"刚刚";let y=Math.floor(_/86400),$=Math.floor(_%86400/3600),r=Math.floor(_%3600/60),j=_%60;if(y>0)return`${y}天${$>0?`${$}小时`:""}前`;if($>0)return`${$}小时${r>0?`${r}分钟`:""}前`;if(r>0)return`${r}分钟${j}秒前`;return`${j}秒前`}function Dj(...f){let u="",l=-1/0;for(let _ of f){let y=String(_||"");if(y.length===0)continue;let $=D$(_);if($!==null&&$>=l)u=y,l=$;else if(u.length===0)u=y}return u}function lX(f,u){let l=D$(f);if(l===null)return!1;let _=D$(u);return _===null||l>_+1}function _X(f){let u=Number(f);if(!Number.isFinite(u)||u<0)return"--";if(u<1000)return`${Math.round(u)}ms`;return`${(u/1000).toFixed(u<1e4?2:1)}s`}function Ej(f,u=180){let l=String(f||"").replace(/\s+/gu," ").trim();return l.length>u?`${l.slice(0,u-1)}…`:l}async function D0(f,u={}){return Mf(f,{strictJson:!0,retryInvalidJson:1,invalidJsonPrefix:"Code Queue 返回了无效 JSON",invalidJsonPreview:!0,responsePreviewLength:uX,...u})}function Wy({status:f,children:u,title:l}){let _=String(f||"unknown").toLowerCase();return L("span",{className:`status-badge ${_}`,title:l},u||f||"unknown")}function B$({title:f,eyebrow:u,summary:l,actions:_,children:y,className:$,loading:r}){return L("section",{className:`panel ${$||""}`},L("div",{className:"panel-head"},L("div",null,u?L("p",{className:"panel-eyebrow"},u):null,L(j0,{title:f,loading:r}),l?L("div",{className:"panel-summary"},l):null),_?L("div",{className:"panel-actions"},_):null),L("div",{className:"panel-body"},y))}function nG({title:f,data:u,onOpen:l,testId:_}){return L("button",{type:"button",className:"ghost-btn","data-testid":_,onClick:()=>l(f,u)},"查看原始JSON")}function zy({title:f,text:u}){return L("div",{className:"empty-state"},L("strong",null,f),L("span",null,u))}function yX(f){return f?.runtime&&typeof f.runtime==="object"&&!Array.isArray(f.runtime)?f.runtime:{}}function $X(f){return f?.backend&&typeof f.backend==="object"&&!Array.isArray(f.backend)?f.backend:{}}function T0(f,u){return`${f}/code-queue-direct${u}`}function yu(f){return Array.isArray(f?.tasks)?f.tasks:[]}function Q_(f){return f?.pagination&&typeof f.pagination==="object"&&!Array.isArray(f.pagination)?f.pagination:{}}function EG(f){let u=Date.parse(String(f?.updatedAt||f?.createdAt||""));return Number.isFinite(u)?u:0}function SG(f,u=""){let l=new Map;for(let _ of f)for(let y of _){let $=String(y?.id||"");if($.length>0&&!l.has($))l.set($,y)}return Array.from(l.values()).sort((_,y)=>{let $=wG(_)-wG(y);if($!==0)return $;let r=String(_?.id||"")===u?0:1,j=String(y?.id||"")===u?0:1;if(r!==j)return r-j;return EG(y)-EG(_)})}function X$(f,u=""){let l=new Map;for(let _ of f)for(let y of _){let $=String(y?.id||"");if($.length===0)continue;l.set($,{...l.get($)||{},...y})}return SG([Array.from(l.values())],u)}function q6(f){return Array.isArray(f?.activeTaskIds)?f.activeTaskIds.map((u)=>String(u||"")).filter(Boolean):[String(f?.activeTaskId||"")].filter(Boolean)}var G_="__all__",rX="(max-width: 760px)",jX="(min-width: 761px)";function cu(f){return!f||f===G_}function AX(){return typeof window<"u"&&window.matchMedia(rX).matches}function FX(f){return cu(f)?"":`&queueId=${encodeURIComponent(f)}`}function Hj(f){return String(f||"").trim().replace(/\s+/gu," ").slice(0,200)}function JX(f){let u=Hj(f);return u.length===0?"":`&search=${encodeURIComponent(u)}`}function Tj(f,u=""){return`${FX(f)}${JX(u)}`}function V2(f,u){return Number(f?.counts?.[u]||0)}function HG(f,u=""){let l=new Map;for(let y of Array.isArray(f?.queues)?f.queues:[]){let $=String(y?.id||"").trim();if($.length>0)l.set($,{...y,name:String(y?.name||$).trim()||$})}for(let y of[String(f?.defaultQueueId||"default"),u].map(($)=>$.trim()).filter(Boolean))if(!l.has(y))l.set(y,{id:y,name:y,total:0,counts:{},activeTaskId:null,runnableTaskId:null,processing:!1});return Array.from(l.values()).sort((y,$)=>{let r=String(y?.id||"")===String(f?.defaultQueueId||"default")?0:1,j=String($?.id||"")===String(f?.defaultQueueId||"default")?0:1;if(r!==j)return r-j;return String(y?.id||"").localeCompare(String($?.id||""))})}function CG(f){let u=String(f?.id||"default"),l=String(f?.name||"").trim();return l.length>0?l:u}function Oj(f){let u=String(f?.id||"default"),l=CG(f);return l===u?u:`${l} (${u})`}function Vj(f){let u=V2(f,"running")+V2(f,"judging"),l=V2(f,"queued")+V2(f,"retry_wait"),_=Number(f?.total||0),y=[Oj(f),`${_} tasks`];if(u>0)y.push(`${u} running`);if(l>0)y.push(`${l} queued`);return y.join(" · ")}function L6(f,u){if(cu(u))return null;return f.find((l)=>String(l?.id||"")===u)||null}function OG(f,u,l,_){if(cu(l)){let $=q6(f);return String(f?.activeTaskId||$[0]||_.find((r)=>BG(r))?.id||"")}let y=L6(u,l);return String(y?.activeTaskId||_.find(($)=>BG($))?.id||"")}function UX(f,u,l){if(!cu(u)){let _=L6(f,u);return String(_?.runnableTaskId||l.find((y)=>String(y?.status||"")==="queued"||String(y?.status||"")==="retry_wait")?.id||"")}return String(l.find((_)=>String(_?.status||"")==="queued"||String(_?.status||"")==="retry_wait")?.id||"")}async function VG(f,u,l=G_,_=""){let y=Tj(l,_);try{return await D0(T0(f,`/api/tasks?limit=${Zj}&lite=1&devReady=0${y}`))}catch{let r=await Promise.all(["running","judging","retry_wait","queued"].map(async(U)=>{try{return await D0(T0(f,`/api/tasks?status=${encodeURIComponent(U)}&limit=80&lite=1&devReady=0${y}`))}catch{return null}})),j=await D0(T0(f,`/api/tasks?limit=${Zj}&lite=1&devReady=0${y}`)).catch(()=>null),A=r.find((U)=>U?.queue)?.queue||j?.queue||u?.queue||u?.body?.queue||{},J=SG([...r.map((U)=>yu(U)),yu(j)],String(A?.activeTaskId||""));if(J.length>0)return{ok:!0,queue:A,statistics:j?.statistics||r.find((U)=>U?.statistics)?.statistics||null,tasks:J};return D0(T0(f,`/api/tasks?limit=5&lite=1&devReady=0${y}`))}}async function QX(f,u,l=0,_=G_,y=""){return D0(T0(f,`/api/tasks/overview?limit=${Zj}&transcriptLimit=3&compact=1&afterSeq=${encodeURIComponent(String(Math.max(0,l)))}&preferId=${encodeURIComponent(u)}${Tj(_,y)}`))}async function qG(f,u,l,_=MG,y=""){return D0(T0(f,`/api/tasks?limit=${encodeURIComponent(String(_))}&lite=1&devReady=0&includeActive=0&beforeId=${encodeURIComponent(l)}${Tj(u,y)}`))}async function WX(f,u){return D0(T0(f,`/api/tasks/${encodeURIComponent(u)}/trace-summary`))}async function zX(f,u,l,_=null){let y=_===null||_===void 0||String(_).length===0?"":`&attempt=${encodeURIComponent(String(_))}`;return D0(T0(f,`/api/tasks/${encodeURIComponent(u)}/prompt?part=${encodeURIComponent(l)}${y}`))}async function GX(f,u,l=0,_=500,y=null){let $=y===null||y===void 0||String(y).length===0?"":`&attempt=${encodeURIComponent(String(y))}`;return D0(T0(f,`/api/tasks/${encodeURIComponent(u)}/trace-steps?afterSeq=${encodeURIComponent(String(l))}&limit=${encodeURIComponent(String(_))}${$}`))}async function KX(f,u,l){return D0(T0(f,`/api/tasks/${encodeURIComponent(u)}/trace-step?seq=${encodeURIComponent(String(l))}`))}async function NX(f,u){return D0(T0(f,`/api/tasks/${encodeURIComponent(u)}/read`),{method:"POST",body:{}})}async function ZX(f){return D0(T0(f,"/api/tasks/read-all"),{method:"POST",body:{}})}function EX(f){return Array.isArray(f?.output)?f.output:[]}function iG(f){return Array.isArray(f?.attempts)?f.attempts:[]}function Wj(f){return f?.counts&&typeof f.counts==="object"&&!Array.isArray(f.counts)?f.counts:{}}function HX(f){return f.split(/^\s*---+\s*$/gmu).map((u)=>u.trim()).filter(Boolean)}function LG(f){let u=Number(f);return Number.isFinite(u)?Math.max(1,Math.min(50,Math.floor(u))):1}function Jy(f){let u=[];for(let l of f.split(/[\s,,;;]+/u)){let _=l.trim();if(/^codex_\d+_[A-Za-z0-9_-]+$/u.test(_)&&!u.includes(_))u.push(_)}return u}function OX(f,u){let l=Jy(u);if(l.length===0)return f;return[`引用 Code Queue 任务 ${l.join(" ")}。后端会在入队时只注入这些任务的 initial prompt 和 final response 全文;中间执行过程不注入,如需补充核查可运行:${l.map((_)=>`bun scripts/cli.ts codex task ${_}`).join(";")}`,"","本次任务:",f].join(` -`)}function VX(f){let _=f.trimStart();if(!_.startsWith("# Code Queue 已解析引用上下文"))return{hasInjection:!1,reference:"",userPrompt:f};let y=f.length-_.length,$=f.lastIndexOf(` +`).trimEnd();return f.length>0?f.split(` +`):[]}function AA(u){let f=String(u.status||"").trim();if(f.length>0)return f;let l=String(u.bodyPreview||"");return/^(item\/[A-Za-z]+(?:\/[A-Za-z]+)?):/u.exec(l)?.[1]||"item/fileChange"}function bE(u){let f=String(u.bodyPreview||"");return/file changes status=([A-Za-z0-9_-]+)/u.exec(f)?.[1]}function vE(u){return/^item\/(?:started|completed): file changes status=/u.test(String(u||"").trim())}function Aq(u){if(String(u.kind||"")!=="edited")return!1;let f=String(u.status||""),l=String(u.title||""),r=String(u.bodyPreview||""),y=String(u.commandPreview||"");if(l==="Edited files")return!0;if(/^item\/fileChange\//u.test(f))return!0;if((f==="item/started"||f==="item/completed")&&/file changes status=/u.test(r))return!0;if(/^Success\. Updated the following files:/mu.test(r))return!0;if(/^diff --git /mu.test(r))return!0;return/^([AMDRCU?]{1,2})\s+\S+/mu.test(r)||y.length>0&&Z6(r).length>0}function Li(u){return nq(String(u||"").replace(/^[ab]\//u,"").trim())}function FA(u){let f=/^([AMDRCU?]{1,2})\s+(.+)$/u.exec(u);if(!f)return null;let l=Li(f[2]||"");return l.length>0?{status:f[1]||"M",path:l}:null}function JA(u){let f=/^\*\*\*\s+(Add|Update|Delete)\s+File:\s+(.+)$/u.exec(u);if(f){let r=f[1]==="Add"?"A":f[1]==="Delete"?"D":"M",y=Li(f[2]||"");return y.length>0?{status:r,path:y}:null}let l=/^\*\*\*\s+Move to:\s+(.+)$/u.exec(u);if(l){let r=Li(l[1]||"");return r.length>0?{status:"R",path:r}:null}return null}function Z6(u){let f=[],l=(y,i)=>{let _=Li(i);if(_.length===0||_==="/dev/null")return;let n=f.find(($)=>$.path===_);if(n){if(n.status==="M"&&y!=="M")n.status=y;return}f.push({status:y,path:_})},r="";for(let y of $q(u)){let i=FA(y)||JA(y);if(i!==null){l(i.status,i.path),r=i.path;continue}let _=/^diff --git a\/(.+?) b\/(.+)$/u.exec(y);if(_){let J=_[2]||_[1]||"";l("M",J),r=Li(J);continue}let n=/^\+\+\+ b\/(.+)$/u.exec(y);if(n&&n[1]!=="/dev/null"){l("M",n[1]||""),r=Li(n[1]||"");continue}if(/^new file mode /u.exec(y)&&r)l("A",r);if(/^deleted file mode /u.exec(y)&&r)l("D",r);let F=/^rename to (.+)$/u.exec(y);if(F)l("R",F[1]||"")}return f}function IE(u){if(FA(u)!==null||JA(u)!==null)return"file";if(/^(diff --git |index |--- |\+\+\+ |\*\*\* Begin Patch|\*\*\* End Patch)/u.test(u))return"meta";if(/^@@ /u.test(u))return"hunk";if(/^\+/u.test(u))return"add";if(/^-/u.test(u))return"del";if(/^(Success\.|No changes|Updated\b|Created\b|Deleted\b|Added\s+\d+\s+lines?|Wrote\s+\d+\s+lines?|Read\s+\d+\s+files?|\.\.\.\[patch content truncated)/iu.test(u))return"note";return"context"}function UA(u){return $q(u).map((f)=>{let l=FA(f)||JA(f);if(l!==null)return{text:f,kind:"file",path:l.path,status:l.status};return{text:f,kind:IE(f)}})}function kE(u){return u.reduce((f,l)=>{if(l.kind==="add")f.added+=1;else if(l.kind==="del")f.removed+=1;return f},{added:0,removed:0})}function uq(u,f){return`${f} ${u} line${u===1?"":"s"}`}function gE(u,f){let l=[];if(u>0)l.push(uq(u,"Added"));if(f>0)l.push(uq(f,"removed"));return l.join(", ")}function sE(u){for(let l=u.length-1;l>=0;l-=1){let r=String(u[l]?.status||"").trim();if(r.length>0)return r}let f=String(u[u.length-1]?.method||"").trim();if(f==="item/fileChange/outputDelta")return"updated";if(f==="item/started")return"started";if(f==="item/completed")return"completed";return f.replace(/^item\//u,"")||"changed"}function aE(u){return`${u} file${u===1?"":"s"}`}function jq(u){let f=u.length>0?u:[],l=eQ(f.map((U)=>String(U.bodyPreview||""))),y=eQ(f.map((U)=>String(U.bodyPreview||"")).filter((U)=>U.trim().length>0&&!vE(U)))||l,i=Z6(y||l),_=f.map((U)=>({method:AA(U),status:bE(U),at:U.at})),n=UA(y||l),$=kE(n),j=gE($.added,$.removed),F=i.length>0?aE(i.length):"",J=j.length>0?`${j}${F?` in ${F}`:""}`:i.length>0?F:wi(y||l||"File changes",72);return{status:sE(_),summary:J,files:i,stages:_,lines:n,addedLines:$.added,removedLines:$.removed,rawText:l}}function oE(u){let f=u[0],l=u[u.length-1]||f,r=jq(u);return{...f,seq:Number.isFinite(Number(l?.seq))?Number(l?.seq):Number(f?.seq??0),at:l?.at||f?.at,title:r.files.length>0?`Edited ${r.summary}`:"Edited files",status:r.status,commandPreview:"",commandOmittedLines:void 0,bodyPreview:r.rawText,bodyOmittedLines:u.reduce((y,i)=>y+Number(i.bodyOmittedLines||0),0)||void 0,rawSeqs:u.flatMap((y)=>Array.isArray(y?.rawSeqs)?y.rawSeqs:[y?.seq]).filter((y)=>y!==void 0),editObservation:r}}function dE(u){let f=Array.isArray(u)?u:[],l=[],r=[],y=()=>{if(r.length===0)return;l.push(oE(r)),r=[]};for(let i of f){if(Aq(i)){if(AA(i)==="item/started"&&r.length>0)y();if(r.push(i),AA(i)==="item/completed")y();continue}y(),l.push(i)}return y(),l}function Fq(u){let f=[],l=[],r=[],y=(j,F)=>{for(let J of F)if(!j.includes(J))j.push(J)};for(let j of u){let F=String(j?.kind||""),J=[j?.commandPreview,j?.bodyPreview,j?.title].map((U)=>String(U||"")).join(` +`);if(F==="explored")y(f,dQ(J));else if(F==="edited")y(l,dQ(J));else if(F==="ran"){let U=String(j?.commandPreview||j?.title||"").trim();if(U.length>0&&!r.includes(U))r.push(wi(U,90))}}let i=u.map((j)=>Date.parse(String(j?.at||""))).filter((j)=>Number.isFinite(j)),_=i.length>=2?Math.max(0,Math.max(...i)-Math.min(...i)):0,n=u.reduce((j,F)=>j+(Sr(F?.durationMs)??Sr(F?.elapsedMs)??0),0),$=_>0?_:n;return{readFiles:f,editedFiles:l,runCommands:r,durationLabel:xE($)}}function eE(u,f=3){let l=Array.isArray(u)?u:[],r=[],y=[],i=Math.max(0,f),_=new Set;for(let $=l.length-1;$>=0&&i>0;$-=1){let j=l[$];if(!oQ(j))continue;_.add(j),i-=1}let n=()=>{if(y.length>=2){let $=iq(y);r.push({seq:Number(y[0]?.seq??0),at:y[0]?.at||y.at(-1)?.at,kind:"toolGroup",title:_q(y),status:`${y.length} calls`,items:y,counts:$,digest:Fq(y),rawSeqs:y.flatMap((j)=>Array.isArray(j?.rawSeqs)?j.rawSeqs:[j?.seq]).filter((j)=>j!==void 0)})}else r.push(...y);y=[]};for(let $ of l){if(oQ($)&&!_.has($)){y.push($);continue}n(),r.push($)}return n(),r}function Jq(u){return(Array.isArray(u)?u:[]).map((f,l)=>({...f,seq:Number.isFinite(Number(f?.seq))?Number(f.seq):l+1,kind:String(f?.kind||"message"),at:f?.at===void 0?void 0:String(f.at),durationMs:Sr(f?.durationMs)??void 0,title:f?.title===void 0?void 0:String(f.title),status:f?.status===void 0?void 0:String(f.status)}))}function Gn(u){let f=Sr(u?.state?.time?.start)??Sr(u?.time?.start),l=Sr(u?.state?.time?.end)??Sr(u?.time?.end);return Sr(u?.durationMs)??Sr(u?.elapsedMs)??Sr(u?.timing?.durationMs)??Sr(u?.metadata?.durationMs)??(f!==null&&l!==null&&l>=f?l-f:null)??void 0}function Kn(u,f){return u?.createdAt||u?.updatedAt||u?.completedAt||f||void 0}function _A(u,f){return u?.id||u?.messageId||f}function uT(u,f=1200){if(typeof u==="string")return u;if(u===void 0||u===null)return"";try{return wi(JSON.stringify(u),f)}catch{return wi(String(u),f)}}function Uq(u,f,l){if(typeof u?.metadata?.diff==="string"&&u.metadata.diff.length>0)return u.metadata.diff;if(typeof u?.metadata?.filediff?.patch==="string"&&u.metadata.filediff.patch.length>0)return u.metadata.filediff.patch;if(typeof u?.output==="string"&&u.output.length>0)return u.output;if(typeof u?.result==="string"&&u.result.length>0)return u.result;if(typeof f?.output==="string"&&f.output.length>0)return f.output;if(typeof l?.output==="string"&&l.output.length>0)return l.output;if(typeof u?.metadata?.output==="string"&&u.metadata.output.length>0)return u.metadata.output;return""}function T6(u,f){if(!u||typeof u!=="object"||Array.isArray(u))return"";for(let l of f){let r=u[l];if(typeof r==="string"&&r.length>0)return r;if(r!==void 0&&r!==null&&typeof r!=="object")return String(r)}return""}function fq(u,f){if(!u||typeof u!=="object"||Array.isArray(u))return null;for(let l of f){let r=Number(u[l]);if(Number.isFinite(r))return r}return null}function Qq(u,f){let l=f?.input&&typeof f.input==="object"&&!Array.isArray(f.input)?f.input:u?.input&&typeof u.input==="object"&&!Array.isArray(u.input)?u.input:{},r=T6(l,["command","cmd","script"]);if(r.length>0)return r;if(typeof u?.command==="string"&&u.command.length>0)return u.command;if(typeof f?.command==="string"&&f.command.length>0)return f.command;let y=String(u?.tool||u?.title||"tool"),i=T6(l,["filePath","filepath","path"])||T6(u,["filePath","filepath","path"]),_=T6(l,["pattern","query"]),n=fq(l,["offset"]),$=fq(l,["limit"]),j=[y];if(_.length>0)j.push(_);if(i.length>0)j.push(i);if(n!==null)j.push(`offset=${n}`);if($!==null)j.push(`limit=${$}`);return j.length>1?j.join(" "):y}function fT(u,f){let l=u?.part&&typeof u.part==="object"&&!Array.isArray(u.part)?u.part:{},r=String(u?.type||u?.event||u?.name||l?.type||"").toLowerCase(),y=String(l?.type||"").toLowerCase(),i=u?.at||u?.timestamp||l?.updatedAt||l?.createdAt,_=Number.isFinite(Number(u?.seq))?Number(u.seq):f;if(r==="step_start"||r==="step-start"||y==="step-start")return null;if(r==="step_finish"||r==="step-finish"||y==="step-finish")return null;if(y==="tool"||/tool|bash|command/iu.test(`${r} ${y}`)){let $=l?.state&&typeof l.state==="object"&&!Array.isArray(l.state)?l.state:{},j=Qq(l,$),F=Uq($,l,u),J=qq(j,String(l?.tool||l?.title||"")),U=J==="edited"?{status:String($?.status||l?.status||u?.status||""),summary:wi(F||j,72),files:Z6(F),stages:[],lines:UA(F),addedLines:0,removedLines:0,rawText:F}:void 0;return{seq:_,at:Kn(l,i),kind:J,title:String($?.title||l?.title||$?.metadata?.description||l?.tool||"OpenCode tool"),status:String($?.status||l?.status||u?.status||""),commandPreview:j,bodyPreview:F,durationMs:Gn(l),rawSeqs:[l?.id||l?.callID||u?.sessionID||_],editObservation:U}}let n=uT(l?.text??l?.content??l?.delta??u?.text??u?.content??u?.delta,3000).trim();if(n.length>0)return{seq:_,at:Kn(l,i),kind:y==="reasoning"?"message":/error|failed/iu.test(`${r} ${y}`)?"error":"message",title:y==="reasoning"?"Reasoning":/error|failed/iu.test(`${r} ${y}`)?"OpenCode error":"Assistant message",status:`opencode/${r||y||"event"}`,bodyPreview:n,durationMs:Gn(l),rawSeqs:[l?.id||u?.sessionID||_]};return null}function qq(u,f){let l=`${f} ${u}`.toLowerCase();if(/\b(read|grep|glob|list|ls|find|search|view|cat|sed|rg|head|tail|wc|file)\b/iu.test(l))return"explored";if(/\b(edit|write|patch|apply|update|create|delete|apply_patch|git apply|cat >|tee .*<<|sed -i|python3? .*write_text|mkdir|rm |touch )\b/iu.test(l))return"edited";return"ran"}function lT(u){let f=[],l=1;for(let r of Array.isArray(u)?u:[]){if(r?.kind&&r?.title){let n=String(r?.status||"");if(n==="opencode/step-start"||n==="opencode/step-finish")continue;f.push({...r,seq:Number.isFinite(Number(r?.seq))?Number(r.seq):l++});continue}let y=r?.createdAt||r?.updatedAt||r?.completedAt,i=String(r?.role||"assistant").toLowerCase(),_=Array.isArray(r?.parts)?r.parts:[];if(_.length===0){if(r?.part&&(r?.sessionID||String(r?.type||"").startsWith("step_")||String(r?.type||"").includes("tool"))){let n=fT(r,l);if(n!==null)f.push(n),l=Math.max(l+1,Number(n.seq)+1)}else if(r?.textPreview)f.push({seq:l++,at:y,kind:"message",title:`${i||"assistant"} message`,status:i,bodyPreview:String(r.textPreview),rawSeqs:[r?.messageId||l]});continue}for(let n of _){let $=String(n?.type||"").toLowerCase();if($==="step-start"||$==="step-finish")continue;if($==="text"||$==="reasoning"){let F=String(n?.textPreview||r?.textPreview||"").trim();if(F.length===0)continue;f.push({seq:l++,at:Kn(n,y),kind:"message",title:$==="reasoning"?"Reasoning":i==="user"?"User message":i==="system"?"System message":"Assistant message",status:$==="reasoning"?"reasoning":i,bodyPreview:F,durationMs:Gn(n),rawSeqs:[_A(n,l)]});continue}if($==="tool"){let F=n?.state&&typeof n.state==="object"&&!Array.isArray(n.state)?n.state:{},J=Qq(n,F),U=Uq(F,n,{}),q=qq(J,String(n?.tool||n?.title||"")),W=q==="edited"?{status:String(F?.status||n?.status||""),summary:wi(U||J,72),files:Z6(U),stages:[],lines:UA(U),addedLines:0,removedLines:0,rawText:U}:void 0;f.push({seq:l++,at:Kn(n,y),kind:q,title:String(n?.title||n?.tool||"tool"),status:String(n?.status||""),commandPreview:J,bodyPreview:U,durationMs:Gn(n),rawSeqs:[_A(n,l)],editObservation:W});continue}let j=String(n?.textPreview||n?.title||$||"").trim();if(j)f.push({seq:l++,at:Kn(n,y),kind:"system",title:$||"part",bodyPreview:j,status:String(n?.status||""),durationMs:Gn(n),rawSeqs:[_A(n,l)]})}}return f}var Wq={source:"opencode",toTrace:lT};function rT(u){return String(u||"unknown").toLowerCase().replace(/[^a-z0-9_-]+/gu,"-")||"unknown"}function lq(u){let f=String(u||"M").toUpperCase();if(f.startsWith("A")||f==="??")return"added";if(f.startsWith("D"))return"deleted";if(f.startsWith("R"))return"renamed";return"modified"}function yT(u){if(u==="item/fileChange/outputDelta")return"delta";return u.replace(/^item\//u,"")}function iT(u,f){if(u.kind==="file"){let y=String(u.status||"M");return Su("div",{key:`${f}-${u.text}`,className:`codex-edit-diff-line file ${lq(y)}`},Su("span",{className:`codex-edit-file-status ${lq(y)}`},y),Su("code",null,u.path||u.text.replace(/^([AMDRCU?]{1,2})\s+/u,"")))}let l=u.kind==="add"||u.kind==="del"?u.text.slice(0,1):u.kind==="hunk"?"@@":u.kind==="note"?"ok":"",r=u.kind==="add"||u.kind==="del"?u.text.slice(1):u.text;return Su("div",{key:`${f}-${u.text}`,className:`codex-edit-diff-line ${u.kind}`},Su("span",{className:"codex-edit-diff-sign"},l),Su("code",null,r||" "))}function _T(u,f){let l=u.lines.length>0?u.lines:u.files.map((y)=>({text:`${y.status} ${y.path}`,kind:"file",path:y.path,status:y.status})),r=Number(u.addedLines||0)+Number(u.removedLines||0)>0;return Su("div",{className:"codex-edit-observation","data-testid":"codex-edit-observation"},Su("div",{className:"codex-edit-observation-head"},Su("span",{className:"codex-edit-window-controls","aria-hidden":"true"},Su("i",null),Su("i",null),Su("i",null)),Su("strong",null,r?"git diff":"git diff --stat"),Su("code",null,u.summary||"File changes")),u.stages.length>0?Su("div",{className:"codex-edit-stage-strip"},u.stages.map((y,i)=>Su("span",{key:`${y.method}-${i}`,className:`codex-edit-stage ${rT(y.status||y.method)}`},Su("b",null,yT(y.method)),y.status?Su("em",null,y.status):null))):null,l.length>0?Su("div",{className:"codex-edit-diff",role:"list"},l.map(iT)):null,f?Su("div",{className:"codex-edit-omitted"},`${f} (查看原始JSON获取完整记录)`):null)}function rq(u,f,l){let r=$A(l);return Su("div",{className:`codex-transcript-stream ${u}`,"data-testid":`codex-trace-${u}`},Su("span",{className:"codex-transcript-stream-label"},u),Su("pre",{className:"codex-transcript-body"},f,r?` +${r} (查看原始JSON获取完整记录)`:""))}function cq(u,f=!1){let l=String(u.kind||"message"),r=["ran","explored","edited"].includes(l),y=$A(u.commandOmittedLines),i=$A(u.bodyOmittedLines),_=String(u.commandPreview||(r?u.title||"":"")),n=String(u.stdoutPreview||""),$=String(u.stderrPreview||""),j=n.length>0||$.length>0,F=Boolean(u.foldedReferencePrompt)&&String(u.fullPrompt||"").length>0,J=l==="edited"&&(u.editObservation!==void 0||Aq(u))?u.editObservation||jq([u]):null;return Su("article",{key:`${u.seq}-${l}`,className:`codex-transcript-item ${l} ${f?"nested":""}`},Su("div",{className:"codex-transcript-main"},Su("div",{className:"codex-transcript-title"},Su("span",{className:"codex-output-channel"},nA(l)),r&&J===null?null:Su("strong",null,J!==null?"File changes":String(u.title||nA(l))),u.status?Su("code",null,String(J?.status||u.status)):null,Su("time",null,Nu(u.at))),_&&J===null?Su("pre",{className:"codex-transcript-command"},_,y?` +${y}`:""):null,J!==null?_T(J,i):j?Su("div",{className:"codex-transcript-streams"},n.length>0?rq("stdout",n,u.stdoutOmittedLines):null,$.length>0?rq("stderr",$,u.stderrOmittedLines):null):u.bodyPreview?Su("pre",{className:"codex-transcript-body"},String(u.bodyPreview),i?` +${i} (查看原始JSON获取完整记录)`:""):null,F?Su("details",{className:"codex-initial-prompt-full","data-testid":"codex-initial-prompt-full"},Su("summary",null,Su("span",null,"引用注入已折叠,点击查看最终传入 Codex 的完整 prompt"),Su("code",null,`${u.fullPromptLines||RE(String(u.fullPrompt||""))} lines / ${u.fullPromptChars||String(u.fullPrompt||"").length} chars`)),Su("pre",{className:"codex-transcript-body codex-transcript-full-prompt","data-testid":"codex-initial-prompt-full-text"},String(u.fullPrompt||""))):null))}function nT(u){let f=Array.isArray(u.items)?u.items:[],l=u.digest&&typeof u.digest==="object"?u.digest:Fq(f);return Su("article",{key:`${u.seq}-toolGroup`,className:"codex-transcript-item toolGroup"},Su("div",{className:"codex-transcript-main"},Su("details",{className:"codex-tool-group","data-testid":"codex-tool-group"},Su("summary",null,Su("div",{className:"codex-tool-group-head"},Su("span",{className:"codex-output-channel"},nA("toolGroup")),Su("strong",null,String(u.title||_q(f))),Su("code",null,String(u.status||`${f.length} calls`)),Su("time",null,Nu(u.at)))),Su("div",{className:"codex-tool-group-digest"},Su("span",null,`read: ${iA(Array.isArray(l.readFiles)?l.readFiles:[])}`),Su("span",null,`edit: ${iA(Array.isArray(l.editedFiles)?l.editedFiles:[])}`),Su("span",null,`run: ${iA(Array.isArray(l.runCommands)?l.runCommands:[],2)}`),Su("span",null,`duration: ${l.durationLabel||"--"}`)),Su("div",{className:"codex-tool-group-items"},f.map((r)=>cq(r,!0))))))}var $T=16;function yq(u){return u.scrollHeight-u.scrollTop-u.clientHeight<=$T}function H6({items:u,input:f,port:l,autoScroll:r=!1,loading:y=!1,hasDetail:i=!0,emptyText:_="等待 Trace 输出...",loadingText:n="正在加载完整 Trace...",testId:$="trace-output",className:j="codex-transcript",keepRecentToolCalls:F=3,collapseTools:J=!0}){let U=aQ(null),q=aQ(!0),W=dE(l?CE(l,f):Jq(u)),G=J?eE(W,F):W,K=hE(W);pE(()=>{let c=U.current;if(!r||!c)return;if(!q.current&&!yq(c))return;c.scrollTop=c.scrollHeight,q.current=!0},[r,W.length,K]);let N={className:j,ref:U,onScroll:(c)=>{let z=c.currentTarget;q.current=yq(z)},"data-testid":$};if(y&&!i)return Su("div",N,Su("div",{className:"codex-output-empty"},n));return Su("div",N,G.length===0?Su("div",{className:"codex-output-empty"},_):G.map((c)=>String(c.kind||"")==="toolGroup"?nT(c):cq(c)))}var E=On.default.createElement,{useEffect:Q1,useMemo:Nq,useRef:Xf}=On.default,su=On.default.useState,AT=120,Yq=24,Dq=48,jT=1200;function QA(){return typeof document>"u"||document.visibilityState!=="hidden"}function _l(u,f="操作失败"){return Bu(u,f)}function Mr(u){let f=Number(u);if(!Number.isFinite(f)||f<0)return"--";let l=Math.floor(f/1000),r=Math.floor(l/3600),y=Math.floor(l%3600/60),i=l%60;if(r>0)return`${r}h ${String(y).padStart(2,"0")}m`;if(y>0)return`${y}m ${String(i).padStart(2,"0")}s`;return`${i}s`}function H0(u){if(u===null||u===void 0||u==="")return null;let f=u instanceof Date?u.getTime():new Date(u).getTime();return Number.isFinite(f)?f:null}function tq(u,f=Date.now()){let l=H0(u);if(l===null)return"--";let r=Math.max(0,Math.floor((f-l)/1000));if(r<1)return"刚刚";let y=Math.floor(r/86400),i=Math.floor(r%86400/3600),_=Math.floor(r%3600/60),n=r%60;if(y>0)return`${y}天${i>0?`${i}小时`:""}前`;if(i>0)return`${i}小时${_>0?`${_}分钟`:""}前`;if(_>0)return`${_}分钟${n}秒前`;return`${n}秒前`}function Sq(...u){let f="",l=-1/0;for(let r of u){let y=String(r||"");if(y.length===0)continue;let i=H0(r);if(i!==null&&i>=l)f=y,l=i;else if(f.length===0)f=y}return f}function FT(u){let f=Number(u);if(!Number.isFinite(f)||f<0)return"--";if(f<1000)return`${Math.round(f)}ms`;return`${(f/1000).toFixed(f<1e4?2:1)}s`}function GA(u,f=180){let l=String(u||"").replace(/\s+/gu," ").trim();return l.length>f?`${l.slice(0,f-1)}…`:l}async function mf(u,f={}){return Xu(u,{strictJson:!0,retryInvalidJson:1,invalidJsonPrefix:"Code Queue 返回了无效 JSON",invalidJsonPreview:!0,responsePreviewLength:jT,...f})}function jy({status:u,children:f,title:l}){let r=String(u||"unknown").toLowerCase();return E("span",{className:`status-badge ${r}`,title:l},f||u||"unknown")}function Ti({title:u,eyebrow:f,summary:l,actions:r,children:y,className:i,loading:_}){return E("section",{className:`panel ${i||""}`},E("div",{className:"panel-head"},E("div",null,f?E("p",{className:"panel-eyebrow"},f):null,E(Af,{title:u,loading:_}),l?E("div",{className:"panel-summary"},l):null),r?E("div",{className:"panel-actions"},r):null),E("div",{className:"panel-body"},y))}function Pq({title:u,data:f,onOpen:l,testId:r}){return E("button",{type:"button",className:"ghost-btn","data-testid":r,onClick:()=>l(u,f)},"查看原始JSON")}function Fy({title:u,text:f}){return E("div",{className:"empty-state"},E("strong",null,u),E("span",null,f))}function JT(u){return u?.runtime&&typeof u.runtime==="object"&&!Array.isArray(u.runtime)?u.runtime:{}}function UT(u){return u?.backend&&typeof u.backend==="object"&&!Array.isArray(u.backend)?u.backend:{}}function Sf(u,f){return`${u}/code-queue-direct${f}`}function BA(){return{headers:{"cache-control":"no-cache","x-unidesk-no-cache":"1"}}}function nl(u){return Array.isArray(u?.tasks)?u.tasks:[]}function U1(u){return u?.pagination&&typeof u.pagination==="object"&&!Array.isArray(u.pagination)?u.pagination:{}}function zq(u){let f=Date.parse(String(u?.updatedAt||u?.createdAt||""));return Number.isFinite(f)?f:0}function Gq(u){return H0(u?.queueEnteredAt)??H0(u?.createdAt)??H0(u?.updatedAt)??0}function QT(u,f){let l=Gq(u)-Gq(f);if(l!==0)return l;let r=(H0(u?.createdAt)??0)-(H0(f?.createdAt)??0);if(r!==0)return r;return String(u?.id||"").localeCompare(String(f?.id||""))}function qT(u,f=""){let l=new Map;for(let r of u)for(let y of r){let i=String(y?.id||"");if(i.length>0&&!l.has(i))l.set(i,y)}return Array.from(l.values()).sort((r,y)=>{let i=Oq(r)-Oq(y);if(i!==0)return i;let _=String(r?.id||"")===f?0:1,n=String(y?.id||"")===f?0:1;if(_!==n)return _-n;return zq(y)-zq(r)})}function Ei(u,f=""){let l=new Map;for(let r of u)for(let y of r){let i=String(y?.id||"");if(i.length===0)continue;l.set(i,{...l.get(i)||{},...y})}return qT([Array.from(l.values())],f)}function wn(u){return Array.isArray(u?.activeTaskIds)?u.activeTaskIds.map((f)=>String(f||"")).filter(Boolean):[String(u?.activeTaskId||"")].filter(Boolean)}var W1="__all__",WT="(max-width: 760px)",cT="(min-width: 761px)";function ml(u){return!u||u===W1}function NT(){return typeof window<"u"&&window.matchMedia(WT).matches}function zT(u){return ml(u)?"":`&queueId=${encodeURIComponent(u)}`}function KA(u){return String(u||"").trim().replace(/\s+/gu," ").slice(0,200)}function GT(u){let f=KA(u);return f.length===0?"":`&search=${encodeURIComponent(f)}`}function VA(u,f=""){return`${zT(u)}${GT(f)}`}function O6(u,f){return Number(u?.counts?.[f]||0)}function Kq(u,f=""){let l=new Map;for(let y of Array.isArray(u?.queues)?u.queues:[]){let i=String(y?.id||"").trim();if(i.length>0)l.set(i,{...y,name:String(y?.name||i).trim()||i})}for(let y of[String(u?.defaultQueueId||"default"),f].map((i)=>i.trim()).filter(Boolean))if(!l.has(y))l.set(y,{id:y,name:y,total:0,counts:{},activeTaskId:null,runnableTaskId:null,processing:!1});return Array.from(l.values()).sort((y,i)=>{let _=String(y?.id||"")===String(u?.defaultQueueId||"default")?0:1,n=String(i?.id||"")===String(u?.defaultQueueId||"default")?0:1;if(_!==n)return _-n;return String(y?.id||"").localeCompare(String(i?.id||""))})}function Mq(u){let f=String(u?.id||"default"),l=String(u?.name||"").trim();return l.length>0?l:f}function LA(u){let f=String(u?.id||"default"),l=Mq(u);return l===f?f:`${l} (${f})`}function wA(u){let f=O6(u,"running")+O6(u,"judging"),l=O6(u,"queued")+O6(u,"retry_wait"),r=Number(u?.total||0),y=[LA(u),`${r} tasks`];if(f>0)y.push(`${f} running`);if(l>0)y.push(`${l} queued`);return y.join(" · ")}function En(u,f){if(ml(f))return null;return u.find((l)=>String(l?.id||"")===f)||null}function Lq(u,f,l,r){if(ml(l)){let i=wn(u);return String(u?.activeTaskId||i[0]||r.find((_)=>Zq(_))?.id||"")}let y=En(f,l);return String(y?.activeTaskId||r.find((i)=>Zq(i))?.id||"")}function KT(u,f,l){if(!ml(f)){let r=En(u,f);return String(r?.runnableTaskId||l.find((y)=>String(y?.status||"")==="queued"||String(y?.status||"")==="retry_wait")?.id||"")}return String(l.find((r)=>String(r?.status||"")==="queued"||String(r?.status||"")==="retry_wait")?.id||"")}async function LT(u,f=W1,l=""){return mf(Sf(u,`/api/tasks/overview?limit=${Yq}&transcriptLimit=1&compact=1&selected=0${VA(f,l)}`),BA())}async function wT(u,f,l=0,r=W1,y=""){return mf(Sf(u,`/api/tasks/overview?limit=${Yq}&transcriptLimit=3&compact=1&afterSeq=${encodeURIComponent(String(Math.max(0,l)))}&preferId=${encodeURIComponent(f)}${VA(r,y)}`),BA())}async function wq(u,f,l,r=Dq,y=""){return mf(Sf(u,`/api/tasks/overview?limit=${encodeURIComponent(String(r))}&transcriptLimit=1&compact=1&selected=0&includeActive=0&stats=0&beforeId=${encodeURIComponent(l)}${VA(f,y)}`),BA())}async function ET(u,f){return mf(Sf(u,`/api/tasks/${encodeURIComponent(f)}/trace-summary`))}async function TT(u,f,l,r=null){let y=r===null||r===void 0||String(r).length===0?"":`&attempt=${encodeURIComponent(String(r))}`;return mf(Sf(u,`/api/tasks/${encodeURIComponent(f)}/prompt?part=${encodeURIComponent(l)}${y}`))}async function ZT(u,f,l=0,r=500,y=null){let i=y===null||y===void 0||String(y).length===0?"":`&attempt=${encodeURIComponent(String(y))}`;return mf(Sf(u,`/api/tasks/${encodeURIComponent(f)}/trace-steps?afterSeq=${encodeURIComponent(String(l))}&limit=${encodeURIComponent(String(r))}${i}`))}async function HT(u,f,l){return mf(Sf(u,`/api/tasks/${encodeURIComponent(f)}/trace-step?seq=${encodeURIComponent(String(l))}`))}async function OT(u,f){return mf(Sf(u,`/api/tasks/${encodeURIComponent(f)}/read`),{method:"POST",body:{}})}async function BT(u){return mf(Sf(u,"/api/tasks/read-all"),{method:"POST",body:{}})}function VT(u){return Array.isArray(u?.output)?u.output:[]}function XT(u){return Array.isArray(u?.attempts)?u.attempts:[]}function qA(u){return u?.counts&&typeof u.counts==="object"&&!Array.isArray(u.counts)?u.counts:{}}function YT(u){return u.split(/^\s*---+\s*$/gmu).map((f)=>f.trim()).filter(Boolean)}function Eq(u){let f=Number(u);return Number.isFinite(f)?Math.max(1,Math.min(50,Math.floor(f))):1}function ny(u){let f=[];for(let l of u.split(/[\s,,;;]+/u)){let r=l.trim();if(/^codex_\d+_[A-Za-z0-9_-]+$/u.test(r)&&!f.includes(r))f.push(r)}return f}function DT(u,f){let l=ny(f);if(l.length===0)return u;return[`引用 Code Queue 任务 ${l.join(" ")}。后端会在入队时只注入这些任务的 initial prompt 和 final response 全文;中间执行过程不注入,如需补充核查可运行:${l.map((r)=>`bun scripts/cli.ts codex task ${r}`).join(";")}`,"","本次任务:",u].join(` +`)}function tT(u){let r=u.trimStart();if(!r.startsWith("# Code Queue 已解析引用上下文"))return{hasInjection:!1,reference:"",userPrompt:u};let y=u.length-r.length,i=u.lastIndexOf(` # 本次任务 -`);if($0?f.split(/\r\n|\r|\n/u).length:0}function cG(f){let u=String(f?.displayPrompt||"");if(u.length>0)return u;let l=String(f?.prompt||"");return qX(VX(l).userPrompt)}function _l(f){return f?._traceSummary&&typeof f._traceSummary==="object"&&!Array.isArray(f._traceSummary)?f._traceSummary:null}function D2(f){return f?._promptDetails&&typeof f._promptDetails==="object"&&!Array.isArray(f._promptDetails)?f._promptDetails:{}}function Mj(f){let u=_l(f)?.prompt;return u&&typeof u==="object"&&!Array.isArray(u)?u:{}}function T2(f){let u=_l(f)?.execution;return u&&typeof u==="object"&&!Array.isArray(u)?u:{}}function M2(f){let u=Number(f?.stepCount??f?.llmStepCount??0);return Number.isFinite(u)&&u>=0?Math.floor(u):0}function qj(f){let u=Bu(f?.execution)||{},l=Number(f?.stepCount??f?.llmStepCount??u.stepCount??u.llmStepCount??u.toolCallCount??0);return Number.isFinite(l)&&l>=0?Math.floor(l):0}function q2(f){if(!f||f?._traceSummaryLoaded!==!0)return!1;let u=_l(f),l=String(f?._traceSummaryUpdatedAt||u?.updatedAt||""),_=String(f?.updatedAt||"");if(_.length>0){let $=D$(l),r=D$(_);if($!==null&&r!==null){if($+1=y}function B2(f){let u=Mj(f),l=String(u.basePrompt||"");return l.length>0?l:cG(f)}function Lj(f){let u=_l(f);return String(u?.finalResponse||f?.finalResponse||"").trimEnd()}function Xj(f){let l=_l(f)?.lastJudge||f?.lastJudge;return l&&typeof l==="object"&&!Array.isArray(l)?l:null}function Bu(f){return f&&typeof f==="object"&&!Array.isArray(f)?f:null}function Pj(f){let u=_l(f)?.attempts;if(Array.isArray(u)&&u.length>0)return u;let l=iG(f);if(l.length>0)return l.map((r,j)=>({...r,index:Number(r?.index||j+1),execution:j===l.length-1?T2(f):Bu(r?.execution)||{},finalResponse:String(r?.finalResponse||r?.finalResponsePreview||(j===l.length-1?Lj(f):"")),judge:Bu(r?.judge)||(j===l.length-1?Xj(f):null)}));let _=T2(f),y=Lj(f),$=Xj(f);if(Object.keys(_).length===0&&y.length===0&&$===null)return[];return[{index:Number(f?.currentAttempt||1),mode:f?.currentMode||"initial",startedAt:f?.startedAt,finishedAt:f?.finishedAt,terminalStatus:f?.status,execution:_,finalResponse:y,finalResponseChars:y.length,judge:$}]}function RG(f,u){return Bu(u?.execution)||T2(f)}function LX(f,u,l,_){let y=_l(f),$=Number(y?.currentAttempt||f?.currentAttempt||0),r=Number(l),j=Number.isFinite(r)&&r>0&&r===$,A=Dj(f?.updatedAt,y?.updatedAt);if(j&&!u?.finishedAt&&A.length>0)return A;return String(u?.updatedAt||u?.finishedAt||_.effectiveEndAt||(j?A:"")||A||f?.finishedAt||f?.startedAt||"")}function XX(f,u){let l=String(u?.finalResponse||u?.finalResponsePreview||"");if(Object.prototype.hasOwnProperty.call(u||{},"finalResponse")||Object.prototype.hasOwnProperty.call(u||{},"finalResponsePreview"))return l.trimEnd();return l.length>0?l.trimEnd():Lj(f)}function xG(f,u){if(Object.prototype.hasOwnProperty.call(u||{},"judge"))return Bu(u?.judge);return Xj(f)}function BX(f,u,l){if(!hX(f))return!1;if(B6(u,l))return!1;if(u?.finishedAt)return!1;if(["succeeded","failed","canceled"].includes(String(u?.terminalStatus||"")))return!1;let _=_l(f),y=Number(_?.currentAttempt||f?.currentAttempt||0),$=Number(l);if(Number.isFinite($)&&$>0&&Number.isFinite(y)&&y>0)return $===y;return!0}function bG(f){return`feedback:${String(f||"latest")}`}function YX(f,u,l){let _=String(u?.feedbackPrompt||"").trimEnd(),y=String(u?.feedbackPromptPreview||_||"").trimEnd(),$=Number(u?.feedbackPromptChars||_.length||y.length||0),r=Number(u?.feedbackPromptLines||Qy(_||y));if(_.length>0||y.length>0||$>0)return{text:_,preview:y,chars:$,lines:r,source:u?.feedbackPromptSource||"judge-feedback",forAttempt:u?.feedbackPromptForAttempt||Number(l||0)+1,truncated:Boolean(u?.feedbackPromptTruncated)};let j=xG(f,u),A=String(j?.continuePrompt||"").trimEnd();if(j?.decision==="retry"&&A.length>0)return{text:"",preview:A,chars:A.length,lines:Qy(A),source:"judge-continue-prompt",forAttempt:Number(l||0)+1,truncated:!1};return null}function wX(f){let u=Mj(f);return Boolean(u.hasReferenceInjection||Number(u.referencePromptChars||0)>0||f?.referenceInjection||f?.referenceInjectionSummary)}function DX(f,u=null){if(u!==null&&u!==void 0){let _=(Bu(f?._traceStepsByAttempt)||{})[String(u)];return Array.isArray(_)?_:[]}return Array.isArray(f?._traceSteps)?f._traceSteps:[]}function w$(f){return(Array.isArray(f?.summaryLines)?f.summaryLines:[]).map((u)=>String(u||""))}function vG(f){let u=String(f?.kind||"").trim().toLowerCase(),l=String(f?.status||"").trim().toLowerCase();return u==="error"||l==="error"}function TX(f){return(Array.isArray(f)?f:[]).reduce((u,l)=>u+(vG(l)?1:0),0)}function P2(f){let u=String(f?.status||"").trim();if(u.length>0)return u;let l=w$(f).join(` -`);return/^(item\/[A-Za-z]+(?:\/[A-Za-z]+)?):/u.exec(l)?.[1]||""}function XG(f){return/^item\/(?:started|completed): file changes status=/u.test(String(f||"").trim())}function MX(f){let u=w$(f);for(let _=u.length-1;_>=0;_-=1){let y=/file changes status=([A-Za-z0-9_-]+)/u.exec(u[_]||"")?.[1];if(y)return y}let l=P2(f);if(l==="item/fileChange/outputDelta")return"updated";if(l==="item/started")return"started";if(l==="item/completed")return"completed";return l.replace(/^item\//u,"")||String(f?.status||"changed")}function PX(f){if(String(f?.kind||"")!=="edited")return!1;let u=String(f?.title||""),l=String(f?.status||""),_=w$(f).join(` -`);if(u==="Edited files")return!0;if(/^item\/fileChange\//u.test(l))return!0;if((l==="item/started"||l==="item/completed")&&/file changes status=/u.test(_))return!0;if(/^Success\. Updated the following files:/mu.test(_))return!0;if(/^diff --git /mu.test(_))return!0;return/^([AMDRCU?]{1,2})\s+\S+/mu.test(_)}function nX(f){if(f.length<=1)return f[0];let u=f.find(($)=>P2($)==="item/fileChange/outputDelta")||f.find(($)=>w$($).some((r)=>!XG(r)))||f.at(-1)||f[0],l=f.flatMap(($)=>Array.isArray($?.rawSeqs)?$.rawSeqs:[$?.seq]).filter(($)=>$!==void 0),_=f.flatMap(w$).filter(($)=>$.trim().length>0&&!XG($)),y=f[f.length-1]||u;return{...u,at:u?.at||y?.at,title:String(u?.title||"Edited files"),status:MX(y),summaryLines:_.length>0?_:w$(u),rawSeqs:l}}function SX(f){let u=Array.isArray(f)?f:[],l=[],_=[],y=()=>{if(_.length>0)l.push(nX(_));_=[]};for(let $ of u){if(PX($)){if(P2($)==="item/started"&&_.length>0)y();if(_.push($),P2($)==="item/completed")y();continue}y(),l.push($)}return y(),l}function Bj(f){let u=Number(f?.toolCallCount);if(Number.isFinite(u)&&u>=0)return Math.floor(u);let l=Number(f?.readCount||0)+Number(f?.editCount||0)+Number(f?.runCount||0);return Number.isFinite(l)&&l>=0?Math.floor(l):0}function CX(f){let l=(Array.isArray(f)?f:[]).reduce((_,y)=>{let $=String(y?.kind||"");if($==="explored")_.readCount+=1;else if($==="edited")_.editCount+=1;else if($==="ran")_.runCount+=1;return _},{readCount:0,editCount:0,runCount:0});return l.toolCallCount=l.readCount+l.editCount+l.runCount,l}function iX(f,u){if(u.length===0){let _=Bj(f);return{...f,stepCount:_,llmStepCount:_}}let l=CX(u);return{...f,...l,stepCount:l.toolCallCount,llmStepCount:l.toolCallCount,traceLineCount:u.length}}function hG(f,u=null){if(u!==null&&u!==void 0){let l=Bu(f?._traceStepsLoadedByAttempt)||{};return Boolean(l[String(u)])}return Boolean(f?._traceStepsLoaded)}function Yj(f){return f?._traceStepDetails&&typeof f._traceStepDetails==="object"&&!Array.isArray(f._traceStepDetails)?f._traceStepDetails:{}}function cX(f,u){let l=Number(f?.index);return Number.isFinite(l)?l:u+1}function B6(f,u){return Boolean(f?.synthetic)||Number(u)<=0}function S2(f){let u=Number(f);return Number.isFinite(u)?String(u):void 0}function RX(f){let u=f?.timing&&typeof f.timing==="object"?f.timing:{},l=String(f?.status||"");if(["queued"].includes(l))return`等待 ${Rl(u.queueWaitMs??u.totalElapsedMs)}`;if(["running","judging","retry_wait"].includes(l))return`耗时 ${Rl(u.durationMs??u.totalElapsedMs)}`;return`耗时 ${Rl(u.durationMs??u.totalElapsedMs)}`}function n2(f){return String(f?.queueId||"default")}function IG(f){return Bu(f?.queuedReason)}function pG(f){let u=String(f?.queuedReasonLabel||"").trim();if(u.length>0)return u.toUpperCase();let l=IG(f),_=String(l?.label||"").trim();return _.length>0?_.toUpperCase():""}function xX(f){let u=String(f?.status||"unknown");if(u!=="queued")return u;let l=pG(f);return l.length>0?`QUEUED(${l})`:"QUEUED"}function bX(f){if(String(f?.status||"")!=="queued")return;let u=IG(f),l=String(u?.message||"").trim(),_=pG(f);if(l.length>0&&_.length>0)return`${_}: ${l}`;if(l.length>0)return l;return _.length>0?_:void 0}function vX(f){return{system:"SYS",user:"YOU",assistant:"GPT",reasoning:"THINK",command:"CMD",diff:"DIFF",tool:"TOOL",error:"ERR"}[f]||f.toUpperCase()}function BG(f){return["running","judging","retry_wait"].includes(String(f?.status||""))}function hX(f){return String(f?.status||"")==="running"}function cl(f){return["succeeded","failed","canceled"].includes(String(f?.status||""))}function mG(f){if(f?.promptEditable===!0)return!0;if(f?.promptEditable===!1)return!1;return String(f?.status||"")==="queued"&&!f?.startedAt&&Number(f?.currentAttempt||0)===0&&!f?.codexThreadId&&!f?.nextMode}function M1(f){if(!cl(f))return!1;if(f?.terminalUnread===!0)return!0;if(f?.terminalUnread===!1)return!1;return!f?.readAt}function R0(f){let u=Number(f||0);return Number.isFinite(u)?u:0}function IX(f){return R0(f.queued)+R0(f.retry_wait)}function pX(f){return R0(f.running)+R0(f.judging)}function mX(f,u){return Bu(f?.statistics)||Bu(u?.statistics)||{}}function gX(f){return Array.isArray(f?.daily)?f.daily:[]}function kX(f){return Bu(f?.totals)||{}}function nj(f,u){let l=Number(f?.[u]??0);return Number.isFinite(l)&&l>0?l:0}function zj(f,u){return f.reduce((l,_)=>Math.max(l,nj(_,u)),0)}var Uy=700,YG=220,z_=30,Y$=24,X6=184,wj=X6-Y$;function gG(f,u){if(u<=1)return Uy/2;return z_+f*(Uy-z_*2)/(u-1)}function kG(f,u){let l=u>0?u:1;return X6-Math.min(1,f/l)*wj}function Gj(f,u,l){let _=f.length>0?f:[{[u]:0}],y=_.length>1?_:[_[0],_[0]];return y.map(($,r)=>`${gG(r,y.length).toFixed(2)},${kG(nj($,u),l).toFixed(2)}`).join(" ")}function T1(f){let u=String(f||"");return/^\d{4}-\d{2}-\d{2}$/u.test(u)?u.slice(5):u||"--"}function L2(f){if(!f)return"";return`${String(f.seriesKey||"")}:${String(f.row?.date||f.index||"")}`}function tX(f,u,l,_){let y=nj(f,_.key);return{..._,row:f,index:u,value:y,valueLabel:_.format(y),x:gG(u,l),y:kG(y,_.max),seriesKey:_.key}}function wG(f){if(M1(f))return 0;return{running:1,judging:2,retry_wait:3,queued:4,succeeded:8,failed:8,canceled:8}[String(f?.status||"")]??9}function V6(f){if(!f)return!1;if(f?._traceSummaryLoaded===!0)return!1;return f?.summaryOnly===!0||f?._metaLoaded!==!0}function sX(f){return Boolean(f?._metaLoaded)||f?.summaryOnly===!1}function tG(f,u,l){let _=String(f?.[l]||""),y=String(u?.[l]||"");return _.length>y.length?_:y}function Y2(f,u,l){let _=Array.isArray(f?.[l])?f[l]:[],y=Array.isArray(u?.[l])?u[l]:[];if(y.length===0&&_.length>0)return _;return _.length>y.length?_:y}function oX(f,u){let l=u?.summaryOnly===!0&&sX(f),_={...f,...u};if(!l)return _;for(let y of["prompt","basePrompt","displayPrompt","finalResponse"])_[y]=tG(f,u,y);for(let y of["promptHistory","attempts","output","events"])_[y]=Y2(f,u,y);if(f?.referenceInjection?.items&&!u?.referenceInjection?.items)_.referenceInjection=f.referenceInjection;if(f?.referenceInjectionSummary&&!u?.referenceInjectionSummary)_.referenceInjectionSummary=f.referenceInjectionSummary;_.summaryOnly=f?.summaryOnly===!1?!1:u.summaryOnly,_._metaLoaded=f?._metaLoaded,_._detailLoaded=f?._detailLoaded,_._transcriptComplete=f?._transcriptComplete,_._transcriptPreview=Object.prototype.hasOwnProperty.call(u,"_transcriptPreview")?u._transcriptPreview:f?._transcriptPreview;for(let y of["_traceSummary","_traceSummaryLoaded","_traceSteps","_traceStepsLoaded","_traceStepsByAttempt","_traceStepsLoadedByAttempt","_traceStepDetails","_promptDetails"])if(!Object.prototype.hasOwnProperty.call(u,y)&&Object.prototype.hasOwnProperty.call(f||{},y))_[y]=f[y];return _}function aX(f){let u=f?.selected,l=u?.task&&typeof u.task==="object"?u.task:null;if(l!==null){let y=Boolean(u?.preview);return{...l,transcript:Array.isArray(u?.transcript)?u.transcript:[],_detailLoaded:Array.isArray(u?.transcript)&&u.transcript.length>0,_transcriptComplete:Boolean(!y&&!u?.hasMore&&cl(l)),_transcriptPreview:y,_summaryLoaded:!0}}let _=yu(f)[0];return _?{..._,_summaryLoaded:!0}:null}function Kj(f,u){let l=new Map;for(let _ of[...Array.isArray(f)?f:[],...Array.isArray(u)?u:[]]){let y=`${Number(_?.seq??0)}:${String(_?.kind||"message")}`,$=l.get(y);if(!$){l.set(y,_);continue}let r={...$,..._};for(let[j,A]of[["bodyPreview","bodyOmittedLines"],["commandPreview","commandOmittedLines"]]){let J=String($?.[j]||""),U=String(_?.[j]||"");if(J.length>U.length)r[j]=$[j],r[A]=$[A]}l.set(y,r)}return Array.from(l.values()).sort((_,y)=>Number(_?.seq??0)-Number(y?.seq??0))}function X2(f){return(Array.isArray(f)?f:[]).reduce((u,l)=>Math.max(u,Number(l?.seq??0)),0)}function DG(f,u=8){let l=Array.from(new Set((Array.isArray(f)?f:[]).map((y)=>Number(y?.seq??0)).filter((y)=>Number.isFinite(y)&&y>0))).sort((y,$)=>y-$);if(l.length===0)return 0;let _=l[Math.max(0,l.length-u)]??0;return Math.max(0,_-0.001)}function dX(f,u){let l=Array.isArray(f?.codeModels)?f.codeModels:Array.isArray(f?.codexModels)?f.codexModels:[],_=["gpt-5.5","gpt-5.4-mini","gpt-5.4","minimax-m2.7"];return Array.from(new Set([...l,..._,u].map((y)=>String(y||"").trim()).filter(Boolean)))}function eX(f,u){let _=(Array.isArray(f?.executionProviders)?f.executionProviders:[]).map((r)=>({id:String(r?.id||"").trim(),label:String(r?.label||r?.id||"").trim(),defaultWorkdir:String(r?.defaultWorkdir||"").trim(),kind:String(r?.kind||"").trim()})).filter((r)=>r.id.length>0),y=String(f?.mainProviderId||f?.defaultProviderId||"main-server").trim()||"main-server",$=new Map;for(let r of[..._,{id:y,label:`${y} (master)`,defaultWorkdir:String(f?.defaultWorkdir||"/root/unidesk"),kind:"local"},u?{id:u,label:u,defaultWorkdir:w2(f,u),kind:""}:null].filter(Boolean))if(!$.has(r.id))$.set(r.id,r);return Array.from($.values())}function w2(f,u){let l=String(u||"").trim(),_=f?.defaultWorkdirByProvider&&typeof f.defaultWorkdirByProvider==="object"?f.defaultWorkdirByProvider:{};if(typeof _[l]==="string"&&String(_[l]).trim().length>0)return String(_[l]).trim();let y=Array.isArray(f?.executionProviders)?f.executionProviders.find((r)=>String(r?.id||"")===l):null;if(typeof y?.defaultWorkdir==="string"&&y.defaultWorkdir.trim().length>0)return y.defaultWorkdir.trim();let $=String(f?.mainProviderId||f?.defaultProviderId||"main-server");return l===$?String(f?.defaultWorkdir||"/root/unidesk"):String(f?.remoteDefaultWorkdir||"/home/ubuntu")}function fB(f){let u=Pj(f).filter((y)=>!B6(y,y?.index));if(u.length>0){let y=u.reduce(($,r)=>$+Bj(RG(f,r)),0);if(y>0)return y}let l=Bj(T2(f));if(l>0)return l;let _=Number(f?.stepCount??f?.llmStepCount??0);return Number.isFinite(_)&&_>=0?Math.floor(_):0}function uB({task:f,selected:u,onSelect:l,onCopy:_,onReference:y,onMarkRead:$,copied:r,markingRead:j}){let A=f?.lastJudge||{},J=String(f?.id||""),U=M1(f),Q=Dj(f?.updatedAt,_l(f)?.updatedAt),W=`最近更新: ${PG(Q)}`,G=fB(f);return L("article",{role:"button",tabIndex:0,className:`codex-task-card ${u?"selected":""} ${U?"unread-terminal":""}`,onClick:l,onKeyDown:(K)=>{if(K.key==="Enter"||K.key===" ")K.preventDefault(),l()},"data-unread-terminal":U?"true":"false","data-testid":`codex-task-${f?.id||"unknown"}`},U?L("span",{className:"codex-unread-badge",title:"待读","aria-label":"待读","data-testid":`codex-unread-task-${J||"unknown"}`}):null,L("div",{className:"codex-task-card-head"},L("div",{className:"codex-task-status-line"},L(Wy,{status:f?.status,title:bX(f)},xX(f))),L("span",{className:"mono-text"},`${f?.currentAttempt||0}/${f?.maxAttempts||0}`)),L("div",{className:"codex-task-id-row"},L("code",{title:J},J||"unknown"),L("div",{className:"codex-task-id-actions"},L("button",{type:"button",className:"codex-copy-id-btn",onClick:(K)=>{K.stopPropagation(),y(J)},"data-testid":`codex-reference-task-${J||"unknown"}`},"引用"),L("button",{type:"button",className:"codex-copy-id-btn",onClick:(K)=>{K.stopPropagation(),_(J)},"data-testid":`codex-copy-task-id-${J||"unknown"}`},r?"已复制":"复制ID"),U?L("button",{type:"button",className:"codex-copy-id-btn codex-mark-read-btn",disabled:Boolean(j),onClick:(K)=>{K.stopPropagation(),$(J)},"data-testid":`codex-mark-task-read-${J||"unknown"}`},j?"标记中":"标为已读"):null)),L("strong",null,Ej(cG(f),120)||"空任务"),L("div",{className:"codex-task-meta"},L("span",null,`queue=${n2(f)}`),L("span",null,`provider=${f?.providerId||"main-server"}`),L("span",null,f?.model||"--"),L("span",null,RX(f))),L("div",{className:"codex-task-meta codex-task-update-meta"},L("span",{className:"codex-task-recent-update codex-task-step-count",title:"STEP 按 read/edit/run 工具动作统计","data-testid":`codex-task-step-count-${J||"unknown"}`},`STEP ${G}`),L("span",{className:"codex-task-recent-update",title:Q?`更新时间: ${Nf(Q)}`:W,"data-testid":`codex-task-recent-update-${J||"unknown"}`},W),L("span",null,Nf(Q||f?.updatedAt))),mG(f)?L("div",{className:"codex-judge-line","data-testid":`codex-task-prompt-editable-${J||"unknown"}`},"queued prompt 可编辑"):null,A?.decision?L("div",{className:"codex-judge-line"},`judge=${A.decision} ${Math.round(Number(A.confidence||0)*100)}%`):null)}function Nj({title:f,tasks:u,selectedId:l,onSelect:_,onCopy:y,onReference:$,onMarkRead:r,copiedTaskId:j,markingReadTaskId:A,emptyText:J}){let U=Array.isArray(u)?u:[];return L("section",{className:"codex-task-section"},L("div",{className:"codex-task-section-head"},L("span",null,f),L("code",null,String(U.length))),U.length===0?L("p",{className:"codex-task-section-empty"},J):L("div",{className:"codex-task-section-list"},U.map((Q)=>L(uB,{key:Q.id,task:Q,selected:l===Q.id,onSelect:()=>_(Q.id),onCopy:y,onReference:$,onMarkRead:r,copied:j===Q.id,markingRead:A===Q.id}))))}function lB(){return L("span",{className:"codex-stats-icon","aria-hidden":"true"},L("svg",{viewBox:"0 0 36 24",focusable:"false"},L("path",{className:"grid",d:"M3 20.5H33M3 12.5H33M3 4.5H33"}),L("polyline",{className:"line tasks",points:"3,18 9,14 15,15 21,8 27,10 33,4"}),L("polyline",{className:"line retry",points:"3,20 9,17 15,18 21,13 27,14 33,9"})))}function _B({stats:f,queueName:u,onRaw:l}){let _=gX(f),y=kX(f),$=_.at(-1)||{},r=zj(_,"executedTasks"),j=zj(_,"retryAttempts"),A=zj(_,"avgDurationMs"),J=_.length>0,U=Bu(f?.range)||{},[Q,W]=tf(null),[G,K]=tf(null),H=[];if(r>0)H.push(`tasks ${r}`);if(j>0)H.push(`retry ${j}`);if(A>0)H.push(`avg ${Rl(A)}`);let O=[{key:"executedTasks",className:"tasks",label:"执行任务",max:r,format:(B)=>`${R0(B)} tasks`},{key:"retryAttempts",className:"retry",label:"重试次数",max:j,format:(B)=>`${R0(B)} retries`},{key:"avgDurationMs",className:"duration",label:"平均耗时",max:A,format:(B)=>Rl(B)}],z=Q||G,Z=L2(z),N=String(z?.row?.date||""),E=z?{left:`${Math.max(8,Math.min(92,Number(z.x)/Uy*100))}%`,top:`${Math.max(14,Math.min(86,Number(z.y)/YG*100))}%`}:void 0;W_(()=>{W(null),K(null)},[u,U.startDate,U.endDate,_.length]);let q=(B)=>{W(B)},Y=(B)=>{let P=L2(B);K((h)=>L2(h)===P?null:B),W(B)},w=O.flatMap((B)=>_.map((P,h)=>{let M=tX(P,h,_.length,B),n=L2(M),S=Z===n,T=String(P?.date||`day-${h}`),i=`${T1(T)} ${B.label}: ${M.valueLabel}`;return L("g",{key:`${B.key}-${T}`,className:`stat-point-group ${B.className} ${S?"active":""}`,role:"button",tabIndex:0,"aria-label":i,"data-testid":`codex-stats-point-${B.className}-${T}`,onMouseEnter:()=>q(M),onFocus:()=>q(M),onClick:()=>Y(M),onKeyDown:(C)=>{if(C.key==="Enter"||C.key===" ")C.preventDefault(),Y(M)}},L("circle",{className:"stat-hit-point",cx:M.x,cy:M.y,r:13}),L("circle",{className:`stat-point ${B.className} ${S?"active":""}`,cx:M.x,cy:M.y,r:S?5.6:4.2}))}));return L(B$,{title:"统计曲线",eyebrow:`Daily task stats / ${u}`,className:"codex-stats-panel",summary:L("span",null,`${T1(U.startDate)} -> ${T1(U.endDate)} · ${f?.timezone||"Asia/Shanghai"}`),actions:Bu(f)?L(nG,{title:"Code Queue Stats",data:f,onOpen:l,testId:"raw-codex-stats"}):null},L("div",{className:"codex-stats-hero","data-testid":"codex-stats-panel"},L(lB),L("div",null,L("strong",null,`${R0(y.executedTasks)} tasks / ${R0(y.retryAttempts)} retries`),L("span",null,`平均完成耗时 ${Rl(y.avgDurationMs??void 0)} · 终态 ${R0(y.completedTasks)} 个`))),J?L("div",{className:"codex-stats-chart","data-testid":"codex-stats-chart",onMouseLeave:()=>W(null)},L("svg",{viewBox:`0 0 ${Uy} ${YG}`,preserveAspectRatio:"none",role:"img","aria-label":"Code Queue daily task statistics"},L("line",{className:"axis",x1:z_,x2:Uy-z_,y1:X6,y2:X6}),L("line",{className:"grid",x1:z_,x2:Uy-z_,y1:Y$+wj/2,y2:Y$+wj/2}),L("line",{className:"grid",x1:z_,x2:Uy-z_,y1:Y$,y2:Y$}),L("polyline",{className:"stat-line tasks",points:Gj(_,"executedTasks",r)}),L("polyline",{className:"stat-line retry",points:Gj(_,"retryAttempts",j)}),L("polyline",{className:"stat-line duration",points:Gj(_,"avgDurationMs",A)}),z?L("g",{className:"stat-cursor-layer","data-testid":"codex-stats-active-point"},L("line",{className:"stat-cursor",x1:z.x,x2:z.x,y1:Y$,y2:X6}),L("circle",{className:`stat-point-active ${z.className}`,cx:z.x,cy:z.y,r:8})):null,L("g",{className:"stat-point-layer"},w)),z?L("div",{className:"codex-stats-tooltip active",style:E,"data-testid":"codex-stats-tooltip"},L("b",null,T1(z.row?.date)),L("span",null,`${z.label} · ${z.valueLabel}`),L("code",null,`${R0(z.row?.executedTasks)} exec / ${R0(z.row?.retryAttempts)} retry / ${Rl(z.row?.avgDurationMs??void 0)}`)):null,L("div",{className:"codex-stats-legend"},L("span",{className:"tasks"},"执行任务"),L("span",{className:"retry"},"重试次数"),L("span",{className:"duration"},"平均耗时")),L("div",{className:"codex-stats-scale"},L("span",null,T1(_[0]?.date)),L("span",null,H.join(" · ")||"暂无峰值"),L("span",null,T1(_.at(-1)?.date))),L("div",{className:`codex-stats-focus ${z?"active":""}`,"data-testid":"codex-stats-focus"},z?L(Y6.default.Fragment,null,L("div",null,L("strong",null,T1(z.row?.date)),L("span",null,`${z.label} · ${z.valueLabel}`)),L("div",{className:"codex-stats-focus-metrics"},L("code",null,`${R0(z.row?.executedTasks)} exec`),L("code",null,`${R0(z.row?.retryAttempts)} retry`),L("code",null,Rl(z.row?.avgDurationMs??void 0)))):L("span",null,"将鼠标悬停到曲线数据点查看明细,点击数据点可固定。"))):L(zy,{title:"暂无统计",text:"任务开始执行后会生成按天汇总的曲线。"}),L("div",{className:"codex-stats-summary-grid"},L("article",null,L("span",null,"今日执行"),L("strong",null,String(R0($.executedTasks))),L("code",null,T1($.date))),L("article",null,L("span",null,"今日重试"),L("strong",null,String(R0($.retryAttempts))),L("code",null,`累计 ${R0(y.retryAttempts)}`)),L("article",null,L("span",null,"平均耗时"),L("strong",null,Rl(y.avgDurationMs??void 0)),L("code",null,`${R0(y.durationSamples)} samples`))),L("div",{className:"codex-stats-daily-list","data-testid":"codex-stats-daily-list"},_.slice(-7).map((B)=>L("div",{key:String(B?.date||""),className:`codex-stats-daily-row ${N===String(B?.date||"")?"active":""}`,"data-testid":`codex-stats-day-${String(B?.date||"unknown")}`},L("span",null,T1(B?.date)),L("b",null,`${R0(B?.executedTasks)} exec`),L("b",null,`${R0(B?.retryAttempts)} retry`),L("code",null,Rl(B?.avgDurationMs??void 0))))))}function yB({task:f,queueRows:u,busy:l,onMove:_}){let y=String(f?.id||""),$=n2(f),[r,j]=tf($);W_(()=>{j($)},[y,$]);let A=!y||l||["running","judging","retry_wait"].includes(String(f?.status||""));return L("div",{className:"codex-task-move-control","data-testid":"codex-task-queue-move-control"},L("label",null,"任务 queue",L("select",{value:r,disabled:!y||l,onChange:(J)=>j(String(J.target.value||$)),"data-testid":"codex-task-queue-move-select"},u.map((J)=>L("option",{key:String(J?.id||""),value:String(J?.id||"")},Vj(J))))),L("button",{type:"button",className:"ghost-btn",disabled:A||r===$,onClick:()=>_(r),title:A?"运行中 / judging / retry_wait 的任务不能移动;请先打断或等当前 turn 结束":"移动已创建任务到另一个 queue","data-testid":"codex-task-queue-move-button"},"移动"))}function TG(f,u=4){let l=(Array.isArray(f)?f:[]).map((y)=>String(y||"").trim()).filter(Boolean);if(l.length===0)return"--";let _=l.slice(0,u).join(" / ");return l.length>u?`${_} +${l.length-u}`:_}function $B({task:f,loading:u,onLoadPromptPart:l,testId:_="codex-initial-prompt-full",textTestId:y="codex-initial-prompt-full-text",baseTextTestId:$="codex-initial-prompt-base"}){let r=Mj(f),j=D2(f),A=B2(f).trimEnd(),J=String(j.full?.text||""),U=wX(f),Q=Number(r.promptChars||f?.promptChars||J.length),W=Number(r.basePromptLines||Qy(A)),G=Number(r.promptLines||Qy(J));return L("section",{className:"codex-progressive-card codex-progressive-prompt","data-testid":"codex-progressive-prompt"},L("div",{className:"codex-progressive-card-head"},L("span",{className:"codex-output-channel"},"Prompt"),L("strong",null,"Submitted prompt / 原始用户 prompt"),L("code",null,`${W||Qy(A)} lines / ${A.length} chars`)),L("pre",{className:"codex-prompt-full","data-testid":$},A||"空 prompt"),U?L("details",{className:"codex-reference-injection codex-progressive-full-prompt","data-testid":_,onToggle:(K)=>{if(K.currentTarget?.open&&!J)l?.("full")}},L("summary",null,L("span",null,"引用注入已折叠,点击按需拉取最终进入 Code agent 的完整 prompt"),L("code",null,J?`${G||Qy(J)} lines / ${J.length} chars`:`${Number.isFinite(Q)&&Q>0?Q:"--"} chars`)),L("pre",{className:"codex-prompt-full codex-prompt-final-full","data-testid":y},J||(u?"正在按需拉取完整 prompt...":"展开后将只请求 full prompt,不拉取完整 transcript。"))):null)}function sG({task:f,attempt:u,attemptIndex:l,loading:_,onLoadSteps:y,onLoadStep:$,testId:r="codex-execution-summary"}){let j=SX(DX(f,l)),A=iX(RG(f,u),j),J=_l(f),U=Yj(f),Q=hG(f,l),W=Number(u?.errorCount??J?.errorCount??TX(j)),G=Number(A.toolCallCount||0),K=Number(A.stepCount??A.llmStepCount??0),H=Number.isFinite(K)&&K>=0?Math.floor(K):0,O=Array.isArray(A.editedFiles)?A.editedFiles:[],z=Array.isArray(A.commands)?A.commands:[],Z=B6(u,l),N=Z?` · ${String(u?.label||"recovered thread execution")}`:l?` #${l}`:"",E=LX(f,u,l,A),q=`最近更新: ${PG(E)}`,Y=BX(f,u,l),w=M2(f),B=Pj(f).filter((n)=>!B6(n,n?.index)).length,P=!Z&&j.length===0&&w>0&&B<=1,h=P?Math.max(H,w):H,M=P?Math.max(G,h):G;return L("details",{className:`codex-progressive-card codex-execution-summary ${Y?"running":""}`,"data-testid":r,"data-attempt-index":S2(l),"data-running":Y?"true":"false",onToggle:(n)=>{if(n.currentTarget?.open&&!Q)y?.(l)}},L("summary",null,L("div",{className:"codex-progressive-card-head"},L("span",{className:"codex-output-channel"},"Summary"),L("strong",null,`执行过程摘要${N}`),Y?L("span",{className:"codex-summary-running-pill","data-testid":`${r}-running`},"执行中"):null,L("code",{title:E?`最近更新: ${Nf(E)}`:q},`${Rl(A.durationMs??A.totalElapsedMs)} / ${M} tools / ${q}`)),L("div",{className:"codex-execution-digest"},L("span",null,`read ${Number(A.readCount||0)}`),L("span",null,`edit ${Number(A.editCount||0)}`),L("span",null,`run ${Number(A.runCount||0)}`),L("span",null,`STEP ${Number.isFinite(h)?Math.max(0,Math.floor(h)):0}`),W>0?L("span",{className:"codex-execution-error-pill","data-testid":`${r}-error-count`},`Error ${W}`):null)),L("div",{className:"codex-execution-digest expanded"},L("span",null,`修改文件:${TG(O,6)}`),L("span",null,`执行命令:${TG(z,4)}`)),j.length===0?L("div",{className:"codex-output-empty"},_?"正在按需拉取步骤 summary...":"展开后将只请求执行步骤 summary,不拉取单步骤全量。"):L("div",{className:"codex-trace-step-list"},j.map((n)=>{let S=String(n?.seq??""),T=U[S],i=Array.isArray(n?.summaryLines)?n.summaryLines.slice(0,4):[];return L("details",{key:S||`${n?.title}-${n?.at}`,className:`codex-trace-step ${String(n?.kind||"message")} ${vG(n)?"error":""}`,"data-testid":`codex-trace-step-${S||"unknown"}`,onToggle:(C)=>{if(C.currentTarget?.open&&!T)$?.(n?.seq)}},L("summary",null,L("span",{className:"codex-output-channel"},rB(n?.kind)),L("strong",null,String(n?.title||"Trace step")),n?.status?L("code",null,String(n.status)):null,L("time",null,Nf(n?.at))),L("div",{className:"codex-trace-step-summary"},i.length>0?i.map((C,v)=>L("pre",{key:`${S}-${v}`},String(C||""))):L("span",null,"无 summary")),T?.line?L(O2,{items:[T.line],autoScroll:!1,loading:!1,hasDetail:!0,emptyText:"无步骤详情",testId:`codex-trace-step-detail-${S||"unknown"}`,className:"codex-transcript codex-step-detail-transcript",collapseTools:!1}):L("div",{className:"codex-output-empty"},_?"正在按需拉取这个步骤的全量数据...":"展开后将只请求这个单步骤的全量数据。"))})))}function rB(f){let u=String(f||"");if(u==="ran")return"Ran";if(u==="explored")return"Explored";if(u==="edited")return"Edited";if(u==="error")return"Error";if(u==="system")return"System";return"Message"}function oG({task:f,attempt:u,attemptIndex:l,testId:_="codex-final-response"}){let y=XX(f,u);if(y.length===0)return null;let $=Number(u?.finalResponseChars||y.length),r=l?` #${l}`:"";return L("section",{className:"codex-progressive-card codex-final-response","data-testid":_,"data-attempt-index":S2(l)},L("div",{className:"codex-progressive-card-head"},L("span",{className:"codex-output-channel"},"Final"),L("strong",null,`最终 response${r}`),L("code",null,`${Number.isFinite($)?$:y.length} chars`)),L(mz,{markdown:y,className:"codex-transcript-body codex-markdown",testId:`${_}-markdown`}))}function aG({task:f,attempt:u,attemptIndex:l,testId:_="codex-progressive-judge"}){let y=xG(f,u);if(!y?.decision)return null;let $=l?` #${l}`:"";return L("section",{className:"codex-progressive-card codex-progressive-judge","data-testid":_,"data-attempt-index":S2(l)},L("div",{className:"codex-progressive-card-head"},L("span",{className:"codex-output-channel"},"Judge"),L("strong",null,`完成判定${$}`),L("code",null,`${y.decision} ${Math.round(Number(y.confidence||0)*100)}%`)),L("div",{className:"codex-judge-card","data-testid":`${_}-card`},L(Wy,{status:y.decision},y.decision),L("strong",null,`${Math.round(Number(y.confidence||0)*100)}% confidence`),L("p",{"data-testid":`${_}-reason`},y.reason||"--"),y.continuePrompt?L("pre",{"data-testid":`${_}-continue-prompt`},String(y.continuePrompt||"")):null))}function jB({task:f,attempt:u,attemptIndex:l,loading:_,onLoadPromptPart:y,testId:$="codex-judge-feedback-prompt"}){let r=YX(f,u,l);if(r===null)return null;let j=bG(l),J=D2(f)[j],U=String(J?.text||"").trimEnd(),Q=String(r.preview||r.text||"").trimEnd(),W=U||String(r.text||"").trimEnd(),G=Number(J?.chars||r.chars||W.length||Q.length),K=Number(J?.lines||r.lines||Qy(W||Q)),H=J?.forAttempt||r.forAttempt||Number(l||0)+1;return L("details",{className:"codex-progressive-card codex-judge-feedback-prompt","data-testid":$,"data-attempt-index":S2(l),onToggle:(O)=>{if(O.currentTarget?.open&&!U)y?.("feedback",l)}},L("summary",null,L("div",{className:"codex-progressive-card-head"},L("span",{className:"codex-output-channel"},"Prompt"),L("strong",null,`judge feedback prompt #${l} -> #${H}`),L("code",null,`${K||"--"} lines / ${Number.isFinite(G)?G:Q.length} chars`)),L("p",{className:"codex-feedback-preview","data-testid":`${$}-preview`},Q||"展开后按需拉取 judge feedback prompt。")),L("pre",{className:"codex-prompt-full codex-feedback-full","data-testid":`${$}-text`},W||(_?"正在按需拉取 judge feedback prompt...":"展开后将只请求这一次 judge feedback prompt。")))}function AB({task:f,attempt:u,position:l,loading:_,onLoadPromptPart:y,onLoadSteps:$,onLoadStep:r}){let j=cX(u,l),A=l===0,J=B6(u,j),U=J?String(u?.label||"Recovered thread execution"):`Attempt ${j}`;return L("section",{className:"codex-attempt-cycle","data-testid":`codex-attempt-cycle-${j}`},L("div",{className:"codex-attempt-cycle-head"},L("span",{className:"codex-output-channel"},U),L("strong",null,String(u?.mode||(j<=1?"initial":"retry"))),u?.terminalStatus?L(Wy,{status:u.terminalStatus},u.terminalStatus):null,L("code",null,`${Nf(u?.startedAt)} -> ${Nf(u?.finishedAt)}`)),L(sG,{task:f,attempt:u,attemptIndex:j,loading:_,onLoadSteps:$,onLoadStep:r,testId:A?"codex-execution-summary":`codex-execution-summary-attempt-${j}`}),J?null:L(oG,{task:f,attempt:u,attemptIndex:j,testId:A?"codex-final-response":`codex-final-response-attempt-${j}`}),J?null:L(aG,{task:f,attempt:u,attemptIndex:j,testId:A?"codex-progressive-judge":`codex-progressive-judge-attempt-${j}`}),J?null:L(jB,{task:f,attempt:u,attemptIndex:j,loading:_,onLoadPromptPart:y,testId:A?"codex-judge-feedback-prompt":`codex-judge-feedback-prompt-attempt-${j}`}))}function FB({task:f,loading:u,onLoadPromptPart:l,onLoadSteps:_,onLoadStep:y}){if(!f)return L(zy,{title:"未选择任务",text:"从左侧队列选择任务,或提交新 Codex 任务。"});let $=Pj(f);return L("div",{className:"codex-transcript codex-progressive-trace","data-testid":"codex-output"},u&&!_l(f)?L("div",{className:"codex-output-empty"},"正在加载 Trace Summary..."):null,L($B,{task:f,loading:u,onLoadPromptPart:l}),$.length>0?$.map((r,j)=>L(AB,{key:`${r?.index||j+1}-${r?.startedAt||j}`,task:f,attempt:r,position:j,loading:u,onLoadPromptPart:l,onLoadSteps:_,onLoadStep:y})):[L(sG,{key:"execution",task:f,loading:u,onLoadSteps:_,onLoadStep:y}),L(oG,{key:"final",task:f}),L(aG,{key:"judge",task:f})])}function JB({task:f}){let u=EX(f);if(!f||u.length===0)return L(zy,{title:"暂无原始消息",text:"原始 Codex app-server 消息会保留在任务 JSON 中。"});return L("details",{className:"codex-raw-output"},L("summary",null,`原始 messages (${u.length})`),L("div",null,u.map((l)=>L("article",{key:`${l.seq}-${l.channel}`,className:`codex-output-line ${l.channel||"system"}`},L("div",{className:"codex-output-meta"},L("span",{className:"codex-output-channel"},vX(String(l.channel||"system"))),L("span",null,Nf(l.at)),l.method?L("code",null,l.method):null),L("pre",null,String(l.text||""))))))}function UB({task:f}){let u=iG(f).slice().reverse();if(u.length===0)return L(zy,{title:"尚无 attempt",text:"任务开始运行后,这里会记录 Codex 终态、传输中断和 stderr tail。"});return L("div",{className:"table-wrap codex-attempt-table"},L("table",null,L("thead",null,L("tr",null,L("th",null,"#"),L("th",null,"模式"),L("th",null,"终态"),L("th",null,"传输"),L("th",null,"退出"),L("th",null,"完成时间"))),L("tbody",null,u.map((l)=>L("tr",{key:`${l.index}-${l.startedAt}`},L("td",null,l.index),L("td",null,l.mode),L("td",null,L(Wy,{status:l.terminalStatus||"unknown"},l.terminalStatus||"unknown")),L("td",null,l.transportClosedBeforeTerminal?L(Wy,{status:"failed"},"closed-before-terminal"):L(Wy,{status:"succeeded"},"normal")),L("td",null,`code=${l.appServerExitCode??"--"} signal=${l.appServerSignal??"--"}`),L("td",null,Nf(l.finishedAt)))))))}function dG({microservices:f,onRaw:u,apiBaseUrl:l="/api",initialTasksData:_=null,standalone:y=!1}){let $=f.find((x)=>x.id==="code-queue")||null,r=aX(_),j=String(r?.id||""),A=new Map;if(r!==null&&j.length>0)A.set(j,{task:r,maxSeq:X2(Array.isArray(r.transcript)?r.transcript:[]),complete:Boolean(r._transcriptComplete),completeUpdatedAt:r._transcriptComplete?String(r.updatedAt||""):""});let J=typeof performance>"u"?0:performance.now(),U=m0(j),Q=m0(0),W=m0(0),G=m0(0),K=m0(!1),H=m0(!1),O=m0(!1),z=m0(null),Z=m0(new Map),N=m0(new Map),E=m0(new Map),q=m0(new Map),Y=m0(new Set),w=m0(!1),B=m0(Boolean(_)),P=m0(new Map),h=m0(new Set),M=m0(A),n=m0(_),[S,T]=tf(null),[i,C]=tf(_),[v,X]=tf(j),[D,p]=tf(r),[m,s]=tf(!1),[d,a]=tf(""),[I,ff]=tf(null),[yf,rf]=tf(!1),[Wf,Ef]=tf(!1),[Gf,c]=tf(""),[o,e]=tf(""),[Kf,k]=tf("default"),[Af,Yf]=tf(G_),[Bf,df]=tf("main-server"),[_0,y0]=tf("gpt-5.5"),[N0,a0]=tf("/root/unidesk"),[pu,mu]=tf(99),[C0,Q1]=tf(1),[ru,Uf]=tf(!1),[nf,Nu]=tf(!1),[Cf,d0]=tf(""),[e0,Zu]=tf(""),[i0,Du]=tf(""),[W1,pl]=tf(!0),[R_,x_]=tf(()=>typeof window>"u"?!0:window.matchMedia(jX).matches),[v0,uf]=tf(!1),[wf,Hf]=tf(""),[gf,pf]=tf(""),{addNotification:Q0}=Lu(),[u0,fu]=tf(""),[Bl,w4]=tf(""),[$3,D4]=tf(!1),[Tu,ml]=tf(_?{phase:"complete",taskId:j,queueMs:0,detailMs:0,totalMs:J,chunks:r?1:0,transcriptRows:Array.isArray(r?.transcript)?r.transcript.length:0,partial:Boolean(_?.selected?.hasMore||V6(r)),completedAt:new Date}:null),[T4,M4]=tf(_?new Date:null),[r3,j3]=tf(!1),Yl=Ry(yu(i)),A3=Yl.filter(M1),h0=i?.queue||S?.body?.queue||S?.queue||{},Nr=mX(i,h0),P4=Q_(i),z1=HG(h0,Kf),ny=L6(z1,Af),b_=Number((cu(Af)?h0?.total:ny?.total)??P4.total??Yl.length),Sy=q6(h0),cJ=cu(Af)?Sy:[String(L6(z1,Af)?.activeTaskId||"")].filter(Boolean),Cy=OG(h0,z1,Af,Yl),RJ=cu(Af)?Wj(h0):Wj(ny||{}),n4=Wj(h0),Zr=IX(n4),Er=Math.max(pX(n4),Sy.length),Hr=R0((cu(Af)?h0?.unreadTerminal:ny?.unreadTerminal)??A3.length),G1=i?A3.length:Hr,iy=cu(Af)?"All queues":Oj(ny||{id:Af,name:Af}),v_=Hj(d),Mu=v_.length>0,S4=Mu?Ry(yu(I)):[],F3=Q_(I),Fl=Mu?S4:Yl,C4=Fl.filter(M1),Or=Fl.filter((x)=>!cl(x)),i4=Fl.filter((x)=>cl(x)&&!M1(x)),c4=Mu?F3:P4,K1=Mu?Number(F3.total??S4.length):b_,R4=c4.hasMore===!0&&String(c4.nextBeforeId||"").length>0,J3=Mu?Wf:r3,U3=$?yX($):{},Vr=$?$X($):{},Q3=NG(()=>HX(Gf),[Gf]),Jl=NG(()=>{let x=LG(C0);return Q3.flatMap((g)=>Array.from({length:x},()=>OX(g,o)))},[Q3,C0,o]),W3=Jl.length,xJ=W3>1&&!ru,kH=nf||v0||W3===0||xJ,bJ=dX(h0,_0),vJ=eX(h0,Bf),tH=w2(h0,Bf),qr=D?.id&&D?.activeTurnId&&String(D?.status)==="running",sH=D?.id&&!["succeeded","failed","canceled"].includes(String(D?.status||"")),oH=D?.id&&["succeeded","failed","canceled"].includes(String(D?.status||"")),cy=D?.id&&mG(D);function N1(x){let g=typeof x==="function"?x(n.current):x;return n.current=g,C(g),g}function aH(x,g,Ff=!0){let jf=Array.from(new Set(x.map((Of)=>String(Of||"")).filter(Boolean)));for(let Of of jf)if(P.current.set(Of,g),Ff)h.current.add(Of);return jf}function hJ(x){for(let g of x.map((Ff)=>String(Ff||"")).filter(Boolean))P.current.delete(g),h.current.delete(g)}function Lr(x){let g=String(x?.id||""),Ff=g?P.current.get(g):void 0;if(!Ff)return x;if(String(x?.status||"").length>0&&!cl(x))return P.current.delete(g),h.current.delete(g),x;return{...x,readAt:x?.readAt||Ff,terminalUnread:!1}}function Xr(x){let g=String(x?.id||"");return g.length>0&&h.current.has(g)&&cl(x)}function Ry(x,g=!0){let Ff=[];for(let jf of Array.isArray(x)?x:[]){let Of=Lr(jf);if(g&&Xr(Of))continue;Ff.push(Of)}return Ff}function dH(x,g=!0){if(!x||!Array.isArray(x?.tasks))return x;let Ff=Ry(yu(x),g),jf=Q_(x);return{...x,tasks:Ff,pagination:x.pagination?{...jf,returned:Ff.length}:x.pagination}}function eH(x){let g=String(x||h0?.mainProviderId||"main-server").trim()||"main-server";df(g),a0(w2(h0,g))}function x4(x,g,Ff=null,jf=null){let Of=new Set(aH(x,g));if(Of.size===0&&jf===null&&Ff===null)return;N1((qf)=>{if(!qf)return qf;let Lf=yu(qf).flatMap((hf)=>{let If=String(hf?.id||"");if(!Of.has(If)){let $0=Lr(hf);return Xr($0)?[]:[$0]}let of=jf&&String(jf?.id||"")===If?jf:{},xf={...hf,...of,readAt:g,terminalUnread:!1};return Xr(xf)?[]:[xf]});return{...qf,queue:Ff||qf.queue,tasks:Of.size>0?X$([Lf],Cy):Lf}});for(let qf of Of){let Lf=M.current.get(qf);if(Lf?.task){let hf=jf&&String(jf?.id||"")===qf?jf:{},If={...Lf.task,...hf,readAt:g,terminalUnread:!1};if(M.current.set(qf,{...Lf,task:If}),U.current===qf)p(If)}}}W_(()=>{Uf(!1)},[Gf,C0,o]),W_(()=>{let x=Hj(d);W.current+=1;let g=W.current;if(!$||x.length===0){ff(null),rf(!1),Ef(!1),O.current=!1;return}rf(!0),ff(null);let Ff=window.setTimeout(()=>{(async()=>{try{let jf=await VG(l,{},Af,x);if(g!==W.current)return;ff(dH(jf))}catch(jf){if(g===W.current)ff(null),Hf(ll(jf,"搜索 Codex tasks 失败"))}finally{if(g===W.current)rf(!1)}})()},240);return()=>window.clearTimeout(Ff)},[$?.id,l,Af,d]),W_(()=>{Zu(D?B2(D):""),Du(Array.isArray(D?.referenceTaskIds)?D.referenceTaskIds.join(" "):"")},[v]);function v1(x,g,Ff){let jf=M.current.get(x)||{},Of=jf.task||{},qf=Array.isArray(Of.transcript)?Of.transcript:[],Lf=oX(Of,g),hf=Object.prototype.hasOwnProperty.call(g,"transcript")?Kj(qf,Array.isArray(g.transcript)?g.transcript:[]):qf,If={...Of,...Lf,transcript:hf,output:Array.isArray(Lf.output)?Y2(Of,Lf,"output"):Array.isArray(Of.output)?Of.output:[],events:Array.isArray(Lf.events)?Y2(Of,Lf,"events"):Array.isArray(Of.events)?Of.events:[]},of=Lr(If),xf=String(of?.updatedAt||""),$0=Boolean(g._transcriptComplete)&&cl(of),ju=Boolean(jf.complete)&&cl(of)&&String(jf.completeUpdatedAt||"")===xf,af=$0||ju,n0={...jf,task:of,maxSeq:X2(hf),complete:af,completeUpdatedAt:af?xf:""};if(M.current.set(x,n0),Ff===G.current&&U.current===x)p(of);return n0}async function z3(x,g=!1,Ff,jf){if(!$||!x)return;let qf=M.current.get(x)?.task;if(!g&&q2(qf))return;let Lf=x,hf=Z.current.get(Lf);if(hf){if(g||!q2(qf))hf.refreshAfter=!0;return hf.promise}let If=G.current,of=performance.now();if(U.current===x)s(!0);let xf={promise:Promise.resolve(),refreshAfter:!1},$0=(async()=>{try{let ju=await WX(l,x);if(If!==G.current||U.current!==x)return;let af=ju?.summary||{},n0=M.current.get(x)?.task||{},ku=String(af.updatedAt||""),gl=String(n0?.updatedAt||""),tu=lX(gl,ku)||M2(n0)>qj(af);if(tu)xf.refreshAfter=!0;let xy=tu?Dj(gl,ku):ku||gl;v1(x,{id:x,status:tu?n0?.status||af.status:af.status,updatedAt:xy,startedAt:af.startedAt||n0?.startedAt,finishedAt:tu?n0?.finishedAt||af.finishedAt:af.finishedAt,currentAttempt:af.currentAttempt??n0?.currentAttempt,maxAttempts:af.maxAttempts??n0?.maxAttempts,finalResponse:tu?tG(n0,af,"finalResponse"):af.finalResponse,lastJudge:tu?n0?.lastJudge||af.lastJudge:af.lastJudge,lastError:tu?n0?.lastError||af.lastError:af.lastError,attempts:tu?Y2(n0,{attempts:Array.isArray(af.attempts)?af.attempts:[]},"attempts"):Array.isArray(af.attempts)?af.attempts:[],timing:af.timing,_traceSummary:af,_traceSummaryLoaded:!0,_traceSummaryUpdatedAt:ku,_detailLoaded:!0},If),ml({phase:"complete",taskId:x,queueMs:jf??0,detailMs:performance.now()-of,totalMs:Ff===void 0?performance.now()-of:performance.now()-Ff,chunks:1,transcriptRows:Number(af?.execution?.traceLineCount||af?.execution?.stepCount||0),partial:!1,completedAt:new Date})}finally{let ju=Boolean(xf.refreshAfter&&U.current===x&&!q2(M.current.get(x)?.task));if(Z.current.delete(Lf),If===G.current&&U.current===x)s(!1);if(ju)window.setTimeout(()=>{z3(x,!0).catch((af)=>Hf(ll(af,"自动刷新 Trace Summary 失败")))},0)}})();xf.promise=$0,Z.current.set(Lf,xf),await $0}async function fO(x,g=null){let Ff=U.current;if(!$||!Ff||!x)return;let jf=M.current.get(Ff)?.task,Of=D2(jf),qf=x==="feedback"||x==="judge-feedback"?bG(g):x;if(Of[qf]?.text)return;let Lf=`${Ff}:${qf}`,hf=N.current.get(Lf);if(hf)return hf;let If=G.current;if(U.current===Ff)s(!0);let of=(async()=>{try{let xf=await zX(l,Ff,x,g);if(If!==G.current||U.current!==Ff)return;let $0=M.current.get(Ff)?.task,ju=D2($0);v1(Ff,{...x==="full"?{prompt:String(xf?.text||""),promptChars:Number(xf?.chars||0)}:{},_promptDetails:{...ju,[qf]:xf}},If)}finally{if(N.current.delete(Lf),If===G.current&&U.current===Ff)s(!1)}})();N.current.set(Lf,of),await of}async function uO(x=null){let g=U.current;if(!$||!g)return;let Ff=M.current.get(g)?.task,jf=x===null||x===void 0||String(x).length===0?"":String(x);if(hG(Ff,jf||null))return;let Of=`${g}:${jf||"all"}`,qf=E.current.get(Of);if(qf)return qf;let Lf=G.current;if(U.current===g)s(!0);let hf=(async()=>{try{let If=await GX(l,g,0,500,jf||null);if(Lf!==G.current||U.current!==g)return;let of=Array.isArray(If?.steps)?If.steps:[];if(jf){let xf=M.current.get(g)?.task,$0=Bu(xf?._traceStepsByAttempt)||{},ju=Bu(xf?._traceStepsLoadedByAttempt)||{};v1(g,{_traceStepsByAttempt:{...$0,[jf]:of},_traceStepsLoadedByAttempt:{...ju,[jf]:!0}},Lf)}else v1(g,{_traceSteps:of,_traceStepsLoaded:!0,_traceStepsHasMore:Boolean(If?.hasMore),_traceStepsNextAfterSeq:If?.nextAfterSeq},Lf)}finally{if(E.current.delete(Of),Lf===G.current&&U.current===g)s(!1)}})();E.current.set(Of,hf),await hf}async function lO(x){let g=U.current,Ff=String(x??"");if(!$||!g||Ff.length===0)return;let jf=M.current.get(g)?.task;if(Yj(jf)[Ff]?.line)return;let qf=`${g}:${Ff}`,Lf=q.current.get(qf);if(Lf)return Lf;let hf=G.current;if(U.current===g)s(!0);let If=(async()=>{try{let of=await KX(l,g,x);if(hf!==G.current||U.current!==g)return;let xf=M.current.get(g)?.task,$0=Yj(xf);v1(g,{_traceStepDetails:{...$0,[Ff]:of}},hf)}finally{if(q.current.delete(qf),hf===G.current&&U.current===g)s(!1)}})();q.current.set(qf,If),await If}async function BC(x,g,Ff){if(!$||!x)return;let jf=performance.now(),Of=G.current,qf=M.current.get(x);if(qf?.task){if(p(qf.task),s(V6(qf.task)||!qf.complete),!V6(qf.task)&&qf.complete&&cl(qf.task)&&String(qf.completeUpdatedAt||"")===String(qf.task?.updatedAt||"")){ml({phase:"complete",taskId:x,queueMs:Ff??0,detailMs:0,totalMs:g===void 0?0:performance.now()-g,chunks:0,transcriptRows:Array.isArray(qf.task.transcript)?qf.task.transcript.length:0,completedAt:new Date});return}}else s(!0);let Lf=z.current;if(Lf?.taskId===x&&Lf.token===Of)return Lf.promise;let hf=(async()=>{try{let If=await D0(T0(l,`/api/tasks/${encodeURIComponent(x)}?meta=1`));if(Of!==G.current||U.current!==x)return;let of=M.current.get(x),xf=Array.isArray(of?.task?.transcript)?of.task.transcript:[],$0=If?.task||{},ju=Boolean(of?.complete)&&String(of?.completeUpdatedAt||"")===String($0?.updatedAt||"");v1(x,{...$0,summaryOnly:!1,_metaLoaded:!0,transcript:xf,_detailLoaded:xf.length>0,_transcriptComplete:ju},Of);let af=V6(of?.task)||Boolean(of?.task?._transcriptPreview),n0=af?0:xf.length>0?DG(xf):0,ku=!af&&of?.complete&&cl($0)&&String(of?.completeUpdatedAt||"")===String($0?.updatedAt||"")?X2(xf):n0,gl=!0,tu=0,xy=xf.length;while(gl){let Ql=await D0(T0(l,`/api/tasks/${encodeURIComponent(x)}/transcript?afterSeq=${encodeURIComponent(String(ku))}&limit=${fX}&fullText=1`));if(Of!==G.current||U.current!==x)return;let kl=M.current.get(x),h_=Array.isArray(kl?.task?.transcript)?kl.task.transcript:[],I_=Kj(h_,Array.isArray(Ql?.transcript)?Ql.transcript:[]);tu+=1,xy=I_.length;let t0=Boolean(!Ql?.hasMore);if(v1(x,{status:Ql?.status||$0.status,updatedAt:Ql?.updatedAt||$0.updatedAt,transcript:I_,_detailLoaded:t0||I_.length>0,_transcriptComplete:t0,_transcriptPreview:af&&!t0},Of),gl=Boolean(Ql?.hasMore),ku=Number(Ql?.nextAfterSeq??X2(I_)),!gl)break;await new Promise((sJ)=>window.setTimeout(sJ,0))}ml({phase:"complete",taskId:x,queueMs:Ff??0,detailMs:performance.now()-jf,totalMs:g===void 0?performance.now()-jf:performance.now()-g,chunks:tu,transcriptRows:xy,completedAt:new Date})}finally{if(z.current?.taskId===x&&z.current?.token===Of)z.current=null;if(Of===G.current&&U.current===x)s(!1)}})();z.current={taskId:x,token:Of,promise:hf},await hf}async function gu(x=U.current,g=!0,Ff=Af){if(!$)return;if(!g&&w.current)return;let jf=performance.now();if(g)w.current=!0;if(g)ml({phase:"loading",taskId:String(x||U.current||""),startedAt:new Date});let Of=Q.current+1;Q.current=Of;let qf=String(x||U.current||""),Lf=qf?M.current.get(qf):null,hf=Array.isArray(Lf?.task?.transcript)?Lf.task.transcript:[],If=DG(hf),of=S||{},xf=null;try{xf=await QX(l,qf,If,Ff)}catch{xf=await VG(l,of,Ff)}if(Of!==Q.current){if(g)w.current=!1;return}let $0=performance.now()-jf;T(of);let ju=xf?.queue||{},af=String(ju?.activeTaskId||q6(ju)[0]||""),n0=xf;N1((Eu)=>{let G3=yu(xf),p_=yu(Eu),K3=p_.length>0?X$([p_,G3],af):X$([G3],af),v4=Ry(K3),OO=Q_(xf),h4=Q_(Eu),VO=p_.length>G3.length&&(h4.hasMore===!1||String(h4.nextBeforeId||"").length>0),qO={...OO,...VO?{hasMore:h4.hasMore,nextBeforeId:h4.nextBeforeId}:{},returned:v4.length};return n0={...xf,tasks:v4,pagination:qO},n0});let ku=yu(n0),gl=HG(ju,Kf),tu=OG(ju,gl,Ff,ku),xy=UX(gl,Ff,ku),Ql=qf||U.current,kl=n0?.selected||null,h_=kl?.task||null,I_=Array.isArray(kl?.transcript)?kl.transcript:null,t0=Ql&&(ku.some((Eu)=>Eu.id===Ql)||String(h_?.id||"")===Ql)?Ql:tu||xy||ku[0]?.id||"";if(U.current!==t0)G.current+=1;U.current=t0,X(t0);let b4=ku.find((Eu)=>Eu.id===t0);if(b4){let Eu=M.current.get(t0);if(Eu?.task)M.current.set(t0,{...Eu,task:{...b4,...Eu.task,status:b4.status,updatedAt:b4.updatedAt}})}if(h_?.id===t0&&I_!==null){let Eu=M.current.get(t0),G3=Array.isArray(Eu?.task?.transcript)?Eu.task.transcript:[],p_=Kj(G3,I_),K3=Boolean(kl?.preview);if(v1(t0,{...h_,_summaryLoaded:!0,transcript:p_,_detailLoaded:!kl?.hasMore||p_.length>0,_transcriptComplete:!K3&&!kl?.hasMore&&cl(h_),_transcriptPreview:K3},G.current),s(!1),g)ml({phase:"complete",taskId:t0,queueMs:$0,detailMs:Math.max(0,performance.now()-jf-$0),totalMs:performance.now()-jf,chunks:1,transcriptRows:p_.length,partial:Boolean(K3||kl?.hasMore||V6(h_)),completedAt:new Date});if(M4(new Date),g)w.current=!1;z3(t0,!1,g?jf:void 0,g?$0:void 0).catch((v4)=>Hf(ll(v4,"加载 Codex Trace Summary 失败")));return}if(g)ml({phase:"session",taskId:t0,queueMs:$0,totalMs:$0,startedAt:new Date(Date.now()-$0)});if(t0)z3(t0,!0,g?jf:void 0,g?$0:void 0).catch((Eu)=>Hf(ll(Eu,"加载 Codex Trace Summary 失败")));else if(G.current+=1,p(null),s(!1),g)ml({phase:"complete",taskId:"",queueMs:$0,detailMs:0,totalMs:performance.now()-jf,chunks:0,transcriptRows:0,completedAt:new Date});if(M4(new Date),g)w.current=!1}async function IJ(){if(Mu){if(!$||Wf||O.current)return;let g=String(F3.nextBeforeId||"");if(!g)return;O.current=!0,Ef(!0),Hf("");try{let Ff=await qG(l,Af,g,MG,v_),jf=yu(Ff),Of=Ff?.queue||h0||{},qf=String(Of?.activeTaskId||q6(Of)[0]||Cy||"");ff((Lf)=>{let hf=Ry(X$([yu(Lf),jf],qf)),If=Q_(Ff);return{...Lf||{},queue:Of,tasks:hf,pagination:{...If,returned:hf.length}}})}catch(Ff){Hf(ll(Ff,"加载更多搜索结果失败"))}finally{O.current=!1,Ef(!1)}return}if(!$||r3||H.current)return;let x=String(Q_(i).nextBeforeId||"");if(!x)return;H.current=!0,j3(!0),Hf("");try{let g=await qG(l,Af,x),Ff=yu(g),jf=g?.queue||h0||{},Of=String(jf?.activeTaskId||q6(jf)[0]||Cy||"");N1((qf)=>{let Lf=Ry(X$([yu(qf),Ff],Of)),hf=Q_(g);return{...qf||{},queue:jf,statistics:g?.statistics||qf?.statistics,tasks:Lf,pagination:{...hf,returned:Lf.length}}})}catch(g){Hf(ll(g,"加载更早 Codex tasks 失败"))}finally{H.current=!1,j3(!1)}}function _O(x){let g=x.currentTarget;if(!g||J3||!R4)return;if(g.scrollHeight-g.scrollTop-g.clientHeight<120)IJ()}async function Ul(x,g){uf(!0),Hf("");try{await x()}catch(Ff){Hf(ll(Ff,g))}finally{uf(!1)}}async function Br(x){if(!x)return;try{let g=!1;try{if(navigator.clipboard?.writeText)await navigator.clipboard.writeText(x),g=!0}catch{g=!1}if(!g){let jf=document.createElement("textarea");jf.value=x,jf.style.position="fixed",jf.style.opacity="0",document.body.appendChild(jf),jf.select(),g=document.execCommand("copy"),document.body.removeChild(jf)}if(!g)throw Error("browser clipboard rejected the copy request");fu(x);let Ff=`已复制任务 ID:${x}`;pf(Ff),Q0("success",Ff),window.setTimeout(()=>fu((jf)=>jf===x?"":jf),1600)}catch(g){Hf(`复制任务 ID 失败:${ll(g)}`)}}function Yr(x){if(!x)return;e(x);let g=`已引用任务 ID:${x};提交时后端会读取并注入该任务上下文`;pf(g),Q0("success",g)}async function wr(x){if(!$||!x)return;let g=new Date().toISOString();Q.current+=1,x4([x],g,null,{id:x,readAt:g,terminalUnread:!1}),w4(x);let Ff=!1;if(await Ul(async()=>{let jf=await NX(l,x),Of=jf?.task||{id:x,readAt:new Date().toISOString(),terminalUnread:!1},qf=String(Of?.readAt||new Date().toISOString());x4([x],qf,jf?.queue||null,Of),Ff=!0;let Lf=`已将任务 ${x} 标为已读`;pf(Lf),Q0("success",Lf)},"标记 Codex task 已读失败"),!Ff)hJ([x]),gu(U.current,!1).catch((jf)=>Hf(ll(jf,"刷新 Codex tasks 失败")));w4((jf)=>jf===x?"":jf)}async function yO(){if(!$||$3)return;D4(!0);let x=new Date().toISOString(),g=Array.from(new Set([...yu(n.current).filter(M1).map((jf)=>String(jf?.id||"")).filter(Boolean),...Array.from(M.current.entries()).filter(([,jf])=>M1(jf?.task)).map(([jf])=>jf)]));if(Q.current+=1,g.length>0)x4(g,x);let Ff=!1;if(await Ul(async()=>{let jf=await ZX(l),Of=String(jf?.readAt||new Date().toISOString()),qf=yu(n.current).filter(M1).map((xf)=>String(xf?.id||"")).filter(Boolean),Lf=Array.from(M.current.entries()).filter(([,xf])=>M1(xf?.task)).map(([xf])=>xf),hf=Array.from(new Set([...g,...qf,...Lf]));x4(hf,Of,jf?.queue||null);let If=Number(jf?.count||hf.length);Ff=!0;let of=`已将 ${If} 个已结束未读任务标为已读`;pf(of),Q0("success",of)},"全部标为已读失败"),!Ff&&g.length>0)hJ(g),gu(U.current,!1).catch((jf)=>Hf(ll(jf,"刷新 Codex tasks 失败")));D4(!1)}function $O(x){let g=x||G_;if(Yf(g),!cu(g))k(g);if(N1(null),!(cu(g)?U.current:""))U.current="",G.current+=1,X(""),p(null),s(!0)}async function rO(){let x=typeof window>"u"?"":window.prompt("输入新的 Codex queue ID(字母/数字/._-,最长 64)","new-lane"),g=String(x||"").trim();if(!g)return;await Ul(async()=>{let Ff=await D0(T0(l,"/api/queues"),{method:"POST",body:{queueId:g}}),jf=String(Ff?.queue?.id||g);k(jf),Yf(jf),N1(null),U.current="",G.current+=1,X(""),p(null);let Of=`已创建并切换到 queue:${jf}`;pf(Of),Q0("success",Of),await gu("",!0,jf)},"创建 Codex queue 失败")}async function jO(){let x=String(Kf||"default").trim()||"default",g=L6(z1,x)||{id:x,name:x},Ff=typeof window>"u"?null:window.prompt(`输入 queue 显示名称(ID 不变:${x};留空恢复为 ID)`,CG(g));if(Ff===null)return;await Ul(async()=>{let jf=await D0(T0(l,`/api/queues/${encodeURIComponent(x)}`),{method:"PATCH",body:{name:String(Ff)}}),Of=jf?.queue||{id:x,name:String(Ff||x)};if(jf?.summary)N1((Lf)=>Lf?{...Lf,queue:jf.summary}:Lf);let qf=`已更新 queue 名称:${Oj(Of)}`;pf(qf),Q0("success",qf),await gu(U.current,!0,Af)},"修改 Codex queue 名称失败")}async function AO(x){if(x.preventDefault(),K.current){pf("任务正在提交中,请等待当前请求完成,已阻止重复提交。");return}if(Jl.length>1&&!ru){Hf(`检测到将创建 ${Jl.length} 个任务;请先勾选“确认批量入队”,避免误传多个任务。`);return}K.current=!0,Nu(!0),pf("正在提交 Code Queue 任务,请等待后端确认,输入已临时锁定。"),await Ul(async()=>{if(Jl.length===0)throw Error("prompt 不能为空");let g=Jy(o),Ff=Kf.trim()||"default",jf=[...Jl],Of=(xf)=>({prompt:xf,queueId:Ff,providerId:Bf,model:_0,cwd:N0,maxAttempts:Number(pu),...g.length>0?{referenceTaskIds:g}:{}}),qf=jf.length===1?Of(jf[0]):{tasks:jf.map(Of)},Lf=await D0(T0(l,jf.length===1?"/api/tasks":"/api/tasks/batch"),{method:"POST",body:qf}),hf=Lf?.tasks?.[0]?.id||"",If=Array.isArray(Lf?.tasks)?Lf.tasks.map((xf)=>String(xf?.id||"")).filter(Boolean):[],of=`已创建 ${If.length||jf.length} 个任务${If.length>0?`:${If.join(" / ")}`:""}`;if(pf(of),Q0("success",of),c(""),e(""),Uf(!1),U.current=hf,Af!==Ff)N1(null);k(Ff),await gu(hf,!0,Ff)},"Codex 任务入队失败"),K.current=!1,Nu(!1)}async function FO(x){if(x.preventDefault(),!D?.id)return;await Ul(async()=>{await D0(T0(l,`/api/tasks/${encodeURIComponent(D.id)}/steer`),{method:"POST",body:{prompt:Cf}}),d0(""),await gu(D.id)},"追加 prompt 失败")}async function JO(x){x.preventDefault();let g=String(D?.id||"");if(!g||!cy)return;await Ul(async()=>{let Ff=Jy(i0),jf=await D0(T0(l,`/api/tasks/${encodeURIComponent(g)}/edit`),{method:"POST",body:{prompt:e0,referenceTaskIds:Ff}}),Of={...jf?.task||D||{},_traceSummary:null,_traceSummaryLoaded:!1,_traceSummaryUpdatedAt:"",_promptDetails:{},_traceSteps:[],_traceStepsLoaded:!1,_traceStepsByAttempt:{},_traceStepsLoadedByAttempt:{},_traceStepDetails:{}};M.current.set(g,{...M.current.get(g)||{},task:Of,complete:!1,completeUpdatedAt:""}),U.current=g,p(Of),X(g),Zu(B2(Of)),Du(Array.isArray(Of?.referenceTaskIds)?Of.referenceTaskIds.join(" "):""),N1((Lf)=>{if(!Lf)return Lf;let hf=yu(Lf).map((If)=>String(If?.id||"")===g?{...If,...Of}:If);return{...Lf,queue:jf?.queue||Lf.queue,tasks:X$([hf],Cy)}});let qf=jf?.changed===!1?`任务 ${g} 的 prompt 未变化`:`已更新 queued 任务 ${g} 的用户 prompt`;pf(qf),Q0("success",qf),await gu(g,!0,Af)},"编辑 queued 任务 prompt 失败")}async function UO(){if(!D?.id)return;await Ul(async()=>{await D0(T0(l,`/api/tasks/${encodeURIComponent(D.id)}/interrupt`),{method:"POST",body:{}}),await gu(D.id)},"打断 Codex session 失败")}async function QO(){if(!D?.id)return;await Ul(async()=>{await D0(T0(l,`/api/tasks/${encodeURIComponent(D.id)}/retry`),{method:"POST",body:{}}),await gu(D.id)},"重新入队失败")}async function WO(x){let g=String(D?.id||""),Ff=String(x||"").trim();if(!g||!Ff)return;let jf=n2(D);if(Ff===jf){pf(`任务 ${g} 已在 queue=${Ff}`);return}await Ul(async()=>{let qf=(await D0(T0(l,`/api/tasks/${encodeURIComponent(g)}/move`),{method:"POST",body:{queueId:Ff}}))?.task||{...D,queueId:Ff};if(M.current.set(g,{...M.current.get(g)||{},task:qf}),U.current=g,p(qf),X(g),k(Ff),!cu(Af))N1(null),Yf(Ff);let Lf=`已将任务 ${g} 从 ${jf} 移动到 ${Ff}`;pf(Lf),Q0("success",Lf),await gu(g,!0,cu(Af)?G_:Ff)},"移动任务 queue 失败")}async function zO(){let x=U.current;if(!x)return;let g=performance.now();await Ul(async()=>{ml({phase:"session",taskId:x,queueMs:0,totalMs:0,partial:!0,startedAt:new Date}),await z3(x,!0,g,0)},"刷新 Trace Summary 失败")}function GO(x){U.current=x,G.current+=1,X(x);let g=M.current.get(x);if(g?.task)p(g.task),s(!1);else{s(!0);let Ff=Yl.find((jf)=>jf.id===x);if(Ff)p(Ff);else p(null)}gu(x).catch((Ff)=>Hf(ll(Ff,"切换 Codex session 失败")))}function Dr(x){if(GO(x),AX())x_(!1)}W_(()=>{if(B.current){B.current=!1;return}Ul(()=>gu(U.current),"Code Queue 加载失败")},[$?.id,Af]),W_(()=>{if(!$)return;let x=()=>{if(!ZG())return;gu(U.current,!1).catch((jf)=>Hf(ll(jf,"Code Queue 轮询失败")))},g=window.setInterval(()=>{x()},1500),Ff=()=>{if(ZG())x()};return document.addEventListener("visibilitychange",Ff),()=>{window.clearInterval(g),document.removeEventListener("visibilitychange",Ff)}},[$?.id,Af]),W_(()=>{if(!$||!D||m)return;let x=String(D.id||"");if(!x)return;let g=String(D.updatedAt||"");if(q2(D))return;let Ff=`${x}:${g||"unknown"}:${M2(D)}:${qj(_l(D))}`;if(Y.current.has(Ff))return;Y.current.add(Ff),z3(x,!0).catch((jf)=>Hf(ll(jf,"自动加载 Trace Summary 失败")))},[$?.id,D?.id,D?.updatedAt,D?.stepCount,D?.llmStepCount,D?._traceSummaryUpdatedAt,D?._traceSummaryLoaded,m]);let KO=Fl.length===0?L(zy,{title:Mu?yf?"搜索中":"没有匹配任务":"队列为空",text:Mu?yf?`正在搜索包含“${v_}”的 task...`:`未找到包含“${v_}”的 task;可换个关键词或切换 queue。`:"提交一个任务后,Codex 会串行执行并保存输出。"}):[C4.length>0?L(Nj,{key:"unread",title:"已结束未读",tasks:C4,selectedId:v,emptyText:"暂无已结束未读任务。",onSelect:Dr,onCopy:Br,onReference:Yr,onMarkRead:wr,copiedTaskId:u0,markingReadTaskId:Bl}):null,L(Nj,{key:"active",title:"运行 / 排队",tasks:Or,selectedId:v,emptyText:"当前没有运行或排队任务。",onSelect:Dr,onCopy:Br,onReference:Yr,onMarkRead:wr,copiedTaskId:u0,markingReadTaskId:Bl}),L(Nj,{key:"history",title:"历史 session",tasks:i4,selectedId:v,emptyText:"最近没有完成、失败或取消的 session。",onSelect:Dr,onCopy:Br,onReference:Yr,onMarkRead:wr,copiedTaskId:u0,markingReadTaskId:Bl}),L("div",{key:"pagination",className:"codex-task-pagination","data-testid":"codex-task-pagination"},L("span",null,Mu?`搜索“${v_}” · 已显示 ${Fl.length} / ${Number.isFinite(K1)?K1:Fl.length}`:`已加载 ${Fl.length} / ${Number.isFinite(K1)?K1:Fl.length}`),R4?L("button",{type:"button",className:"ghost-btn",disabled:J3,onClick:()=>void IJ(),"data-testid":"codex-load-more-tasks-button"},J3?"加载中":Mu?"加载更多结果":"加载更早任务"):L("code",null,Mu?"已到结果末尾":"已到队列末尾"))],pJ=(x,g=!1)=>L("label",{className:`code-queue-switcher ${g?"compact":""}`},L("span",null,g?"Queue":"查看 queue"),L("select",{value:Af,onChange:(Ff)=>$O(String(Ff.target.value||G_)),"data-testid":x},L("option",{value:G_},`All queues · ${Number.isFinite(b_)?b_:Yl.length} tasks · ${Sy.length} running`),z1.map((Ff)=>L("option",{key:String(Ff?.id||""),value:String(Ff?.id||"")},Vj(Ff))))),NO=L("div",{className:"codex-task-search","data-testid":"codex-task-search"},L("label",{htmlFor:"codex-task-search-input"},"搜索 task"),L("div",{className:"codex-task-search-row"},L("input",{id:"codex-task-search-input",type:"search",value:d,placeholder:"关键词 / task ID / prompt",autoComplete:"off",onChange:(x)=>a(String(x.target.value||"")),"data-testid":"codex-task-search-input"}),d?L("button",{type:"button",className:"ghost-btn",onClick:()=>a(""),"data-testid":"codex-task-search-clear"},"清除"):null),L("small",{"data-testid":"codex-task-search-summary"},Mu?yf?"搜索中...":`匹配 ${Fl.length}/${Number.isFinite(K1)?K1:Fl.length}`:"支持 task ID、prompt、状态、provider、模型和最近输出关键词")),ZO=L("div",{className:"codex-trace-status","data-testid":"codex-trace-status-summary"},L("span",{className:"codex-trace-status-chip queued"},L("b",null,"排队"),String(Zr)),L("span",{className:"codex-trace-status-chip running"},L("b",null,"运行"),String(Er)),L("span",{className:`codex-trace-status-chip unread ${G1>0?"warn":""}`},L("b",null,"结束未读"),String(G1)),L("span",{className:"codex-trace-status-chip service"},L("b",null,"服务"),`${U3.providerStatus||"unknown"} · ${$?.providerId||"main-server"} · ${Vr.public?"公网暴露":"仅 UniDesk frontend 代理访问"}`),L("span",{className:"codex-trace-status-chip"},L("b",null,"执行节点"),vJ.map((x)=>x.id).join(" / ")),L("span",{className:"codex-trace-status-chip"},L("b",null,"模型"),bJ.join(" / ")),L("span",{className:"codex-trace-status-chip"},L("b",null,"加载"),Tu?.phase==="complete"?_X(Tu?.totalMs):String(Tu?.phase||"idle")),L("span",{className:"codex-trace-status-chip"},L("b",null,"刷新"),T4?W0(T4):"--")),EO=L(B$,{title:D?`Trace ${String(D.id).slice(0,22)}`:"Trace 输出",eyebrow:D?`${D.status} / view=${iy} / task queue=${n2(D)} / provider=${D.providerId||"main-server"} / ${D.model} / agent loop trace`:`Agent loop trace / view=${iy}`,summary:ZO,loading:m||r3||yf||Wf||Tu?.phase==="loading",actions:L("div",{className:"panel-actions"},pJ("code-queue-filter-select"),L("button",{type:"button",className:"ghost-btn codex-mark-all-read-btn",disabled:G1===0||v0||$3,onClick:()=>void yO(),"data-testid":"codex-mark-all-read-button"},$3?"标记中":`全部标已读${G1>0?` (${G1})`:""}`),D?L("button",{type:"button",className:"ghost-btn",disabled:m||v0,onClick:()=>void zO(),"data-testid":"codex-load-full-trace-button"},m?"加载中":_l(D)?"刷新 Summary":"加载 Summary"):null,L("button",{type:"button",className:"codex-session-title-toggle",onClick:()=>x_((x)=>!x),"data-testid":"code-queue-sidebar-toggle"},R_?"收起队列":"展开队列"),L("label",{className:"inline-check"},L("input",{type:"checkbox",checked:W1,onChange:(x)=>pl(Boolean(x.target.checked))}),"自动滚动"),L("button",{type:"button",className:"ghost-btn",disabled:!sH||v0,onClick:()=>void UO(),"data-testid":"codex-interrupt-button"},"打断"),L("button",{type:"button",className:"ghost-btn",disabled:!oH||v0,onClick:()=>void QO()},"重试"),D?L(nG,{title:"Codex Task",data:D,onOpen:u,testId:"raw-codex-task"}):null),className:"codex-output-panel"},L("div",{className:`codex-session-shell ${R_?"":"queue-collapsed"}`},R_?L("aside",{className:"codex-session-sidebar","data-testid":"codex-session-sidebar"},L("div",{className:"codex-session-sidebar-head"},L("div",null,L("span",null,cu(Af)?"All queues":"Queue lane"),L("strong",null,`${iy} · ${Yl.length}/${Number.isFinite(b_)?b_:Yl.length} sessions · 未读 ${G1}`)),L("button",{type:"button",className:"ghost-btn",onClick:()=>x_(!1)},"收起")),pJ("code-queue-filter-sidebar",!0),NO,L("div",{className:"codex-task-list codex-task-list-session",onScroll:_O,"data-testid":"codex-task-list-scroll"},KO)):null,L("div",{className:"codex-session-main"},L("div",{className:"codex-output-stack"},L(FB,{task:D,loading:m,onLoadPromptPart:fO,onLoadSteps:uO,onLoadStep:lO}),L(JB,{task:D})))));if(!$)return L(zy,{title:"Code Queue 未登记",text:"请在 config.json 的 microservices 中登记用户服务 id=code-queue"});let mJ=Number(Tu?.totalMs),gJ=Number(Tu?.queueMs),kJ=Number(Tu?.detailMs),tJ=Number(Tu?.transcriptRows),HO=Tu?.phase==="complete"?"complete":String(Tu?.phase||"idle");return L("div",{className:`code-queue-page ${y?"codex-standalone-page":""}`,"data-testid":"code-queue-page","data-load-state":HO,"data-load-total-ms":Number.isFinite(mJ)?String(Math.round(mJ*10)/10):"","data-load-queue-ms":Number.isFinite(gJ)?String(Math.round(gJ*10)/10):"","data-load-detail-ms":Number.isFinite(kJ)?String(Math.round(kJ*10)/10):"","data-load-transcript-rows":Number.isFinite(tJ)?String(tJ):"","data-load-task-id":String(Tu?.taskId||v||""),"data-load-partial":Tu?.partial?"true":"false"},L(A0,{error:wf,wide:!0}),gf?L("div",{className:"form-success wide","data-testid":"codex-create-success"},gf):null,L("div",{className:"codex-session-stage codex-session-stage-top"},EO),L("div",{className:"code-queue-layout"},L("div",{className:"codex-left-rail"},L(B$,{title:"提交任务",eyebrow:nf?"Submitting...":Jl.length>1?`${Jl.length} tasks`:"Single or Batch",className:"codex-compose-panel",loading:nf},L("form",{className:`codex-task-form ${nf?"is-submitting":""}`,onSubmit:AO,"data-testid":"code-queue-task-form","aria-busy":nf?"true":"false"},L("label",null,"Prompt / 多任务用单独一行 --- 分隔",L("textarea",{value:Gf,rows:8,disabled:nf,onChange:(x)=>c(x.target.value),placeholder:"写入 Codex 任务;多个任务之间用 --- 分隔。"})),L("label",{className:"codex-reference-field"},"引用任务 ID(可选)",L("input",{value:o,disabled:nf,onChange:(x)=>e(x.target.value),placeholder:"codex_...;支持空格/逗号分隔多个 ID","data-testid":"codex-reference-task-id"}),Jy(o).length>0?L("code",null,`后端将解析并注入:${Jy(o).join(" / ")}`):null),L("div",{className:"codex-form-grid"},L("label",{className:"codex-submit-queue-field"},"Queue",L("div",{className:"codex-submit-queue-row"},L("select",{value:Kf,disabled:nf,onChange:(x)=>k(String(x.target.value||"default")),"data-testid":"code-queue-id-select"},z1.map((x)=>L("option",{key:String(x?.id||""),value:String(x?.id||"")},Vj(x)))),L("button",{type:"button",className:"ghost-btn codex-rename-queue-btn",onClick:()=>void jO(),disabled:v0||nf||!Kf,title:"修改当前 queue 的显示名称,ID 不变","data-testid":"codex-rename-queue-button"},"改名"),L("button",{type:"button",className:"ghost-btn codex-create-queue-btn",onClick:()=>void rO(),disabled:v0||nf,"data-testid":"codex-create-queue-button"},"创建 queue"))),L("label",null,"模型",L("select",{value:_0,disabled:nf,onChange:(x)=>y0(x.target.value),"data-testid":"codex-model-select"},bJ.map((x)=>L("option",{key:x,value:x},x)))),L("label",null,"执行 Provider",L("select",{value:Bf,disabled:nf,onChange:(x)=>eH(String(x.target.value||"main-server")),"data-testid":"codex-provider-select"},vJ.map((x)=>L("option",{key:x.id,value:x.id},`${x.label||x.id} · ${x.defaultWorkdir||w2(h0,x.id)}`)))),L("label",null,"工作目录",L("input",{value:N0,disabled:nf,onChange:(x)=>a0(x.target.value),placeholder:tH||h0?.defaultWorkdir||"/root/unidesk","data-testid":"codex-cwd-input"})),L("label",null,"最大尝试",L("input",{type:"number",min:1,max:99,value:pu,disabled:nf,onChange:(x)=>mu(Number(x.target.value)),"data-testid":"codex-max-attempts-input"})),L("label",null,"入队份数",L("input",{type:"number",min:1,max:50,value:C0,disabled:nf,onChange:(x)=>Q1(Number(x.target.value)),"data-testid":"codex-repeat-count-input"}))),W3>1?L("label",{className:`codex-batch-confirm ${ru?"confirmed":""}`,"data-testid":"codex-batch-confirm-row"},L("input",{type:"checkbox",checked:ru,disabled:nf,onChange:(x)=>Uf(Boolean(x.target.checked)),"data-testid":"codex-batch-confirm-checkbox"}),L("span",null,`确认批量入队 ${W3} 个任务(prompt 分段 ${Q3.length} × 入队份数 ${LG(C0)})`)):null,nf?L("div",{className:"codex-submit-wait","data-testid":"codex-submit-wait"},"正在提交到后端,已锁定输入以防重复提交..."):null,L("div",{className:"codex-form-actions"},L("button",{type:"button",className:"ghost-btn",disabled:v0||nf||Gf.length===0&&o.length===0,onClick:()=>{c(""),e(""),Uf(!1);let x="已清空任务输入栏";pf(x),Q0("success",x)},"data-testid":"codex-clear-input-button"},"清空输入"),L("button",{type:"submit",className:"primary-btn",disabled:kH,"data-testid":"codex-enqueue-button"},nf?"提交中,请等待...":xJ?`请确认批量入队 ${W3} 个任务`:Jl.length>1?`批量入队 ${Jl.length} 个任务`:"入队并运行"))))),L("div",{className:"codex-main-stage"},L("div",{className:"codex-detail-grid"},L(B$,{title:"运行控制",eyebrow:cy?"Queued prompt editable":qr?"Active turn steer":"Steer when running",loading:v0},L("div",{className:"codex-run-control-stack"},L(yB,{task:D,queueRows:z1,busy:v0,onMove:WO}),D?.id?L("form",{className:"codex-steer-form codex-edit-prompt-form",onSubmit:JO,"data-testid":"codex-edit-prompt-form"},L("label",null,"编辑 queued 用户 prompt",L("textarea",{value:e0,rows:5,onChange:(x)=>Zu(x.target.value),placeholder:"仅 QUEUED 且尚未开始运行的任务可在这里修改原始用户 prompt。",disabled:!cy||v0,"data-testid":"codex-edit-prompt-textarea"})),L("label",{className:"codex-reference-field"},"引用任务 ID(可选,留空会清除引用)",L("input",{value:i0,disabled:!cy||v0,onChange:(x)=>Du(x.target.value),placeholder:"codex_...;支持空格/逗号分隔多个 ID","data-testid":"codex-edit-reference-task-id"}),Jy(i0).length>0?L("code",null,`将保留/注入:${Jy(i0).join(" / ")}`):null),L("div",{className:"codex-form-actions"},L("button",{type:"button",className:"ghost-btn",disabled:!D?.id||v0,onClick:()=>{Zu(D?B2(D):""),Du(Array.isArray(D?.referenceTaskIds)?D.referenceTaskIds.join(" "):"")},"data-testid":"codex-edit-prompt-reset"},"恢复当前值"),L("button",{type:"submit",className:"primary-btn",disabled:!cy||v0||e0.trim().length===0,title:cy?"保存后会重写尚未运行任务的用户 prompt":"只有 QUEUED 且尚未开始的任务可编辑 prompt","data-testid":"codex-edit-prompt-submit"},"保存 queued prompt"))):null,L("form",{className:"codex-steer-form",onSubmit:FO},L("label",null,"追加 prompt",L("textarea",{value:Cf,rows:4,onChange:(x)=>d0(x.target.value),placeholder:"给正在运行的 Codex session 推入新的指令或纠偏。",disabled:!qr})),L("button",{type:"submit",className:"primary-btn",disabled:!qr||v0||Cf.trim().length===0,"data-testid":"codex-steer-button"},"推入运行中 session")))),L(B$,{title:"完成判定",eyebrow:D?.lastJudge?D.lastJudge.source:"judge",loading:m},D?.lastJudge?L("div",{className:"codex-judge-card","data-testid":"codex-task-judge-card"},L(Wy,{status:D.lastJudge.decision},D.lastJudge.decision),L("strong",null,`${Math.round(Number(D.lastJudge.confidence||0)*100)}% confidence`),L("p",{"data-testid":"codex-task-judge-reason"},Ej(D.lastJudge.reason||"--",180)),D.lastJudge.continuePrompt?L("code",{"data-testid":"codex-task-judge-continue-prompt"},Ej(D.lastJudge.continuePrompt,160)):null):L(zy,{title:"尚未判定",text:"Codex turn 结束后会由 MiniMax M2.7 或 fallback judge 判定 complete/retry/fail;retry 会在已有 thread 追加继续执行 prompt。"}))),L(_B,{stats:Nr,queueName:iy,onRaw:u}),L(B$,{title:"Attempts",eyebrow:"terminal vs interruption",loading:m},L(UB,{task:D})))))}var w6=cf(O0(),1);var Tf=w6.default.createElement,{useEffect:Sj}=w6.default,Cj=w6.default.useState,QB=w6.default.useRef,cj=` +本次任务:`,r=f.indexOf(l);if(r===-1)return u;return f.slice(r+l.length).trimStart()}function Ay(u){return u.length>0?u.split(/\r\n|\r|\n/u).length:0}function mq(u){let f=String(u?.displayPrompt||"");if(f.length>0)return f;let l=String(u?.prompt||"");return ST(tT(l).userPrompt)}function yr(u){return u?._traceSummary&&typeof u._traceSummary==="object"&&!Array.isArray(u._traceSummary)?u._traceSummary:null}function t6(u){return u?._promptDetails&&typeof u._promptDetails==="object"&&!Array.isArray(u._promptDetails)?u._promptDetails:{}}function XA(u){let f=yr(u)?.prompt;return f&&typeof f==="object"&&!Array.isArray(f)?f:{}}function pq(u){let f=yr(u)?.execution;return f&&typeof f==="object"&&!Array.isArray(f)?f:{}}function Hn(u){let f=Number(u);return Number.isFinite(f)&&f>=0?Math.floor(f):0}function PT(u){let f=yr(u);if(f!==null)return MT(f);let l=Number(u?.stepCount??u?.llmStepCount??0);return Number.isFinite(l)&&l>=0?Math.floor(l):0}function MT(u){let f=Tl(u?.execution)||{},l=Number(u?.stepCount??u?.llmStepCount??f.stepCount??f.llmStepCount??f.toolCallCount??0);return Hn(l)}function B6(u){if(!u||u?._traceSummaryLoaded!==!0)return!1;let f=yr(u),l=String(u?._traceSummaryUpdatedAt||f?.updatedAt||""),r=String(u?.updatedAt||"");if(r.length>0){let y=H0(l),i=H0(r);if(y!==null&&i!==null){if(y+10?l:mq(u)}function Cq(u){let f=yr(u);return String(f?.finalResponse||u?.finalResponse||"").trimEnd()}function xq(u){let l=yr(u)?.lastJudge||u?.lastJudge;return l&&typeof l==="object"&&!Array.isArray(l)?l:null}function Tl(u){return u&&typeof u==="object"&&!Array.isArray(u)?u:null}function mT(u){let f=yr(u)?.attempts;if(Array.isArray(f)&&f.length>0)return f;let l=pq(u),r=Cq(u),y=xq(u);if(Object.keys(l).length===0&&r.length===0&&y===null)return[];return[{index:Number(u?.currentAttempt||1),mode:u?.currentMode||"initial",startedAt:u?.startedAt,finishedAt:u?.finishedAt,terminalStatus:u?.status,execution:l,finalResponse:r,finalResponseChars:r.length,judge:y}]}function pT(u,f){return Tl(f?.execution)||pq(u)}function CT(u,f,l,r){let y=yr(u),i=Number(y?.currentAttempt||u?.currentAttempt||0),_=Number(l),n=Number.isFinite(_)&&_>0&&_===i,$=Sq(u?.updatedAt,y?.updatedAt);if(n&&!f?.finishedAt&&$.length>0)return $;return String(f?.updatedAt||f?.finishedAt||r.effectiveEndAt||(n?$:"")||$||u?.finishedAt||u?.startedAt||"")}function xT(u,f){let l=String(f?.finalResponse||f?.finalResponsePreview||"");if(Object.prototype.hasOwnProperty.call(f||{},"finalResponse")||Object.prototype.hasOwnProperty.call(f||{},"finalResponsePreview"))return l.trimEnd();return l.length>0?l.trimEnd():Cq(u)}function Rq(u,f){if(Object.prototype.hasOwnProperty.call(f||{},"judge"))return Tl(f?.judge);return xq(u)}function RT(u,f,l){if(!yZ(u))return!1;if(YA(f,l))return!1;if(f?.finishedAt)return!1;if(["succeeded","failed","canceled"].includes(String(f?.terminalStatus||"")))return!1;let r=yr(u),y=Number(r?.currentAttempt||u?.currentAttempt||0),i=Number(l);if(Number.isFinite(i)&&i>0&&Number.isFinite(y)&&y>0)return i===y;return!0}function hq(u){return`feedback:${String(u||"latest")}`}function hT(u,f,l){let r=String(f?.feedbackPrompt||"").trimEnd(),y=String(f?.feedbackPromptPreview||r||"").trimEnd(),i=Number(f?.feedbackPromptChars||r.length||y.length||0),_=Number(f?.feedbackPromptLines||Ay(r||y));if(r.length>0||y.length>0||i>0)return{text:r,preview:y,chars:i,lines:_,source:f?.feedbackPromptSource||"judge-feedback",forAttempt:f?.feedbackPromptForAttempt||Number(l||0)+1,truncated:Boolean(f?.feedbackPromptTruncated)};let n=Rq(u,f),$=String(n?.continuePrompt||"").trimEnd();if(n?.decision==="retry"&&$.length>0)return{text:"",preview:$,chars:$.length,lines:Ay($),source:"judge-continue-prompt",forAttempt:Number(l||0)+1,truncated:!1};return null}function bT(u){let f=XA(u);return Boolean(f.hasReferenceInjection||Number(f.referencePromptChars||0)>0||u?.referenceInjection||u?.referenceInjectionSummary)}function bq(u,f=null){if(f!==null&&f!==void 0){let r=(Tl(u?._traceStepsByAttempt)||{})[String(f)];return Array.isArray(r)?r:[]}return Array.isArray(u?._traceSteps)?u._traceSteps:[]}function EA(u){let l=[u?.seq,...Array.isArray(u?.rawSeqs)?u.rawSeqs:[]].map((r)=>Number(r)).filter((r)=>Number.isFinite(r));return l.length>0?Math.max(...l):0}function vT(u){return(Array.isArray(u)?u:[]).reduce((f,l)=>Math.max(f,EA(l)),0)}function IT(u,f){let l=new Map;for(let r of[...Array.isArray(u)?u:[],...Array.isArray(f)?f:[]]){let y=String(r?.seq??`${r?.title||"step"}:${r?.at||""}`);l.set(y,{...l.get(y)||{},...r})}return Array.from(l.values()).sort((r,y)=>EA(r)-EA(y))}function Hi(u){return(Array.isArray(u?.summaryLines)?u.summaryLines:[]).map((f)=>String(f||""))}function vq(u){let f=String(u?.kind||"").trim().toLowerCase(),l=String(u?.status||"").trim().toLowerCase();return f==="error"||l==="error"}function kT(u){return(Array.isArray(u)?u:[]).reduce((f,l)=>f+(vq(l)?1:0),0)}function S6(u){let f=String(u?.status||"").trim();if(f.length>0)return f;let l=Hi(u).join(` +`);return/^(item\/[A-Za-z]+(?:\/[A-Za-z]+)?):/u.exec(l)?.[1]||""}function Tq(u){return/^item\/(?:started|completed): file changes status=/u.test(String(u||"").trim())}function gT(u){let f=Hi(u);for(let r=f.length-1;r>=0;r-=1){let y=/file changes status=([A-Za-z0-9_-]+)/u.exec(f[r]||"")?.[1];if(y)return y}let l=S6(u);if(l==="item/fileChange/outputDelta")return"updated";if(l==="item/started")return"started";if(l==="item/completed")return"completed";return l.replace(/^item\//u,"")||String(u?.status||"changed")}function sT(u){if(String(u?.kind||"")!=="edited")return!1;let f=String(u?.title||""),l=String(u?.status||""),r=Hi(u).join(` +`);if(f==="Edited files")return!0;if(/^item\/fileChange\//u.test(l))return!0;if((l==="item/started"||l==="item/completed")&&/file changes status=/u.test(r))return!0;if(/^Success\. Updated the following files:/mu.test(r))return!0;if(/^diff --git /mu.test(r))return!0;return/^([AMDRCU?]{1,2})\s+\S+/mu.test(r)}function aT(u){if(u.length<=1)return u[0];let f=u.find((i)=>S6(i)==="item/fileChange/outputDelta")||u.find((i)=>Hi(i).some((_)=>!Tq(_)))||u.at(-1)||u[0],l=u.flatMap((i)=>Array.isArray(i?.rawSeqs)?i.rawSeqs:[i?.seq]).filter((i)=>i!==void 0),r=u.flatMap(Hi).filter((i)=>i.trim().length>0&&!Tq(i)),y=u[u.length-1]||f;return{...f,at:f?.at||y?.at,title:String(f?.title||"Edited files"),status:gT(y),summaryLines:r.length>0?r:Hi(f),rawSeqs:l}}function oT(u){let f=Array.isArray(u)?u:[],l=[],r=[],y=()=>{if(r.length>0)l.push(aT(r));r=[]};for(let i of f){if(sT(i)){if(S6(i)==="item/started"&&r.length>0)y();if(r.push(i),S6(i)==="item/completed")y();continue}y(),l.push(i)}return y(),l}function dT(u){let f=Hn(u?.stepCount??u?.llmStepCount??u?.toolCallCount);return{...u,stepCount:f,llmStepCount:f}}function TA(u,f=null){if(f!==null&&f!==void 0){let l=Tl(u?._traceStepsLoadedByAttempt)||{};return Boolean(l[String(f)])}return Boolean(u?._traceStepsLoaded)}function ZA(u){return u?._traceStepDetails&&typeof u._traceStepDetails==="object"&&!Array.isArray(u._traceStepDetails)?u._traceStepDetails:{}}function eT(u,f){let l=Number(u?.index);return Number.isFinite(l)?l:f+1}function YA(u,f){return Boolean(u?.synthetic)||Number(f)<=0}function P6(u){let f=Number(u);return Number.isFinite(f)?String(f):void 0}function uZ(u){let f=u?.timing&&typeof u.timing==="object"?u.timing:{},l=String(u?.status||"");if(["queued"].includes(l))return`等待 ${Mr(f.queueWaitMs??f.totalElapsedMs)}`;if(["running","judging","retry_wait"].includes(l))return`耗时 ${Mr(f.durationMs??f.totalElapsedMs)}`;return`耗时 ${Mr(f.durationMs??f.totalElapsedMs)}`}function Tn(u){return String(u?.queueId||"default")}function Iq(u){return Tl(u?.queuedReason)}function kq(u){let f=String(u?.queuedReasonLabel||"").trim();if(f.length>0)return f.toUpperCase();let l=Iq(u),r=String(l?.label||"").trim();return r.length>0?r.toUpperCase():""}function fZ(u){let f=String(u?.status||"unknown");if(f!=="queued")return f;let l=kq(u);return l.length>0?`QUEUED(${l})`:"QUEUED"}function lZ(u){if(String(u?.status||"")!=="queued")return;let f=Iq(u),l=String(f?.message||"").trim(),r=kq(u);if(l.length>0&&r.length>0)return`${r}: ${l}`;if(l.length>0)return l;return r.length>0?r:void 0}function rZ(u){return{system:"SYS",user:"YOU",assistant:"GPT",reasoning:"THINK",command:"CMD",diff:"DIFF",tool:"TOOL",error:"ERR"}[u]||u.toUpperCase()}function Zq(u){return["running","judging","retry_wait"].includes(String(u?.status||""))}function yZ(u){return String(u?.status||"")==="running"}function Pr(u){return["succeeded","failed","canceled"].includes(String(u?.status||""))}function gq(u){if(u?.promptEditable===!0)return!0;if(u?.promptEditable===!1)return!1;return String(u?.status||"")==="queued"&&!u?.startedAt&&Number(u?.currentAttempt||0)===0&&!u?.codexThreadId&&!u?.nextMode}function Z0(u){if(!Pr(u))return!1;if(u?.terminalUnread===!0)return!0;if(u?.terminalUnread===!1)return!1;return!u?.readAt}function Mf(u){let f=Number(u||0);return Number.isFinite(f)?f:0}function iZ(u){return Mf(u.queued)+Mf(u.retry_wait)}function _Z(u){return Mf(u.running)+Mf(u.judging)}function nZ(u,f){return Tl(u?.statistics)||Tl(f?.statistics)||{}}function $Z(u){return Array.isArray(u?.daily)?u.daily:[]}function AZ(u){return Tl(u?.totals)||{}}function DA(u,f){let l=Number(u?.[f]??0);return Number.isFinite(l)&&l>0?l:0}function WA(u,f){return u.reduce((l,r)=>Math.max(l,DA(r,f)),0)}var $y=700,Hq=220,q1=30,Zi=24,Zn=184,HA=Zn-Zi;function sq(u,f){if(f<=1)return $y/2;return q1+u*($y-q1*2)/(f-1)}function aq(u,f){let l=f>0?f:1;return Zn-Math.min(1,u/l)*HA}function cA(u,f,l){let r=u.length>0?u:[{[f]:0}],y=r.length>1?r:[r[0],r[0]];return y.map((i,_)=>`${sq(_,y.length).toFixed(2)},${aq(DA(i,f),l).toFixed(2)}`).join(" ")}function T0(u){let f=String(u||"");return/^\d{4}-\d{2}-\d{2}$/u.test(f)?f.slice(5):f||"--"}function V6(u){if(!u)return"";return`${String(u.seriesKey||"")}:${String(u.row?.date||u.index||"")}`}function jZ(u,f,l,r){let y=DA(u,r.key);return{...r,row:u,index:f,value:y,valueLabel:r.format(y),x:sq(f,l),y:aq(y,r.max),seriesKey:r.key}}function Oq(u){if(Z0(u))return 0;return{running:1,judging:2,retry_wait:3,queued:4,succeeded:8,failed:8,canceled:8}[String(u?.status||"")]??9}function Ln(u){if(!u)return!1;if(u?._traceSummaryLoaded===!0)return!1;return u?.summaryOnly===!0||u?._metaLoaded!==!0}function FZ(u){return Boolean(u?._metaLoaded)||u?.summaryOnly===!1}function JZ(u,f,l){let r=String(u?.[l]||""),y=String(f?.[l]||"");return r.length>y.length?r:y}function OA(u,f,l){let r=Array.isArray(u?.[l])?u[l]:[],y=Array.isArray(f?.[l])?f[l]:[];if(y.length===0&&r.length>0)return r;return r.length>y.length?r:y}function Bq(u,f){let l=f?.summaryOnly===!0&&FZ(u),r={...u,...f};if(!l)return r;for(let y of["prompt","basePrompt","displayPrompt","finalResponse"])r[y]=JZ(u,f,y);for(let y of["promptHistory","attempts","output","events"])r[y]=OA(u,f,y);if(u?.referenceInjection?.items&&!f?.referenceInjection?.items)r.referenceInjection=u.referenceInjection;if(u?.referenceInjectionSummary&&!f?.referenceInjectionSummary)r.referenceInjectionSummary=u.referenceInjectionSummary;r.summaryOnly=u?.summaryOnly===!1?!1:f.summaryOnly,r._metaLoaded=u?._metaLoaded,r._detailLoaded=u?._detailLoaded,r._transcriptComplete=u?._transcriptComplete,r._transcriptPreview=Object.prototype.hasOwnProperty.call(f,"_transcriptPreview")?f._transcriptPreview:u?._transcriptPreview;for(let y of["_traceSummary","_traceSummaryLoaded","_traceSteps","_traceStepsLoaded","_traceStepsByAttempt","_traceStepsLoadedByAttempt","_traceStepsNextAfterSeqByAttempt","_traceStepDetails","_promptDetails"])if(!Object.prototype.hasOwnProperty.call(f,y)&&Object.prototype.hasOwnProperty.call(u||{},y))r[y]=u[y];return r}function UZ(u){let f=u?.selected,l=f?.task&&typeof f.task==="object"?f.task:null;if(l!==null){let y=Boolean(f?.preview);return{...l,transcript:Array.isArray(f?.transcript)?f.transcript:[],_detailLoaded:Array.isArray(f?.transcript)&&f.transcript.length>0,_transcriptComplete:Boolean(!y&&!f?.hasMore&&Pr(l)),_transcriptPreview:y,_summaryLoaded:!0}}let r=nl(u)[0];return r?{...r,_summaryLoaded:!0}:null}function NA(u,f){let l=new Map;for(let r of[...Array.isArray(u)?u:[],...Array.isArray(f)?f:[]]){let y=`${Number(r?.seq??0)}:${String(r?.kind||"message")}`,i=l.get(y);if(!i){l.set(y,r);continue}let _={...i,...r};for(let[n,$]of[["bodyPreview","bodyOmittedLines"],["commandPreview","commandOmittedLines"]]){let j=String(i?.[n]||""),F=String(r?.[n]||"");if(j.length>F.length)_[n]=i[n],_[$]=i[$]}l.set(y,_)}return Array.from(l.values()).sort((r,y)=>Number(r?.seq??0)-Number(y?.seq??0))}function X6(u){return(Array.isArray(u)?u:[]).reduce((f,l)=>Math.max(f,Number(l?.seq??0)),0)}function Vq(u,f=8){let l=Array.from(new Set((Array.isArray(u)?u:[]).map((y)=>Number(y?.seq??0)).filter((y)=>Number.isFinite(y)&&y>0))).sort((y,i)=>y-i);if(l.length===0)return 0;let r=l[Math.max(0,l.length-f)]??0;return Math.max(0,r-0.001)}function QZ(u,f){let l=Array.isArray(u?.codeModels)?u.codeModels:Array.isArray(u?.codexModels)?u.codexModels:[],r=["gpt-5.5","gpt-5.4-mini","gpt-5.4","minimax-m2.7"];return Array.from(new Set([...l,...r,f].map((y)=>String(y||"").trim()).filter(Boolean)))}function qZ(u,f){let r=(Array.isArray(u?.executionProviders)?u.executionProviders:[]).map((_)=>({id:String(_?.id||"").trim(),label:String(_?.label||_?.id||"").trim(),defaultWorkdir:String(_?.defaultWorkdir||"").trim(),kind:String(_?.kind||"").trim()})).filter((_)=>_.id.length>0),y=String(u?.mainProviderId||u?.defaultProviderId||"main-server").trim()||"main-server",i=new Map;for(let _ of[...r,{id:y,label:`${y} (master)`,defaultWorkdir:String(u?.defaultWorkdir||"/root/unidesk"),kind:"local"},f?{id:f,label:f,defaultWorkdir:D6(u,f),kind:""}:null].filter(Boolean))if(!i.has(_.id))i.set(_.id,_);return Array.from(i.values())}function D6(u,f){let l=String(f||"").trim(),r=u?.defaultWorkdirByProvider&&typeof u.defaultWorkdirByProvider==="object"?u.defaultWorkdirByProvider:{};if(typeof r[l]==="string"&&String(r[l]).trim().length>0)return String(r[l]).trim();let y=Array.isArray(u?.executionProviders)?u.executionProviders.find((_)=>String(_?.id||"")===l):null;if(typeof y?.defaultWorkdir==="string"&&y.defaultWorkdir.trim().length>0)return y.defaultWorkdir.trim();let i=String(u?.mainProviderId||u?.defaultProviderId||"main-server");return l===i?String(u?.defaultWorkdir||"/root/unidesk"):String(u?.remoteDefaultWorkdir||"/home/ubuntu")}function WZ(u){return PT(u)}function cZ({task:u,selected:f,onSelect:l,onCopy:r,onReference:y,onMarkRead:i,copied:_,markingRead:n}){let $=u?.lastJudge||{},j=String(u?.id||""),F=Z0(u),J=Sq(u?.updatedAt,yr(u)?.updatedAt),U=`最近更新: ${tq(J)}`,q=WZ(u);return E("article",{role:"button",tabIndex:0,className:`codex-task-card ${f?"selected":""} ${F?"unread-terminal":""}`,onClick:l,onKeyDown:(W)=>{if(W.key==="Enter"||W.key===" ")W.preventDefault(),l()},"data-unread-terminal":F?"true":"false","data-testid":`codex-task-${u?.id||"unknown"}`},F?E("span",{className:"codex-unread-badge",title:"待读","aria-label":"待读","data-testid":`codex-unread-task-${j||"unknown"}`}):null,E("div",{className:"codex-task-card-head"},E("div",{className:"codex-task-status-line"},E(jy,{status:u?.status,title:lZ(u)},fZ(u))),E("span",{className:"mono-text"},`${u?.currentAttempt||0}/${u?.maxAttempts||0}`)),E("div",{className:"codex-task-id-row"},E("code",{title:j},j||"unknown"),E("div",{className:"codex-task-id-actions"},E("button",{type:"button",className:"codex-copy-id-btn",onClick:(W)=>{W.stopPropagation(),y(j)},"data-testid":`codex-reference-task-${j||"unknown"}`},"引用"),E("button",{type:"button",className:"codex-copy-id-btn",onClick:(W)=>{W.stopPropagation(),r(j)},"data-testid":`codex-copy-task-id-${j||"unknown"}`},_?"已复制":"复制ID"),F?E("button",{type:"button",className:"codex-copy-id-btn codex-mark-read-btn",disabled:Boolean(n),onClick:(W)=>{W.stopPropagation(),i(j)},"data-testid":`codex-mark-task-read-${j||"unknown"}`},n?"标记中":"标为已读"):null)),E("strong",null,GA(mq(u),120)||"空任务"),E("div",{className:"codex-task-meta"},E("span",null,`queue=${Tn(u)}`),E("span",null,`provider=${u?.providerId||"main-server"}`),E("span",null,u?.model||"--"),E("span",null,uZ(u))),E("div",{className:"codex-task-meta codex-task-update-meta"},E("span",{className:"codex-task-recent-update codex-task-step-count",title:"STEP 按 read/edit/run 工具动作统计","data-testid":`codex-task-step-count-${j||"unknown"}`},`STEP ${q}`),E("span",{className:"codex-task-recent-update",title:J?`更新时间: ${Nu(J)}`:U,"data-testid":`codex-task-recent-update-${j||"unknown"}`},U),E("span",null,Nu(J||u?.updatedAt))),gq(u)?E("div",{className:"codex-judge-line","data-testid":`codex-task-prompt-editable-${j||"unknown"}`},"queued prompt 可编辑"):null,$?.decision?E("div",{className:"codex-judge-line"},`judge=${$.decision} ${Math.round(Number($.confidence||0)*100)}%`):null)}function zA({title:u,tasks:f,selectedId:l,onSelect:r,onCopy:y,onReference:i,onMarkRead:_,copiedTaskId:n,markingReadTaskId:$,emptyText:j}){let F=Array.isArray(f)?f:[];return E("section",{className:"codex-task-section"},E("div",{className:"codex-task-section-head"},E("span",null,u),E("code",null,String(F.length))),F.length===0?E("p",{className:"codex-task-section-empty"},j):E("div",{className:"codex-task-section-list"},F.map((J)=>E(cZ,{key:J.id,task:J,selected:l===J.id,onSelect:()=>r(J.id),onCopy:y,onReference:i,onMarkRead:_,copied:n===J.id,markingRead:$===J.id}))))}function NZ(){return E("span",{className:"codex-stats-icon","aria-hidden":"true"},E("svg",{viewBox:"0 0 36 24",focusable:"false"},E("path",{className:"grid",d:"M3 20.5H33M3 12.5H33M3 4.5H33"}),E("polyline",{className:"line tasks",points:"3,18 9,14 15,15 21,8 27,10 33,4"}),E("polyline",{className:"line retry",points:"3,20 9,17 15,18 21,13 27,14 33,9"})))}function zZ({stats:u,queueName:f,onRaw:l}){let r=$Z(u),y=AZ(u),i=r.at(-1)||{},_=WA(r,"executedTasks"),n=WA(r,"retryAttempts"),$=WA(r,"avgDurationMs"),j=r.length>0,F=Tl(u?.range)||{},[J,U]=su(null),[q,W]=su(null),G=[];if(_>0)G.push(`tasks ${_}`);if(n>0)G.push(`retry ${n}`);if($>0)G.push(`avg ${Mr($)}`);let K=[{key:"executedTasks",className:"tasks",label:"执行任务",max:_,format:(T)=>`${Mf(T)} tasks`},{key:"retryAttempts",className:"retry",label:"重试次数",max:n,format:(T)=>`${Mf(T)} retries`},{key:"avgDurationMs",className:"duration",label:"平均耗时",max:$,format:(T)=>Mr(T)}],Q=J||q,N=V6(Q),c=String(Q?.row?.date||""),z=Q?{left:`${Math.max(8,Math.min(92,Number(Q.x)/$y*100))}%`,top:`${Math.max(14,Math.min(86,Number(Q.y)/Hq*100))}%`}:void 0;Q1(()=>{U(null),W(null)},[f,F.startDate,F.endDate,r.length]);let w=(T)=>{U(T)},H=(T)=>{let X=V6(T);W((R)=>V6(R)===X?null:T),U(T)},B=K.flatMap((T)=>r.map((X,R)=>{let Y=jZ(X,R,r.length,T),P=V6(Y),t=N===P,O=String(X?.date||`day-${R}`),M=`${T0(O)} ${T.label}: ${Y.valueLabel}`;return E("g",{key:`${T.key}-${O}`,className:`stat-point-group ${T.className} ${t?"active":""}`,role:"button",tabIndex:0,"aria-label":M,"data-testid":`codex-stats-point-${T.className}-${O}`,onMouseEnter:()=>w(Y),onFocus:()=>w(Y),onClick:()=>H(Y),onKeyDown:(S)=>{if(S.key==="Enter"||S.key===" ")S.preventDefault(),H(Y)}},E("circle",{className:"stat-hit-point",cx:Y.x,cy:Y.y,r:13}),E("circle",{className:`stat-point ${T.className} ${t?"active":""}`,cx:Y.x,cy:Y.y,r:t?5.6:4.2}))}));return E(Ti,{title:"统计曲线",eyebrow:`Daily task stats / ${f}`,className:"codex-stats-panel",summary:E("span",null,`${T0(F.startDate)} -> ${T0(F.endDate)} · ${u?.timezone||"Asia/Shanghai"}`),actions:Tl(u)?E(Pq,{title:"Code Queue Stats",data:u,onOpen:l,testId:"raw-codex-stats"}):null},E("div",{className:"codex-stats-hero","data-testid":"codex-stats-panel"},E(NZ),E("div",null,E("strong",null,`${Mf(y.executedTasks)} tasks / ${Mf(y.retryAttempts)} retries`),E("span",null,`平均完成耗时 ${Mr(y.avgDurationMs??void 0)} · 终态 ${Mf(y.completedTasks)} 个`))),j?E("div",{className:"codex-stats-chart","data-testid":"codex-stats-chart",onMouseLeave:()=>U(null)},E("svg",{viewBox:`0 0 ${$y} ${Hq}`,preserveAspectRatio:"none",role:"img","aria-label":"Code Queue daily task statistics"},E("line",{className:"axis",x1:q1,x2:$y-q1,y1:Zn,y2:Zn}),E("line",{className:"grid",x1:q1,x2:$y-q1,y1:Zi+HA/2,y2:Zi+HA/2}),E("line",{className:"grid",x1:q1,x2:$y-q1,y1:Zi,y2:Zi}),E("polyline",{className:"stat-line tasks",points:cA(r,"executedTasks",_)}),E("polyline",{className:"stat-line retry",points:cA(r,"retryAttempts",n)}),E("polyline",{className:"stat-line duration",points:cA(r,"avgDurationMs",$)}),Q?E("g",{className:"stat-cursor-layer","data-testid":"codex-stats-active-point"},E("line",{className:"stat-cursor",x1:Q.x,x2:Q.x,y1:Zi,y2:Zn}),E("circle",{className:`stat-point-active ${Q.className}`,cx:Q.x,cy:Q.y,r:8})):null,E("g",{className:"stat-point-layer"},B)),Q?E("div",{className:"codex-stats-tooltip active",style:z,"data-testid":"codex-stats-tooltip"},E("b",null,T0(Q.row?.date)),E("span",null,`${Q.label} · ${Q.valueLabel}`),E("code",null,`${Mf(Q.row?.executedTasks)} exec / ${Mf(Q.row?.retryAttempts)} retry / ${Mr(Q.row?.avgDurationMs??void 0)}`)):null,E("div",{className:"codex-stats-legend"},E("span",{className:"tasks"},"执行任务"),E("span",{className:"retry"},"重试次数"),E("span",{className:"duration"},"平均耗时")),E("div",{className:"codex-stats-scale"},E("span",null,T0(r[0]?.date)),E("span",null,G.join(" · ")||"暂无峰值"),E("span",null,T0(r.at(-1)?.date))),E("div",{className:`codex-stats-focus ${Q?"active":""}`,"data-testid":"codex-stats-focus"},Q?E(On.default.Fragment,null,E("div",null,E("strong",null,T0(Q.row?.date)),E("span",null,`${Q.label} · ${Q.valueLabel}`)),E("div",{className:"codex-stats-focus-metrics"},E("code",null,`${Mf(Q.row?.executedTasks)} exec`),E("code",null,`${Mf(Q.row?.retryAttempts)} retry`),E("code",null,Mr(Q.row?.avgDurationMs??void 0)))):E("span",null,"将鼠标悬停到曲线数据点查看明细,点击数据点可固定。"))):E(Fy,{title:"暂无统计",text:"任务开始执行后会生成按天汇总的曲线。"}),E("div",{className:"codex-stats-summary-grid"},E("article",null,E("span",null,"今日执行"),E("strong",null,String(Mf(i.executedTasks))),E("code",null,T0(i.date))),E("article",null,E("span",null,"今日重试"),E("strong",null,String(Mf(i.retryAttempts))),E("code",null,`累计 ${Mf(y.retryAttempts)}`)),E("article",null,E("span",null,"平均耗时"),E("strong",null,Mr(y.avgDurationMs??void 0)),E("code",null,`${Mf(y.durationSamples)} samples`))),E("div",{className:"codex-stats-daily-list","data-testid":"codex-stats-daily-list"},r.slice(-7).map((T)=>E("div",{key:String(T?.date||""),className:`codex-stats-daily-row ${c===String(T?.date||"")?"active":""}`,"data-testid":`codex-stats-day-${String(T?.date||"unknown")}`},E("span",null,T0(T?.date)),E("b",null,`${Mf(T?.executedTasks)} exec`),E("b",null,`${Mf(T?.retryAttempts)} retry`),E("code",null,Mr(T?.avgDurationMs??void 0))))))}function GZ({task:u,queueRows:f,busy:l,onMove:r}){let y=String(u?.id||""),i=Tn(u),[_,n]=su(i);Q1(()=>{n(i)},[y,i]);let $=!y||l||["running","judging","retry_wait"].includes(String(u?.status||""));return E("div",{className:"codex-task-move-control","data-testid":"codex-task-queue-move-control"},E("label",null,"任务 queue",E("select",{value:_,disabled:!y||l,onChange:(j)=>n(String(j.target.value||i)),"data-testid":"codex-task-queue-move-select"},f.map((j)=>E("option",{key:String(j?.id||""),value:String(j?.id||"")},wA(j))))),E("button",{type:"button",className:"ghost-btn",disabled:$||_===i,onClick:()=>r(_),title:$?"运行中 / judging / retry_wait 的任务不能移动;请先打断或等当前 turn 结束":"移动已创建任务到另一个 queue","data-testid":"codex-task-queue-move-button"},"移动"))}function Xq(u,f=4){let l=(Array.isArray(u)?u:[]).map((y)=>String(y||"").trim()).filter(Boolean);if(l.length===0)return"--";let r=l.slice(0,f).join(" / ");return l.length>f?`${r} +${l.length-f}`:r}function KZ({task:u,loading:f,onLoadPromptPart:l,testId:r="codex-initial-prompt-full",textTestId:y="codex-initial-prompt-full-text",baseTextTestId:i="codex-initial-prompt-base"}){let _=XA(u),n=t6(u),$=Y6(u).trimEnd(),j=String(n.full?.text||""),F=bT(u),J=Number(_.promptChars||u?.promptChars||j.length),U=Number(_.basePromptLines||Ay($)),q=Number(_.promptLines||Ay(j));return E("section",{className:"codex-progressive-card codex-progressive-prompt","data-testid":"codex-progressive-prompt"},E("div",{className:"codex-progressive-card-head"},E("span",{className:"codex-output-channel"},"Prompt"),E("strong",null,"Submitted prompt / 原始用户 prompt"),E("code",null,`${U||Ay($)} lines / ${$.length} chars`)),E("pre",{className:"codex-prompt-full","data-testid":i},$||"空 prompt"),F?E("details",{className:"codex-reference-injection codex-progressive-full-prompt","data-testid":r,onToggle:(W)=>{if(W.currentTarget?.open&&!j)l?.("full")}},E("summary",null,E("span",null,"引用注入已折叠,点击按需拉取最终进入 Code agent 的完整 prompt"),E("code",null,j?`${q||Ay(j)} lines / ${j.length} chars`:`${Number.isFinite(J)&&J>0?J:"--"} chars`)),E("pre",{className:"codex-prompt-full codex-prompt-final-full","data-testid":y},j||(f?"正在按需拉取完整 prompt...":"展开后将只请求 full prompt,不拉取完整 transcript。"))):null)}function oq({task:u,attempt:f,attemptIndex:l,loading:r,onLoadSteps:y,onLoadStep:i,testId:_="codex-execution-summary"}){let n=oT(bq(u,l)),$=dT(pT(u,f)),j=yr(u),F=ZA(u),J=TA(u,l),U=Number(f?.errorCount??j?.errorCount??kT(n)),q=Hn($.toolCallCount),W=Hn($.stepCount??$.llmStepCount??$.toolCallCount),G=Array.isArray($.editedFiles)?$.editedFiles:[],K=Array.isArray($.commands)?$.commands:[],N=YA(f,l)?` · ${String(f?.label||"recovered thread execution")}`:l?` #${l}`:"",c=CT(u,f,l,$),z=`最近更新: ${tq(c)}`,w=RT(u,f,l);return E("details",{className:`codex-progressive-card codex-execution-summary ${w?"running":""}`,"data-testid":_,"data-attempt-index":P6(l),"data-running":w?"true":"false",onToggle:(H)=>{if(H.currentTarget?.open&&!J)y?.(l)}},E("summary",null,E("div",{className:"codex-progressive-card-head"},E("span",{className:"codex-output-channel"},"Summary"),E("strong",null,`执行过程摘要${N}`),w?E("span",{className:"codex-summary-running-pill","data-testid":`${_}-running`},"执行中"):null,E("code",{title:c?`最近更新: ${Nu(c)}`:z},`${Mr($.durationMs??$.totalElapsedMs)} / ${q} tools / ${z}`)),E("div",{className:"codex-execution-digest"},E("span",null,`read ${Number($.readCount||0)}`),E("span",null,`edit ${Number($.editCount||0)}`),E("span",null,`run ${Number($.runCount||0)}`),E("span",null,`STEP ${W}`),U>0?E("span",{className:"codex-execution-error-pill","data-testid":`${_}-error-count`},`Error ${U}`):null)),E("div",{className:"codex-execution-digest expanded"},E("span",null,`修改文件:${Xq(G,6)}`),E("span",null,`执行命令:${Xq(K,4)}`)),n.length===0?E("div",{className:"codex-output-empty"},r?"正在按需拉取步骤 summary...":"展开后将只请求执行步骤 summary,不拉取单步骤全量。"):E("div",{className:"codex-trace-step-list"},n.map((H)=>{let B=String(H?.seq??""),T=F[B],X=Array.isArray(H?.summaryLines)?H.summaryLines.slice(0,4):[];return E("details",{key:B||`${H?.title}-${H?.at}`,className:`codex-trace-step ${String(H?.kind||"message")} ${vq(H)?"error":""}`,"data-testid":`codex-trace-step-${B||"unknown"}`,onToggle:(R)=>{if(R.currentTarget?.open&&!T)i?.(H?.seq)}},E("summary",null,E("span",{className:"codex-output-channel"},LZ(H?.kind)),E("strong",null,String(H?.title||"Trace step")),H?.status?E("code",null,String(H.status)):null,E("time",null,Nu(H?.at))),E("div",{className:"codex-trace-step-summary"},X.length>0?X.map((R,Y)=>E("pre",{key:`${B}-${Y}`},String(R||""))):E("span",null,"无 summary")),T?.line?E(H6,{items:[T.line],autoScroll:!1,loading:!1,hasDetail:!0,emptyText:"无步骤详情",testId:`codex-trace-step-detail-${B||"unknown"}`,className:"codex-transcript codex-step-detail-transcript",collapseTools:!1}):E("div",{className:"codex-output-empty"},r?"正在按需拉取这个步骤的全量数据...":"展开后将只请求这个单步骤的全量数据。"))})))}function LZ(u){let f=String(u||"");if(f==="ran")return"Ran";if(f==="explored")return"Explored";if(f==="edited")return"Edited";if(f==="error")return"Error";if(f==="system")return"System";return"Message"}function dq({task:u,attempt:f,attemptIndex:l,testId:r="codex-final-response"}){let y=xT(u,f);if(y.length===0)return null;let i=Number(f?.finalResponseChars||y.length),_=l?` #${l}`:"";return E("section",{className:"codex-progressive-card codex-final-response","data-testid":r,"data-attempt-index":P6(l)},E("div",{className:"codex-progressive-card-head"},E("span",{className:"codex-output-channel"},"Final"),E("strong",null,`最终 response${_}`),E("code",null,`${Number.isFinite(i)?i:y.length} chars`)),E(IQ,{markdown:y,className:"codex-transcript-body codex-markdown",testId:`${r}-markdown`}))}function eq({task:u,attempt:f,attemptIndex:l,testId:r="codex-progressive-judge"}){let y=Rq(u,f);if(!y?.decision)return null;let i=l?` #${l}`:"";return E("section",{className:"codex-progressive-card codex-progressive-judge","data-testid":r,"data-attempt-index":P6(l)},E("div",{className:"codex-progressive-card-head"},E("span",{className:"codex-output-channel"},"Judge"),E("strong",null,`完成判定${i}`),E("code",null,`${y.decision} ${Math.round(Number(y.confidence||0)*100)}%`)),E("div",{className:"codex-judge-card","data-testid":`${r}-card`},E(jy,{status:y.decision},y.decision),E("strong",null,`${Math.round(Number(y.confidence||0)*100)}% confidence`),E("p",{"data-testid":`${r}-reason`},y.reason||"--"),y.continuePrompt?E("pre",{"data-testid":`${r}-continue-prompt`},String(y.continuePrompt||"")):null))}function wZ({task:u,attempt:f,attemptIndex:l,loading:r,onLoadPromptPart:y,testId:i="codex-judge-feedback-prompt"}){let _=hT(u,f,l);if(_===null)return null;let n=hq(l),j=t6(u)[n],F=String(j?.text||"").trimEnd(),J=String(_.preview||_.text||"").trimEnd(),U=F||String(_.text||"").trimEnd(),q=Number(j?.chars||_.chars||U.length||J.length),W=Number(j?.lines||_.lines||Ay(U||J)),G=j?.forAttempt||_.forAttempt||Number(l||0)+1;return E("details",{className:"codex-progressive-card codex-judge-feedback-prompt","data-testid":i,"data-attempt-index":P6(l),onToggle:(K)=>{if(K.currentTarget?.open&&!F)y?.("feedback",l)}},E("summary",null,E("div",{className:"codex-progressive-card-head"},E("span",{className:"codex-output-channel"},"Prompt"),E("strong",null,`judge feedback prompt #${l} -> #${G}`),E("code",null,`${W||"--"} lines / ${Number.isFinite(q)?q:J.length} chars`)),E("p",{className:"codex-feedback-preview","data-testid":`${i}-preview`},J||"展开后按需拉取 judge feedback prompt。")),E("pre",{className:"codex-prompt-full codex-feedback-full","data-testid":`${i}-text`},U||(r?"正在按需拉取 judge feedback prompt...":"展开后将只请求这一次 judge feedback prompt。")))}function EZ({task:u,attempt:f,position:l,loading:r,onLoadPromptPart:y,onLoadSteps:i,onLoadStep:_}){let n=eT(f,l),$=l===0,j=YA(f,n),F=j?String(f?.label||"Recovered thread execution"):`Attempt ${n}`;return E("section",{className:"codex-attempt-cycle","data-testid":`codex-attempt-cycle-${n}`},E("div",{className:"codex-attempt-cycle-head"},E("span",{className:"codex-output-channel"},F),E("strong",null,String(f?.mode||(n<=1?"initial":"retry"))),f?.terminalStatus?E(jy,{status:f.terminalStatus},f.terminalStatus):null,E("code",null,`${Nu(f?.startedAt)} -> ${Nu(f?.finishedAt)}`)),E(oq,{task:u,attempt:f,attemptIndex:n,loading:r,onLoadSteps:i,onLoadStep:_,testId:$?"codex-execution-summary":`codex-execution-summary-attempt-${n}`}),j?null:E(dq,{task:u,attempt:f,attemptIndex:n,testId:$?"codex-final-response":`codex-final-response-attempt-${n}`}),j?null:E(eq,{task:u,attempt:f,attemptIndex:n,testId:$?"codex-progressive-judge":`codex-progressive-judge-attempt-${n}`}),j?null:E(wZ,{task:u,attempt:f,attemptIndex:n,loading:r,onLoadPromptPart:y,testId:$?"codex-judge-feedback-prompt":`codex-judge-feedback-prompt-attempt-${n}`}))}function TZ({task:u,loading:f,onLoadPromptPart:l,onLoadSteps:r,onLoadStep:y}){if(!u)return E(Fy,{title:"未选择任务",text:"从左侧队列选择任务,或提交新 Codex 任务。"});let i=mT(u);return E("div",{className:"codex-transcript codex-progressive-trace","data-testid":"codex-output"},f&&!yr(u)?E("div",{className:"codex-output-empty"},"正在加载 Trace Summary..."):null,E(KZ,{task:u,loading:f,onLoadPromptPart:l}),i.length>0?i.map((_,n)=>E(EZ,{key:`${_?.index||n+1}-${_?.startedAt||n}`,task:u,attempt:_,position:n,loading:f,onLoadPromptPart:l,onLoadSteps:r,onLoadStep:y})):[E(oq,{key:"execution",task:u,loading:f,onLoadSteps:r,onLoadStep:y}),E(dq,{key:"final",task:u}),E(eq,{key:"judge",task:u})])}function ZZ({task:u}){let f=VT(u);if(!u||f.length===0)return E(Fy,{title:"暂无原始消息",text:"原始 Codex app-server 消息会保留在任务 JSON 中。"});return E("details",{className:"codex-raw-output"},E("summary",null,`原始 messages (${f.length})`),E("div",null,f.map((l)=>E("article",{key:`${l.seq}-${l.channel}`,className:`codex-output-line ${l.channel||"system"}`},E("div",{className:"codex-output-meta"},E("span",{className:"codex-output-channel"},rZ(String(l.channel||"system"))),E("span",null,Nu(l.at)),l.method?E("code",null,l.method):null),E("pre",null,String(l.text||""))))))}function HZ({task:u}){let f=XT(u).slice().reverse();if(f.length===0)return E(Fy,{title:"尚无 attempt",text:"任务开始运行后,这里会记录 Codex 终态、传输中断和 stderr tail。"});return E("div",{className:"table-wrap codex-attempt-table"},E("table",null,E("thead",null,E("tr",null,E("th",null,"#"),E("th",null,"模式"),E("th",null,"终态"),E("th",null,"传输"),E("th",null,"退出"),E("th",null,"完成时间"))),E("tbody",null,f.map((l)=>E("tr",{key:`${l.index}-${l.startedAt}`},E("td",null,l.index),E("td",null,l.mode),E("td",null,E(jy,{status:l.terminalStatus||"unknown"},l.terminalStatus||"unknown")),E("td",null,l.transportClosedBeforeTerminal?E(jy,{status:"failed"},"closed-before-terminal"):E(jy,{status:"succeeded"},"normal")),E("td",null,`code=${l.appServerExitCode??"--"} signal=${l.appServerSignal??"--"}`),E("td",null,Nu(l.finishedAt)))))))}function uW({microservices:u,onRaw:f,apiBaseUrl:l="/api",initialTasksData:r=null,standalone:y=!1}){let i=u.find((V)=>V.id==="code-queue")||null,_=UZ(r),n=String(_?.id||""),$=new Map;if(_!==null&&n.length>0)$.set(n,{task:_,maxSeq:X6(Array.isArray(_.transcript)?_.transcript:[]),complete:Boolean(_._transcriptComplete),completeUpdatedAt:_._transcriptComplete?String(_.updatedAt||""):""});let j=typeof performance>"u"?0:performance.now(),F=Xf(n),J=Xf(0),U=Xf(0),q=Xf(0),W=Xf(!1),G=Xf(!1),K=Xf(!1),Q=Xf(null),N=Xf(new Map),c=Xf(new Map),z=Xf(new Map),w=Xf(new Map),H=Xf(new Set),B=Xf(null),T=Xf(null),X=Xf(!1),R=Xf(!1),Y=Xf(Boolean(r)),P=Xf(new Map),t=Xf(new Set),O=Xf($),M=Xf(r),[S,b]=su(null),[Z,D]=su(r),[I,k]=su(n),[h,o]=su(_),[s,x]=su(!1),[uu,nu]=su(""),[$u,Fu]=su(null),[Ku,Wu]=su(!1),[m,d]=su(!1),[e,cu]=su(""),[g,Qu]=su(""),[Eu,Tu]=su("default"),[Du,ff]=su(W1),[rf,Lf]=su("main-server"),[gf,jr]=su("gpt-5.5"),[Ol,ef]=su("/root/unidesk"),[hr,vl]=su(99),[ju,bu]=su(1),[ul,tu]=su(!1),[ou,Al]=su(!1),[Bl,sf]=su(""),[Il,Fr]=su(""),[kl,M0]=su(""),[r_,y_]=su(!0),[fu,Zu]=su(()=>typeof window>"u"?!0:window.matchMedia(cT).matches),[Lu,ku]=su(!1),[Uf,vu]=su(""),[yf,_f]=su(""),{addNotification:xf}=wl(),[i_,B$]=su(""),[__,V$]=su(""),[n_,X$]=su(!1),[Vl,br]=su(r?{phase:"complete",taskId:n,queueMs:0,detailMs:0,totalMs:j,chunks:_?1:0,transcriptRows:Array.isArray(_?.transcript)?_.transcript.length:0,partial:Boolean(r?.selected?.hasMore||Ln(_)),completedAt:new Date}:null),[$_,A_]=su(r?new Date:null),[Vy,Y$]=su(!1),vr=Sy(nl(Z)),D$=vr.filter(Z0),Rf=Z?.queue||S?.body?.queue||S?.queue||{},z8=nZ(Z,Rf),t$=U1(Z),Jr=Kq(Rf,Eu),Xy=En(Jr,Du),p1=Number((ml(Du)?Rf?.total:Xy?.total)??t$.total??vr.length),j_=wn(Rf),Mj=ml(Du)?j_:[String(En(Jr,Du)?.activeTaskId||"")].filter(Boolean),Yy=Lq(Rf,Jr,Du,vr),mj=ml(Du)?qA(Rf):qA(Xy||{}),S$=qA(Rf),P$=iZ(S$),G8=Math.max(_Z(S$),j_.length),K8=Mf((ml(Du)?Rf?.unreadTerminal:Xy?.unreadTerminal)??D$.length),m0=Z?D$.length:K8,Dy=ml(Du)?"All queues":LA(Xy||{id:Du,name:Du}),C1=KA(uu),Xl=C1.length>0,M$=Xl?Sy(nl($u)):[],F_=U1($u),gl=Xl?M$:vr,m$=gl.filter(Z0),p$=gl.filter((V)=>!Pr(V)).sort(QT),L8=gl.filter((V)=>Pr(V)&&!Z0(V)),C$=Xl?F_:t$,Ir=Xl?Number(F_.total??M$.length):p1,x$=C$.hasMore===!0&&String(C$.nextBeforeId||"").length>0,J_=Xl?m:Vy,R$=i?JT(i):{},sG=i?UT(i):{},w8=Nq(()=>YT(e),[e]),F0=Nq(()=>{let V=Eq(ju);return w8.flatMap((v)=>Array.from({length:V},()=>DT(v,g)))},[w8,ju,g]),U_=F0.length,pj=U_>1&&!ul,aG=ou||Lu||U_===0||pj,Cj=QZ(Rf,gf),xj=qZ(Rf,rf),oG=D6(Rf,rf),E8=h?.id&&h?.activeTurnId&&String(h?.status)==="running",dG=h?.id&&!["succeeded","failed","canceled"].includes(String(h?.status||"")),eG=h?.id&&["succeeded","failed","canceled"].includes(String(h?.status||"")),ty=h?.id&&gq(h);function Ur(V){let v=typeof V==="function"?V(M.current):V;return M.current=v,D(v),v}function uK(V,v,lu=!0){let yu=Array.from(new Set(V.map((qu)=>String(qu||"")).filter(Boolean)));for(let qu of yu)if(P.current.set(qu,v),lu)t.current.add(qu);return yu}function Rj(V){for(let v of V.map((lu)=>String(lu||"")).filter(Boolean))P.current.delete(v),t.current.delete(v)}function h$(V){let v=String(V?.id||""),lu=v?P.current.get(v):void 0;if(!lu)return V;if(String(V?.status||"").length>0&&!Pr(V))return P.current.delete(v),t.current.delete(v),V;return{...V,readAt:V?.readAt||lu,terminalUnread:!1}}function T8(V){let v=String(V?.id||"");return v.length>0&&t.current.has(v)&&Pr(V)}function Sy(V,v=!0){let lu=[];for(let yu of Array.isArray(V)?V:[]){let qu=h$(yu);if(v&&T8(qu))continue;lu.push(qu)}return lu}function fK(V,v=!0){if(!V||!Array.isArray(V?.tasks))return V;let lu=Sy(nl(V),v),yu=U1(V);return{...V,tasks:lu,pagination:V.pagination?{...yu,returned:lu.length}:V.pagination}}function lK(V){let v=String(V||Rf?.mainProviderId||"main-server").trim()||"main-server";Lf(v),ef(D6(Rf,v))}function b$(V,v,lu=null,yu=null){let qu=new Set(uK(V,v));if(qu.size===0&&yu===null&&lu===null)return;Ur((Gu)=>{if(!Gu)return Gu;let Ou=nl(Gu).flatMap((Cu)=>{let xu=String(Cu?.id||"");if(!qu.has(xu)){let Qf=h$(Cu);return T8(Qf)?[]:[Qf]}let Ru=yu&&String(yu?.id||"")===xu?yu:{},mu={...Cu,...Ru,readAt:v,terminalUnread:!1};return T8(mu)?[]:[mu]});return{...Gu,queue:lu||Gu.queue,tasks:qu.size>0?Ei([Ou],Yy):Ou}});for(let Gu of qu){let Ou=O.current.get(Gu);if(Ou?.task){let Cu=yu&&String(yu?.id||"")===Gu?yu:{},xu={...Ou.task,...Cu,readAt:v,terminalUnread:!1};if(O.current.set(Gu,{...Ou,task:xu}),F.current===Gu)o(xu)}}}Q1(()=>{tu(!1)},[e,ju,g]),Q1(()=>{let V=KA(uu);U.current+=1;let v=U.current;if(!i||V.length===0){Fu(null),Wu(!1),d(!1),K.current=!1;return}Wu(!0),Fu(null);let lu=window.setTimeout(()=>{(async()=>{try{let yu=await LT(l,Du,V);if(v!==U.current)return;Fu(fK(yu))}catch(yu){if(v===U.current)Fu(null),vu(_l(yu,"搜索 Codex tasks 失败"))}finally{if(v===U.current)Wu(!1)}})()},240);return()=>window.clearTimeout(lu)},[i?.id,l,Du,uu]),Q1(()=>{Fr(h?Y6(h):""),M0(Array.isArray(h?.referenceTaskIds)?h.referenceTaskIds.join(" "):"")},[I]);function J0(V,v,lu){let yu=O.current.get(V)||{},qu=yu.task||{},Gu=Array.isArray(qu.transcript)?qu.transcript:[],Ou=Bq(qu,v),Cu=Object.prototype.hasOwnProperty.call(v,"transcript")?NA(Gu,Array.isArray(v.transcript)?v.transcript:[]):Gu,xu={...qu,...Ou,transcript:Cu,output:Array.isArray(Ou.output)?OA(qu,Ou,"output"):Array.isArray(qu.output)?qu.output:[],events:Array.isArray(Ou.events)?OA(qu,Ou,"events"):Array.isArray(qu.events)?qu.events:[]},Ru=h$(xu),mu=String(Ru?.updatedAt||""),Qf=Boolean(v._transcriptComplete)&&Pr(Ru),fl=Boolean(yu.complete)&&Pr(Ru)&&String(yu.completeUpdatedAt||"")===mu,du=Qf||fl,af={...yu,task:Ru,maxSeq:X6(Cu),complete:du,completeUpdatedAt:du?mu:""};if(O.current.set(V,af),lu===q.current&&F.current===V)o(Ru);return af}async function Py(V,v=!1,lu,yu){if(!i||!V)return;let Gu=O.current.get(V)?.task;if(!v&&B6(Gu))return;let Ou=V,Cu=N.current.get(Ou);if(Cu){if(v||!B6(Gu))Cu.refreshAfter=!0;return Cu.promise}let xu=q.current,Ru=performance.now();if(F.current===V)x(!0);let mu={promise:Promise.resolve(),refreshAfter:!1},Qf=(async()=>{try{let fl=await ET(l,V);if(xu!==q.current||F.current!==V)return;let du=fl?.summary||{},af=String(du.updatedAt||"");J0(V,{id:V,status:du.status,updatedAt:af,startedAt:du.startedAt,finishedAt:du.finishedAt,currentAttempt:du.currentAttempt,maxAttempts:du.maxAttempts,finalResponse:du.finalResponse,lastJudge:du.lastJudge,lastError:du.lastError,attempts:Array.isArray(du.attempts)?du.attempts:[],stepCount:du.stepCount,llmStepCount:du.llmStepCount,timing:du.timing,_traceSummary:du,_traceSummaryLoaded:!0,_traceSummaryUpdatedAt:af,_detailLoaded:!0},xu),br({phase:"complete",taskId:V,queueMs:yu??0,detailMs:performance.now()-Ru,totalMs:lu===void 0?performance.now()-Ru:performance.now()-lu,chunks:1,transcriptRows:Number(du?.execution?.traceLineCount||du?.execution?.stepCount||0),partial:!1,completedAt:new Date})}finally{let fl=Boolean(mu.refreshAfter&&F.current===V&&!B6(O.current.get(V)?.task));if(N.current.delete(Ou),xu===q.current&&F.current===V)x(!1);if(fl)window.setTimeout(()=>{Py(V,!0).catch((du)=>vu(_l(du,"自动刷新 Trace Summary 失败")))},0)}})();mu.promise=Qf,N.current.set(Ou,mu),await Qf}async function rK(V,v=null){let lu=F.current;if(!i||!lu||!V)return;let yu=O.current.get(lu)?.task,qu=t6(yu),Gu=V==="feedback"||V==="judge-feedback"?hq(v):V;if(qu[Gu]?.text)return;let Ou=`${lu}:${Gu}`,Cu=c.current.get(Ou);if(Cu)return Cu;let xu=q.current;if(F.current===lu)x(!0);let Ru=(async()=>{try{let mu=await TT(l,lu,V,v);if(xu!==q.current||F.current!==lu)return;let Qf=O.current.get(lu)?.task,fl=t6(Qf);J0(lu,{...V==="full"?{prompt:String(mu?.text||""),promptChars:Number(mu?.chars||0)}:{},_promptDetails:{...fl,[Gu]:mu}},xu)}finally{if(c.current.delete(Ou),xu===q.current&&F.current===lu)x(!1)}})();c.current.set(Ou,Ru),await Ru}async function Z8(V=null,v={}){let lu=F.current;if(!i||!lu)return;let yu=O.current.get(lu)?.task,qu=V===null||V===void 0||String(V).length===0?"":String(V),Gu=TA(yu,qu||null),Ou=Boolean(v.force),Cu=Boolean(v.incremental);if(Gu&&!Ou)return;let xu=bq(yu,qu||null),Ru=Cu&&xu.length>0?vT(xu):0,mu=`${lu}:${qu||"all"}:${Ru}`,Qf=z.current.get(mu);if(Qf)return Qf;let fl=q.current;if(F.current===lu)x(!0);let du=(async()=>{try{let af=await ZT(l,lu,Ru,500,qu||null);if(fl!==q.current||F.current!==lu)return;let p0=Array.isArray(af?.steps)?af.steps:[],C0=Ru>0?IT(xu,p0):p0;if(qu){let x0=O.current.get(lu)?.task,My=Tl(x0?._traceStepsByAttempt)||{},ll=Tl(x0?._traceStepsLoadedByAttempt)||{},U0=Tl(x0?._traceStepsNextAfterSeqByAttempt)||{};J0(lu,{_traceStepsByAttempt:{...My,[qu]:C0},_traceStepsLoadedByAttempt:{...ll,[qu]:!0},_traceStepsNextAfterSeqByAttempt:{...U0,[qu]:af?.nextAfterSeq}},fl)}else J0(lu,{_traceSteps:C0,_traceStepsLoaded:!0,_traceStepsHasMore:Boolean(af?.hasMore),_traceStepsNextAfterSeq:af?.nextAfterSeq},fl)}finally{if(z.current.delete(mu),fl===q.current&&F.current===lu)x(!1)}})();z.current.set(mu,du),await du}async function yK(V){let v=F.current,lu=String(V??"");if(!i||!v||lu.length===0)return;let yu=O.current.get(v)?.task;if(ZA(yu)[lu]?.line)return;let Gu=`${v}:${lu}`,Ou=w.current.get(Gu);if(Ou)return Ou;let Cu=q.current;if(F.current===v)x(!0);let xu=(async()=>{try{let Ru=await HT(l,v,V);if(Cu!==q.current||F.current!==v)return;let mu=O.current.get(v)?.task,Qf=ZA(mu);J0(v,{_traceStepDetails:{...Qf,[lu]:Ru}},Cu)}finally{if(w.current.delete(Gu),Cu===q.current&&F.current===v)x(!1)}})();w.current.set(Gu,xu),await xu}function iK(V){if(F.current!==V)return;let v=O.current.get(V)?.task;if(!v)return;if(TA(v,null))Z8(null,{force:!0,incremental:!0}).catch((yu)=>vu(_l(yu,"增量刷新 Trace Steps 失败")));let lu=Tl(v?._traceStepsLoadedByAttempt)||{};for(let yu of Object.keys(lu).filter((qu)=>lu[qu]))Z8(yu,{force:!0,incremental:!0}).catch((qu)=>vu(_l(qu,"增量刷新 Attempt Trace Steps 失败")))}async function xS(V,v,lu){if(!i||!V)return;let yu=performance.now(),qu=q.current,Gu=O.current.get(V);if(Gu?.task){if(o(Gu.task),x(Ln(Gu.task)||!Gu.complete),!Ln(Gu.task)&&Gu.complete&&Pr(Gu.task)&&String(Gu.completeUpdatedAt||"")===String(Gu.task?.updatedAt||"")){br({phase:"complete",taskId:V,queueMs:lu??0,detailMs:0,totalMs:v===void 0?0:performance.now()-v,chunks:0,transcriptRows:Array.isArray(Gu.task.transcript)?Gu.task.transcript.length:0,completedAt:new Date});return}}else x(!0);let Ou=Q.current;if(Ou?.taskId===V&&Ou.token===qu)return Ou.promise;let Cu=(async()=>{try{let xu=await mf(Sf(l,`/api/tasks/${encodeURIComponent(V)}?meta=1`));if(qu!==q.current||F.current!==V)return;let Ru=O.current.get(V),mu=Array.isArray(Ru?.task?.transcript)?Ru.task.transcript:[],Qf=xu?.task||{},fl=Boolean(Ru?.complete)&&String(Ru?.completeUpdatedAt||"")===String(Qf?.updatedAt||"");J0(V,{...Qf,summaryOnly:!1,_metaLoaded:!0,transcript:mu,_detailLoaded:mu.length>0,_transcriptComplete:fl},qu);let du=Ln(Ru?.task)||Boolean(Ru?.task?._transcriptPreview),af=du?0:mu.length>0?Vq(mu):0,p0=!du&&Ru?.complete&&Pr(Qf)&&String(Ru?.completeUpdatedAt||"")===String(Qf?.updatedAt||"")?X6(mu):af,C0=!0,x0=0,My=mu.length;while(C0){let ll=await mf(Sf(l,`/api/tasks/${encodeURIComponent(V)}/transcript?afterSeq=${encodeURIComponent(String(p0))}&limit=${AT}&fullText=1`));if(qu!==q.current||F.current!==V)return;let U0=O.current.get(V),v$=Array.isArray(U0?.task?.transcript)?U0.task.transcript:[],hf=NA(v$,Array.isArray(ll?.transcript)?ll.transcript:[]);x0+=1,My=hf.length;let I$=Boolean(!ll?.hasMore);if(J0(V,{status:ll?.status||Qf.status,updatedAt:ll?.updatedAt||Qf.updatedAt,transcript:hf,_detailLoaded:I$||hf.length>0,_transcriptComplete:I$,_transcriptPreview:du&&!I$},qu),C0=Boolean(ll?.hasMore),p0=Number(ll?.nextAfterSeq??X6(hf)),!C0)break;await new Promise((my)=>window.setTimeout(my,0))}br({phase:"complete",taskId:V,queueMs:lu??0,detailMs:performance.now()-yu,totalMs:v===void 0?performance.now()-yu:performance.now()-v,chunks:x0,transcriptRows:My,completedAt:new Date})}finally{if(Q.current?.taskId===V&&Q.current?.token===qu)Q.current=null;if(qu===q.current&&F.current===V)x(!1)}})();Q.current={taskId:V,token:qu,promise:Cu},await Cu}async function Yl(V=F.current,v=!0,lu=Du){if(!i)return;if(!v&&R.current)return;let yu=performance.now();if(v)R.current=!0;if(v)br({phase:"loading",taskId:String(V||F.current||""),startedAt:new Date});let qu=J.current+1;J.current=qu;let Gu=String(V||F.current||""),Ou=Gu?O.current.get(Gu):null,Cu=Array.isArray(Ou?.task?.transcript)?Ou.task.transcript:[],xu=Vq(Cu),Ru=null;if(Ru=await wT(l,Gu,xu,lu),qu!==J.current){if(v)R.current=!1;return}let mu=performance.now()-yu;b(S||{});let Qf=Ru?.queue||{},fl=String(Qf?.activeTaskId||wn(Qf)[0]||""),du=Ru;Ur((al)=>{let Q_=nl(Ru),x1=nl(al),q_=x1.length>0?Ei([x1,Q_],fl):Ei([Q_],fl),k$=Sy(q_),BK=U1(Ru),g$=U1(al),VK=x1.length>Q_.length&&(g$.hasMore===!1||String(g$.nextBeforeId||"").length>0),XK={...BK,...VK?{hasMore:g$.hasMore,nextBeforeId:g$.nextBeforeId}:{},returned:k$.length};return du={...Ru,tasks:k$,pagination:XK},du});let af=nl(du),p0=Kq(Qf,Eu),C0=Lq(Qf,p0,lu,af),x0=KT(p0,lu,af),My=Gu||F.current,ll=du?.selected||null,U0=ll?.task||null,v$=Array.isArray(ll?.transcript)?ll.transcript:null,hf=My||C0||x0||af[0]?.id||"";if(F.current!==hf)q.current+=1;F.current=hf,k(hf);let my=af.find((al)=>al.id===hf);if(my){let al=O.current.get(hf);if(al?.task)O.current.set(hf,{...al,task:{...my,...al.task,status:my.status,updatedAt:my.updatedAt}})}if(U0?.id===hf&&v$!==null){let al=O.current.get(hf),Q_=Array.isArray(al?.task?.transcript)?al.task.transcript:[],x1=NA(Q_,v$),q_=Boolean(ll?.preview);if(J0(hf,{...U0,_summaryLoaded:!0,transcript:x1,_detailLoaded:!ll?.hasMore||x1.length>0,_transcriptComplete:!q_&&!ll?.hasMore&&Pr(U0),_transcriptPreview:q_},q.current),x(!1),v)br({phase:"complete",taskId:hf,queueMs:mu,detailMs:Math.max(0,performance.now()-yu-mu),totalMs:performance.now()-yu,chunks:1,transcriptRows:x1.length,partial:Boolean(q_||ll?.hasMore||Ln(U0)),completedAt:new Date});if(A_(new Date),v)R.current=!1;Py(hf,!1,v?yu:void 0,v?mu:void 0).catch((k$)=>vu(_l(k$,"加载 Codex Trace Summary 失败")));return}if(v)br({phase:"session",taskId:hf,queueMs:mu,totalMs:mu,startedAt:new Date(Date.now()-mu)});if(hf)Py(hf,!0,v?yu:void 0,v?mu:void 0).catch((al)=>vu(_l(al,"加载 Codex Trace Summary 失败")));else if(q.current+=1,o(null),x(!1),v)br({phase:"complete",taskId:"",queueMs:mu,detailMs:0,totalMs:performance.now()-yu,chunks:0,transcriptRows:0,completedAt:new Date});if(A_(new Date),v)R.current=!1}async function hj(){if(Xl){if(!i||m||K.current)return;let v=String(F_.nextBeforeId||"");if(!v)return;K.current=!0,d(!0),vu("");try{let lu=await wq(l,Du,v,Dq,C1),yu=nl(lu),qu=lu?.queue||Rf||{},Gu=String(qu?.activeTaskId||wn(qu)[0]||Yy||"");Fu((Ou)=>{let Cu=Sy(Ei([nl(Ou),yu],Gu)),xu=U1(lu);return{...Ou||{},queue:qu,tasks:Cu,pagination:{...xu,returned:Cu.length}}})}catch(lu){vu(_l(lu,"加载更多搜索结果失败"))}finally{K.current=!1,d(!1)}return}if(!i||Vy||G.current)return;let V=String(U1(Z).nextBeforeId||"");if(!V)return;G.current=!0,Y$(!0),vu("");try{let v=await wq(l,Du,V),lu=nl(v),yu=v?.queue||Rf||{},qu=String(yu?.activeTaskId||wn(yu)[0]||Yy||"");Ur((Gu)=>{let Ou=Sy(Ei([nl(Gu),lu],qu)),Cu=U1(v);return{...Gu||{},queue:yu,statistics:v?.statistics||Gu?.statistics,tasks:Ou,pagination:{...Cu,returned:Ou.length}}})}catch(v){vu(_l(v,"加载更早 Codex tasks 失败"))}finally{G.current=!1,Y$(!1)}}function _K(V){let v=V.currentTarget;if(!v||J_||!x$)return;if(v.scrollHeight-v.scrollTop-v.clientHeight<120)hj()}async function sl(V,v){ku(!0),vu("");try{await V()}catch(lu){vu(_l(lu,v))}finally{ku(!1)}}async function H8(V){if(!V)return;try{let v=!1;try{if(navigator.clipboard?.writeText)await navigator.clipboard.writeText(V),v=!0}catch{v=!1}if(!v){let yu=document.createElement("textarea");yu.value=V,yu.style.position="fixed",yu.style.opacity="0",document.body.appendChild(yu),yu.select(),v=document.execCommand("copy"),document.body.removeChild(yu)}if(!v)throw Error("browser clipboard rejected the copy request");B$(V);let lu=`已复制任务 ID:${V}`;_f(lu),xf("success",lu),window.setTimeout(()=>B$((yu)=>yu===V?"":yu),1600)}catch(v){vu(`复制任务 ID 失败:${_l(v)}`)}}function O8(V){if(!V)return;Qu(V);let v=`已引用任务 ID:${V};提交时后端会读取并注入该任务上下文`;_f(v),xf("success",v)}async function B8(V){if(!i||!V)return;let v=new Date().toISOString();J.current+=1,b$([V],v,null,{id:V,readAt:v,terminalUnread:!1}),V$(V);let lu=!1;if(await sl(async()=>{let yu=await OT(l,V),qu=yu?.task||{id:V,readAt:new Date().toISOString(),terminalUnread:!1},Gu=String(qu?.readAt||new Date().toISOString());b$([V],Gu,yu?.queue||null,qu),lu=!0;let Ou=`已将任务 ${V} 标为已读`;_f(Ou),xf("success",Ou)},"标记 Codex task 已读失败"),!lu)Rj([V]),Yl(F.current,!1).catch((yu)=>vu(_l(yu,"刷新 Codex tasks 失败")));V$((yu)=>yu===V?"":yu)}async function nK(){if(!i||n_)return;X$(!0);let V=new Date().toISOString(),v=Array.from(new Set([...nl(M.current).filter(Z0).map((yu)=>String(yu?.id||"")).filter(Boolean),...Array.from(O.current.entries()).filter(([,yu])=>Z0(yu?.task)).map(([yu])=>yu)]));if(J.current+=1,v.length>0)b$(v,V);let lu=!1;if(await sl(async()=>{let yu=await BT(l),qu=String(yu?.readAt||new Date().toISOString()),Gu=nl(M.current).filter(Z0).map((mu)=>String(mu?.id||"")).filter(Boolean),Ou=Array.from(O.current.entries()).filter(([,mu])=>Z0(mu?.task)).map(([mu])=>mu),Cu=Array.from(new Set([...v,...Gu,...Ou]));b$(Cu,qu,yu?.queue||null);let xu=Number(yu?.count||Cu.length);lu=!0;let Ru=`已将 ${xu} 个已结束未读任务标为已读`;_f(Ru),xf("success",Ru)},"全部标为已读失败"),!lu&&v.length>0)Rj(v),Yl(F.current,!1).catch((yu)=>vu(_l(yu,"刷新 Codex tasks 失败")));X$(!1)}function $K(V){let v=V||W1;if(ff(v),!ml(v))Tu(v);if(Ur(null),!(ml(v)?F.current:""))F.current="",q.current+=1,k(""),o(null),x(!0)}async function AK(){let V=typeof window>"u"?"":window.prompt("输入新的 Codex queue ID(字母/数字/._-,最长 64)","new-lane"),v=String(V||"").trim();if(!v)return;await sl(async()=>{let lu=await mf(Sf(l,"/api/queues"),{method:"POST",body:{queueId:v}}),yu=String(lu?.queue?.id||v);Tu(yu),ff(yu),Ur(null),F.current="",q.current+=1,k(""),o(null);let qu=`已创建并切换到 queue:${yu}`;_f(qu),xf("success",qu),await Yl("",!0,yu)},"创建 Codex queue 失败")}async function jK(){let V=String(Eu||"default").trim()||"default",v=En(Jr,V)||{id:V,name:V},lu=typeof window>"u"?null:window.prompt(`输入 queue 显示名称(ID 不变:${V};留空恢复为 ID)`,Mq(v));if(lu===null)return;await sl(async()=>{let yu=await mf(Sf(l,`/api/queues/${encodeURIComponent(V)}`),{method:"PATCH",body:{name:String(lu)}}),qu=yu?.queue||{id:V,name:String(lu||V)};if(yu?.summary)Ur((Ou)=>Ou?{...Ou,queue:yu.summary}:Ou);let Gu=`已更新 queue 名称:${LA(qu)}`;_f(Gu),xf("success",Gu),await Yl(F.current,!0,Du)},"修改 Codex queue 名称失败")}async function FK(){let V=String(Eu||"default").trim()||"default",v=Jr.filter((Gu)=>String(Gu?.id||"")!==V);if(v.length===0){_f("没有可合并的其他 queue;请先创建或选择另一个 queue。");return}let lu=typeof window>"u"?"":window.prompt(`将源 queue 合并到当前 queue=${V};源 queue 记录会保留且不会删除。请输入源 queue ID:`,String(v[0]?.id||"")),yu=String(lu||"").trim();if(!yu)return;if(yu===V){vu("源 queue 和目标 queue 不能相同。");return}if(!(typeof window>"u"?!0:window.confirm(`确认把 queue=${yu} 的全部任务合并到 queue=${V}?源 queue 不会删除;任务会按原 queueEnteredAt/createdAt 时间顺序进入目标 queue。`)))return;await sl(async()=>{let Gu=await mf(Sf(l,`/api/queues/${encodeURIComponent(V)}/merge`),{method:"POST",body:{sourceQueueId:yu}});if(Gu?.summary)Ur((xu)=>xu?{...xu,queue:Gu.summary}:xu);Tu(V),ff(V),Ur(null);let Ou=Number(Gu?.mergedTaskCount||0),Cu=`已将 queue=${yu} 合并到 ${V},移动 ${Ou} 个任务;源 queue 已保留。`;_f(Cu),xf("success",Cu),await Yl(F.current,!0,V)},"合并 Codex queue 失败")}async function JK(V){if(V.preventDefault(),W.current){_f("任务正在提交中,请等待当前请求完成,已阻止重复提交。");return}if(F0.length>1&&!ul){vu(`检测到将创建 ${F0.length} 个任务;请先勾选“确认批量入队”,避免误传多个任务。`);return}W.current=!0,Al(!0),_f("正在提交 Code Queue 任务,请等待后端确认,输入已临时锁定。"),await sl(async()=>{if(F0.length===0)throw Error("prompt 不能为空");let v=ny(g),lu=Eu.trim()||"default",yu=[...F0],qu=(mu)=>({prompt:mu,queueId:lu,providerId:rf,model:gf,cwd:Ol,maxAttempts:Number(hr),...v.length>0?{referenceTaskIds:v}:{}}),Gu=yu.length===1?qu(yu[0]):{tasks:yu.map(qu)},Ou=await mf(Sf(l,yu.length===1?"/api/tasks":"/api/tasks/batch"),{method:"POST",body:Gu}),Cu=Ou?.tasks?.[0]?.id||"",xu=Array.isArray(Ou?.tasks)?Ou.tasks.map((mu)=>String(mu?.id||"")).filter(Boolean):[],Ru=`已创建 ${xu.length||yu.length} 个任务${xu.length>0?`:${xu.join(" / ")}`:""}`;if(_f(Ru),xf("success",Ru),cu(""),Qu(""),tu(!1),F.current=Cu,Du!==lu)Ur(null);Tu(lu),await Yl(Cu,!0,lu)},"Codex 任务入队失败"),W.current=!1,Al(!1)}async function UK(V){if(V.preventDefault(),!h?.id)return;await sl(async()=>{await mf(Sf(l,`/api/tasks/${encodeURIComponent(h.id)}/steer`),{method:"POST",body:{prompt:Bl}}),sf(""),await Yl(h.id)},"追加 prompt 失败")}async function QK(V){V.preventDefault();let v=String(h?.id||"");if(!v||!ty)return;await sl(async()=>{let lu=ny(kl),yu=await mf(Sf(l,`/api/tasks/${encodeURIComponent(v)}/edit`),{method:"POST",body:{prompt:Il,referenceTaskIds:lu}}),qu={...yu?.task||h||{},_traceSummary:null,_traceSummaryLoaded:!1,_traceSummaryUpdatedAt:"",_promptDetails:{},_traceSteps:[],_traceStepsLoaded:!1,_traceStepsByAttempt:{},_traceStepsLoadedByAttempt:{},_traceStepsNextAfterSeqByAttempt:{},_traceStepDetails:{}};O.current.set(v,{...O.current.get(v)||{},task:qu,complete:!1,completeUpdatedAt:""}),F.current=v,o(qu),k(v),Fr(Y6(qu)),M0(Array.isArray(qu?.referenceTaskIds)?qu.referenceTaskIds.join(" "):""),Ur((Ou)=>{if(!Ou)return Ou;let Cu=nl(Ou).map((xu)=>String(xu?.id||"")===v?{...xu,...qu}:xu);return{...Ou,queue:yu?.queue||Ou.queue,tasks:Ei([Cu],Yy)}});let Gu=yu?.changed===!1?`任务 ${v} 的 prompt 未变化`:`已更新 queued 任务 ${v} 的用户 prompt`;_f(Gu),xf("success",Gu),await Yl(v,!0,Du)},"编辑 queued 任务 prompt 失败")}async function qK(){if(!h?.id)return;await sl(async()=>{await mf(Sf(l,`/api/tasks/${encodeURIComponent(h.id)}/interrupt`),{method:"POST",body:{}}),await Yl(h.id)},"打断 Codex session 失败")}async function WK(){if(!h?.id)return;await sl(async()=>{await mf(Sf(l,`/api/tasks/${encodeURIComponent(h.id)}/retry`),{method:"POST",body:{}}),await Yl(h.id)},"重新入队失败")}async function cK(V){let v=String(h?.id||""),lu=String(V||"").trim();if(!v||!lu)return;let yu=Tn(h);if(lu===yu){_f(`任务 ${v} 已在 queue=${lu}`);return}await sl(async()=>{let Gu=(await mf(Sf(l,`/api/tasks/${encodeURIComponent(v)}/move`),{method:"POST",body:{queueId:lu}}))?.task||{...h,queueId:lu};if(O.current.set(v,{...O.current.get(v)||{},task:Gu}),F.current=v,o(Gu),k(v),Tu(lu),!ml(Du))Ur(null),ff(lu);let Ou=`已将任务 ${v} 从 ${yu} 移动到 ${lu}`;_f(Ou),xf("success",Ou),await Yl(v,!0,ml(Du)?W1:lu)},"移动任务 queue 失败")}async function NK(){let V=F.current;if(!V)return;let v=performance.now();await sl(async()=>{br({phase:"session",taskId:V,queueMs:0,totalMs:0,partial:!0,startedAt:new Date}),await Py(V,!0,v,0)},"刷新 Trace Summary 失败")}function zK(V){F.current=V,q.current+=1,k(V);let v=O.current.get(V);if(v?.task)o(v.task),x(!1);else{x(!0);let lu=vr.find((yu)=>yu.id===V);if(lu)o(lu);else o(null)}Yl(V).catch((lu)=>vu(_l(lu,"切换 Codex session 失败")))}function V8(V){if(zK(V),NT())Zu(!1)}function bj(V,v,lu){if(!V||!Array.isArray(V?.tasks)||v.length===0||Object.keys(lu).length===0)return V;let yu=!1,qu=nl(V).map((Gu)=>{if(String(Gu?.id||"")!==v)return Gu;return yu=!0,h$(Bq(Gu,lu))});return yu?{...V,tasks:qu}:V}function GK(V,v){Ur((lu)=>bj(lu,V,v)),Fu((lu)=>bj(lu,V,v))}function KK(V,v,lu){let yu=String(V?.type||"");if(yu==="queue-updated")return!0;if(v.length===0)return!0;if(!lu)return yu!=="task-step";if(V?.queueId&&String(V.queueId)!==Tn(lu))return!0;if(V?.status&&String(V.status)!==String(lu?.status||""))return!0;return yu!=="task-step"&&String(V?.reason||"")!=="output"}function vj(){if(!i||!QA())return;if(B.current!==null)window.clearTimeout(B.current);B.current=window.setTimeout(()=>{B.current=null,Yl(F.current,!1).catch((V)=>vu(_l(V,"Code Queue 事件刷新失败")))},120)}function LK(V,v){if(!i||!QA()||F.current!==V)return;if(X.current=X.current||v,T.current!==null)return;T.current=window.setTimeout(()=>{T.current=null;let lu=X.current;if(X.current=!1,Py(V,!0).catch((yu)=>vu(_l(yu,"事件刷新 Trace Summary 失败"))),lu)iK(V)},250)}function wK(V){let v=String(V?.taskId||""),lu=Hn(V?.stepCount),yu={},qu=v.length>0?nl(M.current).find((Gu)=>String(Gu?.id||"")===v):null;if(v.length>0){if(V?.status)yu.status=String(V.status);if(V?.updatedAt)yu.updatedAt=String(V.updatedAt);if(V?.queueId)yu.queueId=String(V.queueId);if(Number.isFinite(Number(V?.stepCount)))yu.stepCount=lu,yu.llmStepCount=lu;if(Object.keys(yu).length>0&&(O.current.has(v)||F.current===v))J0(v,yu,q.current);if(Object.keys(yu).length>0)GK(v,yu);if(F.current===v&&(V?.type==="task-step"||V?.type==="task-updated"))LK(v,V?.type==="task-step")}if(KK(V,v,qu))vj()}Q1(()=>{if(Y.current){Y.current=!1;return}sl(()=>Yl(F.current),"Code Queue 加载失败")},[i?.id,Du]),Q1(()=>{if(!i||typeof EventSource>"u")return;let V=new EventSource(Sf(l,"/api/events"),{withCredentials:!0}),v=(yu)=>{try{wK(JSON.parse(String(yu.data||"{}")))}catch(qu){vu(_l(qu,"解析 Code Queue 事件失败"))}},lu=()=>{if(QA())vj()};return V.addEventListener("task-step",v),V.addEventListener("task-updated",v),V.addEventListener("queue-updated",v),document.addEventListener("visibilitychange",lu),()=>{if(V.close(),document.removeEventListener("visibilitychange",lu),B.current!==null)window.clearTimeout(B.current),B.current=null;if(T.current!==null)window.clearTimeout(T.current),T.current=null}},[i?.id,l,Du]),Q1(()=>{if(!i||!h||s)return;let V=String(h.id||"");if(!V)return;let v=String(h.updatedAt||"");if(B6(h))return;let lu=`${V}:${v||"unknown"}:${String(h?._traceSummaryUpdatedAt||"")}`;if(H.current.has(lu))return;H.current.add(lu),Py(V,!0).catch((yu)=>vu(_l(yu,"自动加载 Trace Summary 失败")))},[i?.id,h?.id,h?.updatedAt,h?.stepCount,h?.llmStepCount,h?._traceSummaryUpdatedAt,h?._traceSummaryLoaded,s]);let EK=gl.length===0?E(Fy,{title:Xl?Ku?"搜索中":"没有匹配任务":"队列为空",text:Xl?Ku?`正在搜索包含“${C1}”的 task...`:`未找到包含“${C1}”的 task;可换个关键词或切换 queue。`:"提交一个任务后,Codex 会串行执行并保存输出。"}):[m$.length>0?E(zA,{key:"unread",title:"已结束未读",tasks:m$,selectedId:I,emptyText:"暂无已结束未读任务。",onSelect:V8,onCopy:H8,onReference:O8,onMarkRead:B8,copiedTaskId:i_,markingReadTaskId:__}):null,E(zA,{key:"active",title:"运行 / 排队",tasks:p$,selectedId:I,emptyText:"当前没有运行或排队任务。",onSelect:V8,onCopy:H8,onReference:O8,onMarkRead:B8,copiedTaskId:i_,markingReadTaskId:__}),E(zA,{key:"history",title:"历史 session",tasks:L8,selectedId:I,emptyText:"最近没有完成、失败或取消的 session。",onSelect:V8,onCopy:H8,onReference:O8,onMarkRead:B8,copiedTaskId:i_,markingReadTaskId:__}),E("div",{key:"pagination",className:"codex-task-pagination","data-testid":"codex-task-pagination"},E("span",null,Xl?`搜索“${C1}” · 已显示 ${gl.length} / ${Number.isFinite(Ir)?Ir:gl.length}`:`已加载 ${gl.length} / ${Number.isFinite(Ir)?Ir:gl.length}`),x$?E("button",{type:"button",className:"ghost-btn",disabled:J_,onClick:()=>void hj(),"data-testid":"codex-load-more-tasks-button"},J_?"加载中":Xl?"加载更多结果":"加载更早任务"):E("code",null,Xl?"已到结果末尾":"已到队列末尾"))],Ij=(V,v=!1)=>E("label",{className:`code-queue-switcher ${v?"compact":""}`},E("span",null,v?"Queue":"查看 queue"),E("select",{value:Du,onChange:(lu)=>$K(String(lu.target.value||W1)),"data-testid":V},E("option",{value:W1},`All queues · ${Number.isFinite(p1)?p1:vr.length} tasks · ${j_.length} running`),Jr.map((lu)=>E("option",{key:String(lu?.id||""),value:String(lu?.id||"")},wA(lu))))),TK=E("div",{className:"codex-task-search","data-testid":"codex-task-search"},E("label",{htmlFor:"codex-task-search-input"},"搜索 task"),E("div",{className:"codex-task-search-row"},E("input",{id:"codex-task-search-input",type:"search",value:uu,placeholder:"关键词 / task ID / prompt",autoComplete:"off",onChange:(V)=>nu(String(V.target.value||"")),"data-testid":"codex-task-search-input"}),uu?E("button",{type:"button",className:"ghost-btn",onClick:()=>nu(""),"data-testid":"codex-task-search-clear"},"清除"):null),E("small",{"data-testid":"codex-task-search-summary"},Xl?Ku?"搜索中...":`匹配 ${gl.length}/${Number.isFinite(Ir)?Ir:gl.length}`:"支持 task ID、prompt、状态、provider、模型和最近输出关键词")),ZK=E("div",{className:"codex-trace-status","data-testid":"codex-trace-status-summary"},E("span",{className:"codex-trace-status-chip queued"},E("b",null,"排队"),String(P$)),E("span",{className:"codex-trace-status-chip running"},E("b",null,"运行"),String(G8)),E("span",{className:`codex-trace-status-chip unread ${m0>0?"warn":""}`},E("b",null,"结束未读"),String(m0)),E("span",{className:"codex-trace-status-chip service"},E("b",null,"服务"),`${R$.providerStatus||"unknown"} · ${i?.providerId||"main-server"} · ${sG.public?"公网暴露":"仅 UniDesk frontend 代理访问"}`),E("span",{className:"codex-trace-status-chip"},E("b",null,"执行节点"),xj.map((V)=>V.id).join(" / ")),E("span",{className:"codex-trace-status-chip"},E("b",null,"模型"),Cj.join(" / ")),E("span",{className:"codex-trace-status-chip"},E("b",null,"加载"),Vl?.phase==="complete"?FT(Vl?.totalMs):String(Vl?.phase||"idle")),E("span",{className:"codex-trace-status-chip"},E("b",null,"刷新"),$_?qf($_):"--")),HK=E(Ti,{title:h?`Trace ${String(h.id).slice(0,22)}`:"Trace 输出",eyebrow:h?`${h.status} / view=${Dy} / task queue=${Tn(h)} / provider=${h.providerId||"main-server"} / ${h.model} / agent loop trace`:`Agent loop trace / view=${Dy}`,summary:ZK,loading:s||Vy||Ku||m||Vl?.phase==="loading",actions:E("div",{className:"panel-actions"},Ij("code-queue-filter-select"),E("button",{type:"button",className:"ghost-btn codex-mark-all-read-btn",disabled:m0===0||Lu||n_,onClick:()=>void nK(),"data-testid":"codex-mark-all-read-button"},n_?"标记中":`全部标已读${m0>0?` (${m0})`:""}`),h?E("button",{type:"button",className:"ghost-btn",disabled:s||Lu,onClick:()=>void NK(),"data-testid":"codex-load-full-trace-button"},s?"加载中":yr(h)?"刷新 Summary":"加载 Summary"):null,E("button",{type:"button",className:"codex-session-title-toggle",onClick:()=>Zu((V)=>!V),"data-testid":"code-queue-sidebar-toggle"},fu?"收起队列":"展开队列"),E("label",{className:"inline-check"},E("input",{type:"checkbox",checked:r_,onChange:(V)=>y_(Boolean(V.target.checked))}),"自动滚动"),E("button",{type:"button",className:"ghost-btn",disabled:!dG||Lu,onClick:()=>void qK(),"data-testid":"codex-interrupt-button"},"打断"),E("button",{type:"button",className:"ghost-btn",disabled:!eG||Lu,onClick:()=>void WK()},"重试"),h?E(Pq,{title:"Codex Task",data:h,onOpen:f,testId:"raw-codex-task"}):null),className:"codex-output-panel"},E("div",{className:`codex-session-shell ${fu?"":"queue-collapsed"}`},fu?E("aside",{className:"codex-session-sidebar","data-testid":"codex-session-sidebar"},E("div",{className:"codex-session-sidebar-head"},E("div",null,E("span",null,ml(Du)?"All queues":"Queue lane"),E("strong",null,`${Dy} · ${vr.length}/${Number.isFinite(p1)?p1:vr.length} sessions · 未读 ${m0}`)),E("button",{type:"button",className:"ghost-btn",onClick:()=>Zu(!1)},"收起")),Ij("code-queue-filter-sidebar",!0),TK,E("div",{className:"codex-task-list codex-task-list-session",onScroll:_K,"data-testid":"codex-task-list-scroll"},EK)):null,E("div",{className:"codex-session-main"},E("div",{className:"codex-output-stack"},E(TZ,{task:h,loading:s,onLoadPromptPart:rK,onLoadSteps:Z8,onLoadStep:yK}),E(ZZ,{task:h})))));if(!i)return E(Fy,{title:"Code Queue 未登记",text:"请在 config.json 的 microservices 中登记用户服务 id=code-queue"});let kj=Number(Vl?.totalMs),gj=Number(Vl?.queueMs),sj=Number(Vl?.detailMs),aj=Number(Vl?.transcriptRows),OK=Vl?.phase==="complete"?"complete":String(Vl?.phase||"idle");return E("div",{className:`code-queue-page ${y?"codex-standalone-page":""}`,"data-testid":"code-queue-page","data-load-state":OK,"data-load-total-ms":Number.isFinite(kj)?String(Math.round(kj*10)/10):"","data-load-queue-ms":Number.isFinite(gj)?String(Math.round(gj*10)/10):"","data-load-detail-ms":Number.isFinite(sj)?String(Math.round(sj*10)/10):"","data-load-transcript-rows":Number.isFinite(aj)?String(aj):"","data-load-task-id":String(Vl?.taskId||I||""),"data-load-partial":Vl?.partial?"true":"false"},E(jf,{error:Uf,wide:!0}),yf?E("div",{className:"form-success wide","data-testid":"codex-create-success"},yf):null,E("div",{className:"codex-session-stage codex-session-stage-top"},HK),E("div",{className:"code-queue-layout"},E("div",{className:"codex-left-rail"},E(Ti,{title:"提交任务",eyebrow:ou?"Submitting...":F0.length>1?`${F0.length} tasks`:"Single or Batch",className:"codex-compose-panel",loading:ou},E("form",{className:`codex-task-form ${ou?"is-submitting":""}`,onSubmit:JK,"data-testid":"code-queue-task-form","aria-busy":ou?"true":"false"},E("label",null,"Prompt / 多任务用单独一行 --- 分隔",E("textarea",{value:e,rows:8,disabled:ou,onChange:(V)=>cu(V.target.value),placeholder:"写入 Codex 任务;多个任务之间用 --- 分隔。"})),E("label",{className:"codex-reference-field"},"引用任务 ID(可选)",E("input",{value:g,disabled:ou,onChange:(V)=>Qu(V.target.value),placeholder:"codex_...;支持空格/逗号分隔多个 ID","data-testid":"codex-reference-task-id"}),ny(g).length>0?E("code",null,`后端将解析并注入:${ny(g).join(" / ")}`):null),E("div",{className:"codex-form-grid"},E("label",{className:"codex-submit-queue-field"},"Queue",E("div",{className:"codex-submit-queue-row"},E("select",{value:Eu,disabled:ou,onChange:(V)=>Tu(String(V.target.value||"default")),"data-testid":"code-queue-id-select"},Jr.map((V)=>E("option",{key:String(V?.id||""),value:String(V?.id||"")},wA(V)))),E("button",{type:"button",className:"ghost-btn codex-rename-queue-btn",onClick:()=>void jK(),disabled:Lu||ou||!Eu,title:"修改当前 queue 的显示名称,ID 不变","data-testid":"codex-rename-queue-button"},"改名"),E("button",{type:"button",className:"ghost-btn codex-merge-queue-btn",onClick:()=>void FK(),disabled:Lu||ou||Jr.length<2,title:"把其他 queue 合并到当前 queue;源 queue 记录会保留,不会删除","data-testid":"codex-merge-queue-button"},"合并 queue"),E("button",{type:"button",className:"ghost-btn codex-create-queue-btn",onClick:()=>void AK(),disabled:Lu||ou,"data-testid":"codex-create-queue-button"},"创建 queue"))),E("label",null,"模型",E("select",{value:gf,disabled:ou,onChange:(V)=>jr(V.target.value),"data-testid":"codex-model-select"},Cj.map((V)=>E("option",{key:V,value:V},V)))),E("label",null,"执行 Provider",E("select",{value:rf,disabled:ou,onChange:(V)=>lK(String(V.target.value||"main-server")),"data-testid":"codex-provider-select"},xj.map((V)=>E("option",{key:V.id,value:V.id},`${V.label||V.id} · ${V.defaultWorkdir||D6(Rf,V.id)}`)))),E("label",null,"工作目录",E("input",{value:Ol,disabled:ou,onChange:(V)=>ef(V.target.value),placeholder:oG||Rf?.defaultWorkdir||"/root/unidesk","data-testid":"codex-cwd-input"})),E("label",null,"最大尝试",E("input",{type:"number",min:1,max:99,value:hr,disabled:ou,onChange:(V)=>vl(Number(V.target.value)),"data-testid":"codex-max-attempts-input"})),E("label",null,"入队份数",E("input",{type:"number",min:1,max:50,value:ju,disabled:ou,onChange:(V)=>bu(Number(V.target.value)),"data-testid":"codex-repeat-count-input"}))),U_>1?E("label",{className:`codex-batch-confirm ${ul?"confirmed":""}`,"data-testid":"codex-batch-confirm-row"},E("input",{type:"checkbox",checked:ul,disabled:ou,onChange:(V)=>tu(Boolean(V.target.checked)),"data-testid":"codex-batch-confirm-checkbox"}),E("span",null,`确认批量入队 ${U_} 个任务(prompt 分段 ${w8.length} × 入队份数 ${Eq(ju)})`)):null,ou?E("div",{className:"codex-submit-wait","data-testid":"codex-submit-wait"},"正在提交到后端,已锁定输入以防重复提交..."):null,E("div",{className:"codex-form-actions"},E("button",{type:"button",className:"ghost-btn",disabled:Lu||ou||e.length===0&&g.length===0,onClick:()=>{cu(""),Qu(""),tu(!1);let V="已清空任务输入栏";_f(V),xf("success",V)},"data-testid":"codex-clear-input-button"},"清空输入"),E("button",{type:"submit",className:"primary-btn",disabled:aG,"data-testid":"codex-enqueue-button"},ou?"提交中,请等待...":pj?`请确认批量入队 ${U_} 个任务`:F0.length>1?`批量入队 ${F0.length} 个任务`:"入队并运行"))))),E("div",{className:"codex-main-stage"},E("div",{className:"codex-detail-grid"},E(Ti,{title:"运行控制",eyebrow:ty?"Queued prompt editable":E8?"Active turn steer":"Steer when running",loading:Lu},E("div",{className:"codex-run-control-stack"},E(GZ,{task:h,queueRows:Jr,busy:Lu,onMove:cK}),h?.id?E("form",{className:"codex-steer-form codex-edit-prompt-form",onSubmit:QK,"data-testid":"codex-edit-prompt-form"},E("label",null,"编辑 queued 用户 prompt",E("textarea",{value:Il,rows:5,onChange:(V)=>Fr(V.target.value),placeholder:"仅 QUEUED 且尚未开始运行的任务可在这里修改原始用户 prompt。",disabled:!ty||Lu,"data-testid":"codex-edit-prompt-textarea"})),E("label",{className:"codex-reference-field"},"引用任务 ID(可选,留空会清除引用)",E("input",{value:kl,disabled:!ty||Lu,onChange:(V)=>M0(V.target.value),placeholder:"codex_...;支持空格/逗号分隔多个 ID","data-testid":"codex-edit-reference-task-id"}),ny(kl).length>0?E("code",null,`将保留/注入:${ny(kl).join(" / ")}`):null),E("div",{className:"codex-form-actions"},E("button",{type:"button",className:"ghost-btn",disabled:!h?.id||Lu,onClick:()=>{Fr(h?Y6(h):""),M0(Array.isArray(h?.referenceTaskIds)?h.referenceTaskIds.join(" "):"")},"data-testid":"codex-edit-prompt-reset"},"恢复当前值"),E("button",{type:"submit",className:"primary-btn",disabled:!ty||Lu||Il.trim().length===0,title:ty?"保存后会重写尚未运行任务的用户 prompt":"只有 QUEUED 且尚未开始的任务可编辑 prompt","data-testid":"codex-edit-prompt-submit"},"保存 queued prompt"))):null,E("form",{className:"codex-steer-form",onSubmit:UK},E("label",null,"追加 prompt",E("textarea",{value:Bl,rows:4,onChange:(V)=>sf(V.target.value),placeholder:"给正在运行的 Codex session 推入新的指令或纠偏。",disabled:!E8})),E("button",{type:"submit",className:"primary-btn",disabled:!E8||Lu||Bl.trim().length===0,"data-testid":"codex-steer-button"},"推入运行中 session")))),E(Ti,{title:"完成判定",eyebrow:h?.lastJudge?h.lastJudge.source:"judge",loading:s},h?.lastJudge?E("div",{className:"codex-judge-card","data-testid":"codex-task-judge-card"},E(jy,{status:h.lastJudge.decision},h.lastJudge.decision),E("strong",null,`${Math.round(Number(h.lastJudge.confidence||0)*100)}% confidence`),E("p",{"data-testid":"codex-task-judge-reason"},GA(h.lastJudge.reason||"--",180)),h.lastJudge.continuePrompt?E("code",{"data-testid":"codex-task-judge-continue-prompt"},GA(h.lastJudge.continuePrompt,160)):null):E(Fy,{title:"尚未判定",text:"Codex turn 结束后会由 MiniMax M2.7 或 fallback judge 判定 complete/retry/fail;retry 会在已有 thread 追加继续执行 prompt。"}))),E(zZ,{stats:z8,queueName:Dy,onRaw:f}),E(Ti,{title:"Attempts",eyebrow:"terminal vs interruption",loading:s},E(HZ,{task:h})))))}var Bn=Pu(wf(),1);var Vu=Bn.default.createElement,{useEffect:tA}=Bn.default,SA=Bn.default.useState,OZ=Bn.default.useRef,MA=` :root { --surfacePrimary: #ffffff; --surfaceSecondary: #f8fafc; @@ -224,64 +224,64 @@ nav .material-icons::before { display: none !important; } } -`;function ij({title:f,eyebrow:u,actions:l,children:_,className:y,loading:$}){return Tf("section",{className:`panel ${y||""}`},Tf("div",{className:"panel-head"},Tf("div",null,u?Tf("p",{className:"panel-eyebrow"},u):null,Tf(j0,{title:f,loading:$})),l?Tf("div",{className:"panel-actions"},l):null),Tf("div",{className:"panel-body"},_))}function WB({title:f,data:u,onOpen:l,testId:_}){return Tf("button",{type:"button",className:"ghost-btn","data-testid":_,onClick:()=>l(f,u)},"查看原始JSON")}function zB({title:f,text:u}){return Tf("div",{className:"empty-state"},Tf("strong",null,f),Tf("span",null,u))}function eG(f){return f?.runtime&&typeof f.runtime==="object"&&!Array.isArray(f.runtime)?f.runtime:{}}function fK(f){return f?.backend&&typeof f.backend==="object"&&!Array.isArray(f.backend)?f.backend:{}}function uK(f){return f?.repository&&typeof f.repository==="object"&&!Array.isArray(f.repository)?f.repository:{}}function GB(f){return f.filter((l)=>l?.id==="filebrowser"||String(l?.id||"").startsWith("filebrowser-")).sort((l,_)=>{let y=($)=>$.providerId==="D518"?0:$.providerId==="D601"?1:$.id==="filebrowser"?2:3;return y(l)-y(_)||String(l.id).localeCompare(String(_.id))})}function KB(f){if(f?.providerId==="D518")return"D518";return f?.providerId||f?.name||f?.id||"Unknown"}function NB(f,u,l="/"){let _=l.startsWith("/")?l:`/${l}`;return`${f}/microservices/${encodeURIComponent(u)}/proxy${_}`}function ZB(f,u){return`${f}/microservices/${encodeURIComponent(u)}/health`}async function EB(f,u=16000){let l=new AbortController,_=setTimeout(()=>l.abort(),u);try{return await Mf(f,{signal:l.signal,failureFields:[!1]})}finally{clearTimeout(_)}}function lK(f){if(f?.providerId==="main-server")return"host / -> /srv";if(f?.providerId==="D601"||f?.providerId==="D518")return"WSL / + /mnt/c -> /srv";return"provider / -> /srv"}function C2(f){return f?.status==="OK"||f?.ok===!0}function HB({service:f,active:u,health:l,onSelect:_,onRaw:y}){let $=eG(f),r=fK(f),j=uK(f),A=$.container||{},J=C2(l?.body);return Tf("button",{type:"button",className:`filebrowser-target-card ${u?"active":""}`,"data-testid":`filebrowser-target-card-${f.id}`,onClick:_},Tf("span",{className:`status-badge ${J?"ok":$.providerStatus==="online"?"running":"warn"}`},J?"Health OK":$.providerStatus||"unknown"),Tf("strong",null,f.name||f.id),Tf("span",null,lK(f)),Tf("code",null,`${r.nodeBindHost||"--"}:${r.nodePort||"--"}`),Tf("small",null,A.name?`${A.name} / ${A.state||"--"}`:`${j.composeService||"--"}`),Tf("span",{className:"filebrowser-card-raw",onClick:(U)=>{U.stopPropagation(),y(`${f.name} service`,f)}},"JSON"))}function _K(f){try{return f?.contentDocument||f?.contentWindow?.document||null}catch{return null}}function Rj(f){let u=_K(f);if(u===null||u.head===null)return!1;let l=u.getElementById("unidesk-filebrowser-compact-style");if(l===null)l=u.createElement("style"),l.id="unidesk-filebrowser-compact-style",u.head.appendChild(l);if(l.textContent!==cj)l.textContent=cj;return!0}function OB(f,u){let l=URL.createObjectURL(f),_=document.createElement("a");_.href=l,_.download=u,document.body.appendChild(_),_.click(),_.remove(),setTimeout(()=>URL.revokeObjectURL(l),2000)}function VB(f,u){let l=_K(f);if(l===null||l.documentElement===null)throw Error("无法访问 File Browser iframe 文档");Rj(f);let _=Math.max(640,Math.ceil(f.clientWidth||l.documentElement.clientWidth||1280)),y=Math.max(480,Math.ceil(f.clientHeight||l.documentElement.clientHeight||720)),$=l.documentElement.cloneNode(!0);$.querySelectorAll("script, style, link[rel='stylesheet'], link[rel='preload'], link[rel='icon']").forEach((U)=>U.remove()),$.querySelectorAll("img").forEach((U)=>{U.removeAttribute("src"),U.removeAttribute("srcset")});let r=$.querySelector("head");if(r===null)r=l.createElement("head"),$.insertBefore(r,$.firstChild);let j=l.createElement("style");j.textContent=`${cj} -html,body{width:${_}px!important;min-height:${y}px!important;overflow:hidden!important;}`,r.appendChild(j);let A=new XMLSerializer().serializeToString($),J=`${A}`;OB(new Blob([J],{type:"image/svg+xml;charset=utf-8"}),u.replace(/\.png$/i,".svg"))}function yK({microservices:f,onRaw:u,apiBaseUrl:l="/api"}){let _=GB(Array.isArray(f)?f:[]),y=new URLSearchParams(window.location.search).get("target")||"",$=y==="filebrowser-d518"?"filebrowser":y,r=_.some((Y)=>Y.id===$)?$:_[0]?.id||"",[j,A]=Cj(r),[J,U]=Cj({loading:!1,refreshedAt:null,health:{},error:""}),[Q,W]=Cj({exporting:!1,message:"",error:""}),G=QB(null),K=_.find((Y)=>Y.id===j)||_[0]||null,H=eG(K),O=fK(K),z=uK(K),Z=K?J.health[K.id]:null,N=K?NB(l,K.id,"/"):"about:blank";Sj(()=>{if(_.length===0)return;if(!j||!_.some((Y)=>Y.id===j))A(_[0].id)},[_.map((Y)=>Y.id).join(",")]),Sj(()=>{let Y=0,w=setInterval(()=>{if(Y+=1,Rj(G.current)||Y>=24)clearInterval(w)},500);return()=>clearInterval(w)},[N]),Sj(()=>{if(_.length===0)return;let Y=!1;async function w(){U((h)=>({...h,loading:!0,error:""}));let P=await Promise.all(_.map(async(h)=>{try{let M=await EB(ZB(l,h.id));return[h.id,{ok:!0,body:M}]}catch(M){return[h.id,{ok:!1,error:Df(M,"File Browser health failed")}]}}));if(Y)return;U({loading:!1,refreshedAt:new Date().toISOString(),health:Object.fromEntries(P),error:""})}w();let B=setInterval(w,30000);return()=>{Y=!0,clearInterval(B)}},[_.map((Y)=>`${Y.id}:${Y.runtime?.providerStatus||""}`).join(","),l]);function E(Y){A(Y);let w=new URL(window.location.href);w.searchParams.set("target",Y),window.history.replaceState({},"",`${w.pathname}${w.search}`)}async function q(){if(Q.exporting)return;W({exporting:!0,message:"",error:""});try{let Y=new Date().toISOString().replace(/[-:.TZ]/g,"").slice(0,14);await VB(G.current,`unidesk-filebrowser-${K?.id||"target"}-${Y}.png`),W({exporting:!1,message:"截图已导出",error:""})}catch(Y){W({exporting:!1,message:"",error:Df(Y,"截图导出失败")})}}if(_.length===0)return Tf(zB,{title:"File Browser 未登记",text:"请在 config.json 的 microservices 中登记 id=filebrowser 或 filebrowser-* 用户服务"});return Tf("div",{className:"filebrowser-page","data-testid":"filebrowser-page"},J.error?Tf(A0,{error:J.error,wide:!0}):null,Tf(ij,{title:"文件管理器",eyebrow:"File Browser / Host Files",loading:J.loading,actions:Tf("div",{className:"panel-actions"},K?Tf("button",{type:"button",className:"ghost-btn",onClick:q,disabled:Q.exporting,"data-testid":"filebrowser-export-screenshot"},Q.exporting?"导出中...":"导出截图"):null,K?Tf("a",{className:"ghost-btn",href:N,target:"_blank",rel:"noreferrer"},"新窗口打开"):null,K?Tf(WB,{title:"File Browser 当前目标",data:{service:K,health:Z},onOpen:u,testId:"raw-filebrowser-active"}):null)},Tf("div",{className:"filebrowser-hero"},Tf("div",null,Tf("span",{className:`status-badge ${C2(Z?.body)?"ok":"warn"}`},C2(Z?.body)?"Health OK":"Health Pending"),Tf("h3",null,K?.name||"File Browser"),Tf("p",{className:"muted paragraph"},K?.description||"通过 UniDesk 登录态代理访问,不开放 File Browser 公网端口。"),Q.error?Tf("p",{className:"filebrowser-shot-error"},Q.error):null,Q.message?Tf("p",{className:"filebrowser-shot-ok"},Q.message):null),Tf("div",{className:"microservice-ref-card"},Tf("span",null,"Provider"),Tf("strong",null,K?.providerId||"--"),Tf("code",null,H.providerName||K?.providerId||"--")),Tf("div",{className:"microservice-ref-card"},Tf("span",null,"Private Backend"),Tf("strong",null,`${O.nodeBindHost||"--"}:${O.nodePort||"--"}`),Tf("code",null,O.nodeBaseUrl||"--")),Tf("div",{className:"microservice-ref-card"},Tf("span",null,"Image"),Tf("strong",null,z.dockerfile||"filebrowser/filebrowser:v2.63.3"),Tf("code",null,z.commitId||"--")),Tf("div",{className:"microservice-ref-card"},Tf("span",null,"Mount"),Tf("strong",null,lK(K)),Tf("code",null,K?.providerId==="main-server"?"/root, /var, /home":"/home, /mnt/c, /mnt/d")))),Tf(ij,{title:"浏览目标",eyebrow:`${_.length} host targets`,loading:J.loading},Tf("div",{className:"filebrowser-target-grid"},_.map((Y)=>Tf(HB,{key:Y.id,service:Y,active:Y.id===K?.id,health:J.health[Y.id],onSelect:()=>E(Y.id),onRaw:u})))),Tf(ij,{title:`${KB(K)} 文件视图`,eyebrow:Z?.body?`Health ${C2(Z.body)?"OK":"UNKNOWN"} / ${J.refreshedAt?W0(J.refreshedAt):"--"}`:"Embedded WebUI",className:"filebrowser-frame-panel"},Tf("div",{className:"filebrowser-frame-shell"},Tf("div",{className:"filebrowser-frame-toolbar"},Tf("span",null,"BaseURL"),Tf("code",null,`/api/microservices/${K?.id||"filebrowser"}/proxy`),Tf("span",null,"Root"),Tf("code",null,"/srv"),Tf("span",{className:"filebrowser-compact-note"},"Compact layout injected")),Tf("iframe",{ref:G,key:N,title:`${K?.name||"File Browser"} WebUI`,src:N,className:"filebrowser-frame","data-testid":"filebrowser-frame",onLoad:(Y)=>Rj(Y.currentTarget),sandbox:"allow-downloads allow-forms allow-modals allow-same-origin allow-scripts"}))))}var x2=cf(O0(),1);var Qf=x2.default.createElement,{useEffect:qB}=x2.default,LB=x2.default.useState;function i2({status:f,children:u}){let l=String(f||"unknown").toLowerCase();return Qf("span",{className:`status-badge ${l}`},u||f||"unknown")}function K_({label:f,value:u,hint:l,tone:_}){return Qf("article",{className:`metric-card ${_||""}`},Qf("div",{className:"metric-label"},f),Qf("div",{className:"metric-value"},u),Qf("div",{className:"metric-hint"},l))}function c2({title:f,eyebrow:u,actions:l,children:_,className:y,loading:$}){return Qf("section",{className:`panel ${y||""}`},Qf("div",{className:"panel-head"},Qf("div",null,u?Qf("p",{className:"panel-eyebrow"},u):null,Qf(j0,{title:f,loading:$})),l?Qf("div",{className:"panel-actions"},l):null),Qf("div",{className:"panel-body"},_))}function R2({title:f,data:u,onOpen:l,testId:_}){return Qf("button",{type:"button",className:"ghost-btn","data-testid":_,onClick:()=>l(f,u)},"查看原始JSON")}function xj({title:f,text:u}){return Qf("div",{className:"empty-state"},Qf("strong",null,f),Qf("span",null,u))}function XB(f){return f?.runtime&&typeof f.runtime==="object"&&!Array.isArray(f.runtime)?f.runtime:{}}function BB(f){return f?.backend&&typeof f.backend==="object"&&!Array.isArray(f.backend)?f.backend:{}}function YB(f){return f?.repository&&typeof f.repository==="object"&&!Array.isArray(f.repository)?f.repository:{}}function Gy(f,u){let l=f&&typeof f==="object"?f[u]:void 0;return Number.isFinite(Number(l))?String(l):"--"}function wB(f){return(Array.isArray(f?.jobs)?f.jobs:[]).slice(0,40)}function DB(f){return(Array.isArray(f?.drafts)?f.drafts:[]).slice(0,12)}function $K({microservices:f,onRaw:u,apiBaseUrl:l="/api"}){let _=f.find((K)=>K.id==="findjob")||null,[y,$]=LB({loading:!1,error:"",health:null,summary:null,jobs:null,drafts:null,refreshedAt:null});async function r(){if(!_)return;$((K)=>({...K,loading:!0,error:""}));try{let[K,H,O,z]=await Promise.all([Mf(`${l}/microservices/findjob/health`),Mf(`${l}/microservices/findjob/proxy/api/summary`),Mf(`${l}/microservices/findjob/proxy/api/jobs?__unideskArrayLimit=jobs:40`),Mf(`${l}/microservices/findjob/proxy/api/drafts`)]);$({loading:!1,error:"",health:K,summary:H,jobs:O,drafts:z,refreshedAt:new Date})}catch(K){$((H)=>({...H,loading:!1,error:Df(K,"FindJob 加载失败")}))}}if(qB(()=>{r()},[_?.id,_?.runtime?.providerStatus]),!_)return Qf(xj,{title:"FindJob 未登记",text:"请在 config.json 的 microservices 中登记用户服务 id=findjob"});let j=XB(_),A=YB(_),J=BB(_),U=y.summary||{},Q=wB(y.jobs),W=DB(y.drafts),G=y.jobs?._unidesk?.arrayLimits?.jobs;return Qf("div",{className:"findjob-page","data-testid":"findjob-page"},Qf(c2,{title:"FindJob 工作台",eyebrow:"D601 用户服务",loading:y.loading,actions:Qf("div",{className:"panel-actions"},Qf("button",{type:"button",className:"ghost-btn",onClick:r,disabled:y.loading,"data-testid":"findjob-refresh-button"},y.loading?"刷新中":"刷新"),Qf(R2,{title:"FindJob 用户服务",data:_,onOpen:u,testId:"raw-findjob-service"}))},Qf("div",{className:"findjob-hero"},Qf("div",null,Qf("div",{className:"node-version-line"},Qf(i2,{status:j.providerStatus==="online"?"online":"warn"},j.providerStatus||"unknown"),Qf("span",null,_.providerId),Qf("span",null,J.public?"公网暴露":"仅 UniDesk frontend 代理访问")),Qf("p",{className:"muted paragraph"},_.description)),Qf("div",{className:"microservice-ref-card"},Qf("span",null,"Repo"),Qf("strong",null,A.url||"--"),Qf("code",null,A.commitId||"--")),Qf("div",{className:"microservice-ref-card"},Qf("span",null,"D601 Docker"),Qf("strong",null,`${J.nodeBindHost||"--"}:${J.nodePort||"--"}`),Qf("code",null,`${A.composeFile||"--"} / ${A.composeService||"--"}`))),Qf(A0,{error:y.error,wide:!0})),Qf("div",{className:"findjob-grid"},Qf(c2,{title:"岗位指标",eyebrow:y.refreshedAt?`Updated ${W0(y.refreshedAt)}`:"Summary",loading:y.loading},Qf("div",{className:"metric-grid"},Qf(K_,{label:"岗位总量",value:Gy(U,"totalJobs"),hint:"tracked jobs",tone:"ok"}),Qf(K_,{label:"原始岗位",value:Gy(U,"rawJobs"),hint:"raw queue"}),Qf(K_,{label:"已验证",value:Gy(U,"verifiedJobs"),hint:"verified set"}),Qf(K_,{label:"优先处理",value:Gy(U,"prioritizedJobs"),hint:"prioritized"}),Qf(K_,{label:"过期",value:Gy(U,"staleJobs"),hint:"stale jobs",tone:"warn"}),Qf(K_,{label:"无效",value:Gy(U,"invalidJobs"),hint:"invalid jobs",tone:"warn"}),Qf(K_,{label:"上海",value:Gy(U,"shanghaiJobs"),hint:"city filter"}),Qf(K_,{label:"Health",value:y.health?.ok?"OK":"--",hint:"D601 /api/health"})),Qf("div",{className:"panel-actions inline-actions"},Qf(R2,{title:"FindJob Summary",data:U,onOpen:u,testId:"raw-findjob-summary"}))),Qf(c2,{title:"近期岗位",eyebrow:G?`${G.returnedLength}/${G.originalLength} Preview`:`${Q.length} Preview`,loading:y.loading},Q.length===0?Qf(xj,{title:"暂无岗位预览",text:"等待 D601 findjob backend 返回 /api/jobs"}):Qf("div",{className:"table-wrap findjob-job-table"},Qf("table",null,Qf("thead",null,Qf("tr",null,Qf("th",null,"优先级"),Qf("th",null,"状态"),Qf("th",null,"单位"),Qf("th",null,"职位"),Qf("th",null,"城市"),Qf("th",null,"阶段"),Qf("th",null,"截止"),Qf("th",null,"证据"))),Qf("tbody",null,Q.map((K)=>Qf("tr",{key:K.id},Qf("td",null,Qf(i2,{status:String(K.priority||"").toLowerCase()||"unknown"},K.priority||"--")),Qf("td",null,Qf(i2,{status:String(K.status||"").toLowerCase()||"unknown"},K.status||"--")),Qf("td",null,K.organization_name||"--",Qf("code",null,K.id||"--")),Qf("td",null,K.display_title||K.title||"--"),Qf("td",null,K.display_city||K.city||"--"),Qf("td",null,K.workflow_stage||"--"),Qf("td",null,K.deadline||"--"),Qf("td",null,K.evidence_url?Qf("a",{href:K.evidence_url,target:"_blank",rel:"noreferrer"},"打开"):Qf("span",{className:"muted"},"无"))))))),Qf("div",{className:"panel-actions inline-actions"},Qf(R2,{title:"FindJob Jobs Preview",data:y.jobs,onOpen:u,testId:"raw-findjob-jobs"}))),Qf(c2,{title:"草稿与报告",eyebrow:`${W.length} Drafts`,loading:y.loading},W.length===0?Qf(xj,{title:"暂无草稿",text:"D601 findjob backend 未返回 drafts"}):Qf("div",{className:"draft-list"},W.map((K)=>Qf("article",{key:K.id,className:"draft-card"},Qf("div",{className:"node-card-head"},Qf("strong",null,K.id),Qf(i2,{status:K.status},K.status||"--")),Qf("div",{className:"docker-meta compact"},Qf("span",null,K.workflow_stage||"--"),Qf("span",null,`jobs ${K.counts?.jobs??0}`),Qf("span",null,`reports ${K.counts?.reports??0}`)),Qf("span",null,K.latestReportPath||"暂无报告"),Qf("code",null,Nf(K.updated_at||K.updatedAt))))),Qf("div",{className:"panel-actions inline-actions"},Qf(R2,{title:"FindJob Drafts",data:y.drafts,onOpen:u,testId:"raw-findjob-drafts"})))))}var P6=cf(O0(),1);var R=P6.default.createElement,{useEffect:TB}=P6.default,bj=P6.default.useState;function D6(f){let u=Number(f);return Number.isFinite(u)?`${Math.max(0,Math.min(100,u)).toFixed(1)}%`:"--"}function hj(f){if(f===null||f===void 0||f==="")return"--";let u=Number(f);if(!Number.isFinite(u))return"--";if(u<60)return`${Math.max(0,Math.round(u))}s`;if(u<3600)return`${Math.floor(u/60)}m ${Math.round(u%60)}s`;return`${Math.floor(u/3600)}h ${Math.floor(u%3600/60)}m`}function Ij(f,u=2){let l=Number(f);if(!Number.isFinite(l))return f===!1?"false":f===!0?"true":"--";let _=Math.abs(l);if(Number.isInteger(l)||_>=1000)return l.toLocaleString("zh-CN",{maximumFractionDigits:0});if(_>=1)return l.toLocaleString("zh-CN",{maximumFractionDigits:u});return l.toLocaleString("zh-CN",{maximumFractionDigits:Math.max(u,6)})}function M6(f){if(f===null||f===void 0||f==="")return"--";if(typeof f==="boolean")return f?"true":"false";if(typeof f==="number")return Ij(f,4);if(Array.isArray(f))return f.map((u)=>M6(u)).join(" x ");if(typeof f==="object")return"已上报";return String(f)}function b2(f){let u=Number(f);if(!Number.isFinite(u)||u<=0)return"--";let l=u>=100?0:u>=10?1:2;return`${u.toLocaleString("zh-CN",{maximumFractionDigits:l})} epoch/h`}function v2(f){return f.replace(/[^a-zA-Z0-9_-]/g,"-")}function Ru(f){return f&&typeof f==="object"&&!Array.isArray(f)?f:{}}function T6({status:f,children:u}){let l=String(f||"unknown").toLowerCase();return R("span",{className:`status-badge ${l}`},u||f||"unknown")}function N_({label:f,value:u,hint:l,tone:_}){return R("article",{className:`metric-card ${_||""}`},R("div",{className:"metric-label"},f),R("div",{className:"metric-value"},u),R("div",{className:"metric-hint"},l))}function vj({title:f,eyebrow:u,actions:l,children:_,className:y,loading:$}){return R("section",{className:`panel ${y||""}`},R("div",{className:"panel-head"},R("div",null,u?R("p",{className:"panel-eyebrow"},u):null,R(j0,{title:f,loading:$})),l?R("div",{className:"panel-actions"},l):null),R("div",{className:"panel-body"},_))}function T$({title:f,data:u,onOpen:l,testId:_}){return R("button",{type:"button",className:"ghost-btn","data-testid":_,onClick:(y)=>{y?.stopPropagation?.(),l(f,u)}},"查看原始JSON")}function P1({title:f,text:u}){return R("div",{className:"empty-state"},R("strong",null,f),R("span",null,u))}function MB(f){return f?.runtime&&typeof f.runtime==="object"&&!Array.isArray(f.runtime)?f.runtime:{}}function PB(f){return f?.backend&&typeof f.backend==="object"&&!Array.isArray(f.backend)?f.backend:{}}function nB(f){return f?.repository&&typeof f.repository==="object"&&!Array.isArray(f.repository)?f.repository:{}}function SB(f){return f?.counts&&typeof f.counts==="object"&&!Array.isArray(f.counts)?f.counts:{}}function CB(f){return Array.isArray(f?.jobs)?f.jobs.slice(0,240):[]}function iB(f){return Array.isArray(f?.projects)?f.projects.slice(0,1000):[]}function h2(f){return Array.isArray(f?.projects)?f.projects:[]}function cB(f,u){if(Array.isArray(u?.gpu))return u.gpu;if(Array.isArray(f?.gpu))return f.gpu;return[]}function yl(f,u){return`${f}/microservices/met-nonlinear/proxy${u}`}function rK(f){return f.startedAt&&f.finishedAt?hj((Date.parse(f.finishedAt)-Date.parse(f.startedAt))/1000):"--"}function RB(f){let u=f.progress||{};if(u.etaSeconds!==null&&u.etaSeconds!==void 0&&u.etaSeconds!==""){let r=Number(u.etaSeconds);if(Number.isFinite(r))return Math.max(0,r)}let l=Number(u.currentEpoch),_=Number(u.epochTarget??f.epochTarget),y=Date.parse(f.startedAt||"");if(!Number.isFinite(l)||l<=0||!Number.isFinite(_)||_<=l||!Number.isFinite(y))return null;let $=Math.max(0,(Date.now()-y)/1000);if($<=0)return null;return Math.max(0,$/l*(_-l))}function jK(f){let u=f.progress||{},l=Number(u.epochPerHour);if(Number.isFinite(l)&&l>0)return l;let _=Date.parse(f.startedAt||""),y=["succeeded","failed","canceled"].includes(f.status)?Date.parse(f.finishedAt||""):Date.now();if(!Number.isFinite(_)||!Number.isFinite(y)||y<=_)return null;let $=Number(u.currentEpoch??f.epochTarget);if(!Number.isFinite($)||$<=0)return null;return $/((y-_)/3600000)}function AK(f){if(f==="staged")return"待启动";if(f==="queued")return"排队中";if(f==="running")return"训练中";if(f==="succeeded")return"已完成";if(f==="failed")return"失败";if(f==="canceled")return"已取消";return f||"unknown"}function FK(f,u,l){return{name:f,path:u,depth:l,count:0,children:[],project:null}}function xB(f){let u=FK("","",-1);for(let _ of f){let $=String(_?.projectPath||"").replace(/\\/g,"/").split("/").filter(Boolean);if($.length===0)continue;let r=u,j=[];for(let[A,J]of $.entries()){j.push(J);let U=j.join("/"),Q=r.children.find((W)=>W.path===U);if(!Q)Q=FK(J,U,A),r.children.push(Q);if(A===$.length-1)Q.project=_;r=Q}}let l=(_)=>{let y=_.children.reduce(($,r)=>$+l(r),0);return _.count=(_.project?1:0)+y,_.children.sort(($,r)=>{if(Boolean($.project)!==Boolean(r.project))return $.project?1:-1;return $.name.localeCompare(r.name,"zh-CN",{numeric:!0,sensitivity:"base"})}),_.count};return l(u),u}function bB(f){let u=Ru(f.data);return Ru(u.project).projectPath?Ru(u.project):u}function vB(f){return Ru(Ru(f.data).job)}function JK({microservices:f,onRaw:u,apiBaseUrl:l="/api"}){let _=f.find((c)=>c.id==="met-nonlinear")||null,[y,$]=bj({loading:!1,actionBusy:!1,error:"",health:null,summary:null,queue:null,projects:null,history:null,images:null,refreshedAt:null}),[r,j]=bj({loading:!1,error:"",kind:"",key:"",title:"",data:null}),[A,J]=bj(()=>({activeTab:"projects",selectedProjects:{},expandedProjectDirs:{},sourceProject:"",forkCount:1,forkEpochs:200,forkPrefix:`ui_fork_${Date.now()}`,maxConcurrency:3,targetGpuName:"2080 Ti",actionMessage:""}));function U(c){J((o)=>({...o,...c}))}async function Q(c=A.activeTab){if(!_)return;$((o)=>({...o,loading:!0,error:""}));try{let o=[["health",Mf(`${l}/microservices/met-nonlinear/health`)],["summary",Mf(yl(l,"/api/summary"))]];if(c==="projects")o.push(["projectsRoot",Mf(yl(l,"/api/projects?root=projects&limit=500"))]),o.push(["exProjectsRoot",Mf(yl(l,"/api/projects?root=ex_projects&limit=500"))]);if(c==="current"||c==="completed"||c==="failed")o.push(["queue",Mf(yl(l,"/api/queue"))]);if(c==="completed"||c==="failed")o.push(["history",Mf(yl(l,"/api/history"))]);if(c==="gpu")o.push(["images",Mf(yl(l,"/api/images"))]);let e=Object.fromEntries(await Promise.all(o.map(async([k,Af])=>[k,await Af]))),Kf={loading:!1,actionBusy:!1,error:"",health:e.health,summary:e.summary,refreshedAt:new Date};if(e.projectsRoot||e.exProjectsRoot){let{projectsRoot:k,exProjectsRoot:Af}=e;Kf.projects={ok:k?.ok!==!1&&Af?.ok!==!1,roots:[{root:"projects",count:h2(k).length},{root:"ex_projects",count:h2(Af).length}],projects:[...h2(k),...h2(Af)]}}if(e.queue)Kf.queue=e.queue;if(e.history)Kf.history=e.history;if(e.images)Kf.images=e.images;$((k)=>({...k,...Kf}))}catch(o){$((e)=>({...e,loading:!1,actionBusy:!1,error:Df(o,"MET Nonlinear 加载失败")}))}}async function W(c,o){$((e)=>({...e,actionBusy:!0,error:""})),U({actionMessage:`${c}...`});try{let e=await o();U({actionMessage:e||`${c}完成`}),await Q()}catch(e){$((Kf)=>({...Kf,actionBusy:!1,error:Df(e,`${c}失败`)}))}}async function G(){await W("保存并发设置",async()=>{await Mf(yl(l,"/api/queue/settings"),{method:"PUT",body:JSON.stringify({maxConcurrency:Number(A.maxConcurrency),targetGpuName:A.targetGpuName})})})}function K(){return Object.entries(A.selectedProjects).filter(([,c])=>c).map(([c])=>c)}async function H(){let c=K();if(c.length===0)throw Error("请先选择至少一个 project");await W("加入待启动队列",async()=>{await Mf(yl(l,"/api/queue"),{method:"POST",body:JSON.stringify({projectPaths:c,maxConcurrency:Number(A.maxConcurrency),targetGpuName:A.targetGpuName,start:!1})}),U({activeTab:"current",selectedProjects:{}})})}async function O(){let c=A.sourceProject||S[0]?.projectPath;if(!c)throw Error("请先选择源 project");await W("Fork Project",async()=>{let o=await Mf(yl(l,"/api/projects/fork"),{method:"POST",body:JSON.stringify({sourceProject:c,count:Number(A.forkCount),epochs:Number(A.forkEpochs),prefix:A.forkPrefix})}),e=Array.isArray(o.projectPaths)?o.projectPaths:[],Kf=e.reduce((k,Af)=>{return k[Af]=!0,k},{...A.selectedProjects});return U({selectedProjects:Kf}),`已 fork ${e.length} 个 project,并已自动勾选;请确认后点击加入待启动队列。`})}async function z(){await W("启动队列",async()=>{await Mf(yl(l,"/api/queue/start"),{method:"POST",body:JSON.stringify({maxConcurrency:Number(A.maxConcurrency),targetGpuName:A.targetGpuName})}),U({activeTab:"current"})})}async function Z(c){await W("取消任务",async()=>{await Mf(yl(l,`/api/jobs/${encodeURIComponent(c.id)}/cancel`),{method:"POST",body:JSON.stringify({})})})}async function N(c){let o=String(c?.projectPath||"");if(!o)return;j({loading:!0,error:"",kind:"project",key:o,title:o,data:null});try{let e=await Mf(yl(l,`/api/projects/config?path=${encodeURIComponent(o)}`));j({loading:!1,error:"",kind:"project",key:o,title:o,data:e})}catch(e){j({loading:!1,error:Df(e,"Project 详情加载失败"),kind:"project",key:o,title:o,data:null})}}async function E(c){let o=String(c?.id||"");if(!o)return;j({loading:!0,error:"",kind:"job",key:o,title:c.projectPath||o,data:null});try{let e=await Mf(yl(l,`/api/jobs/${encodeURIComponent(o)}`));j({loading:!1,error:"",kind:"job",key:o,title:e?.job?.projectPath||c.projectPath||o,data:e})}catch(e){j({loading:!1,error:Df(e,"Job 详情加载失败"),kind:"job",key:o,title:c.projectPath||o,data:null})}}if(TB(()=>{Q(A.activeTab)},[_?.id,_?.runtime?.providerStatus,A.activeTab]),!_)return R(P1,{title:"MET Nonlinear 未登记",text:"请在 config.json 的 microservices 中登记用户服务 id=met-nonlinear"});let q=MB(_),Y=nB(_),w=PB(_),B=SB(y.queue?.queue||y.summary?.queue),P=cB(y.health,y.queue),h=y.health?.targetGpu||y.summary?.targetGpu||P.find((c)=>String(c.name||"").includes("2080")),M=y.images?.mlImage||y.health?.image||{},n=CB(y.queue),S=iB(y.projects),T=xB(S),i=A.sourceProject||S[0]?.projectPath||"",C=n.filter((c)=>["staged","queued","running"].includes(c.status)),v=n.filter((c)=>c.status==="succeeded"),X=n.filter((c)=>["failed","canceled"].includes(c.status)),D=Array.isArray(y.history?.jobs)?y.history.jobs.slice(0,120):[],p=[{id:"projects",label:"项目库",count:S.length},{id:"current",label:"当前队列",count:C.length||Number(B.staged||0)+Number(B.queued||0)+Number(B.running||0)},{id:"completed",label:"已完成",count:v.length||Number(B.succeeded||0)},{id:"failed",label:"失败诊断",count:X.length||Number(B.failed||0)+Number(B.canceled||0)},{id:"gpu",label:"GPU/镜像",count:P.length}];function m(c,o){if(c.length===0)return R(P1,{title:o==="current"?"当前队列为空":"暂无记录",text:o==="current"?"从项目库选择或 fork project 后先加入待启动队列,再启动队列。":"终态任务会显示耗时、exit code 和失败诊断。"});return R("div",{className:"table-wrap met-job-table"},R("table",null,R("thead",null,R("tr",null,R("th",null,"状态"),R("th",null,"Project"),R("th",null,"Epoch"),R("th",null,"速度"),R("th",null,"ETA/耗时"),R("th",null,"GPU"),R("th",null,"Exit"),R("th",null,"更新时间"),R("th",null,"操作"))),R("tbody",null,c.map((e)=>{let Kf=e.progress||{},k=["staged","queued","running"].includes(e.status),Af=r.kind==="job"&&r.key===e.id;return R("tr",{key:e.id,className:`met-click-row ${Af?"active":""}`,onClick:()=>E(e),"data-testid":`met-job-row-${v2(e.id)}`},R("td",null,R(T6,{status:e.status},AK(e.status))),R("td",null,R("button",{type:"button",className:"met-inline-link",onClick:(Yf)=>{Yf.stopPropagation(),E(e)}},e.projectPath),R("code",null,e.id)),R("td",null,R("span",null,`${Kf.currentEpoch??"--"} / ${Kf.epochTarget??e.epochTarget??"--"}`),R("div",{className:"met-progress"},R("span",{style:{width:D6(Kf.progressPercent)}}))),R("td",null,R("strong",null,b2(jK(e)))),R("td",null,e.status==="succeeded"||e.status==="failed"||e.status==="canceled"?rK(e):e.status==="running"?`ETA ${hj(RB(e))}`:"--"),R("td",null,e.gpuName||"--"),R("td",null,e.exitCode??"--"),R("td",null,Nf(e.updatedAt)),R("td",null,k?R("button",{type:"button",className:"ghost-btn mini",onClick:(Yf)=>{Yf.stopPropagation(),Z(e)},disabled:y.actionBusy},"取消"):null,R(T$,{title:`MET Job ${e.id}`,data:e,onOpen:u,testId:`raw-met-job-${e.id}`})))}))))}function s(){return R("div",{className:"met-queue-summary","data-testid":"met-current-summary"},R(T6,{status:"staged"},`待启动 ${B.staged??0}`),R(T6,{status:"queued"},`排队中 ${B.queued??0}`),R(T6,{status:"running"},`训练中 ${B.running??0}`),R("span",null,`最大并发 ${y.summary?.queue?.maxConcurrency??y.queue?.queue?.maxConcurrency??A.maxConcurrency}`),R("span",null,`目标 GPU ${y.summary?.queue?.targetGpuName??y.queue?.queue?.targetGpuName??A.targetGpuName}`))}function d(c,o){let e=A.expandedProjectDirs[c];return e===void 0?o<2:Boolean(e)}function a(c,o){let e=d(c,o);U({expandedProjectDirs:{...A.expandedProjectDirs,[c]:!e}})}function I(c){let o=8+Math.max(0,c.depth)*16;if(Boolean(c.project)){let k=c.project,Af=Boolean(A.selectedProjects[k.projectPath]),Yf=r.kind==="project"&&r.key===k.projectPath;return R("div",{key:c.path,className:`met-tree-row project ${Af?"selected":""} ${Yf?"active":""}`,style:{paddingLeft:o},onClick:()=>N(k),"data-testid":`met-project-node-${v2(k.projectPath)}`},R("div",{className:"met-tree-name"},R("input",{type:"checkbox",checked:Af,onClick:(Bf)=>Bf.stopPropagation(),onChange:(Bf)=>U({selectedProjects:{...A.selectedProjects,[k.projectPath]:Bf.target.checked}}),"data-testid":`met-project-checkbox-${v2(k.projectPath)}`}),R("button",{type:"button",className:"met-inline-link project-path",onClick:(Bf)=>{Bf.stopPropagation(),N(k)}},c.name)),R("span",null,k.useModel||"--"),R("span",null,k.epochTrain??"--"),R("span",null,D6(k.progress?.progressPercent)),R("span",null,b2(k.progress?.epochPerHour)))}let Kf=d(c.path,c.depth);return R(P6.default.Fragment,{key:c.path},R("div",{className:"met-tree-row folder",style:{paddingLeft:o},"data-testid":`met-project-folder-${v2(c.path)}`},R("button",{type:"button",className:"met-tree-toggle",onClick:()=>a(c.path,c.depth),"aria-label":Kf?`折叠 ${c.path}`:`展开 ${c.path}`},Kf?"-":"+"),R("strong",null,c.name),R("span",{className:"met-tree-count"},`${c.count} projects`)),Kf?c.children.map((k)=>I(k)):null)}function ff(c){return R("div",{className:"met-detail-kv"},c.map((o)=>R("div",{key:o.label,className:"met-detail-kv-item"},R("span",null,o.label),R("strong",null,M6(o.value)),o.hint?R("small",null,o.hint):null)))}function yf(c,o){return R("div",{className:"met-detail-section"},R("h3",null,c),ff(o))}function rf(c){if(!Array.isArray(c)||c.length===0)return R(P1,{title:"模型层未上报",text:"等待 data/model_info.json 或 compute_analysis.json 生成。"});return R("div",{className:"table-wrap met-layer-table"},R("table",null,R("thead",null,R("tr",null,R("th",null,"Layer"),R("th",null,"Type"),R("th",null,"Params"),R("th",null,"Trainable"),R("th",null,"Compute"))),R("tbody",null,c.slice(0,18).map((o,e)=>R("tr",{key:`${o.name||"layer"}-${e}`},R("td",null,o.name||`#${e+1}`),R("td",null,o.type||"--"),R("td",null,Ij(o.num_params)),R("td",null,o.trainable===void 0?"--":String(Boolean(o.trainable))),R("td",null,Ij(o.compute?.total??o.estimated_cost?.weighted_units?.total)))))))}function Wf(c){let o=Array.isArray(c)?c:[];if(o.length===0)return R(P1,{title:"data/ 暂无文件",text:"训练或评估完成后会生成 training_state、metrics、model_info 等文件。"});return R("div",{className:"met-file-chip-grid"},o.slice(0,48).map((e)=>R("span",{key:e},e)),o.length>48?R("span",null,`+${o.length-48}`):null)}function Ef(c){let o=String(c||"").replace(/\x1b\[[0-9;]*[A-Za-z]/g,"").split(/\r?\n/).map((e)=>e.trim()).filter(Boolean).slice(-12);if(o.length===0)return R(P1,{title:"暂无日志尾部",text:"该任务未上报 logTail 或日志已轮转。"});return R("div",{className:"met-log-lines"},o.map((e,Kf)=>R("div",{key:`${Kf}-${e.slice(0,16)}`},e)))}function Gf(){if(r.loading)return R("section",{className:"met-detail-panel","data-testid":"met-detail-panel"},R("div",{className:"panel-head compact"},R("div",null,R("p",{className:"panel-eyebrow"},"Detail Loading"),R(j0,{title:"详情加载中",loading:!0}))),R(P1,{title:"详情加载中",text:r.title||"正在读取 D601 data/ 和 config.json"}));if(r.error)return R("section",{className:"met-detail-panel","data-testid":"met-detail-panel"},R(A0,{error:r.error,wide:!0}));if(!r.data)return R("section",{className:"met-detail-panel muted","data-testid":"met-detail-panel"},R(P1,{title:"选择一个项目或任务查看详情",text:"项目库、当前队列、已完成和失败诊断中的行都可以点击;默认只展示结构化字段,原始 JSON 需显式点击按钮。"}));let c=bB(r),o=vB(r),e=Ru(c.config),Kf=Ru(c.progress||o.progress),k=Ru(c.data),Af=Ru(c.metrics||k.metrics||Kf.trainingInfo?.evaluation_metrics),Yf=Ru(k.trainingInfo||Kf.trainingInfo),Bf=Ru(k.trainingState),df=Ru(c.model||k.model),_0=Array.isArray(df.modelSummary)&&df.modelSummary.length>0?df.modelSummary:df.computeLayers,y0=Ru(Yf.evaluation_metrics),N0=r.kind==="job"?"训练任务详情":"Project 详情";return R("section",{className:"met-detail-panel","data-testid":"met-detail-panel"},R("div",{className:"panel-head compact"},R("div",null,R("p",{className:"panel-eyebrow"},r.kind==="job"?"Job + Project Detail":"Project Library Detail"),R(j0,{title:N0}),R("code",null,c.projectPath||o.projectPath||r.title)),R("div",{className:"panel-actions"},R(T$,{title:`MET ${N0}`,data:r.data,onOpen:u,testId:"raw-met-detail"}))),r.kind==="job"?yf("任务状态",[{label:"Job ID",value:o.id},{label:"状态",value:AK(o.status)},{label:"GPU",value:o.gpuName},{label:"Exit Code",value:o.exitCode},{label:"耗时",value:rK(o)},{label:"训练速度",value:b2(jK({...o,progress:Kf}))}]):null,yf("config.json",[{label:"use_model",value:e.use_model},{label:"epoch_train",value:e.epoch_train},{label:"step_per_epoch",value:e.step_per_epoch},{label:"learning_rate",value:e.learning_rate},{label:"using_gpu",value:e.using_gpu},{label:"use_points",value:e.use_points},{label:"sample_rate",value:e.sample_rate},{label:"time_clipped_s",value:e.time_clipped_s},{label:"H_UNITS",value:e.H_UNITS},{label:"INNER_KAN_UNITS",value:e.INNER_KAN_UNITS},{label:"INNER_KAN_LAYERS",value:e.INNER_KAN_LAYERS},{label:"GRID_SIZE",value:e.GRID_SIZE},{label:"SPLINE_ORDER",value:e.SPLINE_ORDER},{label:"USE_FAST_MODEL",value:e.USE_FAST_MODEL},{label:"IIR_TRAINABLE",value:e.IIR_TRAINABLE}]),yf("data/ 训练状态",[{label:"Epoch",value:`${Kf.currentEpoch??Bf.current_epoch??Bf.completed_epoch??"--"} / ${Kf.epochTarget??e.epoch_train??"--"}`},{label:"Progress",value:D6(Kf.progressPercent)},{label:"Last Loss",value:Kf.lastLoss??Bf.loss},{label:"Last Val Loss",value:Kf.lastValLoss??Bf.val_loss},{label:"Min Loss",value:Yf.min_loss??Bf.min_loss},{label:"Min Val Loss",value:Yf.min_val_loss??Bf.min_val_loss},{label:"Log Lines",value:Kf.logLineCount},{label:"ETA",value:hj(Kf.etaSeconds??Bf.remaining_time)},{label:"训练速度",value:b2(Kf.epochPerHour??Bf.smoothed_speed)},{label:"Training Alive",value:Bf.training_alive}]),yf("模型参数",[{label:"Model Type",value:df.modelType??e.use_model},{label:"Total Params",value:df.totalParams,hint:df.totalParams===null||df.totalParams===void 0?"未上报":"data/model_info.json"},{label:"Trainable",value:df.trainableParams},{label:"Non-trainable",value:df.nonTrainableParams},{label:"Compute Cost",value:df.computeCost},{label:"Estimate Status",value:df.estimateStatus},{label:"Unsupported Layers",value:df.unsupportedLayerCount}]),yf("指标",[{label:"train_loss",value:Af.train_loss??y0.train_loss},{label:"val_loss",value:Af.val_loss??y0.val_loss},{label:"train_mae",value:Af.train_mae??y0.train_mae},{label:"val_mae",value:Af.val_mae??y0.val_mae},{label:"train_afmae",value:Af.train_afmae??y0.train_afmae},{label:"val_afmae",value:Af.val_afmae??y0.val_afmae},{label:"freq_drift_hz",value:Af.freq_drift_hz},{label:"sens_drift_percent",value:Af.sens_drift_percent},{label:"linearity_percent",value:Af.linearity_percent},{label:"weights_source",value:Af.weights_source??y0.weights_source},{label:"lr min/mean/max",value:`${M6(Yf.learning_rate_min)} / ${M6(Yf.learning_rate_mean)} / ${M6(Yf.learning_rate_max)}`}]),R("div",{className:"met-detail-section"},R("h3",null,"模型层"),rf(_0)),R("div",{className:"met-detail-section"},R("h3",null,"data/ 文件"),Wf(k.files)),r.kind==="job"?R("div",{className:"met-detail-section"},R("h3",null,"日志尾部"),Ef(Ru(r.data).logTail)):null)}return R("div",{className:"met-page","data-testid":"met-nonlinear-page"},R(vj,{title:"MET Nonlinear 训练编排",eyebrow:"D601 GPU 用户服务",loading:y.loading||y.actionBusy,actions:R("div",{className:"panel-actions"},R("button",{type:"button",className:"ghost-btn",onClick:Q,disabled:y.loading,"data-testid":"met-refresh-button"},y.loading?"刷新中":"刷新"),R(T$,{title:"MET Nonlinear 用户服务",data:_,onOpen:u,testId:"raw-met-service"}))},R("div",{className:"findjob-hero"},R("div",null,R("div",{className:"node-version-line"},R(T6,{status:q.providerStatus==="online"?"online":"warn"},q.providerStatus||"unknown"),R("span",null,_.providerId),R("span",null,w.public?"公网暴露":"仅 UniDesk frontend 代理访问")),R("p",{className:"muted paragraph"},_.description)),R("div",{className:"microservice-ref-card"},R("span",null,"Repo"),R("strong",null,Y.url||"--"),R("code",null,Y.commitId||"--")),R("div",{className:"microservice-ref-card"},R("span",null,"D601 Docker"),R("strong",null,`${w.nodeBindHost||"--"}:${w.nodePort||"--"}`),R("code",null,`${Y.composeFile||"--"} / ${Y.containerName||"--"}`))),R(A0,{error:y.error,wide:!0}),A.actionMessage?R("div",{className:"met-action-log","data-testid":"met-action-message"},A.actionMessage):null),R("div",{className:"met-grid"},R(vj,{title:"核心状态",eyebrow:y.refreshedAt?`Updated ${W0(y.refreshedAt)}`:"Queue + GPU",loading:y.loading},R("div",{className:"metric-grid"},R(N_,{label:"Staged",value:B.staged??0,hint:"加入队列未开始",tone:Number(B.staged||0)>0?"warn":""}),R(N_,{label:"Queued",value:B.queued??0,hint:"排队等待调度",tone:Number(B.queued||0)>0?"warn":""}),R(N_,{label:"Running",value:B.running??0,hint:`max ${y.summary?.queue?.maxConcurrency??y.queue?.queue?.maxConcurrency??"--"}`,tone:Number(B.running||0)>0?"ok":""}),R(N_,{label:"Succeeded",value:B.succeeded??0,hint:"已完成"}),R(N_,{label:"Failed",value:B.failed??0,hint:"需要诊断",tone:Number(B.failed||0)>0?"warn":""}),R(N_,{label:"2080Ti Free",value:h?D6(Number(h.freeRatio)*100):"--",hint:h?`${h.memoryFreeMiB}/${h.memoryTotalMiB} MiB`:"等待 GPU 上报"}),R(N_,{label:"ML Image",value:M.present?"READY":"MISSING",hint:M.image||"met-nonlinear-ml:tf26",tone:M.present?"ok":"warn"}),R(N_,{label:"Health",value:y.health?.ok?"OK":"--",hint:"D601 /health"}))),R(vj,{title:"队列控制",eyebrow:"Downloader-like staging",loading:y.actionBusy},R("div",{className:"met-control-strip"},R("label",null,"最大并发",R("input",{type:"number",min:1,max:16,value:A.maxConcurrency,"data-testid":"met-max-concurrency-input",onChange:(c)=>U({maxConcurrency:c.target.value})})),R("label",null,"目标 GPU",R("input",{value:A.targetGpuName,"data-testid":"met-target-gpu-input",onChange:(c)=>U({targetGpuName:c.target.value})})),R("button",{type:"button",className:"ghost-btn",onClick:G,disabled:y.actionBusy,"data-testid":"met-save-settings-button"},"保存设置"),R("button",{type:"button",className:"primary-btn",onClick:z,disabled:y.actionBusy||Number(B.staged||0)===0,"data-testid":"met-start-queue-button"},"启动队列")),R("p",{className:"muted paragraph"},"Project 先进入待启动队列,不会立即训练;点击启动队列后才切换为排队中,并由 D601 scheduler 按最大并发和 2080Ti 显存策略调度。")),R("section",{className:"panel met-workspace"},R("div",{className:"met-tabs",role:"tablist"},p.map((c)=>R("button",{key:c.id,type:"button",className:A.activeTab===c.id?"active":"",onClick:()=>U({activeTab:c.id}),"data-testid":`met-tab-${c.id}`},`${c.label} ${c.count}`))),R("div",{className:"panel-body"},A.activeTab==="projects"?R("div",{className:"met-form-grid","data-testid":"met-projects-pane"},R("div",{className:"met-fork-card"},R("h3",null,"Fork Project"),R("label",null,"源 Project",R("select",{value:i,"data-testid":"met-source-project-select",onChange:(c)=>U({sourceProject:c.target.value})},S.map((c)=>R("option",{key:c.projectPath,value:c.projectPath},`${c.projectPath} · ${c.useModel||"model?"}`)))),R("label",null,"Fork 数量",R("input",{type:"number",min:1,max:100,value:A.forkCount,"data-testid":"met-fork-count-input",onChange:(c)=>U({forkCount:c.target.value})})),R("label",null,"训练轮数",R("input",{type:"number",min:1,max:1e5,value:A.forkEpochs,"data-testid":"met-fork-epochs-input",onChange:(c)=>U({forkEpochs:c.target.value})})),R("label",null,"目标前缀",R("input",{value:A.forkPrefix,"data-testid":"met-fork-prefix-input",onChange:(c)=>U({forkPrefix:c.target.value})})),R("button",{type:"button",className:"primary-btn",onClick:O,disabled:y.actionBusy||!i,"data-testid":"met-fork-button"},"Fork Project"),R("p",{className:"muted paragraph"},"Fork 只创建新 Project 并自动勾选,不会直接训练;需要在右侧确认后加入待启动队列。")),R("div",{className:"met-project-list"},R("div",{className:"panel-head compact"},R("div",null,R("p",{className:"panel-eyebrow"},`Existing Projects · ${(y.projects?.roots||[]).map((c)=>`${c.root} ${c.count}`).join(" / ")}`),R(j0,{title:"选择已有 Project",loading:y.loading||y.actionBusy})),R("button",{type:"button",className:"ghost-btn",onClick:H,disabled:y.actionBusy||K().length===0,"data-testid":"met-stage-selected-button"},`加入待启动队列 (${K().length})`)),S.length===0?R(P1,{title:"暂无 project",text:"等待 D601 返回 /api/projects"}):R("div",{className:"met-project-table","data-testid":"met-project-tree"},R("div",{className:"met-tree-header"},R("span",null,"文件树 Project"),R("span",null,"Model"),R("span",null,"Epochs"),R("span",null,"Progress"),R("span",null,"速度")),T.children.map((c)=>I(c)))),Gf()):null,A.activeTab==="current"?R("div",{"data-testid":"met-current-pane"},s(),m(C,"current"),Gf(),R("div",{className:"panel-actions inline-actions"},R(T$,{title:"MET Queue",data:y.queue,onOpen:u,testId:"raw-met-queue"}))):null,A.activeTab==="completed"?R("div",{"data-testid":"met-completed-pane"},m(v.length>0?v:D.filter((c)=>c.status==="succeeded"),"completed"),Gf()):null,A.activeTab==="failed"?R("div",{"data-testid":"met-failed-pane"},m(X.length>0?X:D.filter((c)=>["failed","canceled"].includes(c.status)),"failed"),Gf(),R("div",{className:"panel-actions inline-actions"},R(T$,{title:"MET History",data:y.history,onOpen:u,testId:"raw-met-history"}))):null,A.activeTab==="gpu"?R("div",{className:"met-gpu-pane","data-testid":"met-gpu-pane"},P.length===0?R(P1,{title:"暂无 GPU 上报",text:"等待 D601 met-nonlinear-ts 或 ML image 提供 nvidia-smi 数据"}):R("div",{className:"table-wrap"},R("table",null,R("thead",null,R("tr",null,R("th",null,"Index"),R("th",null,"Name"),R("th",null,"Free"),R("th",null,"Policy"))),R("tbody",null,P.map((c)=>R("tr",{key:c.index},R("td",null,c.index),R("td",null,c.name),R("td",null,`${c.memoryFreeMiB} / ${c.memoryTotalMiB} MiB`,R("div",{className:"met-progress"},R("span",{style:{width:D6(Number(c.freeRatio)*100)}}))),R("td",null,String(c.name||"").includes("2080")?"target 2080Ti, <20% 限制并发":"non-target")))))),R("div",{className:"panel-actions inline-actions"},R(T$,{title:"MET Images",data:y.images,onOpen:u,testId:"raw-met-images"}))):null))))}var p2=[{id:"ops",label:"运行总览",code:"OPS",tabs:[{id:"status",label:"态势总览"},{id:"performance",label:"性能面板"},{id:"events",label:"事件摘要"},{id:"logs",label:"服务日志"}]},{id:"nodes",label:"资源节点",code:"NODE",tabs:[{id:"list",label:"节点清单"},{id:"monitor",label:"资源监控"},{id:"docker",label:"Docker 状态"},{id:"gateway",label:"网关版本"},{id:"labels",label:"资源标签"},{id:"heartbeats",label:"心跳状态"}]},{id:"tasks",label:"任务调度",code:"TASK",tabs:[{id:"dispatch",label:"下发任务"},{id:"scheduled",label:"定时任务"},{id:"pending",label:"待处理任务"},{id:"history",label:"任务历史"},{id:"results",label:"执行结果"}]},{id:"apps",label:"用户服务",code:"APP",routeSegment:"app",tabs:[{id:"catalog",label:"服务目录"},{id:"todo-note",label:"Todo Note"},{id:"findjob",label:"FindJob"},{id:"pipeline",label:"Pipeline"},{id:"met-nonlinear",label:"MET Nonlinear"},{id:"claudeqq",label:"ClaudeQQ"},{id:"baidu-netdisk",label:"Baidu Netdisk"},{id:"filebrowser",label:"File Browser"},{id:"code-queue",label:"Code Queue"},{id:"project-manager",label:"Project Manager"}]},{id:"config",label:"系统配置",code:"CFG",tabs:[{id:"topology",label:"连接拓扑"},{id:"auth",label:"认证策略"},{id:"security",label:"安全边界"}]}],n6=Object.fromEntries(p2.map((f)=>[f.id,f.tabs[0]?.id??""]));function hB(f){let u=String(f||"").trim();if(!u)return"";try{return decodeURIComponent(u)}catch{return u}}function I2(f){let u=String(f||"/"),[l]=u.split(/[?#]/u,1);if(l==="/")return"/";let y=`/${l.split("/").map(hB).filter(Boolean).join("/")}`;return y.endsWith("/")?y:`${y}/`}function IB(f){let u=2166136261;for(let l of f)u^=l.charCodeAt(0),u=Math.imul(u,16777619);return Math.abs(u>>>0).toString(36)}function pj(f){return String(f||"").normalize("NFKD").replace(/[\u0300-\u036f]/gu,"").toLowerCase().replace(/[^a-z0-9]+/gu,"-").replace(/^-+|-+$/gu,"")}function UK(f){return String(f||"").trim().toLowerCase().replace(/[\s/\\?#%]+/gu,"-").replace(/-+/gu,"-").replace(/^-+|-+$/gu,"")}function QK(f){let u=pj(f.routeSegment||"")||UK(f.routeSegment||"");if(u)return u;let l=pj(f.id||"");if(l)return l;let _=pj(f.label||"")||UK(f.label||"");if(_)return _;return`route-${IB(JSON.stringify(f))}`}function mj(f,u){return`${f}:${u}`}function WK(f){let u=f.map((A)=>{let J=QK(A);return{...A,routeSegment:J,tabs:A.tabs.map((U)=>({...U,routeSegment:QK(U)}))}}),l={},_={},y={},$=u.map((A)=>{let J=A.tabs[0]?.id??"";y[A.id]=J;let U=A.tabs.map((G)=>{let K=`/${A.routeSegment}/${G.routeSegment}/`,H=[K],O={moduleId:A.id,tabId:G.id};for(let z of H)l[I2(z)]=O;return _[mj(A.id,G.id)]=K,{...G,canonicalPath:K,aliases:H}}),Q=`/${A.routeSegment}/`,W={moduleId:A.id,tabId:J};return l[I2(Q)]=W,{...A,routeSegment:A.routeSegment,canonicalPath:Q,tabs:U}}),r=$[0],j={moduleId:r?.id||"",tabId:r?.tabs[0]?.id||""};return l["/"]=j,{modules:$,moduleById:Object.fromEntries($.map((A)=>[A.id,A])),defaultActiveTabs:y,routeMap:l,canonicalPathByTarget:_,fallbackTarget:j}}function gj(f,u){return f.routeMap[I2(u)]||f.fallbackTarget}function m2(f,u,l){return f.canonicalPathByTarget[mj(u,l)]||f.canonicalPathByTarget[mj(f.fallbackTarget.moduleId,f.fallbackTarget.tabId)]||"/"}function zK(f,u){let l=f.routeMap[I2(u)];if(!l)return null;return m2(f,l.moduleId,l.tabId)}var M_=cf(O0(),1);var lf=cf(ZK(),1),_f=cf(O0(),1);function M0(f){if(typeof f==="string"||typeof f==="number")return""+f;let u="";if(Array.isArray(f)){for(let l=0,_;l{}};function HK(){for(var f=0,u=arguments.length,l={},_;f=0)_=l.slice(y+1),l=l.slice(0,y);if(l&&!u.hasOwnProperty(l))throw Error("unknown type: "+l);return{type:l,name:_}})}k2.prototype=HK.prototype={constructor:k2,on:function(f,u){var l=this._,_=aB(f+"",l),y,$=-1,r=_.length;if(arguments.length<2){while(++$0)for(var l=Array(y),_=0,y,$;_=0&&(u=f.slice(0,l))!=="xmlns")f=f.slice(l+1);return kj.hasOwnProperty(u)?{space:kj[u],local:f}:f}function tj(f){let u;while(u=f.sourceEvent)f=u;return f}function zu(f,u){if(f=tj(f),u===void 0)u=f.currentTarget;if(u){var l=u.ownerSVGElement||u;if(l.createSVGPoint){var _=l.createSVGPoint();return _.x=f.clientX,_.y=f.clientY,_=_.matrixTransform(u.getScreenCTM().inverse()),[_.x,_.y]}if(u.getBoundingClientRect){var y=u.getBoundingClientRect();return[f.clientX-y.left-u.clientLeft,f.clientY-y.top-u.clientTop]}}return[f.pageX,f.pageY]}function eB(){}function Z_(f){return f==null?eB:function(){return this.querySelector(f)}}function sj(f){if(typeof f!=="function")f=Z_(f);for(var u=this._groups,l=u.length,_=Array(l),y=0;y=N)N=Z+1;while(!(q=O[N])&&++N=0;)if(r=_[y]){if($&&r.compareDocumentPosition($)^4)$.parentNode.insertBefore(r,$);$=r}return this}function AA(f){if(!f)f=QY;function u(Q,W){return Q&&W?f(Q.__data__,W.__data__):!Q-!W}for(var l=this._groups,_=l.length,y=Array(_),$=0;$<_;++$){for(var r=l[$],j=r.length,A=y[$]=Array(j),J,U=0;Uu?1:f>=u?0:NaN}function FA(){var f=arguments[0];return arguments[0]=this,f.apply(null,arguments),this}function JA(){return Array.from(this)}function UA(){for(var f=this._groups,u=0,l=f.length;u1?this.each((u==null?EY:typeof u==="function"?OY:HY)(f,u,l==null?"":l)):E_(this.node(),f)}function E_(f,u){return f.style.getPropertyValue(u)||i6(f).getComputedStyle(f,null).getPropertyValue(u)}function VY(f){return function(){delete this[f]}}function qY(f,u){return function(){this[f]=u}}function LY(f,u){return function(){var l=u.apply(this,arguments);if(l==null)delete this[f];else this[f]=l}}function NA(f,u){return arguments.length>1?this.each((u==null?VY:typeof u==="function"?LY:qY)(f,u)):this.node()[f]}function OK(f){return f.trim().split(/^|\s+/)}function ZA(f){return f.classList||new VK(f)}function VK(f){this._node=f,this._names=OK(f.getAttribute("class")||"")}VK.prototype={add:function(f){var u=this._names.indexOf(f);if(u<0)this._names.push(f),this._node.setAttribute("class",this._names.join(" "))},remove:function(f){var u=this._names.indexOf(f);if(u>=0)this._names.splice(u,1),this._node.setAttribute("class",this._names.join(" "))},contains:function(f){return this._names.indexOf(f)>=0}};function qK(f,u){var l=ZA(f),_=-1,y=u.length;while(++_=0)l=u.slice(_+1),u=u.slice(0,_);return{type:u,name:l}})}function pY(f){return function(){var u=this.__on;if(!u)return;for(var l=0,_=-1,y=u.length,$;l()=>f;function b6(f,{sourceEvent:u,subject:l,target:_,identifier:y,active:$,x:r,y:j,dx:A,dy:J,dispatch:U}){Object.defineProperties(this,{type:{value:f,enumerable:!0,configurable:!0},sourceEvent:{value:u,enumerable:!0,configurable:!0},subject:{value:l,enumerable:!0,configurable:!0},target:{value:_,enumerable:!0,configurable:!0},identifier:{value:y,enumerable:!0,configurable:!0},active:{value:$,enumerable:!0,configurable:!0},x:{value:r,enumerable:!0,configurable:!0},y:{value:j,enumerable:!0,configurable:!0},dx:{value:A,enumerable:!0,configurable:!0},dy:{value:J,enumerable:!0,configurable:!0},_:{value:U}})}b6.prototype.on=function(){var f=this._.on.apply(this._,arguments);return f===this._?this:f};function lw(f){return!f.ctrlKey&&!f.button}function _w(){return this.parentNode}function yw(f,u){return u==null?{x:f.x,y:f.y}:u}function $w(){return navigator.maxTouchPoints||"ontouchstart"in this}function v6(){var f=lw,u=_w,l=yw,_=$w,y={},$=Ky("start","drag","end"),r=0,j,A,J,U,Q=0;function W(E){E.on("mousedown.drag",G).filter(_).on("touchstart.drag",O).on("touchmove.drag",z,YK).on("touchend.drag touchcancel.drag",Z).style("touch-action","none").style("-webkit-tap-highlight-color","rgba(0,0,0,0)")}function G(E,q){if(U||!f.call(this,E,q))return;var Y=N(this,u.call(this,E,q),E,q,"mouse");if(!Y)return;g0(E.view).on("mousemove.drag",K,Ny).on("mouseup.drag",H,Ny),n$(E.view),o2(E),J=!1,j=E.clientX,A=E.clientY,Y("start",E)}function K(E){if(S1(E),!J){var q=E.clientX-j,Y=E.clientY-A;J=q*q+Y*Y>Q}y.mouse("drag",E)}function H(E){g0(E.view).on("mousemove.drag mouseup.drag",null),R6(E.view,J),S1(E),y.mouse("end",E)}function O(E,q){if(!f.call(this,E,q))return;var Y=E.changedTouches,w=u.call(this,E,q),B=Y.length,P,h;for(P=0;P>8&15|u>>4&240,u>>4&15|u&240,(u&15)<<4|u&15,1):l===8?a2(u>>24&255,u>>16&255,u>>8&255,(u&255)/255):l===4?a2(u>>12&15|u>>8&240,u>>8&15|u>>4&240,u>>4&15|u&240,((u&15)<<4|u&15)/255):null):(u=jw.exec(f))?new xu(u[1],u[2],u[3],1):(u=Aw.exec(f))?new xu(u[1]*255/100,u[2]*255/100,u[3]*255/100,1):(u=Fw.exec(f))?a2(u[1],u[2],u[3],u[4]):(u=Jw.exec(f))?a2(u[1]*255/100,u[2]*255/100,u[3]*255/100,u[4]):(u=Uw.exec(f))?SK(u[1],u[2]/100,u[3]/100,1):(u=Qw.exec(f))?SK(u[1],u[2]/100,u[3]/100,u[4]):wK.hasOwnProperty(f)?MK(wK[f]):f==="transparent"?new xu(NaN,NaN,NaN,0):null}function MK(f){return new xu(f>>16&255,f>>8&255,f&255,1)}function a2(f,u,l,_){if(_<=0)f=u=l=NaN;return new xu(f,u,l,_)}function Gw(f){if(!(f instanceof m6))f=bl(f);if(!f)return new xu;return f=f.rgb(),new xu(f.r,f.g,f.b,f.opacity)}function C$(f,u,l,_){return arguments.length===1?Gw(f):new xu(f,u,l,_==null?1:_)}function xu(f,u,l,_){this.r=+f,this.g=+u,this.b=+l,this.opacity=+_}h6(xu,C$,nA(m6,{brighter(f){return f=f==null?e2:Math.pow(e2,f),new xu(this.r*f,this.g*f,this.b*f,this.opacity)},darker(f){return f=f==null?I6:Math.pow(I6,f),new xu(this.r*f,this.g*f,this.b*f,this.opacity)},rgb(){return this},clamp(){return new xu(Ey(this.r),Ey(this.g),Ey(this.b),f5(this.opacity))},displayable(){return-0.5<=this.r&&this.r<255.5&&(-0.5<=this.g&&this.g<255.5)&&(-0.5<=this.b&&this.b<255.5)&&(0<=this.opacity&&this.opacity<=1)},hex:PK,formatHex:PK,formatHex8:Kw,formatRgb:nK,toString:nK}));function PK(){return`#${Zy(this.r)}${Zy(this.g)}${Zy(this.b)}`}function Kw(){return`#${Zy(this.r)}${Zy(this.g)}${Zy(this.b)}${Zy((isNaN(this.opacity)?1:this.opacity)*255)}`}function nK(){let f=f5(this.opacity);return`${f===1?"rgb(":"rgba("}${Ey(this.r)}, ${Ey(this.g)}, ${Ey(this.b)}${f===1?")":`, ${f})`}`}function f5(f){return isNaN(f)?1:Math.max(0,Math.min(1,f))}function Ey(f){return Math.max(0,Math.min(255,Math.round(f)||0))}function Zy(f){return f=Ey(f),(f<16?"0":"")+f.toString(16)}function SK(f,u,l,_){if(_<=0)f=u=l=NaN;else if(l<=0||l>=1)f=u=NaN;else if(u<=0)f=NaN;return new xl(f,u,l,_)}function iK(f){if(f instanceof xl)return new xl(f.h,f.s,f.l,f.opacity);if(!(f instanceof m6))f=bl(f);if(!f)return new xl;if(f instanceof xl)return f;f=f.rgb();var u=f.r/255,l=f.g/255,_=f.b/255,y=Math.min(u,l,_),$=Math.max(u,l,_),r=NaN,j=$-y,A=($+y)/2;if(j){if(u===$)r=(l-_)/j+(l<_)*6;else if(l===$)r=(_-u)/j+2;else r=(u-l)/j+4;j/=A<0.5?$+y:2-$-y,r*=60}else j=A>0&&A<1?0:r;return new xl(r,j,A,f.opacity)}function cK(f,u,l,_){return arguments.length===1?iK(f):new xl(f,u,l,_==null?1:_)}function xl(f,u,l,_){this.h=+f,this.s=+u,this.l=+l,this.opacity=+_}h6(xl,cK,nA(m6,{brighter(f){return f=f==null?e2:Math.pow(e2,f),new xl(this.h,this.s,this.l*f,this.opacity)},darker(f){return f=f==null?I6:Math.pow(I6,f),new xl(this.h,this.s,this.l*f,this.opacity)},rgb(){var f=this.h%360+(this.h<0)*360,u=isNaN(f)||isNaN(this.s)?0:this.s,l=this.l,_=l+(l<0.5?l:1-l)*u,y=2*l-_;return new xu(SA(f>=240?f-240:f+120,y,_),SA(f,y,_),SA(f<120?f+240:f-120,y,_),this.opacity)},clamp(){return new xl(CK(this.h),d2(this.s),d2(this.l),f5(this.opacity))},displayable(){return(0<=this.s&&this.s<=1||isNaN(this.s))&&(0<=this.l&&this.l<=1)&&(0<=this.opacity&&this.opacity<=1)},formatHsl(){let f=f5(this.opacity);return`${f===1?"hsl(":"hsla("}${CK(this.h)}, ${d2(this.s)*100}%, ${d2(this.l)*100}%${f===1?")":`, ${f})`}`}}));function CK(f){return f=(f||0)%360,f<0?f+360:f}function d2(f){return Math.max(0,Math.min(1,f||0))}function SA(f,u,l){return(f<60?u+(l-u)*f/60:f<180?l:f<240?u+(l-u)*(240-f)/60:u)*255}function CA(f,u,l,_,y){var $=f*f,r=$*f;return((1-3*f+3*$-r)*u+(4-6*$+3*r)*l+(1+3*f+3*$-3*r)*_+r*y)/6}function iA(f){var u=f.length-1;return function(l){var _=l<=0?l=0:l>=1?(l=1,u-1):Math.floor(l*u),y=f[_],$=f[_+1],r=_>0?f[_-1]:2*y-$,j=_()=>f;function Zw(f,u){return function(l){return f+l*u}}function Ew(f,u,l){return f=Math.pow(f,l),u=Math.pow(u,l)-f,l=1/l,function(_){return Math.pow(f+_*u,l)}}function RK(f){return(f=+f)===1?l5:function(u,l){return l-u?Ew(u,l,f):g6(isNaN(u)?l:u)}}function l5(f,u){var l=u-f;return l?Zw(f,l):g6(isNaN(f)?u:f)}var Hy=function f(u){var l=RK(u);function _(y,$){var r=l((y=C$(y)).r,($=C$($)).r),j=l(y.g,$.g),A=l(y.b,$.b),J=l5(y.opacity,$.opacity);return function(U){return y.r=r(U),y.g=j(U),y.b=A(U),y.opacity=J(U),y+""}}return _.gamma=f,_}(1);function xK(f){return function(u){var l=u.length,_=Array(l),y=Array(l),$=Array(l),r,j;for(r=0;rl)if($=u.slice(l,$),j[r])j[r]+=$;else j[++r]=$;if((_=_[0])===(y=y[0]))if(j[r])j[r]+=y;else j[++r]=y;else j[++r]=null,A.push({i:r,x:Gu(_,y)});l=vA.lastIndex}if(l180)U+=360;else if(U-J>180)J+=360;W.push({i:Q.push(y(Q)+"rotate(",null,_)-2,x:Gu(J,U)})}else if(U)Q.push(y(Q)+"rotate("+U+_)}function j(J,U,Q,W){if(J!==U)W.push({i:Q.push(y(Q)+"skewX(",null,_)-2,x:Gu(J,U)});else if(U)Q.push(y(Q)+"skewX("+U+_)}function A(J,U,Q,W,G,K){if(J!==Q||U!==W){var H=G.push(y(G)+"scale(",null,",",null,")");K.push({i:H-4,x:Gu(J,Q)},{i:H-2,x:Gu(U,W)})}else if(Q!==1||W!==1)G.push(y(G)+"scale("+Q+","+W+")")}return function(J,U){var Q=[],W=[];return J=f(J),U=f(U),$(J.translateX,J.translateY,U.translateX,U.translateY,Q,W),r(J.rotate,U.rotate,Q,W),j(J.skewX,U.skewX,Q,W),A(J.scaleX,J.scaleY,U.scaleX,U.scaleY,Q,W),J=U=null,function(G){var K=-1,H=W.length,O;while(++K=0)f._call.call(void 0,u);f=f._next}--c$}function oK(){Vy=(j5=o6.now())+A5,c$=t6=0;try{eK()}finally{c$=0,vw(),Vy=0}}function bw(){var f=o6.now(),u=f-j5;if(u>aK)A5-=u,j5=f}function vw(){var f,u=r5,l,_=1/0;while(u)if(u._call){if(_>u._time)_=u._time;f=u,u=u._next}else l=u._next,u._next=null,u=f?f._next=l:r5=l;s6=f,mA(_)}function mA(f){if(c$)return;if(t6)t6=clearTimeout(t6);var u=f-Vy;if(u>24){if(f<1/0)t6=setTimeout(oK,f-o6.now()-A5);if(k6)k6=clearInterval(k6)}else{if(!k6)j5=o6.now(),k6=setInterval(bw,aK);c$=1,dK(oK)}}function e6(f,u,l){var _=new a6;return u=u==null?0:+u,_.restart((y)=>{_.stop(),f(y+u)},u,l),_}var Iw=Ky("start","end","cancel","interrupt"),pw=[],lN=0,fN=1,U5=2,J5=3,uN=4,Q5=5,f4=6;function C1(f,u,l,_,y,$){var r=f.__transition;if(!r)f.__transition={};else if(l in r)return;mw(f,l,{name:u,index:_,group:y,on:Iw,tween:pw,time:$.time,delay:$.delay,duration:$.duration,ease:$.ease,timer:null,state:lN})}function u4(f,u){var l=k0(f,u);if(l.state>lN)throw Error("too late; already scheduled");return l}function $u(f,u){var l=k0(f,u);if(l.state>J5)throw Error("too late; already running");return l}function k0(f,u){var l=f.__transition;if(!l||!(l=l[u]))throw Error("transition not found");return l}function mw(f,u,l){var _=f.__transition,y;_[u]=l,l.timer=F5($,0,l.time);function $(J){if(l.state=fN,l.timer.restart(r,l.delay,l.time),l.delay<=J)r(J-l.delay)}function r(J){var U,Q,W,G;if(l.state!==fN)return A();for(U in _){if(G=_[U],G.name!==l.name)continue;if(G.state===J5)return e6(r);if(G.state===uN)G.state=f4,G.timer.stop(),G.on.call("interrupt",f,f.__data__,G.index,G.group),delete _[U];else if(+UU5&&_.state=0)u=u.slice(0,l);return!u||u==="start"})}function UD(f,u,l){var _,y,$=JD(u)?u4:$u;return function(){var r=$(this,f),j=r.on;if(j!==_)(y=(_=j).copy()).on(u,l);r.on=y}}function lF(f,u){var l=this._id;return arguments.length<2?k0(this.node(),l).on.on(f):this.each(UD(l,f,u))}function QD(f){return function(){var u=this.parentNode;for(var l in this.__transition)if(+l!==f)return;if(u)u.removeChild(this)}}function _F(){return this.on("end.remove",QD(this._id))}function yF(f){var u=this._name,l=this._id;if(typeof f!=="function")f=Z_(f);for(var _=this._groups,y=_.length,$=Array(y),r=0;r()=>f;function zF(f,{sourceEvent:u,target:l,transform:_,dispatch:y}){Object.defineProperties(this,{type:{value:f,enumerable:!0,configurable:!0},sourceEvent:{value:u,enumerable:!0,configurable:!0},target:{value:l,enumerable:!0,configurable:!0},transform:{value:_,enumerable:!0,configurable:!0},_:{value:y}})}function vl(f,u,l){this.k=f,this.x=u,this.y=l}vl.prototype={constructor:vl,scale:function(f){return f===1?this:new vl(this.k*f,this.x,this.y)},translate:function(f,u){return f===0&u===0?this:new vl(this.k,this.x+this.k*f,this.y+this.k*u)},apply:function(f){return[f[0]*this.k+this.x,f[1]*this.k+this.y]},applyX:function(f){return f*this.k+this.x},applyY:function(f){return f*this.k+this.y},invert:function(f){return[(f[0]-this.x)/this.k,(f[1]-this.y)/this.k]},invertX:function(f){return(f-this.x)/this.k},invertY:function(f){return(f-this.y)/this.k},rescaleX:function(f){return f.copy().domain(f.range().map(this.invertX,this).map(f.invert,f))},rescaleY:function(f){return f.copy().domain(f.range().map(this.invertY,this).map(f.invert,f))},toString:function(){return"translate("+this.x+","+this.y+") scale("+this.k+")"}};var qy=new vl(1,0,0);y4.prototype=vl.prototype;function y4(f){while(!f.__zoom)if(!(f=f.parentNode))return qy;return f.__zoom}function q5(f){f.stopImmediatePropagation()}function Ly(f){f.preventDefault(),f.stopImmediatePropagation()}function wD(f){return(!f.ctrlKey||f.type==="wheel")&&!f.button}function DD(){var f=this;if(f instanceof SVGElement){if(f=f.ownerSVGElement||f,f.hasAttribute("viewBox"))return f=f.viewBox.baseVal,[[f.x,f.y],[f.x+f.width,f.y+f.height]];return[[0,0],[f.width.baseVal.value,f.height.baseVal.value]]}return[[0,0],[f.clientWidth,f.clientHeight]]}function $N(){return this.__zoom||qy}function TD(f){return-f.deltaY*(f.deltaMode===1?0.05:f.deltaMode?1:0.002)*(f.ctrlKey?10:1)}function MD(){return navigator.maxTouchPoints||"ontouchstart"in this}function PD(f,u,l){var _=f.invertX(u[0][0])-l[0][0],y=f.invertX(u[1][0])-l[1][0],$=f.invertY(u[0][1])-l[0][1],r=f.invertY(u[1][1])-l[1][1];return f.translate(y>_?(_+y)/2:Math.min(0,_)||Math.max(0,y),r>$?($+r)/2:Math.min(0,$)||Math.max(0,r))}function $4(){var f=wD,u=DD,l=PD,_=TD,y=MD,$=[0,1/0],r=[[-1/0,-1/0],[1/0,1/0]],j=250,A=Oy,J=Ky("start","zoom","end"),U,Q,W,G=500,K=150,H=0,O=10;function z(T){T.property("__zoom",$N).on("wheel.zoom",B,{passive:!1}).on("mousedown.zoom",P).on("dblclick.zoom",h).filter(y).on("touchstart.zoom",M).on("touchmove.zoom",n).on("touchend.zoom touchcancel.zoom",S).style("-webkit-tap-highlight-color","rgba(0,0,0,0)")}z.transform=function(T,i,C,v){var X=T.selection?T.selection():T;if(X.property("__zoom",$N),T!==X)q(T,i,C,v);else X.interrupt().each(function(){Y(this,arguments).event(v).start().zoom(null,typeof i==="function"?i.apply(this,arguments):i).end()})},z.scaleBy=function(T,i,C,v){z.scaleTo(T,function(){var X=this.__zoom.k,D=typeof i==="function"?i.apply(this,arguments):i;return X*D},C,v)},z.scaleTo=function(T,i,C,v){z.transform(T,function(){var X=u.apply(this,arguments),D=this.__zoom,p=C==null?E(X):typeof C==="function"?C.apply(this,arguments):C,m=D.invert(p),s=typeof i==="function"?i.apply(this,arguments):i;return l(N(Z(D,s),p,m),X,r)},C,v)},z.translateBy=function(T,i,C,v){z.transform(T,function(){return l(this.__zoom.translate(typeof i==="function"?i.apply(this,arguments):i,typeof C==="function"?C.apply(this,arguments):C),u.apply(this,arguments),r)},null,v)},z.translateTo=function(T,i,C,v,X){z.transform(T,function(){var D=u.apply(this,arguments),p=this.__zoom,m=v==null?E(D):typeof v==="function"?v.apply(this,arguments):v;return l(qy.translate(m[0],m[1]).scale(p.k).translate(typeof i==="function"?-i.apply(this,arguments):-i,typeof C==="function"?-C.apply(this,arguments):-C),D,r)},v,X)};function Z(T,i){return i=Math.max($[0],Math.min($[1],i)),i===T.k?T:new vl(i,T.x,T.y)}function N(T,i,C){var v=i[0]-C[0]*T.k,X=i[1]-C[1]*T.k;return v===T.x&&X===T.y?T:new vl(T.k,v,X)}function E(T){return[(+T[0][0]+ +T[1][0])/2,(+T[0][1]+ +T[1][1])/2]}function q(T,i,C,v){T.on("start.zoom",function(){Y(this,arguments).event(v).start()}).on("interrupt.zoom end.zoom",function(){Y(this,arguments).event(v).end()}).tween("zoom",function(){var X=this,D=arguments,p=Y(X,D).event(v),m=u.apply(X,D),s=C==null?E(m):typeof C==="function"?C.apply(X,D):C,d=Math.max(m[1][0]-m[0][0],m[1][1]-m[0][1]),a=X.__zoom,I=typeof i==="function"?i.apply(X,D):i,ff=A(a.invert(s).concat(d/a.k),I.invert(s).concat(d/I.k));return function(yf){if(yf===1)yf=I;else{var rf=ff(yf),Wf=d/rf[2];yf=new vl(Wf,s[0]-rf[0]*Wf,s[1]-rf[1]*Wf)}p.zoom(null,yf)}})}function Y(T,i,C){return!C&&T.__zooming||new w(T,i)}function w(T,i){this.that=T,this.args=i,this.active=0,this.sourceEvent=null,this.extent=u.apply(T,i),this.taps=0}w.prototype={event:function(T){if(T)this.sourceEvent=T;return this},start:function(){if(++this.active===1)this.that.__zooming=this,this.emit("start");return this},zoom:function(T,i){if(this.mouse&&T!=="mouse")this.mouse[1]=i.invert(this.mouse[0]);if(this.touch0&&T!=="touch")this.touch0[1]=i.invert(this.touch0[0]);if(this.touch1&&T!=="touch")this.touch1[1]=i.invert(this.touch1[0]);return this.that.__zoom=i,this.emit("zoom"),this},end:function(){if(--this.active===0)delete this.that.__zooming,this.emit("end");return this},emit:function(T){var i=g0(this.that).datum();J.call(T,this.that,new zF(T,{sourceEvent:this.sourceEvent,target:z,type:T,transform:this.that.__zoom,dispatch:J}),i)}};function B(T,...i){if(!f.apply(this,arguments))return;var C=Y(this,i).event(T),v=this.__zoom,X=Math.max($[0],Math.min($[1],v.k*Math.pow(2,_.apply(this,arguments)))),D=zu(T);if(C.wheel){if(C.mouse[0][0]!==D[0]||C.mouse[0][1]!==D[1])C.mouse[1]=v.invert(C.mouse[0]=D);clearTimeout(C.wheel)}else if(v.k===X)return;else C.mouse=[D,v.invert(D)],H_(this),C.start();Ly(T),C.wheel=setTimeout(p,K),C.zoom("mouse",l(N(Z(v,X),C.mouse[0],C.mouse[1]),C.extent,r));function p(){C.wheel=null,C.end()}}function P(T,...i){if(W||!f.apply(this,arguments))return;var C=T.currentTarget,v=Y(this,i,!0).event(T),X=g0(T.view).on("mousemove.zoom",s,!0).on("mouseup.zoom",d,!0),D=zu(T,C),p=T.clientX,m=T.clientY;n$(T.view),q5(T),v.mouse=[D,this.__zoom.invert(D)],H_(this),v.start();function s(a){if(Ly(a),!v.moved){var I=a.clientX-p,ff=a.clientY-m;v.moved=I*I+ff*ff>H}v.event(a).zoom("mouse",l(N(v.that.__zoom,v.mouse[0]=zu(a,C),v.mouse[1]),v.extent,r))}function d(a){X.on("mousemove.zoom mouseup.zoom",null),R6(a.view,v.moved),Ly(a),v.event(a).end()}}function h(T,...i){if(!f.apply(this,arguments))return;var C=this.__zoom,v=zu(T.changedTouches?T.changedTouches[0]:T,this),X=C.invert(v),D=C.k*(T.shiftKey?0.5:2),p=l(N(Z(C,D),v,X),u.apply(this,i),r);if(Ly(T),j>0)g0(this).transition().duration(j).call(q,p,v,T);else g0(this).call(z.transform,p,v,T)}function M(T,...i){if(!f.apply(this,arguments))return;var C=T.touches,v=C.length,X=Y(this,i,T.changedTouches.length===v).event(T),D,p,m,s;q5(T);for(p=0;p"[React Flow]: Seems like you have not used zustand provider as an ancestor. Help: https://reactflow.dev/error#001",error002:()=>"It looks like you've created a new nodeTypes or edgeTypes object. If this wasn't on purpose please define the nodeTypes/edgeTypes outside of the component or memoize them.",error003:(f)=>`Node type "${f}" not found. Using fallback type "default".`,error004:()=>"The React Flow parent container needs a width and a height to render the graph.",error005:()=>"Only child nodes can use a parent extent.",error006:()=>"Can't create edge. An edge needs a source and a target.",error007:(f)=>`The old edge with id=${f} does not exist.`,error009:(f)=>`Marker type "${f}" doesn't exist.`,error008:(f,{id:u,sourceHandle:l,targetHandle:_})=>`Couldn't create edge for ${f} handle id: "${f==="source"?l:_}", edge id: ${u}.`,error010:()=>"Handle: No node id found. Make sure to only use a Handle inside a custom Node.",error011:(f)=>`Edge type "${f}" not found. Using fallback type "default".`,error012:(f)=>`Node with id "${f}" does not exist, it may have been removed. This can happen when a node is deleted before the "onNodeClick" handler is called.`,error013:(f="react")=>`It seems that you haven't loaded the styles. Please import '@xyflow/${f}/dist/style.css' or base.css to make sure everything is working properly.`,error014:()=>"useNodeConnections: No node ID found. Call useNodeConnections inside a custom Node or provide a node ID.",error015:()=>"It seems that you are trying to drag a node that is not initialized. Please use onNodesChange as explained in the docs."},I$=[[Number.NEGATIVE_INFINITY,Number.NEGATIVE_INFINITY],[Number.POSITIVE_INFINITY,Number.POSITIVE_INFINITY]],EF=["Enter"," ","Escape"],HF={"node.a11yDescription.default":"Press enter or space to select a node. Press delete to remove it and escape to cancel.","node.a11yDescription.keyboardDisabled":"Press enter or space to select a node. You can then use the arrow keys to move the node around. Press delete to remove it and escape to cancel.","node.a11yDescription.ariaLiveMessage":({direction:f,x:u,y:l})=>`Moved selected node ${f}. New position, x: ${u}, y: ${l}`,"edge.a11yDescription.default":"Press enter or space to select an edge. You can then press delete to remove it or escape to cancel.","controls.ariaLabel":"Control Panel","controls.zoomIn.ariaLabel":"Zoom In","controls.zoomOut.ariaLabel":"Zoom Out","controls.fitView.ariaLabel":"Fit View","controls.interactive.ariaLabel":"Toggle Interactivity","minimap.ariaLabel":"Mini Map","handle.ariaLabel":"Handle"},q_;(function(f){f.Strict="strict",f.Loose="loose"})(q_||(q_={}));var c1;(function(f){f.Free="free",f.Vertical="vertical",f.Horizontal="horizontal"})(c1||(c1={}));var Xy;(function(f){f.Partial="partial",f.Full="full"})(Xy||(Xy={}));var OF={inProgress:!1,isValid:null,from:null,fromHandle:null,fromPosition:null,fromNode:null,to:null,toHandle:null,toPosition:null,toNode:null,pointer:null},$1;(function(f){f.Bezier="default",f.Straight="straight",f.Step="step",f.SmoothStep="smoothstep",f.SimpleBezier="simplebezier"})($1||($1={}));var L_;(function(f){f.Arrow="arrow",f.ArrowClosed="arrowclosed"})(L_||(L_={}));var Zf;(function(f){f.Left="left",f.Top="top",f.Right="right",f.Bottom="bottom"})(Zf||(Zf={}));var rN={[Zf.Left]:Zf.Right,[Zf.Right]:Zf.Left,[Zf.Top]:Zf.Bottom,[Zf.Bottom]:Zf.Top};function VF(f){return f===null?null:f?"valid":"invalid"}var qF=(f)=>("id"in f)&&("source"in f)&&("target"in f),EN=(f)=>("id"in f)&&("position"in f)&&!("source"in f)&&!("target"in f),LF=(f)=>("id"in f)&&("internals"in f)&&!("source"in f)&&!("target"in f);var A4=(f,u=[0,0])=>{let{width:l,height:_}=r1(f),y=f.origin??u,$=l*y[0],r=_*y[1];return{x:f.position.x-$,y:f.position.y-r}},XF=(f,u={nodeOrigin:[0,0]})=>{if(f.length===0)return{x:0,y:0,width:0,height:0};let l=f.reduce((_,y)=>{let $=typeof y==="string",r=!u.nodeLookup&&!$?y:void 0;if(u.nodeLookup)r=$?u.nodeLookup.get(y):!LF(y)?u.nodeLookup.get(y.id):y;let j=r?B5(r,u.nodeOrigin):{x:0,y:0,x2:0,y2:0};return w5(_,j)},{x:1/0,y:1/0,x2:-1/0,y2:-1/0});return D5(l)},p$=(f,u={})=>{let l={x:1/0,y:1/0,x2:-1/0,y2:-1/0},_=!1;return f.forEach((y)=>{if(u.filter===void 0||u.filter(y))l=w5(l,B5(y)),_=!0}),_?D5(l):{x:0,y:0,width:0,height:0}},Y5=(f,u,[l,_,y]=[0,0,1],$=!1,r=!1)=>{let j={...k$(u,[l,_,y]),width:u.width/y,height:u.height/y},A=[];for(let J of f.values()){let{measured:U,selectable:Q=!0,hidden:W=!1}=J;if(r&&!Q||W)continue;let G=U.width??J.width??J.initialWidth??null,K=U.height??J.height??J.initialHeight??null,H=m$(j,Yy(J)),O=(G??0)*(K??0),z=$&&H>0;if(!J.internals.handleBounds||z||H>=O||J.dragging)A.push(J)}return A},HN=(f,u)=>{let l=new Set;return f.forEach((_)=>{l.add(_.id)}),u.filter((_)=>l.has(_.source)||l.has(_.target))};function nD(f,u){let l=new Map,_=u?.nodes?new Set(u.nodes.map((y)=>y.id)):null;return f.forEach((y)=>{if(y.measured.width&&y.measured.height&&(u?.includeHiddenNodes||!y.hidden)&&(!_||_.has(y.id)))l.set(y.id,y)}),l}async function ON({nodes:f,width:u,height:l,panZoom:_,minZoom:y,maxZoom:$},r){if(f.size===0)return Promise.resolve(!0);let j=nD(f,r),A=p$(j),J=F4(A,u,l,r?.minZoom??y,r?.maxZoom??$,r?.padding??0.1);return await _.setViewport(J,{duration:r?.duration,ease:r?.ease,interpolate:r?.interpolate}),Promise.resolve(!0)}function BF({nodeId:f,nextPosition:u,nodeLookup:l,nodeOrigin:_=[0,0],nodeExtent:y,onError:$}){let r=l.get(f),j=r.parentId?l.get(r.parentId):void 0,{x:A,y:J}=j?j.internals.positionAbsolute:{x:0,y:0},U=r.origin??_,Q=r.extent||y;if(r.extent==="parent"&&!r.expandParent)if(!j)$?.("005",$l.error005());else{let G=j.measured.width,K=j.measured.height;if(G&&K)Q=[[A,J],[A+G,J+K]]}else if(j&&h$(r.extent))Q=[[r.extent[0][0]+A,r.extent[0][1]+J],[r.extent[1][0]+A,r.extent[1][1]+J]];let W=h$(Q)?By(u,Q,r.measured):u;if(r.measured.width===void 0||r.measured.height===void 0)$?.("015",$l.error015());return{position:{x:W.x-A+(r.measured.width??0)*U[0],y:W.y-J+(r.measured.height??0)*U[1]},positionAbsolute:W}}async function VN({nodesToRemove:f=[],edgesToRemove:u=[],nodes:l,edges:_,onBeforeDelete:y}){let $=new Set(f.map((W)=>W.id)),r=[];for(let W of l){if(W.deletable===!1)continue;let G=$.has(W.id),K=!G&&W.parentId&&r.find((H)=>H.id===W.parentId);if(G||K)r.push(W)}let j=new Set(u.map((W)=>W.id)),A=_.filter((W)=>W.deletable!==!1),U=HN(r,A);for(let W of A)if(j.has(W.id)&&!U.find((K)=>K.id===W.id))U.push(W);if(!y)return{edges:U,nodes:r};let Q=await y({nodes:r,edges:U});if(typeof Q==="boolean")return Q?{edges:U,nodes:r}:{edges:[],nodes:[]};return Q}var v$=(f,u=0,l=1)=>Math.min(Math.max(f,u),l),By=(f={x:0,y:0},u,l)=>({x:v$(f.x,u[0][0],u[1][0]-(l?.width??0)),y:v$(f.y,u[0][1],u[1][1]-(l?.height??0))});function qN(f,u,l){let{width:_,height:y}=r1(l),{x:$,y:r}=l.internals.positionAbsolute;return By(f,[[$,r],[$+_,r+y]],u)}var jN=(f,u,l)=>{if(fl)return-v$(Math.abs(f-l),1,u)/u;return 0},LN=(f,u,l=15,_=40)=>{let y=jN(f.x,_,u.width-_)*l,$=jN(f.y,_,u.height-_)*l;return[y,$]},w5=(f,u)=>({x:Math.min(f.x,u.x),y:Math.min(f.y,u.y),x2:Math.max(f.x2,u.x2),y2:Math.max(f.y2,u.y2)}),ZF=({x:f,y:u,width:l,height:_})=>({x:f,y:u,x2:f+l,y2:u+_}),D5=({x:f,y:u,x2:l,y2:_})=>({x:f,y:u,width:l-f,height:_-u}),Yy=(f,u=[0,0])=>{let{x:l,y:_}=LF(f)?f.internals.positionAbsolute:A4(f,u);return{x:l,y:_,width:f.measured?.width??f.width??f.initialWidth??0,height:f.measured?.height??f.height??f.initialHeight??0}},B5=(f,u=[0,0])=>{let{x:l,y:_}=LF(f)?f.internals.positionAbsolute:A4(f,u);return{x:l,y:_,x2:l+(f.measured?.width??f.width??f.initialWidth??0),y2:_+(f.measured?.height??f.height??f.initialHeight??0)}},YF=(f,u)=>D5(w5(ZF(f),ZF(u))),m$=(f,u)=>{let l=Math.max(0,Math.min(f.x+f.width,u.x+u.width)-Math.max(f.x,u.x)),_=Math.max(0,Math.min(f.y+f.height,u.y+u.height)-Math.max(f.y,u.y));return Math.ceil(l*_)},wF=(f)=>Hl(f.width)&&Hl(f.height)&&Hl(f.x)&&Hl(f.y),Hl=(f)=>!isNaN(f)&&isFinite(f),DF=(f,u)=>{},g$=(f,u=[1,1])=>{return{x:u[0]*Math.round(f.x/u[0]),y:u[1]*Math.round(f.y/u[1])}},k$=({x:f,y:u},[l,_,y],$=!1,r=[1,1])=>{let j={x:(f-l)/y,y:(u-_)/y};return $?g$(j,r):j},j4=({x:f,y:u},[l,_,y])=>{return{x:f*y+l,y:u*y+_}};function x$(f,u){if(typeof f==="number")return Math.floor((u-u/(1+f))*0.5);if(typeof f==="string"&&f.endsWith("px")){let l=parseFloat(f);if(!Number.isNaN(l))return Math.floor(l)}if(typeof f==="string"&&f.endsWith("%")){let l=parseFloat(f);if(!Number.isNaN(l))return Math.floor(u*l*0.01)}return console.error(`[React Flow] The padding value "${f}" is invalid. Please provide a number or a string with a valid unit (px or %).`),0}function SD(f,u,l){if(typeof f==="string"||typeof f==="number"){let _=x$(f,l),y=x$(f,u);return{top:_,right:y,bottom:_,left:y,x:y*2,y:_*2}}if(typeof f==="object"){let _=x$(f.top??f.y??0,l),y=x$(f.bottom??f.y??0,l),$=x$(f.left??f.x??0,u),r=x$(f.right??f.x??0,u);return{top:_,right:r,bottom:y,left:$,x:$+r,y:_+y}}return{top:0,right:0,bottom:0,left:0,x:0,y:0}}function CD(f,u,l,_,y,$){let{x:r,y:j}=j4(f,[u,l,_]),{x:A,y:J}=j4({x:f.x+f.width,y:f.y+f.height},[u,l,_]),U=y-A,Q=$-J;return{left:Math.floor(r),top:Math.floor(j),right:Math.floor(U),bottom:Math.floor(Q)}}var F4=(f,u,l,_,y,$)=>{let r=SD($,u,l),j=(u-r.x)/f.width,A=(l-r.y)/f.height,J=Math.min(j,A),U=v$(J,_,y),Q=f.x+f.width/2,W=f.y+f.height/2,G=u/2-Q*U,K=l/2-W*U,H=CD(f,G,K,U,u,l),O={left:Math.min(H.left-r.left,0),top:Math.min(H.top-r.top,0),right:Math.min(H.right-r.right,0),bottom:Math.min(H.bottom-r.bottom,0)};return{x:G-O.left+O.right,y:K-O.top+O.bottom,zoom:U}},t$=()=>typeof navigator<"u"&&navigator?.userAgent?.indexOf("Mac")>=0;function h$(f){return f!==void 0&&f!==null&&f!=="parent"}function r1(f){return{width:f.measured?.width??f.width??f.initialWidth??0,height:f.measured?.height??f.height??f.initialHeight??0}}function TF(f){return(f.measured?.width??f.width??f.initialWidth)!==void 0&&(f.measured?.height??f.height??f.initialHeight)!==void 0}function MF(f,u={width:0,height:0},l,_,y){let $={...f},r=_.get(l);if(r){let j=r.origin||y;$.x+=r.internals.positionAbsolute.x-(u.width??0)*j[0],$.y+=r.internals.positionAbsolute.y-(u.height??0)*j[1]}return $}function PF(f,u){if(f.size!==u.size)return!1;for(let l of f)if(!u.has(l))return!1;return!0}function XN(){let f,u;return{promise:new Promise((_,y)=>{f=_,u=y}),resolve:f,reject:u}}function BN(f){return{...HF,...f||{}}}function r4(f,{snapGrid:u=[0,0],snapToGrid:l=!1,transform:_,containerBounds:y}){let{x:$,y:r}=Ol(f),j=k$({x:$-(y?.left??0),y:r-(y?.top??0)},_),{x:A,y:J}=l?g$(j,u):j;return{xSnapped:A,ySnapped:J,...j}}var T5=(f)=>({width:f.offsetWidth,height:f.offsetHeight}),nF=(f)=>f?.getRootNode?.()||window?.document,iD=["INPUT","SELECT","TEXTAREA"];function SF(f){let u=f.composedPath?.()?.[0]||f.target;if(u?.nodeType!==1)return!1;return iD.includes(u.nodeName)||u.hasAttribute("contenteditable")||!!u.closest(".nokey")}var CF=(f)=>("clientX"in f),Ol=(f,u)=>{let l=CF(f),_=l?f.clientX:f.touches?.[0].clientX,y=l?f.clientY:f.touches?.[0].clientY;return{x:_-(u?.left??0),y:y-(u?.top??0)}},AN=(f,u,l,_,y)=>{let $=u.querySelectorAll(`.${f}`);if(!$||!$.length)return null;return Array.from($).map((r)=>{let j=r.getBoundingClientRect();return{id:r.getAttribute("data-handleid"),type:f,nodeId:y,position:r.getAttribute("data-handlepos"),x:(j.left-l.left)/_,y:(j.top-l.top)/_,...T5(r)}})};function M5({sourceX:f,sourceY:u,targetX:l,targetY:_,sourceControlX:y,sourceControlY:$,targetControlX:r,targetControlY:j}){let A=f*0.125+y*0.375+r*0.375+l*0.125,J=u*0.125+$*0.375+j*0.375+_*0.125,U=Math.abs(A-f),Q=Math.abs(J-u);return[A,J,U,Q]}function L5(f,u){if(f>=0)return 0.5*f;return u*25*Math.sqrt(-f)}function FN({pos:f,x1:u,y1:l,x2:_,y2:y,c:$}){switch(f){case Zf.Left:return[u-L5(u-_,$),l];case Zf.Right:return[u+L5(_-u,$),l];case Zf.Top:return[u,l-L5(l-y,$)];case Zf.Bottom:return[u,l+L5(y-l,$)]}}function P5({sourceX:f,sourceY:u,sourcePosition:l=Zf.Bottom,targetX:_,targetY:y,targetPosition:$=Zf.Top,curvature:r=0.25}){let[j,A]=FN({pos:l,x1:f,y1:u,x2:_,y2:y,c:r}),[J,U]=FN({pos:$,x1:_,y1:y,x2:f,y2:u,c:r}),[Q,W,G,K]=M5({sourceX:f,sourceY:u,targetX:_,targetY:y,sourceControlX:j,sourceControlY:A,targetControlX:J,targetControlY:U});return[`M${f},${u} C${j},${A} ${J},${U} ${_},${y}`,Q,W,G,K]}function iF({sourceX:f,sourceY:u,targetX:l,targetY:_}){let y=Math.abs(l-f)/2,$=l0}var cD=({source:f,sourceHandle:u,target:l,targetHandle:_})=>`xy-edge__${f}${u||""}-${l}${_||""}`,RD=(f,u)=>{return u.some((l)=>l.source===f.source&&l.target===f.target&&(l.sourceHandle===f.sourceHandle||!l.sourceHandle&&!f.sourceHandle)&&(l.targetHandle===f.targetHandle||!l.targetHandle&&!f.targetHandle))},cF=(f,u,l={})=>{if(!f.source||!f.target)return DF("006",$l.error006()),u;let _=l.getEdgeId||cD,y;if(qF(f))y={...f};else y={...f,id:_(f)};if(RD(y,u))return u;if(y.sourceHandle===null)delete y.sourceHandle;if(y.targetHandle===null)delete y.targetHandle;return u.concat(y)};function n5({sourceX:f,sourceY:u,targetX:l,targetY:_}){let[y,$,r,j]=iF({sourceX:f,sourceY:u,targetX:l,targetY:_});return[`M ${f},${u}L ${l},${_}`,y,$,r,j]}var JN={[Zf.Left]:{x:-1,y:0},[Zf.Right]:{x:1,y:0},[Zf.Top]:{x:0,y:-1},[Zf.Bottom]:{x:0,y:1}},xD=({source:f,sourcePosition:u=Zf.Bottom,target:l})=>{if(u===Zf.Left||u===Zf.Right)return f.xMath.sqrt(Math.pow(u.x-f.x,2)+Math.pow(u.y-f.y,2));function bD({source:f,sourcePosition:u=Zf.Bottom,target:l,targetPosition:_=Zf.Top,center:y,offset:$,stepPosition:r}){let j=JN[u],A=JN[_],J={x:f.x+j.x*$,y:f.y+j.y*$},U={x:l.x+A.x*$,y:l.y+A.y*$},Q=xD({source:J,sourcePosition:u,target:U}),W=Q.x!==0?"x":"y",G=Q[W],K=[],H,O,z={x:0,y:0},Z={x:0,y:0},[,,N,E]=iF({sourceX:f.x,sourceY:f.y,targetX:l.x,targetY:l.y});if(j[W]*A[W]===-1){if(W==="x")H=y.x??J.x+(U.x-J.x)*r,O=y.y??(J.y+U.y)/2;else H=y.x??(J.x+U.x)/2,O=y.y??J.y+(U.y-J.y)*r;let B=[{x:H,y:J.y},{x:H,y:U.y}],P=[{x:J.x,y:O},{x:U.x,y:O}];if(j[W]===G)K=W==="x"?B:P;else K=W==="x"?P:B}else{let B=[{x:J.x,y:U.y}],P=[{x:U.x,y:J.y}];if(W==="x")K=j.x===G?P:B;else K=j.y===G?B:P;if(u===_){let T=Math.abs(f[W]-l[W]);if(T<=$){let i=Math.min($-1,$-T);if(j[W]===G)z[W]=(J[W]>f[W]?-1:1)*i;else Z[W]=(U[W]>l[W]?-1:1)*i}}if(u!==_){let T=W==="x"?"y":"x",i=j[W]===A[T],C=J[T]>U[T],v=J[T]=S)H=(h.x+M.x)/2,O=K[0].y;else H=K[0].x,O=(h.y+M.y)/2}let q={x:J.x+z.x,y:J.y+z.y},Y={x:U.x+Z.x,y:U.y+Z.y};return[[f,...q.x!==K[0].x||q.y!==K[0].y?[q]:[],...K,...Y.x!==K[K.length-1].x||Y.y!==K[K.length-1].y?[Y]:[],l],H,O,N,E]}function vD(f,u,l,_){let y=Math.min(UN(f,u)/2,UN(u,l)/2,_),{x:$,y:r}=u;if(f.x===$&&$===l.x||f.y===r&&r===l.y)return`L${$} ${r}`;if(f.y===r){let J=f.xl.id===u))||null}function S5(f,u){if(!f)return"";if(typeof f==="string")return f;return`${u?`${u}__`:""}${Object.keys(f).sort().map((_)=>`${_}=${f[_]}`).join("&")}`}function TN(f,{id:u,defaultColor:l,defaultMarkerStart:_,defaultMarkerEnd:y}){let $=new Set;return f.reduce((r,j)=>{return[j.markerStart||_,j.markerEnd||y].forEach((A)=>{if(A&&typeof A==="object"){let J=S5(A,u);if(!$.has(J))r.push({id:J,color:A.color||l,...A}),$.add(J)}}),r},[]).sort((r,j)=>r.id.localeCompare(j.id))}var MN=1000,hD=10,RF={nodeOrigin:[0,0],nodeExtent:I$,elevateNodesOnSelect:!0,zIndexMode:"basic",defaults:{}},ID={...RF,checkEquality:!0};function xF(f,u){let l={...f};for(let _ in u)if(u[_]!==void 0)l[_]=u[_];return l}function PN(f,u,l){let _=xF(RF,l);for(let y of f.values())if(y.parentId)vF(y,f,u,_);else{let $=A4(y,_.nodeOrigin),r=h$(y.extent)?y.extent:_.nodeExtent,j=By($,r,r1(y));y.internals.positionAbsolute=j}}function pD(f,u){if(!f.handles)return!f.measured?void 0:u?.internals.handleBounds;let l=[],_=[];for(let y of f.handles){let $={id:y.id,width:y.width??1,height:y.height??1,nodeId:f.id,x:y.x,y:y.y,position:y.position,type:y.type};if(y.type==="source")l.push($);else if(y.type==="target")_.push($)}return{source:l,target:_}}function bF(f){return f==="manual"}function C5(f,u,l,_={}){let y=xF(ID,_),$={i:0},r=new Map(u),j=y?.elevateNodesOnSelect&&!bF(y.zIndexMode)?MN:0,A=f.length>0,J=!1;u.clear(),l.clear();for(let U of f){let Q=r.get(U.id);if(y.checkEquality&&U===Q?.internals.userNode)u.set(U.id,Q);else{let W=A4(U,y.nodeOrigin),G=h$(U.extent)?U.extent:y.nodeExtent,K=By(W,G,r1(U));Q={...y.defaults,...U,measured:{width:U.measured?.width,height:U.measured?.height},internals:{positionAbsolute:K,handleBounds:pD(U,Q),z:nN(U,j,y.zIndexMode),userNode:U}},u.set(U.id,Q)}if((Q.measured===void 0||Q.measured.width===void 0||Q.measured.height===void 0)&&!Q.hidden)A=!1;if(U.parentId)vF(Q,u,l,_,$);J||=U.selected??!1}return{nodesInitialized:A,hasSelectedNodes:J}}function mD(f,u){if(!f.parentId)return;let l=u.get(f.parentId);if(l)l.set(f.id,f);else u.set(f.parentId,new Map([[f.id,f]]))}function vF(f,u,l,_,y){let{elevateNodesOnSelect:$,nodeOrigin:r,nodeExtent:j,zIndexMode:A}=xF(RF,_),J=f.parentId,U=u.get(J);if(!U){console.warn(`Parent node ${J} not found. Please make sure that parent nodes are in front of their child nodes in the nodes array.`);return}if(mD(f,l),y&&!U.parentId&&U.internals.rootParentIndex===void 0&&A==="auto")U.internals.rootParentIndex=++y.i,U.internals.z=U.internals.z+y.i*hD;if(y&&U.internals.rootParentIndex!==void 0)y.i=U.internals.rootParentIndex;let Q=$&&!bF(A)?MN:0,{x:W,y:G,z:K}=gD(f,U,r,j,Q,A),{positionAbsolute:H}=f.internals,O=W!==H.x||G!==H.y;if(O||K!==f.internals.z)u.set(f.id,{...f,internals:{...f.internals,positionAbsolute:O?{x:W,y:G}:H,z:K}})}function nN(f,u,l){let _=Hl(f.zIndex)?f.zIndex:0;if(bF(l))return _;return _+(f.selected?u:0)}function gD(f,u,l,_,y,$){let{x:r,y:j}=u.internals.positionAbsolute,A=r1(f),J=A4(f,l),U=h$(f.extent)?By(J,f.extent,A):J,Q=By({x:r+U.x,y:j+U.y},_,A);if(f.extent==="parent")Q=qN(Q,A,u);let W=nN(f,y,$),G=u.internals.z??0;return{x:Q.x,y:Q.y,z:G>=W?G+1:W}}function i5(f,u,l,_=[0,0]){let y=[],$=new Map;for(let r of f){let j=u.get(r.parentId);if(!j)continue;let A=$.get(r.parentId)?.expandedRect??Yy(j),J=YF(A,r.rect);$.set(r.parentId,{expandedRect:J,parent:j})}if($.size>0)$.forEach(({expandedRect:r,parent:j},A)=>{let J=j.internals.positionAbsolute,U=r1(j),Q=j.origin??_,W=r.x0||G>0||O||z)y.push({id:A,type:"position",position:{x:j.position.x-W+O,y:j.position.y-G+z}}),l.get(A)?.forEach((Z)=>{if(!f.some((N)=>N.id===Z.id))y.push({id:Z.id,type:"position",position:{x:Z.position.x+W,y:Z.position.y+G}})});if(U.width0){let G=i5(W,u,l,y);J.push(...G)}return{changes:J,updatedInternals:A}}async function CN({delta:f,panZoom:u,transform:l,translateExtent:_,width:y,height:$}){if(!u||!f.x&&!f.y)return Promise.resolve(!1);let r=await u.setViewportConstrained({x:l[0]+f.x,y:l[1]+f.y,zoom:l[2]},[[0,0],[y,$]],_),j=!!r&&(r.x!==l[0]||r.y!==l[1]||r.k!==l[2]);return Promise.resolve(j)}function GN(f,u,l,_,y,$){let r=y,j=_.get(r)||new Map;_.set(r,j.set(l,u)),r=`${y}-${f}`;let A=_.get(r)||new Map;if(_.set(r,A.set(l,u)),$){r=`${y}-${f}-${$}`;let J=_.get(r)||new Map;_.set(r,J.set(l,u))}}function hF(f,u,l){f.clear(),u.clear();for(let _ of l){let{source:y,target:$,sourceHandle:r=null,targetHandle:j=null}=_,A={edgeId:_.id,source:y,target:$,sourceHandle:r,targetHandle:j},J=`${y}-${r}--${$}-${j}`,U=`${$}-${j}--${y}-${r}`;GN("source",A,U,f,y,r),GN("target",A,J,f,$,j),u.set(_.id,_)}}function iN(f,u){if(!f.parentId)return!1;let l=u.get(f.parentId);if(!l)return!1;if(l.selected)return!0;return iN(l,u)}function KN(f,u,l){let _=f;do{if(_?.matches?.(u))return!0;if(_===l)return!1;_=_?.parentElement}while(_);return!1}function kD(f,u,l,_){let y=new Map;for(let[$,r]of f)if((r.selected||r.id===_)&&(!r.parentId||!iN(r,f))&&(r.draggable||u&&typeof r.draggable>"u")){let j=f.get($);if(j)y.set($,{id:$,position:j.position||{x:0,y:0},distance:{x:l.x-j.internals.positionAbsolute.x,y:l.y-j.internals.positionAbsolute.y},extent:j.extent,parentId:j.parentId,origin:j.origin,expandParent:j.expandParent,internals:{positionAbsolute:j.internals.positionAbsolute||{x:0,y:0}},measured:{width:j.measured.width??0,height:j.measured.height??0}})}return y}function GF({nodeId:f,dragItems:u,nodeLookup:l,dragging:_=!0}){let y=[];for(let[r,j]of u){let A=l.get(r)?.internals.userNode;if(A)y.push({...A,position:j.position,dragging:_})}if(!f)return[y[0],y];let $=l.get(f)?.internals.userNode;return[!$?y[0]:{...$,position:u.get(f)?.position||$.position,dragging:_},y]}function tD({dragItems:f,snapGrid:u,x:l,y:_}){let y=f.values().next().value;if(!y)return null;let $={x:l-y.distance.x,y:_-y.distance.y},r=g$($,u);return{x:r.x-$.x,y:r.y-$.y}}function cN({onNodeMouseDown:f,getStoreItems:u,onDragStart:l,onDrag:_,onDragStop:y}){let $={x:null,y:null},r=0,j=new Map,A=!1,J={x:0,y:0},U=null,Q=!1,W=null,G=!1,K=!1,H=null;function O({noDragClassName:Z,handleSelector:N,domNode:E,isSelectable:q,nodeId:Y,nodeClickDistance:w=0}){W=g0(E);function B({x:n,y:S}){let{nodeLookup:T,nodeExtent:i,snapGrid:C,snapToGrid:v,nodeOrigin:X,onNodeDrag:D,onSelectionDrag:p,onError:m,updateNodePositions:s}=u();$={x:n,y:S};let d=!1,a=j.size>1,I=a&&i?ZF(p$(j)):null,ff=a&&v?tD({dragItems:j,snapGrid:C,x:n,y:S}):null;for(let[yf,rf]of j){if(!T.has(yf))continue;let Wf={x:n-rf.distance.x,y:S-rf.distance.y};if(v)Wf=ff?{x:Math.round(Wf.x+ff.x),y:Math.round(Wf.y+ff.y)}:g$(Wf,C);let Ef=null;if(a&&i&&!rf.extent&&I){let{positionAbsolute:o}=rf.internals,e=o.x-I.x+i[0][0],Kf=o.x+rf.measured.width-I.x2+i[1][0],k=o.y-I.y+i[0][1],Af=o.y+rf.measured.height-I.y2+i[1][1];Ef=[[e,k],[Kf,Af]]}let{position:Gf,positionAbsolute:c}=BF({nodeId:yf,nextPosition:Wf,nodeLookup:T,nodeExtent:Ef?Ef:i,nodeOrigin:X,onError:m});d=d||rf.position.x!==Gf.x||rf.position.y!==Gf.y,rf.position=Gf,rf.internals.positionAbsolute=c}if(K=K||d,!d)return;if(s(j,!0),H&&(_||D||!Y&&p)){let[yf,rf]=GF({nodeId:Y,dragItems:j,nodeLookup:T});if(_?.(H,j,yf,rf),D?.(H,yf,rf),!Y)p?.(H,rf)}}async function P(){if(!U)return;let{transform:n,panBy:S,autoPanSpeed:T,autoPanOnNodeDrag:i}=u();if(!i){A=!1,cancelAnimationFrame(r);return}let[C,v]=LN(J,U,T);if(C!==0||v!==0){if($.x=($.x??0)-C/n[2],$.y=($.y??0)-v/n[2],await S({x:C,y:v}))B($)}r=requestAnimationFrame(P)}function h(n){let{nodeLookup:S,multiSelectionActive:T,nodesDraggable:i,transform:C,snapGrid:v,snapToGrid:X,selectNodesOnDrag:D,onNodeDragStart:p,onSelectionDragStart:m,unselectNodesAndEdges:s}=u();if(Q=!0,(!D||!q)&&!T&&Y){if(!S.get(Y)?.selected)s()}if(q&&D&&Y)f?.(Y);let d=r4(n.sourceEvent,{transform:C,snapGrid:v,snapToGrid:X,containerBounds:U});if($=d,j=kD(S,i,d,Y),j.size>0&&(l||p||!Y&&m)){let[a,I]=GF({nodeId:Y,dragItems:j,nodeLookup:S});if(l?.(n.sourceEvent,j,a,I),p?.(n.sourceEvent,a,I),!Y)m?.(n.sourceEvent,I)}}let M=v6().clickDistance(w).on("start",(n)=>{let{domNode:S,nodeDragThreshold:T,transform:i,snapGrid:C,snapToGrid:v}=u();if(U=S?.getBoundingClientRect()||null,G=!1,K=!1,H=n.sourceEvent,T===0)h(n);$=r4(n.sourceEvent,{transform:i,snapGrid:C,snapToGrid:v,containerBounds:U}),J=Ol(n.sourceEvent,U)}).on("drag",(n)=>{let{autoPanOnNodeDrag:S,transform:T,snapGrid:i,snapToGrid:C,nodeDragThreshold:v,nodeLookup:X}=u(),D=r4(n.sourceEvent,{transform:T,snapGrid:i,snapToGrid:C,containerBounds:U});if(H=n.sourceEvent,n.sourceEvent.type==="touchmove"&&n.sourceEvent.touches.length>1||Y&&!X.has(Y))G=!0;if(G)return;if(!A&&S&&Q)A=!0,P();if(!Q){let p=Ol(n.sourceEvent,U),m=p.x-J.x,s=p.y-J.y;if(Math.sqrt(m*m+s*s)>v)h(n)}if(($.x!==D.xSnapped||$.y!==D.ySnapped)&&j&&Q)J=Ol(n.sourceEvent,U),B(D)}).on("end",(n)=>{if(!Q||G)return;if(A=!1,Q=!1,cancelAnimationFrame(r),j.size>0){let{nodeLookup:S,updateNodePositions:T,onNodeDragStop:i,onSelectionDragStop:C}=u();if(K)T(j,!1),K=!1;if(y||i||!Y&&C){let[v,X]=GF({nodeId:Y,dragItems:j,nodeLookup:S,dragging:!1});if(y?.(n.sourceEvent,j,v,X),i?.(n.sourceEvent,v,X),!Y)C?.(n.sourceEvent,X)}}}).filter((n)=>{let S=n.target;return!n.button&&(!Z||!KN(S,`.${Z}`,E))&&(!N||KN(S,N,E))});W.call(M)}function z(){W?.on(".drag",null)}return{update:O,destroy:z}}function sD(f,u,l){let _=[],y={x:f.x-l,y:f.y-l,width:l*2,height:l*2};for(let $ of u.values())if(m$(y,Yy($))>0)_.push($);return _}var oD=250;function aD(f,u,l,_){let y=[],$=1/0,r=sD(f,l,u+oD);for(let j of r){let A=[...j.internals.handleBounds?.source??[],...j.internals.handleBounds?.target??[]];for(let J of A){if(_.nodeId===J.nodeId&&_.type===J.type&&_.id===J.id)continue;let{x:U,y:Q}=X_(j,J,J.position,!0),W=Math.sqrt(Math.pow(U-f.x,2)+Math.pow(Q-f.y,2));if(W>u)continue;if(W<$)y=[{...J,x:U,y:Q}],$=W;else if(W===$)y.push({...J,x:U,y:Q})}}if(!y.length)return null;if(y.length>1){let j=_.type==="source"?"target":"source";return y.find((A)=>A.type===j)??y[0]}return y[0]}function RN(f,u,l,_,y,$=!1){let r=_.get(f);if(!r)return null;let j=y==="strict"?r.internals.handleBounds?.[u]:[...r.internals.handleBounds?.source??[],...r.internals.handleBounds?.target??[]],A=(l?j?.find((J)=>J.id===l):j?.[0])??null;return A&&$?{...A,...X_(r,A,A.position,!0)}:A}function xN(f,u){if(f)return f;else if(u?.classList.contains("target"))return"target";else if(u?.classList.contains("source"))return"source";return null}function dD(f,u){let l=null;if(u)l=!0;else if(f&&!u)l=!1;return l}var bN=()=>!0;function eD(f,{connectionMode:u,connectionRadius:l,handleId:_,nodeId:y,edgeUpdaterType:$,isTarget:r,domNode:j,nodeLookup:A,lib:J,autoPanOnConnect:U,flowId:Q,panBy:W,cancelConnection:G,onConnectStart:K,onConnect:H,onConnectEnd:O,isValidConnection:z=bN,onReconnectEnd:Z,updateConnection:N,getTransform:E,getFromHandle:q,autoPanSpeed:Y,dragThreshold:w=1,handleDomNode:B}){let P=nF(f.target),h=0,M,{x:n,y:S}=Ol(f),T=xN($,B),i=j?.getBoundingClientRect(),C=!1;if(!i||!T)return;let v=RN(y,T,_,A,u);if(!v)return;let X=Ol(f,i),D=!1,p=null,m=!1,s=null;function d(){if(!U||!i)return;let[Gf,c]=LN(X,i,Y);W({x:Gf,y:c}),h=requestAnimationFrame(d)}let a={...v,nodeId:y,type:T,position:v.position},I=A.get(y),yf={inProgress:!0,isValid:null,from:X_(I,a,Zf.Left,!0),fromHandle:a,fromPosition:a.position,fromNode:I,to:X,toHandle:null,toPosition:rN[a.position],toNode:null,pointer:X};function rf(){C=!0,N(yf),K?.(f,{nodeId:y,handleId:_,handleType:T})}if(w===0)rf();function Wf(Gf){if(!C){let{x:Af,y:Yf}=Ol(Gf),Bf=Af-n,df=Yf-S;if(!(Bf*Bf+df*df>w*w))return;rf()}if(!q()||!a){Ef(Gf);return}let c=E();if(X=Ol(Gf,i),M=aD(k$(X,c,!1,[1,1]),l,A,a),!D)d(),D=!0;let o=vN(Gf,{handle:M,connectionMode:u,fromNodeId:y,fromHandleId:_,fromType:r?"target":"source",isValidConnection:z,doc:P,lib:J,flowId:Q,nodeLookup:A});s=o.handleDomNode,p=o.connection,m=dD(!!M,o.isValid);let e=A.get(y),Kf=e?X_(e,a,Zf.Left,!0):yf.from,k={...yf,from:Kf,isValid:m,to:o.toHandle&&m?j4({x:o.toHandle.x,y:o.toHandle.y},c):X,toHandle:o.toHandle,toPosition:m&&o.toHandle?o.toHandle.position:rN[a.position],toNode:o.toHandle?A.get(o.toHandle.nodeId):null,pointer:X};N(k),yf=k}function Ef(Gf){if("touches"in Gf&&Gf.touches.length>0)return;if(C){if((M||s)&&p&&m)H?.(p);let{inProgress:c,...o}=yf,e={...o,toPosition:yf.toHandle?yf.toPosition:null};if(O?.(Gf,e),$)Z?.(Gf,e)}G(),cancelAnimationFrame(h),D=!1,m=!1,p=null,s=null,P.removeEventListener("mousemove",Wf),P.removeEventListener("mouseup",Ef),P.removeEventListener("touchmove",Wf),P.removeEventListener("touchend",Ef)}P.addEventListener("mousemove",Wf),P.addEventListener("mouseup",Ef),P.addEventListener("touchmove",Wf),P.addEventListener("touchend",Ef)}function vN(f,{handle:u,connectionMode:l,fromNodeId:_,fromHandleId:y,fromType:$,doc:r,lib:j,flowId:A,isValidConnection:J=bN,nodeLookup:U}){let Q=$==="target",W=u?r.querySelector(`.${j}-flow__handle[data-id="${A}-${u?.nodeId}-${u?.id}-${u?.type}"]`):null,{x:G,y:K}=Ol(f),H=r.elementFromPoint(G,K),O=H?.classList.contains(`${j}-flow__handle`)?H:W,z={handleDomNode:O,isValid:!1,connection:null,toHandle:null};if(O){let Z=xN(void 0,O),N=O.getAttribute("data-nodeid"),E=O.getAttribute("data-handleid"),q=O.classList.contains("connectable"),Y=O.classList.contains("connectableend");if(!N||!Z)return z;let w={source:Q?N:_,sourceHandle:Q?E:y,target:Q?_:N,targetHandle:Q?y:E};z.connection=w;let P=q&&Y&&(l===q_.Strict?Q&&Z==="source"||!Q&&Z==="target":N!==_||E!==y);z.isValid=P&&J(w),z.toHandle=RN(N,Z,E,U,l,!0)}return z}var c5={onPointerDown:eD,isValid:vN};function hN({domNode:f,panZoom:u,getTransform:l,getViewScale:_}){let y=g0(f);function $({translateExtent:j,width:A,height:J,zoomStep:U=1,pannable:Q=!0,zoomable:W=!0,inversePan:G=!1}){let K=(N)=>{if(N.sourceEvent.type!=="wheel"||!u)return;let E=l(),q=N.sourceEvent.ctrlKey&&t$()?10:1,Y=-N.sourceEvent.deltaY*(N.sourceEvent.deltaMode===1?0.05:N.sourceEvent.deltaMode?1:0.002)*U,w=E[2]*Math.pow(2,Y*q);u.scaleTo(w)},H=[0,0],O=(N)=>{if(N.sourceEvent.type==="mousedown"||N.sourceEvent.type==="touchstart")H=[N.sourceEvent.clientX??N.sourceEvent.touches[0].clientX,N.sourceEvent.clientY??N.sourceEvent.touches[0].clientY]},z=(N)=>{let E=l();if(N.sourceEvent.type!=="mousemove"&&N.sourceEvent.type!=="touchmove"||!u)return;let q=[N.sourceEvent.clientX??N.sourceEvent.touches[0].clientX,N.sourceEvent.clientY??N.sourceEvent.touches[0].clientY],Y=[q[0]-H[0],q[1]-H[1]];H=q;let w=_()*Math.max(E[2],Math.log(E[2]))*(G?-1:1),B={x:E[0]-Y[0]*w,y:E[1]-Y[1]*w},P=[[0,0],[A,J]];u.setViewportConstrained({x:B.x,y:B.y,zoom:E[2]},P,j)},Z=$4().on("start",O).on("zoom",Q?z:null).on("zoom.wheel",W?K:null);y.call(Z,{})}function r(){y.on("zoom",null)}return{update:$,destroy:r,pointer:zu}}var R5=(f)=>({x:f.x,y:f.y,zoom:f.k}),KF=({x:f,y:u,zoom:l})=>qy.translate(f,u).scale(l),b$=(f,u)=>f.target.closest(`.${u}`),IN=(f,u)=>u===2&&Array.isArray(f)&&f.includes(2),fT=(f)=>((f*=2)<=1?f*f*f:(f-=2)*f*f+2)/2,NF=(f,u=0,l=fT,_=()=>{})=>{let y=typeof u==="number"&&u>0;if(!y)_();return y?f.transition().duration(u).ease(l).on("end",_):f},pN=(f)=>{let u=f.ctrlKey&&t$()?10:1;return-f.deltaY*(f.deltaMode===1?0.05:f.deltaMode?1:0.002)*u};function uT({zoomPanValues:f,noWheelClassName:u,d3Selection:l,d3Zoom:_,panOnScrollMode:y,panOnScrollSpeed:$,zoomOnPinch:r,onPanZoomStart:j,onPanZoom:A,onPanZoomEnd:J}){return(U)=>{if(b$(U,u)){if(U.ctrlKey)U.preventDefault();return!1}U.preventDefault(),U.stopImmediatePropagation();let Q=l.property("__zoom").k||1;if(U.ctrlKey&&r){let O=zu(U),z=pN(U),Z=Q*Math.pow(2,z);_.scaleTo(l,Z,O,U);return}let W=U.deltaMode===1?20:1,G=y===c1.Vertical?0:U.deltaX*W,K=y===c1.Horizontal?0:U.deltaY*W;if(!t$()&&U.shiftKey&&y!==c1.Vertical)G=U.deltaY*W,K=0;_.translateBy(l,-(G/Q)*$,-(K/Q)*$,{internal:!0});let H=R5(l.property("__zoom"));if(clearTimeout(f.panScrollTimeout),!f.isPanScrolling)f.isPanScrolling=!0,j?.(U,H);else A?.(U,H),f.panScrollTimeout=setTimeout(()=>{J?.(U,H),f.isPanScrolling=!1},150)}}function lT({noWheelClassName:f,preventScrolling:u,d3ZoomHandler:l}){return function(_,y){let $=_.type==="wheel",r=!u&&$&&!_.ctrlKey,j=b$(_,f);if(_.ctrlKey&&$&&j)_.preventDefault();if(r||j)return null;_.preventDefault(),l.call(this,_,y)}}function _T({zoomPanValues:f,onDraggingChange:u,onPanZoomStart:l}){return(_)=>{if(_.sourceEvent?.internal)return;let y=R5(_.transform);if(f.mouseButton=_.sourceEvent?.button||0,f.isZoomingOrPanning=!0,f.prevViewport=y,_.sourceEvent?.type==="mousedown")u(!0);if(l)l?.(_.sourceEvent,y)}}function yT({zoomPanValues:f,panOnDrag:u,onPaneContextMenu:l,onTransformChange:_,onPanZoom:y}){return($)=>{if(f.usedRightMouseButton=!!(l&&IN(u,f.mouseButton??0)),!$.sourceEvent?.sync)_([$.transform.x,$.transform.y,$.transform.k]);if(y&&!$.sourceEvent?.internal)y?.($.sourceEvent,R5($.transform))}}function $T({zoomPanValues:f,panOnDrag:u,panOnScroll:l,onDraggingChange:_,onPanZoomEnd:y,onPaneContextMenu:$}){return(r)=>{if(r.sourceEvent?.internal)return;if(f.isZoomingOrPanning=!1,$&&IN(u,f.mouseButton??0)&&!f.usedRightMouseButton&&r.sourceEvent)$(r.sourceEvent);if(f.usedRightMouseButton=!1,_(!1),y){let j=R5(r.transform);f.prevViewport=j,clearTimeout(f.timerId),f.timerId=setTimeout(()=>{y?.(r.sourceEvent,j)},l?150:0)}}}function rT({zoomActivationKeyPressed:f,zoomOnScroll:u,zoomOnPinch:l,panOnDrag:_,panOnScroll:y,zoomOnDoubleClick:$,userSelectionActive:r,noWheelClassName:j,noPanClassName:A,lib:J,connectionInProgress:U}){return(Q)=>{let W=f||u,G=l&&Q.ctrlKey,K=Q.type==="wheel";if(Q.button===1&&Q.type==="mousedown"&&(b$(Q,`${J}-flow__node`)||b$(Q,`${J}-flow__edge`)))return!0;if(!_&&!W&&!y&&!$&&!l)return!1;if(r)return!1;if(U&&!K)return!1;if(b$(Q,j)&&K)return!1;if(b$(Q,A)&&(!K||y&&K&&!f))return!1;if(!l&&Q.ctrlKey&&K)return!1;if(!l&&Q.type==="touchstart"&&Q.touches?.length>1)return Q.preventDefault(),!1;if(!W&&!y&&!G&&K)return!1;if(!_&&(Q.type==="mousedown"||Q.type==="touchstart"))return!1;if(Array.isArray(_)&&!_.includes(Q.button)&&Q.type==="mousedown")return!1;let H=Array.isArray(_)&&_.includes(Q.button)||!Q.button||Q.button<=1;return(!Q.ctrlKey||K)&&H}}function mN({domNode:f,minZoom:u,maxZoom:l,translateExtent:_,viewport:y,onPanZoom:$,onPanZoomStart:r,onPanZoomEnd:j,onDraggingChange:A}){let J={isZoomingOrPanning:!1,usedRightMouseButton:!1,prevViewport:{x:0,y:0,zoom:0},mouseButton:0,timerId:void 0,panScrollTimeout:void 0,isPanScrolling:!1},U=f.getBoundingClientRect(),Q=$4().scaleExtent([u,l]).translateExtent(_),W=g0(f).call(Q);Z({x:y.x,y:y.y,zoom:v$(y.zoom,u,l)},[[0,0],[U.width,U.height]],_);let G=W.on("wheel.zoom"),K=W.on("dblclick.zoom");Q.wheelDelta(pN);function H(M,n){if(W)return new Promise((S)=>{Q?.interpolate(n?.interpolate==="linear"?y1:Oy).transform(NF(W,n?.duration,n?.ease,()=>S(!0)),M)});return Promise.resolve(!1)}function O({noWheelClassName:M,noPanClassName:n,onPaneContextMenu:S,userSelectionActive:T,panOnScroll:i,panOnDrag:C,panOnScrollMode:v,panOnScrollSpeed:X,preventScrolling:D,zoomOnPinch:p,zoomOnScroll:m,zoomOnDoubleClick:s,zoomActivationKeyPressed:d,lib:a,onTransformChange:I,connectionInProgress:ff,paneClickDistance:yf,selectionOnDrag:rf}){if(T&&!J.isZoomingOrPanning)z();let Wf=i&&!d&&!T;Q.clickDistance(rf?1/0:!Hl(yf)||yf<0?0:yf);let Ef=Wf?uT({zoomPanValues:J,noWheelClassName:M,d3Selection:W,d3Zoom:Q,panOnScrollMode:v,panOnScrollSpeed:X,zoomOnPinch:p,onPanZoomStart:r,onPanZoom:$,onPanZoomEnd:j}):lT({noWheelClassName:M,preventScrolling:D,d3ZoomHandler:G});if(W.on("wheel.zoom",Ef,{passive:!1}),!T){let c=_T({zoomPanValues:J,onDraggingChange:A,onPanZoomStart:r});Q.on("start",c);let o=yT({zoomPanValues:J,panOnDrag:C,onPaneContextMenu:!!S,onPanZoom:$,onTransformChange:I});Q.on("zoom",o);let e=$T({zoomPanValues:J,panOnDrag:C,panOnScroll:i,onPaneContextMenu:S,onPanZoomEnd:j,onDraggingChange:A});Q.on("end",e)}let Gf=rT({zoomActivationKeyPressed:d,panOnDrag:C,zoomOnScroll:m,panOnScroll:i,zoomOnDoubleClick:s,zoomOnPinch:p,userSelectionActive:T,noPanClassName:n,noWheelClassName:M,lib:a,connectionInProgress:ff});if(Q.filter(Gf),s)W.on("dblclick.zoom",K);else W.on("dblclick.zoom",null)}function z(){Q.on("zoom",null)}async function Z(M,n,S){let T=KF(M),i=Q?.constrain()(T,n,S);if(i)await H(i);return new Promise((C)=>C(i))}async function N(M,n){let S=KF(M);return await H(S,n),new Promise((T)=>T(S))}function E(M){if(W){let n=KF(M),S=W.property("__zoom");if(S.k!==M.zoom||S.x!==M.x||S.y!==M.y)Q?.transform(W,n,null,{sync:!0})}}function q(){let M=W?y4(W.node()):{x:0,y:0,k:1};return{x:M.x,y:M.y,zoom:M.k}}function Y(M,n){if(W)return new Promise((S)=>{Q?.interpolate(n?.interpolate==="linear"?y1:Oy).scaleTo(NF(W,n?.duration,n?.ease,()=>S(!0)),M)});return Promise.resolve(!1)}function w(M,n){if(W)return new Promise((S)=>{Q?.interpolate(n?.interpolate==="linear"?y1:Oy).scaleBy(NF(W,n?.duration,n?.ease,()=>S(!0)),M)});return Promise.resolve(!1)}function B(M){Q?.scaleExtent(M)}function P(M){Q?.translateExtent(M)}function h(M){let n=!Hl(M)||M<0?0:M;Q?.clickDistance(n)}return{update:O,destroy:z,setViewport:N,setViewportConstrained:Z,getViewport:q,scaleTo:Y,scaleBy:w,setScaleExtent:B,setTranslateExtent:P,syncViewport:E,setClickDistance:h}}var B_;(function(f){f.Line="line",f.Handle="handle"})(B_||(B_={}));function jT({width:f,prevWidth:u,height:l,prevHeight:_,affectsX:y,affectsY:$}){let r=f-u,j=l-_,A=[r>0?1:r<0?-1:0,j>0?1:j<0?-1:0];if(r&&y)A[0]=A[0]*-1;if(j&&$)A[1]=A[1]*-1;return A}function NN(f){let u=f.includes("right")||f.includes("left"),l=f.includes("bottom")||f.includes("top"),_=f.includes("left"),y=f.includes("top");return{isHorizontal:u,isVertical:l,affectsX:_,affectsY:y}}function O_(f,u){return Math.max(0,u-f)}function V_(f,u){return Math.max(0,f-u)}function X5(f,u,l){return Math.max(0,u-f,f-l)}function ZN(f,u){return f?!u:u}function AT(f,u,l,_,y,$,r,j){let{affectsX:A,affectsY:J}=u,{isHorizontal:U,isVertical:Q}=u,W=U&&Q,{xSnapped:G,ySnapped:K}=l,{minWidth:H,maxWidth:O,minHeight:z,maxHeight:Z}=_,{x:N,y:E,width:q,height:Y,aspectRatio:w}=f,B=Math.floor(U?G-f.pointerX:0),P=Math.floor(Q?K-f.pointerY:0),h=q+(A?-B:B),M=Y+(J?-P:P),n=-$[0]*q,S=-$[1]*Y,T=X5(h,H,O),i=X5(M,z,Z);if(r){let X=0,D=0;if(A&&B<0)X=O_(N+B+n,r[0][0]);else if(!A&&B>0)X=V_(N+h+n,r[1][0]);if(J&&P<0)D=O_(E+P+S,r[0][1]);else if(!J&&P>0)D=V_(E+M+S,r[1][1]);T=Math.max(T,X),i=Math.max(i,D)}if(j){let X=0,D=0;if(A&&B>0)X=V_(N+B,j[0][0]);else if(!A&&B<0)X=O_(N+h,j[1][0]);if(J&&P>0)D=V_(E+P,j[0][1]);else if(!J&&P<0)D=O_(E+M,j[1][1]);T=Math.max(T,X),i=Math.max(i,D)}if(y){if(U){let X=X5(h/w,z,Z)*w;if(T=Math.max(T,X),r){let D=0;if(!A&&!J||A&&!J&&W)D=V_(E+S+h/w,r[1][1])*w;else D=O_(E+S+(A?B:-B)/w,r[0][1])*w;T=Math.max(T,D)}if(j){let D=0;if(!A&&!J||A&&!J&&W)D=O_(E+h/w,j[1][1])*w;else D=V_(E+(A?B:-B)/w,j[0][1])*w;T=Math.max(T,D)}}if(Q){let X=X5(M*w,H,O)/w;if(i=Math.max(i,X),r){let D=0;if(!A&&!J||J&&!A&&W)D=V_(N+M*w+n,r[1][0])/w;else D=O_(N+(J?P:-P)*w+n,r[0][0])/w;i=Math.max(i,D)}if(j){let D=0;if(!A&&!J||J&&!A&&W)D=O_(N+M*w,j[1][0])/w;else D=V_(N+(J?P:-P)*w,j[0][0])/w;i=Math.max(i,D)}}}if(P=P+(P<0?i:-i),B=B+(B<0?T:-T),y)if(W)if(h>M*w)P=(ZN(A,J)?-B:B)/w;else B=(ZN(A,J)?-P:P)*w;else if(U)P=B/w,J=A;else B=P*w,A=J;let C=A?N+B:N,v=J?E+P:E;return{width:q+(A?-B:B),height:Y+(J?-P:P),x:$[0]*B*(!A?1:-1)+C,y:$[1]*P*(!J?1:-1)+v}}var gN={width:0,height:0,x:0,y:0},FT={...gN,pointerX:0,pointerY:0,aspectRatio:1};function JT(f){return[[0,0],[f.measured.width,f.measured.height]]}function UT(f,u,l){let _=u.position.x+f.position.x,y=u.position.y+f.position.y,$=f.measured.width??0,r=f.measured.height??0,j=l[0]*$,A=l[1]*r;return[[_-j,y-A],[_+$-j,y+r-A]]}function kN({domNode:f,nodeId:u,getStoreItems:l,onChange:_,onEnd:y}){let $=g0(f),r={controlDirection:NN("bottom-right"),boundaries:{minWidth:0,minHeight:0,maxWidth:Number.MAX_VALUE,maxHeight:Number.MAX_VALUE},resizeDirection:void 0,keepAspectRatio:!1};function j({controlPosition:J,boundaries:U,keepAspectRatio:Q,resizeDirection:W,onResizeStart:G,onResize:K,onResizeEnd:H,shouldResize:O}){let z={...gN},Z={...FT};r={boundaries:U,resizeDirection:W,keepAspectRatio:Q,controlDirection:NN(J)};let N=void 0,E=null,q=[],Y=void 0,w=void 0,B=void 0,P=!1,h=v6().on("start",(M)=>{let{nodeLookup:n,transform:S,snapGrid:T,snapToGrid:i,nodeOrigin:C,paneDomNode:v}=l();if(N=n.get(u),!N)return;E=v?.getBoundingClientRect()??null;let{xSnapped:X,ySnapped:D}=r4(M.sourceEvent,{transform:S,snapGrid:T,snapToGrid:i,containerBounds:E});if(z={width:N.measured.width??0,height:N.measured.height??0,x:N.position.x??0,y:N.position.y??0},Z={...z,pointerX:X,pointerY:D,aspectRatio:z.width/z.height},Y=void 0,N.parentId&&(N.extent==="parent"||N.expandParent))Y=n.get(N.parentId),w=Y&&N.extent==="parent"?JT(Y):void 0;q=[],B=void 0;for(let[p,m]of n)if(m.parentId===u){if(q.push({id:p,position:{...m.position},extent:m.extent}),m.extent==="parent"||m.expandParent){let s=UT(m,N,m.origin??C);if(B)B=[[Math.min(s[0][0],B[0][0]),Math.min(s[0][1],B[0][1])],[Math.max(s[1][0],B[1][0]),Math.max(s[1][1],B[1][1])]];else B=s}}G?.(M,{...z})}).on("drag",(M)=>{let{transform:n,snapGrid:S,snapToGrid:T,nodeOrigin:i}=l(),C=r4(M.sourceEvent,{transform:n,snapGrid:S,snapToGrid:T,containerBounds:E}),v=[];if(!N)return;let{x:X,y:D,width:p,height:m}=z,s={},d=N.origin??i,{width:a,height:I,x:ff,y:yf}=AT(Z,r.controlDirection,C,r.boundaries,r.keepAspectRatio,d,w,B),rf=a!==p,Wf=I!==m,Ef=ff!==X&&rf,Gf=yf!==D&&Wf;if(!Ef&&!Gf&&!rf&&!Wf)return;if(Ef||Gf||d[0]===1||d[1]===1){if(s.x=Ef?ff:z.x,s.y=Gf?yf:z.y,z.x=s.x,z.y=s.y,q.length>0){let Kf=ff-X,k=yf-D;for(let Af of q)Af.position={x:Af.position.x-Kf+d[0]*(a-p),y:Af.position.y-k+d[1]*(I-m)},v.push(Af)}}if(rf||Wf)s.width=rf&&(!r.resizeDirection||r.resizeDirection==="horizontal")?a:z.width,s.height=Wf&&(!r.resizeDirection||r.resizeDirection==="vertical")?I:z.height,z.width=s.width,z.height=s.height;if(Y&&N.expandParent){let Kf=d[0]*(s.width??0);if(s.x&&s.x{if(!P)return;H?.(M,{...z}),y?.({...z}),P=!1});$.call(h)}function A(){$.on(".drag",null)}return{update:j,destroy:A}}var $Z=cf(O0(),1),rZ=cf(uZ(),1);var lZ=(f)=>{let u,l=new Set,_=(U,Q)=>{let W=typeof U==="function"?U(u):U;if(!Object.is(W,u)){let G=u;u=(Q!=null?Q:typeof W!=="object"||W===null)?W:Object.assign({},u,W),l.forEach((K)=>K(u,G))}},y=()=>u,A={setState:_,getState:y,getInitialState:()=>J,subscribe:(U)=>{return l.add(U),()=>l.delete(U)},destroy:()=>{l.clear()}},J=u=f(_,y,A);return A},_Z=(f)=>f?lZ(f):lZ;var{useDebugValue:DT}=$Z.default,{useSyncExternalStoreWithSelector:TT}=rZ.default,MT=(f)=>f;function pF(f,u=MT,l){let _=TT(f.subscribe,f.getState,f.getServerState||f.getInitialState,u,l);return DT(_),_}var yZ=(f,u)=>{let l=_Z(f),_=(y,$=u)=>pF(l,y,$);return Object.assign(_,l),_},jZ=(f,u)=>f?yZ(f,u):yZ;function H0(f,u){if(Object.is(f,u))return!0;if(typeof f!=="object"||f===null||typeof u!=="object"||u===null)return!1;if(f instanceof Map&&u instanceof Map){if(f.size!==u.size)return!1;for(let[_,y]of f)if(!Object.is(y,u.get(_)))return!1;return!0}if(f instanceof Set&&u instanceof Set){if(f.size!==u.size)return!1;for(let _ of f)if(!u.has(_))return!1;return!0}let l=Object.keys(f);if(l.length!==Object.keys(u).length)return!1;for(let _ of l)if(!Object.prototype.hasOwnProperty.call(u,_)||!Object.is(f[_],u[_]))return!1;return!0}var PT=cf(d7(),1),I5=_f.createContext(null),nT=I5.Provider,MZ=$l.error001();function f0(f,u){let l=_f.useContext(I5);if(l===null)throw Error(MZ);return pF(l,f,u)}function q0(){let f=_f.useContext(I5);if(f===null)throw Error(MZ);return _f.useMemo(()=>({getState:f.getState,setState:f.setState,subscribe:f.subscribe}),[f])}var AZ={display:"none"},ST={position:"absolute",width:1,height:1,margin:-1,border:0,padding:0,overflow:"hidden",clip:"rect(0px, 0px, 0px, 0px)",clipPath:"inset(100%)"},PZ="react-flow__node-desc",nZ="react-flow__edge-desc",CT="react-flow__aria-live",iT=(f)=>f.ariaLiveMessage,cT=(f)=>f.ariaLabelConfig;function RT({rfId:f}){let u=f0(iT);return lf.jsx("div",{id:`${CT}-${f}`,"aria-live":"assertive","aria-atomic":"true",style:ST,children:u})}function xT({rfId:f,disableKeyboardA11y:u}){let l=f0(cT);return lf.jsxs(lf.Fragment,{children:[lf.jsx("div",{id:`${PZ}-${f}`,style:AZ,children:u?l["node.a11yDescription.default"]:l["node.a11yDescription.keyboardDisabled"]}),lf.jsx("div",{id:`${nZ}-${f}`,style:AZ,children:l["edge.a11yDescription.default"]}),!u&&lf.jsx(RT,{rfId:f})]})}var p5=_f.forwardRef(({position:f="top-left",children:u,className:l,style:_,...y},$)=>{let r=`${f}`.split("-");return lf.jsx("div",{className:M0(["react-flow__panel",l,...r]),style:_,ref:$,...y,children:u})});p5.displayName="Panel";function bT({proOptions:f,position:u="bottom-right"}){if(f?.hideAttribution)return null;return lf.jsx(p5,{position:u,className:"react-flow__attribution","data-message":"Please only hide this attribution when you are subscribed to React Flow Pro: https://pro.reactflow.dev",children:lf.jsx("a",{href:"https://reactflow.dev",target:"_blank",rel:"noopener noreferrer","aria-label":"React Flow attribution",children:"React Flow"})})}var vT=(f)=>{let u=[],l=[];for(let[,_]of f.nodeLookup)if(_.selected)u.push(_.internals.userNode);for(let[,_]of f.edgeLookup)if(_.selected)l.push(_);return{selectedNodes:u,selectedEdges:l}},b5=(f)=>f.id;function hT(f,u){return H0(f.selectedNodes.map(b5),u.selectedNodes.map(b5))&&H0(f.selectedEdges.map(b5),u.selectedEdges.map(b5))}function IT({onSelectionChange:f}){let u=q0(),{selectedNodes:l,selectedEdges:_}=f0(vT,hT);return _f.useEffect(()=>{let y={nodes:l,edges:_};f?.(y),u.getState().onSelectionChangeHandlers.forEach(($)=>$(y))},[l,_,f]),null}var pT=(f)=>!!f.onSelectionChangeHandlers;function mT({onSelectionChange:f}){let u=f0(pT);if(f||u)return lf.jsx(IT,{onSelectionChange:f});return null}var kF=typeof window<"u"?_f.useLayoutEffect:_f.useEffect,SZ=[0,0],gT={x:0,y:0,zoom:1},kT=["nodes","edges","defaultNodes","defaultEdges","onConnect","onConnectStart","onConnectEnd","onClickConnectStart","onClickConnectEnd","nodesDraggable","autoPanOnNodeFocus","nodesConnectable","nodesFocusable","edgesFocusable","edgesReconnectable","elevateNodesOnSelect","elevateEdgesOnSelect","minZoom","maxZoom","nodeExtent","onNodesChange","onEdgesChange","elementsSelectable","connectionMode","snapGrid","snapToGrid","translateExtent","connectOnClick","defaultEdgeOptions","fitView","fitViewOptions","onNodesDelete","onEdgesDelete","onDelete","onNodeDrag","onNodeDragStart","onNodeDragStop","onSelectionDrag","onSelectionDragStart","onSelectionDragStop","onMoveStart","onMove","onMoveEnd","noPanClassName","nodeOrigin","autoPanOnConnect","autoPanOnNodeDrag","onError","connectionRadius","isValidConnection","selectNodesOnDrag","nodeDragThreshold","connectionDragThreshold","onBeforeDelete","debug","autoPanSpeed","ariaLabelConfig","zIndexMode"],FZ=[...kT,"rfId"],tT=(f)=>({setNodes:f.setNodes,setEdges:f.setEdges,setMinZoom:f.setMinZoom,setMaxZoom:f.setMaxZoom,setTranslateExtent:f.setTranslateExtent,setNodeExtent:f.setNodeExtent,reset:f.reset,setDefaultNodesAndEdges:f.setDefaultNodesAndEdges}),JZ={translateExtent:I$,nodeOrigin:SZ,minZoom:0.5,maxZoom:2,elementsSelectable:!0,noPanClassName:"nopan",rfId:"1"};function sT(f){let{setNodes:u,setEdges:l,setMinZoom:_,setMaxZoom:y,setTranslateExtent:$,setNodeExtent:r,reset:j,setDefaultNodesAndEdges:A}=f0(tT,H0),J=q0();kF(()=>{return A(f.defaultNodes,f.defaultEdges),()=>{U.current=JZ,j()}},[]);let U=_f.useRef(JZ);return kF(()=>{for(let Q of FZ){let W=f[Q],G=U.current[Q];if(W===G)continue;if(typeof f[Q]>"u")continue;if(Q==="nodes")u(W);else if(Q==="edges")l(W);else if(Q==="minZoom")_(W);else if(Q==="maxZoom")y(W);else if(Q==="translateExtent")$(W);else if(Q==="nodeExtent")r(W);else if(Q==="ariaLabelConfig")J.setState({ariaLabelConfig:BN(W)});else if(Q==="fitView")J.setState({fitViewQueued:W});else if(Q==="fitViewOptions")J.setState({fitViewOptions:W});else J.setState({[Q]:W})}U.current=f},FZ.map((Q)=>f[Q])),null}function UZ(){if(typeof window>"u"||!window.matchMedia)return null;return window.matchMedia("(prefers-color-scheme: dark)")}function oT(f){let[u,l]=_f.useState(f==="system"?null:f);return _f.useEffect(()=>{if(f!=="system"){l(f);return}let _=UZ(),y=()=>l(_?.matches?"dark":"light");return y(),_?.addEventListener("change",y),()=>{_?.removeEventListener("change",y)}},[f]),u!==null?u:UZ()?.matches?"dark":"light"}var QZ=typeof document<"u"?document:null;function U4(f=null,u={target:QZ,actInsideInputWithModifier:!0}){let[l,_]=_f.useState(!1),y=_f.useRef(!1),$=_f.useRef(new Set([])),[r,j]=_f.useMemo(()=>{if(f!==null){let J=(Array.isArray(f)?f:[f]).filter((Q)=>typeof Q==="string").map((Q)=>Q.replace("+",` +`;function PA({title:u,eyebrow:f,actions:l,children:r,className:y,loading:i}){return Vu("section",{className:`panel ${y||""}`},Vu("div",{className:"panel-head"},Vu("div",null,f?Vu("p",{className:"panel-eyebrow"},f):null,Vu(Af,{title:u,loading:i})),l?Vu("div",{className:"panel-actions"},l):null),Vu("div",{className:"panel-body"},r))}function BZ({title:u,data:f,onOpen:l,testId:r}){return Vu("button",{type:"button",className:"ghost-btn","data-testid":r,onClick:()=>l(u,f)},"查看原始JSON")}function VZ({title:u,text:f}){return Vu("div",{className:"empty-state"},Vu("strong",null,u),Vu("span",null,f))}function fW(u){return u?.runtime&&typeof u.runtime==="object"&&!Array.isArray(u.runtime)?u.runtime:{}}function lW(u){return u?.backend&&typeof u.backend==="object"&&!Array.isArray(u.backend)?u.backend:{}}function rW(u){return u?.repository&&typeof u.repository==="object"&&!Array.isArray(u.repository)?u.repository:{}}function XZ(u){return u.filter((l)=>l?.id==="filebrowser"||String(l?.id||"").startsWith("filebrowser-")).sort((l,r)=>{let y=(i)=>i.providerId==="D518"?0:i.providerId==="D601"?1:i.id==="filebrowser"?2:3;return y(l)-y(r)||String(l.id).localeCompare(String(r.id))})}function YZ(u){if(u?.providerId==="D518")return"D518";return u?.providerId||u?.name||u?.id||"Unknown"}function DZ(u,f,l="/"){let r=l.startsWith("/")?l:`/${l}`;return`${u}/microservices/${encodeURIComponent(f)}/proxy${r}`}function tZ(u,f){return`${u}/microservices/${encodeURIComponent(f)}/health`}async function SZ(u,f=16000){let l=new AbortController,r=setTimeout(()=>l.abort(),f);try{return await Xu(u,{signal:l.signal,failureFields:[!1]})}finally{clearTimeout(r)}}function yW(u){if(u?.providerId==="main-server")return"host / -> /srv";if(u?.providerId==="D601"||u?.providerId==="D518")return"WSL / + /mnt/c -> /srv";return"provider / -> /srv"}function M6(u){return u?.status==="OK"||u?.ok===!0}function PZ({service:u,active:f,health:l,onSelect:r,onRaw:y}){let i=fW(u),_=lW(u),n=rW(u),$=i.container||{},j=M6(l?.body);return Vu("button",{type:"button",className:`filebrowser-target-card ${f?"active":""}`,"data-testid":`filebrowser-target-card-${u.id}`,onClick:r},Vu("span",{className:`status-badge ${j?"ok":i.providerStatus==="online"?"running":"warn"}`},j?"Health OK":i.providerStatus||"unknown"),Vu("strong",null,u.name||u.id),Vu("span",null,yW(u)),Vu("code",null,`${_.nodeBindHost||"--"}:${_.nodePort||"--"}`),Vu("small",null,$.name?`${$.name} / ${$.state||"--"}`:`${n.composeService||"--"}`),Vu("span",{className:"filebrowser-card-raw",onClick:(F)=>{F.stopPropagation(),y(`${u.name} service`,u)}},"JSON"))}function iW(u){try{return u?.contentDocument||u?.contentWindow?.document||null}catch{return null}}function mA(u){let f=iW(u);if(f===null||f.head===null)return!1;let l=f.getElementById("unidesk-filebrowser-compact-style");if(l===null)l=f.createElement("style"),l.id="unidesk-filebrowser-compact-style",f.head.appendChild(l);if(l.textContent!==MA)l.textContent=MA;return!0}function MZ(u,f){let l=URL.createObjectURL(u),r=document.createElement("a");r.href=l,r.download=f,document.body.appendChild(r),r.click(),r.remove(),setTimeout(()=>URL.revokeObjectURL(l),2000)}function mZ(u,f){let l=iW(u);if(l===null||l.documentElement===null)throw Error("无法访问 File Browser iframe 文档");mA(u);let r=Math.max(640,Math.ceil(u.clientWidth||l.documentElement.clientWidth||1280)),y=Math.max(480,Math.ceil(u.clientHeight||l.documentElement.clientHeight||720)),i=l.documentElement.cloneNode(!0);i.querySelectorAll("script, style, link[rel='stylesheet'], link[rel='preload'], link[rel='icon']").forEach((F)=>F.remove()),i.querySelectorAll("img").forEach((F)=>{F.removeAttribute("src"),F.removeAttribute("srcset")});let _=i.querySelector("head");if(_===null)_=l.createElement("head"),i.insertBefore(_,i.firstChild);let n=l.createElement("style");n.textContent=`${MA} +html,body{width:${r}px!important;min-height:${y}px!important;overflow:hidden!important;}`,_.appendChild(n);let $=new XMLSerializer().serializeToString(i),j=`${$}`;MZ(new Blob([j],{type:"image/svg+xml;charset=utf-8"}),f.replace(/\.png$/i,".svg"))}function _W({microservices:u,onRaw:f,apiBaseUrl:l="/api"}){let r=XZ(Array.isArray(u)?u:[]),y=new URLSearchParams(window.location.search).get("target")||"",i=y==="filebrowser-d518"?"filebrowser":y,_=r.some((H)=>H.id===i)?i:r[0]?.id||"",[n,$]=SA(_),[j,F]=SA({loading:!1,refreshedAt:null,health:{},error:""}),[J,U]=SA({exporting:!1,message:"",error:""}),q=OZ(null),W=r.find((H)=>H.id===n)||r[0]||null,G=fW(W),K=lW(W),Q=rW(W),N=W?j.health[W.id]:null,c=W?DZ(l,W.id,"/"):"about:blank";tA(()=>{if(r.length===0)return;if(!n||!r.some((H)=>H.id===n))$(r[0].id)},[r.map((H)=>H.id).join(",")]),tA(()=>{let H=0,B=setInterval(()=>{if(H+=1,mA(q.current)||H>=24)clearInterval(B)},500);return()=>clearInterval(B)},[c]),tA(()=>{if(r.length===0)return;let H=!1;async function B(){F((R)=>({...R,loading:!0,error:""}));let X=await Promise.all(r.map(async(R)=>{try{let Y=await SZ(tZ(l,R.id));return[R.id,{ok:!0,body:Y}]}catch(Y){return[R.id,{ok:!1,error:Bu(Y,"File Browser health failed")}]}}));if(H)return;F({loading:!1,refreshedAt:new Date().toISOString(),health:Object.fromEntries(X),error:""})}B();let T=setInterval(B,30000);return()=>{H=!0,clearInterval(T)}},[r.map((H)=>`${H.id}:${H.runtime?.providerStatus||""}`).join(","),l]);function z(H){$(H);let B=new URL(window.location.href);B.searchParams.set("target",H),window.history.replaceState({},"",`${B.pathname}${B.search}`)}async function w(){if(J.exporting)return;U({exporting:!0,message:"",error:""});try{let H=new Date().toISOString().replace(/[-:.TZ]/g,"").slice(0,14);await mZ(q.current,`unidesk-filebrowser-${W?.id||"target"}-${H}.png`),U({exporting:!1,message:"截图已导出",error:""})}catch(H){U({exporting:!1,message:"",error:Bu(H,"截图导出失败")})}}if(r.length===0)return Vu(VZ,{title:"File Browser 未登记",text:"请在 config.json 的 microservices 中登记 id=filebrowser 或 filebrowser-* 用户服务"});return Vu("div",{className:"filebrowser-page","data-testid":"filebrowser-page"},j.error?Vu(jf,{error:j.error,wide:!0}):null,Vu(PA,{title:"文件管理器",eyebrow:"File Browser / Host Files",loading:j.loading,actions:Vu("div",{className:"panel-actions"},W?Vu("button",{type:"button",className:"ghost-btn",onClick:w,disabled:J.exporting,"data-testid":"filebrowser-export-screenshot"},J.exporting?"导出中...":"导出截图"):null,W?Vu("a",{className:"ghost-btn",href:c,target:"_blank",rel:"noreferrer"},"新窗口打开"):null,W?Vu(BZ,{title:"File Browser 当前目标",data:{service:W,health:N},onOpen:f,testId:"raw-filebrowser-active"}):null)},Vu("div",{className:"filebrowser-hero"},Vu("div",null,Vu("span",{className:`status-badge ${M6(N?.body)?"ok":"warn"}`},M6(N?.body)?"Health OK":"Health Pending"),Vu("h3",null,W?.name||"File Browser"),Vu("p",{className:"muted paragraph"},W?.description||"通过 UniDesk 登录态代理访问,不开放 File Browser 公网端口。"),J.error?Vu("p",{className:"filebrowser-shot-error"},J.error):null,J.message?Vu("p",{className:"filebrowser-shot-ok"},J.message):null),Vu("div",{className:"microservice-ref-card"},Vu("span",null,"Provider"),Vu("strong",null,W?.providerId||"--"),Vu("code",null,G.providerName||W?.providerId||"--")),Vu("div",{className:"microservice-ref-card"},Vu("span",null,"Private Backend"),Vu("strong",null,`${K.nodeBindHost||"--"}:${K.nodePort||"--"}`),Vu("code",null,K.nodeBaseUrl||"--")),Vu("div",{className:"microservice-ref-card"},Vu("span",null,"Image"),Vu("strong",null,Q.dockerfile||"filebrowser/filebrowser:v2.63.3"),Vu("code",null,Q.commitId||"--")),Vu("div",{className:"microservice-ref-card"},Vu("span",null,"Mount"),Vu("strong",null,yW(W)),Vu("code",null,W?.providerId==="main-server"?"/root, /var, /home":"/home, /mnt/c, /mnt/d")))),Vu(PA,{title:"浏览目标",eyebrow:`${r.length} host targets`,loading:j.loading},Vu("div",{className:"filebrowser-target-grid"},r.map((H)=>Vu(PZ,{key:H.id,service:H,active:H.id===W?.id,health:j.health[H.id],onSelect:()=>z(H.id),onRaw:f})))),Vu(PA,{title:`${YZ(W)} 文件视图`,eyebrow:N?.body?`Health ${M6(N.body)?"OK":"UNKNOWN"} / ${j.refreshedAt?qf(j.refreshedAt):"--"}`:"Embedded WebUI",className:"filebrowser-frame-panel"},Vu("div",{className:"filebrowser-frame-shell"},Vu("div",{className:"filebrowser-frame-toolbar"},Vu("span",null,"BaseURL"),Vu("code",null,`/api/microservices/${W?.id||"filebrowser"}/proxy`),Vu("span",null,"Root"),Vu("code",null,"/srv"),Vu("span",{className:"filebrowser-compact-note"},"Compact layout injected")),Vu("iframe",{ref:q,key:c,title:`${W?.name||"File Browser"} WebUI`,src:c,className:"filebrowser-frame","data-testid":"filebrowser-frame",onLoad:(H)=>mA(H.currentTarget),sandbox:"allow-downloads allow-forms allow-modals allow-same-origin allow-scripts"}))))}var x6=Pu(wf(),1);var Ju=x6.default.createElement,{useEffect:pZ}=x6.default,CZ=x6.default.useState;function m6({status:u,children:f}){let l=String(u||"unknown").toLowerCase();return Ju("span",{className:`status-badge ${l}`},f||u||"unknown")}function c1({label:u,value:f,hint:l,tone:r}){return Ju("article",{className:`metric-card ${r||""}`},Ju("div",{className:"metric-label"},u),Ju("div",{className:"metric-value"},f),Ju("div",{className:"metric-hint"},l))}function p6({title:u,eyebrow:f,actions:l,children:r,className:y,loading:i}){return Ju("section",{className:`panel ${y||""}`},Ju("div",{className:"panel-head"},Ju("div",null,f?Ju("p",{className:"panel-eyebrow"},f):null,Ju(Af,{title:u,loading:i})),l?Ju("div",{className:"panel-actions"},l):null),Ju("div",{className:"panel-body"},r))}function C6({title:u,data:f,onOpen:l,testId:r}){return Ju("button",{type:"button",className:"ghost-btn","data-testid":r,onClick:()=>l(u,f)},"查看原始JSON")}function pA({title:u,text:f}){return Ju("div",{className:"empty-state"},Ju("strong",null,u),Ju("span",null,f))}function xZ(u){return u?.runtime&&typeof u.runtime==="object"&&!Array.isArray(u.runtime)?u.runtime:{}}function RZ(u){return u?.backend&&typeof u.backend==="object"&&!Array.isArray(u.backend)?u.backend:{}}function hZ(u){return u?.repository&&typeof u.repository==="object"&&!Array.isArray(u.repository)?u.repository:{}}function Jy(u,f){let l=u&&typeof u==="object"?u[f]:void 0;return Number.isFinite(Number(l))?String(l):"--"}function bZ(u){return(Array.isArray(u?.jobs)?u.jobs:[]).slice(0,40)}function vZ(u){return(Array.isArray(u?.drafts)?u.drafts:[]).slice(0,12)}function nW({microservices:u,onRaw:f,apiBaseUrl:l="/api"}){let r=u.find((W)=>W.id==="findjob")||null,[y,i]=CZ({loading:!1,error:"",health:null,summary:null,jobs:null,drafts:null,refreshedAt:null});async function _(){if(!r)return;i((W)=>({...W,loading:!0,error:""}));try{let[W,G,K,Q]=await Promise.all([Xu(`${l}/microservices/findjob/health`),Xu(`${l}/microservices/findjob/proxy/api/summary`),Xu(`${l}/microservices/findjob/proxy/api/jobs?__unideskArrayLimit=jobs:40`),Xu(`${l}/microservices/findjob/proxy/api/drafts`)]);i({loading:!1,error:"",health:W,summary:G,jobs:K,drafts:Q,refreshedAt:new Date})}catch(W){i((G)=>({...G,loading:!1,error:Bu(W,"FindJob 加载失败")}))}}if(pZ(()=>{_()},[r?.id,r?.runtime?.providerStatus]),!r)return Ju(pA,{title:"FindJob 未登记",text:"请在 config.json 的 microservices 中登记用户服务 id=findjob"});let n=xZ(r),$=hZ(r),j=RZ(r),F=y.summary||{},J=bZ(y.jobs),U=vZ(y.drafts),q=y.jobs?._unidesk?.arrayLimits?.jobs;return Ju("div",{className:"findjob-page","data-testid":"findjob-page"},Ju(p6,{title:"FindJob 工作台",eyebrow:"D601 用户服务",loading:y.loading,actions:Ju("div",{className:"panel-actions"},Ju("button",{type:"button",className:"ghost-btn",onClick:_,disabled:y.loading,"data-testid":"findjob-refresh-button"},y.loading?"刷新中":"刷新"),Ju(C6,{title:"FindJob 用户服务",data:r,onOpen:f,testId:"raw-findjob-service"}))},Ju("div",{className:"findjob-hero"},Ju("div",null,Ju("div",{className:"node-version-line"},Ju(m6,{status:n.providerStatus==="online"?"online":"warn"},n.providerStatus||"unknown"),Ju("span",null,r.providerId),Ju("span",null,j.public?"公网暴露":"仅 UniDesk frontend 代理访问")),Ju("p",{className:"muted paragraph"},r.description)),Ju("div",{className:"microservice-ref-card"},Ju("span",null,"Repo"),Ju("strong",null,$.url||"--"),Ju("code",null,$.commitId||"--")),Ju("div",{className:"microservice-ref-card"},Ju("span",null,"D601 Docker"),Ju("strong",null,`${j.nodeBindHost||"--"}:${j.nodePort||"--"}`),Ju("code",null,`${$.composeFile||"--"} / ${$.composeService||"--"}`))),Ju(jf,{error:y.error,wide:!0})),Ju("div",{className:"findjob-grid"},Ju(p6,{title:"岗位指标",eyebrow:y.refreshedAt?`Updated ${qf(y.refreshedAt)}`:"Summary",loading:y.loading},Ju("div",{className:"metric-grid"},Ju(c1,{label:"岗位总量",value:Jy(F,"totalJobs"),hint:"tracked jobs",tone:"ok"}),Ju(c1,{label:"原始岗位",value:Jy(F,"rawJobs"),hint:"raw queue"}),Ju(c1,{label:"已验证",value:Jy(F,"verifiedJobs"),hint:"verified set"}),Ju(c1,{label:"优先处理",value:Jy(F,"prioritizedJobs"),hint:"prioritized"}),Ju(c1,{label:"过期",value:Jy(F,"staleJobs"),hint:"stale jobs",tone:"warn"}),Ju(c1,{label:"无效",value:Jy(F,"invalidJobs"),hint:"invalid jobs",tone:"warn"}),Ju(c1,{label:"上海",value:Jy(F,"shanghaiJobs"),hint:"city filter"}),Ju(c1,{label:"Health",value:y.health?.ok?"OK":"--",hint:"D601 /api/health"})),Ju("div",{className:"panel-actions inline-actions"},Ju(C6,{title:"FindJob Summary",data:F,onOpen:f,testId:"raw-findjob-summary"}))),Ju(p6,{title:"近期岗位",eyebrow:q?`${q.returnedLength}/${q.originalLength} Preview`:`${J.length} Preview`,loading:y.loading},J.length===0?Ju(pA,{title:"暂无岗位预览",text:"等待 D601 findjob backend 返回 /api/jobs"}):Ju("div",{className:"table-wrap findjob-job-table"},Ju("table",null,Ju("thead",null,Ju("tr",null,Ju("th",null,"优先级"),Ju("th",null,"状态"),Ju("th",null,"单位"),Ju("th",null,"职位"),Ju("th",null,"城市"),Ju("th",null,"阶段"),Ju("th",null,"截止"),Ju("th",null,"证据"))),Ju("tbody",null,J.map((W)=>Ju("tr",{key:W.id},Ju("td",null,Ju(m6,{status:String(W.priority||"").toLowerCase()||"unknown"},W.priority||"--")),Ju("td",null,Ju(m6,{status:String(W.status||"").toLowerCase()||"unknown"},W.status||"--")),Ju("td",null,W.organization_name||"--",Ju("code",null,W.id||"--")),Ju("td",null,W.display_title||W.title||"--"),Ju("td",null,W.display_city||W.city||"--"),Ju("td",null,W.workflow_stage||"--"),Ju("td",null,W.deadline||"--"),Ju("td",null,W.evidence_url?Ju("a",{href:W.evidence_url,target:"_blank",rel:"noreferrer"},"打开"):Ju("span",{className:"muted"},"无"))))))),Ju("div",{className:"panel-actions inline-actions"},Ju(C6,{title:"FindJob Jobs Preview",data:y.jobs,onOpen:f,testId:"raw-findjob-jobs"}))),Ju(p6,{title:"草稿与报告",eyebrow:`${U.length} Drafts`,loading:y.loading},U.length===0?Ju(pA,{title:"暂无草稿",text:"D601 findjob backend 未返回 drafts"}):Ju("div",{className:"draft-list"},U.map((W)=>Ju("article",{key:W.id,className:"draft-card"},Ju("div",{className:"node-card-head"},Ju("strong",null,W.id),Ju(m6,{status:W.status},W.status||"--")),Ju("div",{className:"docker-meta compact"},Ju("span",null,W.workflow_stage||"--"),Ju("span",null,`jobs ${W.counts?.jobs??0}`),Ju("span",null,`reports ${W.counts?.reports??0}`)),Ju("span",null,W.latestReportPath||"暂无报告"),Ju("code",null,Nu(W.updated_at||W.updatedAt))))),Ju("div",{className:"panel-actions inline-actions"},Ju(C6,{title:"FindJob Drafts",data:y.drafts,onOpen:f,testId:"raw-findjob-drafts"})))))}var Dn=Pu(wf(),1);var p=Dn.default.createElement,{useEffect:IZ}=Dn.default,CA=Dn.default.useState;function Vn(u){let f=Number(u);return Number.isFinite(f)?`${Math.max(0,Math.min(100,f)).toFixed(1)}%`:"--"}function RA(u){if(u===null||u===void 0||u==="")return"--";let f=Number(u);if(!Number.isFinite(f))return"--";if(f<60)return`${Math.max(0,Math.round(f))}s`;if(f<3600)return`${Math.floor(f/60)}m ${Math.round(f%60)}s`;return`${Math.floor(f/3600)}h ${Math.floor(f%3600/60)}m`}function hA(u,f=2){let l=Number(u);if(!Number.isFinite(l))return u===!1?"false":u===!0?"true":"--";let r=Math.abs(l);if(Number.isInteger(l)||r>=1000)return l.toLocaleString("zh-CN",{maximumFractionDigits:0});if(r>=1)return l.toLocaleString("zh-CN",{maximumFractionDigits:f});return l.toLocaleString("zh-CN",{maximumFractionDigits:Math.max(f,6)})}function Yn(u){if(u===null||u===void 0||u==="")return"--";if(typeof u==="boolean")return u?"true":"false";if(typeof u==="number")return hA(u,4);if(Array.isArray(u))return u.map((f)=>Yn(f)).join(" x ");if(typeof u==="object")return"已上报";return String(u)}function R6(u){let f=Number(u);if(!Number.isFinite(f)||f<=0)return"--";let l=f>=100?0:f>=10?1:2;return`${f.toLocaleString("zh-CN",{maximumFractionDigits:l})} epoch/h`}function h6(u){return u.replace(/[^a-zA-Z0-9_-]/g,"-")}function pl(u){return u&&typeof u==="object"&&!Array.isArray(u)?u:{}}function Xn({status:u,children:f}){let l=String(u||"unknown").toLowerCase();return p("span",{className:`status-badge ${l}`},f||u||"unknown")}function N1({label:u,value:f,hint:l,tone:r}){return p("article",{className:`metric-card ${r||""}`},p("div",{className:"metric-label"},u),p("div",{className:"metric-value"},f),p("div",{className:"metric-hint"},l))}function xA({title:u,eyebrow:f,actions:l,children:r,className:y,loading:i}){return p("section",{className:`panel ${y||""}`},p("div",{className:"panel-head"},p("div",null,f?p("p",{className:"panel-eyebrow"},f):null,p(Af,{title:u,loading:i})),l?p("div",{className:"panel-actions"},l):null),p("div",{className:"panel-body"},r))}function Oi({title:u,data:f,onOpen:l,testId:r}){return p("button",{type:"button",className:"ghost-btn","data-testid":r,onClick:(y)=>{y?.stopPropagation?.(),l(u,f)}},"查看原始JSON")}function O0({title:u,text:f}){return p("div",{className:"empty-state"},p("strong",null,u),p("span",null,f))}function kZ(u){return u?.runtime&&typeof u.runtime==="object"&&!Array.isArray(u.runtime)?u.runtime:{}}function gZ(u){return u?.backend&&typeof u.backend==="object"&&!Array.isArray(u.backend)?u.backend:{}}function sZ(u){return u?.repository&&typeof u.repository==="object"&&!Array.isArray(u.repository)?u.repository:{}}function aZ(u){return u?.counts&&typeof u.counts==="object"&&!Array.isArray(u.counts)?u.counts:{}}function oZ(u){return Array.isArray(u?.jobs)?u.jobs.slice(0,240):[]}function dZ(u){return Array.isArray(u?.projects)?u.projects.slice(0,1000):[]}function b6(u){return Array.isArray(u?.projects)?u.projects:[]}function eZ(u,f){if(Array.isArray(f?.gpu))return f.gpu;if(Array.isArray(u?.gpu))return u.gpu;return[]}function ir(u,f){return`${u}/microservices/met-nonlinear/proxy${f}`}function $W(u){return u.startedAt&&u.finishedAt?RA((Date.parse(u.finishedAt)-Date.parse(u.startedAt))/1000):"--"}function uH(u){let f=u.progress||{};if(f.etaSeconds!==null&&f.etaSeconds!==void 0&&f.etaSeconds!==""){let _=Number(f.etaSeconds);if(Number.isFinite(_))return Math.max(0,_)}let l=Number(f.currentEpoch),r=Number(f.epochTarget??u.epochTarget),y=Date.parse(u.startedAt||"");if(!Number.isFinite(l)||l<=0||!Number.isFinite(r)||r<=l||!Number.isFinite(y))return null;let i=Math.max(0,(Date.now()-y)/1000);if(i<=0)return null;return Math.max(0,i/l*(r-l))}function AW(u){let f=u.progress||{},l=Number(f.epochPerHour);if(Number.isFinite(l)&&l>0)return l;let r=Date.parse(u.startedAt||""),y=["succeeded","failed","canceled"].includes(u.status)?Date.parse(u.finishedAt||""):Date.now();if(!Number.isFinite(r)||!Number.isFinite(y)||y<=r)return null;let i=Number(f.currentEpoch??u.epochTarget);if(!Number.isFinite(i)||i<=0)return null;return i/((y-r)/3600000)}function jW(u){if(u==="staged")return"待启动";if(u==="queued")return"排队中";if(u==="running")return"训练中";if(u==="succeeded")return"已完成";if(u==="failed")return"失败";if(u==="canceled")return"已取消";return u||"unknown"}function FW(u,f,l){return{name:u,path:f,depth:l,count:0,children:[],project:null}}function fH(u){let f=FW("","",-1);for(let r of u){let i=String(r?.projectPath||"").replace(/\\/g,"/").split("/").filter(Boolean);if(i.length===0)continue;let _=f,n=[];for(let[$,j]of i.entries()){n.push(j);let F=n.join("/"),J=_.children.find((U)=>U.path===F);if(!J)J=FW(j,F,$),_.children.push(J);if($===i.length-1)J.project=r;_=J}}let l=(r)=>{let y=r.children.reduce((i,_)=>i+l(_),0);return r.count=(r.project?1:0)+y,r.children.sort((i,_)=>{if(Boolean(i.project)!==Boolean(_.project))return i.project?1:-1;return i.name.localeCompare(_.name,"zh-CN",{numeric:!0,sensitivity:"base"})}),r.count};return l(f),f}function lH(u){let f=pl(u.data);return pl(f.project).projectPath?pl(f.project):f}function rH(u){return pl(pl(u.data).job)}function JW({microservices:u,onRaw:f,apiBaseUrl:l="/api"}){let r=u.find((m)=>m.id==="met-nonlinear")||null,[y,i]=CA({loading:!1,actionBusy:!1,error:"",health:null,summary:null,queue:null,projects:null,history:null,images:null,refreshedAt:null}),[_,n]=CA({loading:!1,error:"",kind:"",key:"",title:"",data:null}),[$,j]=CA(()=>({activeTab:"projects",selectedProjects:{},expandedProjectDirs:{},sourceProject:"",forkCount:1,forkEpochs:200,forkPrefix:`ui_fork_${Date.now()}`,maxConcurrency:3,targetGpuName:"2080 Ti",actionMessage:""}));function F(m){j((d)=>({...d,...m}))}async function J(m=$.activeTab){if(!r)return;i((d)=>({...d,loading:!0,error:""}));try{let d=[["health",Xu(`${l}/microservices/met-nonlinear/health`)],["summary",Xu(ir(l,"/api/summary"))]];if(m==="projects")d.push(["projectsRoot",Xu(ir(l,"/api/projects?root=projects&limit=500"))]),d.push(["exProjectsRoot",Xu(ir(l,"/api/projects?root=ex_projects&limit=500"))]);if(m==="current"||m==="completed"||m==="failed")d.push(["queue",Xu(ir(l,"/api/queue"))]);if(m==="completed"||m==="failed")d.push(["history",Xu(ir(l,"/api/history"))]);if(m==="gpu")d.push(["images",Xu(ir(l,"/api/images"))]);let e=Object.fromEntries(await Promise.all(d.map(async([g,Qu])=>[g,await Qu]))),cu={loading:!1,actionBusy:!1,error:"",health:e.health,summary:e.summary,refreshedAt:new Date};if(e.projectsRoot||e.exProjectsRoot){let{projectsRoot:g,exProjectsRoot:Qu}=e;cu.projects={ok:g?.ok!==!1&&Qu?.ok!==!1,roots:[{root:"projects",count:b6(g).length},{root:"ex_projects",count:b6(Qu).length}],projects:[...b6(g),...b6(Qu)]}}if(e.queue)cu.queue=e.queue;if(e.history)cu.history=e.history;if(e.images)cu.images=e.images;i((g)=>({...g,...cu}))}catch(d){i((e)=>({...e,loading:!1,actionBusy:!1,error:Bu(d,"MET Nonlinear 加载失败")}))}}async function U(m,d){i((e)=>({...e,actionBusy:!0,error:""})),F({actionMessage:`${m}...`});try{let e=await d();F({actionMessage:e||`${m}完成`}),await J()}catch(e){i((cu)=>({...cu,actionBusy:!1,error:Bu(e,`${m}失败`)}))}}async function q(){await U("保存并发设置",async()=>{await Xu(ir(l,"/api/queue/settings"),{method:"PUT",body:JSON.stringify({maxConcurrency:Number($.maxConcurrency),targetGpuName:$.targetGpuName})})})}function W(){return Object.entries($.selectedProjects).filter(([,m])=>m).map(([m])=>m)}async function G(){let m=W();if(m.length===0)throw Error("请先选择至少一个 project");await U("加入待启动队列",async()=>{await Xu(ir(l,"/api/queue"),{method:"POST",body:JSON.stringify({projectPaths:m,maxConcurrency:Number($.maxConcurrency),targetGpuName:$.targetGpuName,start:!1})}),F({activeTab:"current",selectedProjects:{}})})}async function K(){let m=$.sourceProject||t[0]?.projectPath;if(!m)throw Error("请先选择源 project");await U("Fork Project",async()=>{let d=await Xu(ir(l,"/api/projects/fork"),{method:"POST",body:JSON.stringify({sourceProject:m,count:Number($.forkCount),epochs:Number($.forkEpochs),prefix:$.forkPrefix})}),e=Array.isArray(d.projectPaths)?d.projectPaths:[],cu=e.reduce((g,Qu)=>{return g[Qu]=!0,g},{...$.selectedProjects});return F({selectedProjects:cu}),`已 fork ${e.length} 个 project,并已自动勾选;请确认后点击加入待启动队列。`})}async function Q(){await U("启动队列",async()=>{await Xu(ir(l,"/api/queue/start"),{method:"POST",body:JSON.stringify({maxConcurrency:Number($.maxConcurrency),targetGpuName:$.targetGpuName})}),F({activeTab:"current"})})}async function N(m){await U("取消任务",async()=>{await Xu(ir(l,`/api/jobs/${encodeURIComponent(m.id)}/cancel`),{method:"POST",body:JSON.stringify({})})})}async function c(m){let d=String(m?.projectPath||"");if(!d)return;n({loading:!0,error:"",kind:"project",key:d,title:d,data:null});try{let e=await Xu(ir(l,`/api/projects/config?path=${encodeURIComponent(d)}`));n({loading:!1,error:"",kind:"project",key:d,title:d,data:e})}catch(e){n({loading:!1,error:Bu(e,"Project 详情加载失败"),kind:"project",key:d,title:d,data:null})}}async function z(m){let d=String(m?.id||"");if(!d)return;n({loading:!0,error:"",kind:"job",key:d,title:m.projectPath||d,data:null});try{let e=await Xu(ir(l,`/api/jobs/${encodeURIComponent(d)}`));n({loading:!1,error:"",kind:"job",key:d,title:e?.job?.projectPath||m.projectPath||d,data:e})}catch(e){n({loading:!1,error:Bu(e,"Job 详情加载失败"),kind:"job",key:d,title:m.projectPath||d,data:null})}}if(IZ(()=>{J($.activeTab)},[r?.id,r?.runtime?.providerStatus,$.activeTab]),!r)return p(O0,{title:"MET Nonlinear 未登记",text:"请在 config.json 的 microservices 中登记用户服务 id=met-nonlinear"});let w=kZ(r),H=sZ(r),B=gZ(r),T=aZ(y.queue?.queue||y.summary?.queue),X=eZ(y.health,y.queue),R=y.health?.targetGpu||y.summary?.targetGpu||X.find((m)=>String(m.name||"").includes("2080")),Y=y.images?.mlImage||y.health?.image||{},P=oZ(y.queue),t=dZ(y.projects),O=fH(t),M=$.sourceProject||t[0]?.projectPath||"",S=P.filter((m)=>["staged","queued","running"].includes(m.status)),b=P.filter((m)=>m.status==="succeeded"),Z=P.filter((m)=>["failed","canceled"].includes(m.status)),D=Array.isArray(y.history?.jobs)?y.history.jobs.slice(0,120):[],I=[{id:"projects",label:"项目库",count:t.length},{id:"current",label:"当前队列",count:S.length||Number(T.staged||0)+Number(T.queued||0)+Number(T.running||0)},{id:"completed",label:"已完成",count:b.length||Number(T.succeeded||0)},{id:"failed",label:"失败诊断",count:Z.length||Number(T.failed||0)+Number(T.canceled||0)},{id:"gpu",label:"GPU/镜像",count:X.length}];function k(m,d){if(m.length===0)return p(O0,{title:d==="current"?"当前队列为空":"暂无记录",text:d==="current"?"从项目库选择或 fork project 后先加入待启动队列,再启动队列。":"终态任务会显示耗时、exit code 和失败诊断。"});return p("div",{className:"table-wrap met-job-table"},p("table",null,p("thead",null,p("tr",null,p("th",null,"状态"),p("th",null,"Project"),p("th",null,"Epoch"),p("th",null,"速度"),p("th",null,"ETA/耗时"),p("th",null,"GPU"),p("th",null,"Exit"),p("th",null,"更新时间"),p("th",null,"操作"))),p("tbody",null,m.map((e)=>{let cu=e.progress||{},g=["staged","queued","running"].includes(e.status),Qu=_.kind==="job"&&_.key===e.id;return p("tr",{key:e.id,className:`met-click-row ${Qu?"active":""}`,onClick:()=>z(e),"data-testid":`met-job-row-${h6(e.id)}`},p("td",null,p(Xn,{status:e.status},jW(e.status))),p("td",null,p("button",{type:"button",className:"met-inline-link",onClick:(Eu)=>{Eu.stopPropagation(),z(e)}},e.projectPath),p("code",null,e.id)),p("td",null,p("span",null,`${cu.currentEpoch??"--"} / ${cu.epochTarget??e.epochTarget??"--"}`),p("div",{className:"met-progress"},p("span",{style:{width:Vn(cu.progressPercent)}}))),p("td",null,p("strong",null,R6(AW(e)))),p("td",null,e.status==="succeeded"||e.status==="failed"||e.status==="canceled"?$W(e):e.status==="running"?`ETA ${RA(uH(e))}`:"--"),p("td",null,e.gpuName||"--"),p("td",null,e.exitCode??"--"),p("td",null,Nu(e.updatedAt)),p("td",null,g?p("button",{type:"button",className:"ghost-btn mini",onClick:(Eu)=>{Eu.stopPropagation(),N(e)},disabled:y.actionBusy},"取消"):null,p(Oi,{title:`MET Job ${e.id}`,data:e,onOpen:f,testId:`raw-met-job-${e.id}`})))}))))}function h(){return p("div",{className:"met-queue-summary","data-testid":"met-current-summary"},p(Xn,{status:"staged"},`待启动 ${T.staged??0}`),p(Xn,{status:"queued"},`排队中 ${T.queued??0}`),p(Xn,{status:"running"},`训练中 ${T.running??0}`),p("span",null,`最大并发 ${y.summary?.queue?.maxConcurrency??y.queue?.queue?.maxConcurrency??$.maxConcurrency}`),p("span",null,`目标 GPU ${y.summary?.queue?.targetGpuName??y.queue?.queue?.targetGpuName??$.targetGpuName}`))}function o(m,d){let e=$.expandedProjectDirs[m];return e===void 0?d<2:Boolean(e)}function s(m,d){let e=o(m,d);F({expandedProjectDirs:{...$.expandedProjectDirs,[m]:!e}})}function x(m){let d=8+Math.max(0,m.depth)*16;if(Boolean(m.project)){let g=m.project,Qu=Boolean($.selectedProjects[g.projectPath]),Eu=_.kind==="project"&&_.key===g.projectPath;return p("div",{key:m.path,className:`met-tree-row project ${Qu?"selected":""} ${Eu?"active":""}`,style:{paddingLeft:d},onClick:()=>c(g),"data-testid":`met-project-node-${h6(g.projectPath)}`},p("div",{className:"met-tree-name"},p("input",{type:"checkbox",checked:Qu,onClick:(Tu)=>Tu.stopPropagation(),onChange:(Tu)=>F({selectedProjects:{...$.selectedProjects,[g.projectPath]:Tu.target.checked}}),"data-testid":`met-project-checkbox-${h6(g.projectPath)}`}),p("button",{type:"button",className:"met-inline-link project-path",onClick:(Tu)=>{Tu.stopPropagation(),c(g)}},m.name)),p("span",null,g.useModel||"--"),p("span",null,g.epochTrain??"--"),p("span",null,Vn(g.progress?.progressPercent)),p("span",null,R6(g.progress?.epochPerHour)))}let cu=o(m.path,m.depth);return p(Dn.default.Fragment,{key:m.path},p("div",{className:"met-tree-row folder",style:{paddingLeft:d},"data-testid":`met-project-folder-${h6(m.path)}`},p("button",{type:"button",className:"met-tree-toggle",onClick:()=>s(m.path,m.depth),"aria-label":cu?`折叠 ${m.path}`:`展开 ${m.path}`},cu?"-":"+"),p("strong",null,m.name),p("span",{className:"met-tree-count"},`${m.count} projects`)),cu?m.children.map((g)=>x(g)):null)}function uu(m){return p("div",{className:"met-detail-kv"},m.map((d)=>p("div",{key:d.label,className:"met-detail-kv-item"},p("span",null,d.label),p("strong",null,Yn(d.value)),d.hint?p("small",null,d.hint):null)))}function nu(m,d){return p("div",{className:"met-detail-section"},p("h3",null,m),uu(d))}function $u(m){if(!Array.isArray(m)||m.length===0)return p(O0,{title:"模型层未上报",text:"等待 data/model_info.json 或 compute_analysis.json 生成。"});return p("div",{className:"table-wrap met-layer-table"},p("table",null,p("thead",null,p("tr",null,p("th",null,"Layer"),p("th",null,"Type"),p("th",null,"Params"),p("th",null,"Trainable"),p("th",null,"Compute"))),p("tbody",null,m.slice(0,18).map((d,e)=>p("tr",{key:`${d.name||"layer"}-${e}`},p("td",null,d.name||`#${e+1}`),p("td",null,d.type||"--"),p("td",null,hA(d.num_params)),p("td",null,d.trainable===void 0?"--":String(Boolean(d.trainable))),p("td",null,hA(d.compute?.total??d.estimated_cost?.weighted_units?.total)))))))}function Fu(m){let d=Array.isArray(m)?m:[];if(d.length===0)return p(O0,{title:"data/ 暂无文件",text:"训练或评估完成后会生成 training_state、metrics、model_info 等文件。"});return p("div",{className:"met-file-chip-grid"},d.slice(0,48).map((e)=>p("span",{key:e},e)),d.length>48?p("span",null,`+${d.length-48}`):null)}function Ku(m){let d=String(m||"").replace(/\x1b\[[0-9;]*[A-Za-z]/g,"").split(/\r?\n/).map((e)=>e.trim()).filter(Boolean).slice(-12);if(d.length===0)return p(O0,{title:"暂无日志尾部",text:"该任务未上报 logTail 或日志已轮转。"});return p("div",{className:"met-log-lines"},d.map((e,cu)=>p("div",{key:`${cu}-${e.slice(0,16)}`},e)))}function Wu(){if(_.loading)return p("section",{className:"met-detail-panel","data-testid":"met-detail-panel"},p("div",{className:"panel-head compact"},p("div",null,p("p",{className:"panel-eyebrow"},"Detail Loading"),p(Af,{title:"详情加载中",loading:!0}))),p(O0,{title:"详情加载中",text:_.title||"正在读取 D601 data/ 和 config.json"}));if(_.error)return p("section",{className:"met-detail-panel","data-testid":"met-detail-panel"},p(jf,{error:_.error,wide:!0}));if(!_.data)return p("section",{className:"met-detail-panel muted","data-testid":"met-detail-panel"},p(O0,{title:"选择一个项目或任务查看详情",text:"项目库、当前队列、已完成和失败诊断中的行都可以点击;默认只展示结构化字段,原始 JSON 需显式点击按钮。"}));let m=lH(_),d=rH(_),e=pl(m.config),cu=pl(m.progress||d.progress),g=pl(m.data),Qu=pl(m.metrics||g.metrics||cu.trainingInfo?.evaluation_metrics),Eu=pl(g.trainingInfo||cu.trainingInfo),Tu=pl(g.trainingState),Du=pl(m.model||g.model),ff=Array.isArray(Du.modelSummary)&&Du.modelSummary.length>0?Du.modelSummary:Du.computeLayers,rf=pl(Eu.evaluation_metrics),Lf=_.kind==="job"?"训练任务详情":"Project 详情";return p("section",{className:"met-detail-panel","data-testid":"met-detail-panel"},p("div",{className:"panel-head compact"},p("div",null,p("p",{className:"panel-eyebrow"},_.kind==="job"?"Job + Project Detail":"Project Library Detail"),p(Af,{title:Lf}),p("code",null,m.projectPath||d.projectPath||_.title)),p("div",{className:"panel-actions"},p(Oi,{title:`MET ${Lf}`,data:_.data,onOpen:f,testId:"raw-met-detail"}))),_.kind==="job"?nu("任务状态",[{label:"Job ID",value:d.id},{label:"状态",value:jW(d.status)},{label:"GPU",value:d.gpuName},{label:"Exit Code",value:d.exitCode},{label:"耗时",value:$W(d)},{label:"训练速度",value:R6(AW({...d,progress:cu}))}]):null,nu("config.json",[{label:"use_model",value:e.use_model},{label:"epoch_train",value:e.epoch_train},{label:"step_per_epoch",value:e.step_per_epoch},{label:"learning_rate",value:e.learning_rate},{label:"using_gpu",value:e.using_gpu},{label:"use_points",value:e.use_points},{label:"sample_rate",value:e.sample_rate},{label:"time_clipped_s",value:e.time_clipped_s},{label:"H_UNITS",value:e.H_UNITS},{label:"INNER_KAN_UNITS",value:e.INNER_KAN_UNITS},{label:"INNER_KAN_LAYERS",value:e.INNER_KAN_LAYERS},{label:"GRID_SIZE",value:e.GRID_SIZE},{label:"SPLINE_ORDER",value:e.SPLINE_ORDER},{label:"USE_FAST_MODEL",value:e.USE_FAST_MODEL},{label:"IIR_TRAINABLE",value:e.IIR_TRAINABLE}]),nu("data/ 训练状态",[{label:"Epoch",value:`${cu.currentEpoch??Tu.current_epoch??Tu.completed_epoch??"--"} / ${cu.epochTarget??e.epoch_train??"--"}`},{label:"Progress",value:Vn(cu.progressPercent)},{label:"Last Loss",value:cu.lastLoss??Tu.loss},{label:"Last Val Loss",value:cu.lastValLoss??Tu.val_loss},{label:"Min Loss",value:Eu.min_loss??Tu.min_loss},{label:"Min Val Loss",value:Eu.min_val_loss??Tu.min_val_loss},{label:"Log Lines",value:cu.logLineCount},{label:"ETA",value:RA(cu.etaSeconds??Tu.remaining_time)},{label:"训练速度",value:R6(cu.epochPerHour??Tu.smoothed_speed)},{label:"Training Alive",value:Tu.training_alive}]),nu("模型参数",[{label:"Model Type",value:Du.modelType??e.use_model},{label:"Total Params",value:Du.totalParams,hint:Du.totalParams===null||Du.totalParams===void 0?"未上报":"data/model_info.json"},{label:"Trainable",value:Du.trainableParams},{label:"Non-trainable",value:Du.nonTrainableParams},{label:"Compute Cost",value:Du.computeCost},{label:"Estimate Status",value:Du.estimateStatus},{label:"Unsupported Layers",value:Du.unsupportedLayerCount}]),nu("指标",[{label:"train_loss",value:Qu.train_loss??rf.train_loss},{label:"val_loss",value:Qu.val_loss??rf.val_loss},{label:"train_mae",value:Qu.train_mae??rf.train_mae},{label:"val_mae",value:Qu.val_mae??rf.val_mae},{label:"train_afmae",value:Qu.train_afmae??rf.train_afmae},{label:"val_afmae",value:Qu.val_afmae??rf.val_afmae},{label:"freq_drift_hz",value:Qu.freq_drift_hz},{label:"sens_drift_percent",value:Qu.sens_drift_percent},{label:"linearity_percent",value:Qu.linearity_percent},{label:"weights_source",value:Qu.weights_source??rf.weights_source},{label:"lr min/mean/max",value:`${Yn(Eu.learning_rate_min)} / ${Yn(Eu.learning_rate_mean)} / ${Yn(Eu.learning_rate_max)}`}]),p("div",{className:"met-detail-section"},p("h3",null,"模型层"),$u(ff)),p("div",{className:"met-detail-section"},p("h3",null,"data/ 文件"),Fu(g.files)),_.kind==="job"?p("div",{className:"met-detail-section"},p("h3",null,"日志尾部"),Ku(pl(_.data).logTail)):null)}return p("div",{className:"met-page","data-testid":"met-nonlinear-page"},p(xA,{title:"MET Nonlinear 训练编排",eyebrow:"D601 GPU 用户服务",loading:y.loading||y.actionBusy,actions:p("div",{className:"panel-actions"},p("button",{type:"button",className:"ghost-btn",onClick:J,disabled:y.loading,"data-testid":"met-refresh-button"},y.loading?"刷新中":"刷新"),p(Oi,{title:"MET Nonlinear 用户服务",data:r,onOpen:f,testId:"raw-met-service"}))},p("div",{className:"findjob-hero"},p("div",null,p("div",{className:"node-version-line"},p(Xn,{status:w.providerStatus==="online"?"online":"warn"},w.providerStatus||"unknown"),p("span",null,r.providerId),p("span",null,B.public?"公网暴露":"仅 UniDesk frontend 代理访问")),p("p",{className:"muted paragraph"},r.description)),p("div",{className:"microservice-ref-card"},p("span",null,"Repo"),p("strong",null,H.url||"--"),p("code",null,H.commitId||"--")),p("div",{className:"microservice-ref-card"},p("span",null,"D601 Docker"),p("strong",null,`${B.nodeBindHost||"--"}:${B.nodePort||"--"}`),p("code",null,`${H.composeFile||"--"} / ${H.containerName||"--"}`))),p(jf,{error:y.error,wide:!0}),$.actionMessage?p("div",{className:"met-action-log","data-testid":"met-action-message"},$.actionMessage):null),p("div",{className:"met-grid"},p(xA,{title:"核心状态",eyebrow:y.refreshedAt?`Updated ${qf(y.refreshedAt)}`:"Queue + GPU",loading:y.loading},p("div",{className:"metric-grid"},p(N1,{label:"Staged",value:T.staged??0,hint:"加入队列未开始",tone:Number(T.staged||0)>0?"warn":""}),p(N1,{label:"Queued",value:T.queued??0,hint:"排队等待调度",tone:Number(T.queued||0)>0?"warn":""}),p(N1,{label:"Running",value:T.running??0,hint:`max ${y.summary?.queue?.maxConcurrency??y.queue?.queue?.maxConcurrency??"--"}`,tone:Number(T.running||0)>0?"ok":""}),p(N1,{label:"Succeeded",value:T.succeeded??0,hint:"已完成"}),p(N1,{label:"Failed",value:T.failed??0,hint:"需要诊断",tone:Number(T.failed||0)>0?"warn":""}),p(N1,{label:"2080Ti Free",value:R?Vn(Number(R.freeRatio)*100):"--",hint:R?`${R.memoryFreeMiB}/${R.memoryTotalMiB} MiB`:"等待 GPU 上报"}),p(N1,{label:"ML Image",value:Y.present?"READY":"MISSING",hint:Y.image||"met-nonlinear-ml:tf26",tone:Y.present?"ok":"warn"}),p(N1,{label:"Health",value:y.health?.ok?"OK":"--",hint:"D601 /health"}))),p(xA,{title:"队列控制",eyebrow:"Downloader-like staging",loading:y.actionBusy},p("div",{className:"met-control-strip"},p("label",null,"最大并发",p("input",{type:"number",min:1,max:16,value:$.maxConcurrency,"data-testid":"met-max-concurrency-input",onChange:(m)=>F({maxConcurrency:m.target.value})})),p("label",null,"目标 GPU",p("input",{value:$.targetGpuName,"data-testid":"met-target-gpu-input",onChange:(m)=>F({targetGpuName:m.target.value})})),p("button",{type:"button",className:"ghost-btn",onClick:q,disabled:y.actionBusy,"data-testid":"met-save-settings-button"},"保存设置"),p("button",{type:"button",className:"primary-btn",onClick:Q,disabled:y.actionBusy||Number(T.staged||0)===0,"data-testid":"met-start-queue-button"},"启动队列")),p("p",{className:"muted paragraph"},"Project 先进入待启动队列,不会立即训练;点击启动队列后才切换为排队中,并由 D601 scheduler 按最大并发和 2080Ti 显存策略调度。")),p("section",{className:"panel met-workspace"},p("div",{className:"met-tabs",role:"tablist"},I.map((m)=>p("button",{key:m.id,type:"button",className:$.activeTab===m.id?"active":"",onClick:()=>F({activeTab:m.id}),"data-testid":`met-tab-${m.id}`},`${m.label} ${m.count}`))),p("div",{className:"panel-body"},$.activeTab==="projects"?p("div",{className:"met-form-grid","data-testid":"met-projects-pane"},p("div",{className:"met-fork-card"},p("h3",null,"Fork Project"),p("label",null,"源 Project",p("select",{value:M,"data-testid":"met-source-project-select",onChange:(m)=>F({sourceProject:m.target.value})},t.map((m)=>p("option",{key:m.projectPath,value:m.projectPath},`${m.projectPath} · ${m.useModel||"model?"}`)))),p("label",null,"Fork 数量",p("input",{type:"number",min:1,max:100,value:$.forkCount,"data-testid":"met-fork-count-input",onChange:(m)=>F({forkCount:m.target.value})})),p("label",null,"训练轮数",p("input",{type:"number",min:1,max:1e5,value:$.forkEpochs,"data-testid":"met-fork-epochs-input",onChange:(m)=>F({forkEpochs:m.target.value})})),p("label",null,"目标前缀",p("input",{value:$.forkPrefix,"data-testid":"met-fork-prefix-input",onChange:(m)=>F({forkPrefix:m.target.value})})),p("button",{type:"button",className:"primary-btn",onClick:K,disabled:y.actionBusy||!M,"data-testid":"met-fork-button"},"Fork Project"),p("p",{className:"muted paragraph"},"Fork 只创建新 Project 并自动勾选,不会直接训练;需要在右侧确认后加入待启动队列。")),p("div",{className:"met-project-list"},p("div",{className:"panel-head compact"},p("div",null,p("p",{className:"panel-eyebrow"},`Existing Projects · ${(y.projects?.roots||[]).map((m)=>`${m.root} ${m.count}`).join(" / ")}`),p(Af,{title:"选择已有 Project",loading:y.loading||y.actionBusy})),p("button",{type:"button",className:"ghost-btn",onClick:G,disabled:y.actionBusy||W().length===0,"data-testid":"met-stage-selected-button"},`加入待启动队列 (${W().length})`)),t.length===0?p(O0,{title:"暂无 project",text:"等待 D601 返回 /api/projects"}):p("div",{className:"met-project-table","data-testid":"met-project-tree"},p("div",{className:"met-tree-header"},p("span",null,"文件树 Project"),p("span",null,"Model"),p("span",null,"Epochs"),p("span",null,"Progress"),p("span",null,"速度")),O.children.map((m)=>x(m)))),Wu()):null,$.activeTab==="current"?p("div",{"data-testid":"met-current-pane"},h(),k(S,"current"),Wu(),p("div",{className:"panel-actions inline-actions"},p(Oi,{title:"MET Queue",data:y.queue,onOpen:f,testId:"raw-met-queue"}))):null,$.activeTab==="completed"?p("div",{"data-testid":"met-completed-pane"},k(b.length>0?b:D.filter((m)=>m.status==="succeeded"),"completed"),Wu()):null,$.activeTab==="failed"?p("div",{"data-testid":"met-failed-pane"},k(Z.length>0?Z:D.filter((m)=>["failed","canceled"].includes(m.status)),"failed"),Wu(),p("div",{className:"panel-actions inline-actions"},p(Oi,{title:"MET History",data:y.history,onOpen:f,testId:"raw-met-history"}))):null,$.activeTab==="gpu"?p("div",{className:"met-gpu-pane","data-testid":"met-gpu-pane"},X.length===0?p(O0,{title:"暂无 GPU 上报",text:"等待 D601 met-nonlinear-ts 或 ML image 提供 nvidia-smi 数据"}):p("div",{className:"table-wrap"},p("table",null,p("thead",null,p("tr",null,p("th",null,"Index"),p("th",null,"Name"),p("th",null,"Free"),p("th",null,"Policy"))),p("tbody",null,X.map((m)=>p("tr",{key:m.index},p("td",null,m.index),p("td",null,m.name),p("td",null,`${m.memoryFreeMiB} / ${m.memoryTotalMiB} MiB`,p("div",{className:"met-progress"},p("span",{style:{width:Vn(Number(m.freeRatio)*100)}}))),p("td",null,String(m.name||"").includes("2080")?"target 2080Ti, <20% 限制并发":"non-target")))))),p("div",{className:"panel-actions inline-actions"},p(Oi,{title:"MET Images",data:y.images,onOpen:f,testId:"raw-met-images"}))):null))))}var I6=[{id:"ops",label:"运行总览",code:"OPS",tabs:[{id:"status",label:"态势总览"},{id:"performance",label:"性能面板"},{id:"events",label:"事件摘要"},{id:"logs",label:"服务日志"}]},{id:"nodes",label:"资源节点",code:"NODE",tabs:[{id:"list",label:"节点清单"},{id:"monitor",label:"资源监控"},{id:"docker",label:"Docker 状态"},{id:"gateway",label:"网关版本"},{id:"labels",label:"资源标签"},{id:"heartbeats",label:"心跳状态"}]},{id:"tasks",label:"任务调度",code:"TASK",tabs:[{id:"dispatch",label:"下发任务"},{id:"scheduled",label:"定时任务"},{id:"pending",label:"待处理任务"},{id:"history",label:"任务历史"},{id:"results",label:"执行结果"}]},{id:"apps",label:"用户服务",code:"APP",routeSegment:"app",tabs:[{id:"catalog",label:"服务目录"},{id:"todo-note",label:"Todo Note"},{id:"findjob",label:"FindJob"},{id:"pipeline",label:"Pipeline"},{id:"met-nonlinear",label:"MET Nonlinear"},{id:"claudeqq",label:"ClaudeQQ"},{id:"baidu-netdisk",label:"Baidu Netdisk"},{id:"filebrowser",label:"File Browser"},{id:"code-queue",label:"Code Queue"},{id:"project-manager",label:"Project Manager"}]},{id:"config",label:"系统配置",code:"CFG",tabs:[{id:"topology",label:"连接拓扑"},{id:"auth",label:"认证策略"},{id:"security",label:"安全边界"}]}],tn=Object.fromEntries(I6.map((u)=>[u.id,u.tabs[0]?.id??""]));function yH(u){let f=String(u||"").trim();if(!f)return"";try{return decodeURIComponent(f)}catch{return f}}function v6(u){let f=String(u||"/"),[l]=f.split(/[?#]/u,1);if(l==="/")return"/";let y=`/${l.split("/").map(yH).filter(Boolean).join("/")}`;return y.endsWith("/")?y:`${y}/`}function iH(u){let f=2166136261;for(let l of u)f^=l.charCodeAt(0),f=Math.imul(f,16777619);return Math.abs(f>>>0).toString(36)}function bA(u){return String(u||"").normalize("NFKD").replace(/[\u0300-\u036f]/gu,"").toLowerCase().replace(/[^a-z0-9]+/gu,"-").replace(/^-+|-+$/gu,"")}function UW(u){return String(u||"").trim().toLowerCase().replace(/[\s/\\?#%]+/gu,"-").replace(/-+/gu,"-").replace(/^-+|-+$/gu,"")}function QW(u){let f=bA(u.routeSegment||"")||UW(u.routeSegment||"");if(f)return f;let l=bA(u.id||"");if(l)return l;let r=bA(u.label||"")||UW(u.label||"");if(r)return r;return`route-${iH(JSON.stringify(u))}`}function vA(u,f){return`${u}:${f}`}function qW(u){let f=u.map(($)=>{let j=QW($);return{...$,routeSegment:j,tabs:$.tabs.map((F)=>({...F,routeSegment:QW(F)}))}}),l={},r={},y={},i=f.map(($)=>{let j=$.tabs[0]?.id??"";y[$.id]=j;let F=$.tabs.map((q)=>{let W=`/${$.routeSegment}/${q.routeSegment}/`,G=[W],K={moduleId:$.id,tabId:q.id};for(let Q of G)l[v6(Q)]=K;return r[vA($.id,q.id)]=W,{...q,canonicalPath:W,aliases:G}}),J=`/${$.routeSegment}/`,U={moduleId:$.id,tabId:j};return l[v6(J)]=U,{...$,routeSegment:$.routeSegment,canonicalPath:J,tabs:F}}),_=i[0],n={moduleId:_?.id||"",tabId:_?.tabs[0]?.id||""};return l["/"]=n,{modules:i,moduleById:Object.fromEntries(i.map(($)=>[$.id,$])),defaultActiveTabs:y,routeMap:l,canonicalPathByTarget:r,fallbackTarget:n}}function IA(u,f){return u.routeMap[v6(f)]||u.fallbackTarget}function k6(u,f,l){return u.canonicalPathByTarget[vA(f,l)]||u.canonicalPathByTarget[vA(u.fallbackTarget.moduleId,u.fallbackTarget.tabId)]||"/"}function WW(u,f){let l=u.routeMap[v6(f)];if(!l)return null;return k6(u,l.moduleId,l.tabId)}var Y1=Pu(wf(),1);var ru=Pu(GW(),1),iu=Pu(wf(),1);function Yf(u){if(typeof u==="string"||typeof u==="number")return""+u;let f="";if(Array.isArray(u)){for(let l=0,r;l{}};function LW(){for(var u=0,f=arguments.length,l={},r;u=0)r=l.slice(y+1),l=l.slice(0,y);if(l&&!f.hasOwnProperty(l))throw Error("unknown type: "+l);return{type:l,name:r}})}s6.prototype=LW.prototype={constructor:s6,on:function(u,f){var l=this._,r=UH(u+"",l),y,i=-1,_=r.length;if(arguments.length<2){while(++i<_)if((y=(u=r[i]).type)&&(y=QH(l[y],u.name)))return y;return}if(f!=null&&typeof f!=="function")throw Error("invalid callback: "+f);while(++i<_)if(y=(u=r[i]).type)l[y]=KW(l[y],u.name,f);else if(f==null)for(y in l)l[y]=KW(l[y],u.name,null);return this},copy:function(){var u={},f=this._;for(var l in f)u[l]=f[l].slice();return new s6(u)},call:function(u,f){if((y=arguments.length-2)>0)for(var l=Array(y),r=0,y,i;r=0&&(f=u.slice(0,l))!=="xmlns")u=u.slice(l+1);return kA.hasOwnProperty(f)?{space:kA[f],local:u}:u}function gA(u){let f;while(f=u.sourceEvent)u=f;return u}function Wl(u,f){if(u=gA(u),f===void 0)f=u.currentTarget;if(f){var l=f.ownerSVGElement||f;if(l.createSVGPoint){var r=l.createSVGPoint();return r.x=u.clientX,r.y=u.clientY,r=r.matrixTransform(f.getScreenCTM().inverse()),[r.x,r.y]}if(f.getBoundingClientRect){var y=f.getBoundingClientRect();return[u.clientX-y.left-f.clientLeft,u.clientY-y.top-f.clientTop]}}return[u.pageX,u.pageY]}function qH(){}function z1(u){return u==null?qH:function(){return this.querySelector(u)}}function sA(u){if(typeof u!=="function")u=z1(u);for(var f=this._groups,l=f.length,r=Array(l),y=0;y=c)c=N+1;while(!(w=K[c])&&++c=0;)if(_=r[y]){if(i&&_.compareDocumentPosition(i)^4)i.parentNode.insertBefore(_,i);i=_}return this}function $9(u){if(!u)u=OH;function f(J,U){return J&&U?u(J.__data__,U.__data__):!J-!U}for(var l=this._groups,r=l.length,y=Array(r),i=0;if?1:u>=f?0:NaN}function A9(){var u=arguments[0];return arguments[0]=this,u.apply(null,arguments),this}function j9(){return Array.from(this)}function F9(){for(var u=this._groups,f=0,l=u.length;f1?this.each((f==null?SH:typeof f==="function"?MH:PH)(u,f,l==null?"":l)):G1(this.node(),u)}function G1(u,f){return u.style.getPropertyValue(f)||Mn(u).getComputedStyle(u,null).getPropertyValue(f)}function mH(u){return function(){delete this[u]}}function pH(u,f){return function(){this[u]=f}}function CH(u,f){return function(){var l=f.apply(this,arguments);if(l==null)delete this[u];else this[u]=l}}function c9(u,f){return arguments.length>1?this.each((f==null?mH:typeof f==="function"?CH:pH)(u,f)):this.node()[u]}function wW(u){return u.trim().split(/^|\s+/)}function N9(u){return u.classList||new EW(u)}function EW(u){this._node=u,this._names=wW(u.getAttribute("class")||"")}EW.prototype={add:function(u){var f=this._names.indexOf(u);if(f<0)this._names.push(u),this._node.setAttribute("class",this._names.join(" "))},remove:function(u){var f=this._names.indexOf(u);if(f>=0)this._names.splice(f,1),this._node.setAttribute("class",this._names.join(" "))},contains:function(u){return this._names.indexOf(u)>=0}};function TW(u,f){var l=N9(u),r=-1,y=f.length;while(++r=0)l=f.slice(r+1),f=f.slice(0,r);return{type:f,name:l}})}function _O(u){return function(){var f=this.__on;if(!f)return;for(var l=0,r=-1,y=f.length,i;l()=>u;function xn(u,{sourceEvent:f,subject:l,target:r,identifier:y,active:i,x:_,y:n,dx:$,dy:j,dispatch:F}){Object.defineProperties(this,{type:{value:u,enumerable:!0,configurable:!0},sourceEvent:{value:f,enumerable:!0,configurable:!0},subject:{value:l,enumerable:!0,configurable:!0},target:{value:r,enumerable:!0,configurable:!0},identifier:{value:y,enumerable:!0,configurable:!0},active:{value:i,enumerable:!0,configurable:!0},x:{value:_,enumerable:!0,configurable:!0},y:{value:n,enumerable:!0,configurable:!0},dx:{value:$,enumerable:!0,configurable:!0},dy:{value:j,enumerable:!0,configurable:!0},_:{value:F}})}xn.prototype.on=function(){var u=this._.on.apply(this._,arguments);return u===this._?this:u};function NO(u){return!u.ctrlKey&&!u.button}function zO(){return this.parentNode}function GO(u,f){return f==null?{x:u.x,y:u.y}:f}function KO(){return navigator.maxTouchPoints||"ontouchstart"in this}function Rn(){var u=NO,f=zO,l=GO,r=KO,y={},i=Uy("start","drag","end"),_=0,n,$,j,F,J=0;function U(z){z.on("mousedown.drag",q).filter(r).on("touchstart.drag",K).on("touchmove.drag",Q,BW).on("touchend.drag touchcancel.drag",N).style("touch-action","none").style("-webkit-tap-highlight-color","rgba(0,0,0,0)")}function q(z,w){if(F||!u.call(this,z,w))return;var H=c(this,f.call(this,z,w),z,w,"mouse");if(!H)return;If(z.view).on("mousemove.drag",W,Qy).on("mouseup.drag",G,Qy),Xi(z.view),d6(z),j=!1,n=z.clientX,$=z.clientY,H("start",z)}function W(z){if(V0(z),!j){var w=z.clientX-n,H=z.clientY-$;j=w*w+H*H>J}y.mouse("drag",z)}function G(z){If(z.view).on("mousemove.drag mouseup.drag",null),pn(z.view,j),V0(z),y.mouse("end",z)}function K(z,w){if(!u.call(this,z,w))return;var H=z.changedTouches,B=f.call(this,z,w),T=H.length,X,R;for(X=0;X>8&15|f>>4&240,f>>4&15|f&240,(f&15)<<4|f&15,1):l===8?e6(f>>24&255,f>>16&255,f>>8&255,(f&255)/255):l===4?e6(f>>12&15|f>>8&240,f>>8&15|f>>4&240,f>>4&15|f&240,((f&15)<<4|f&15)/255):null):(f=wO.exec(u))?new Cl(f[1],f[2],f[3],1):(f=EO.exec(u))?new Cl(f[1]*255/100,f[2]*255/100,f[3]*255/100,1):(f=TO.exec(u))?e6(f[1],f[2],f[3],f[4]):(f=ZO.exec(u))?e6(f[1]*255/100,f[2]*255/100,f[3]*255/100,f[4]):(f=HO.exec(u))?PW(f[1],f[2]/100,f[3]/100,1):(f=OO.exec(u))?PW(f[1],f[2]/100,f[3]/100,f[4]):VW.hasOwnProperty(u)?DW(VW[u]):u==="transparent"?new Cl(NaN,NaN,NaN,0):null}function DW(u){return new Cl(u>>16&255,u>>8&255,u&255,1)}function e6(u,f,l,r){if(r<=0)u=f=l=NaN;return new Cl(u,f,l,r)}function XO(u){if(!(u instanceof In))u=pr(u);if(!u)return new Cl;return u=u.rgb(),new Cl(u.r,u.g,u.b,u.opacity)}function Di(u,f,l,r){return arguments.length===1?XO(u):new Cl(u,f,l,r==null?1:r)}function Cl(u,f,l,r){this.r=+u,this.g=+f,this.b=+l,this.opacity=+r}hn(Cl,Di,D9(In,{brighter(u){return u=u==null?f4:Math.pow(f4,u),new Cl(this.r*u,this.g*u,this.b*u,this.opacity)},darker(u){return u=u==null?bn:Math.pow(bn,u),new Cl(this.r*u,this.g*u,this.b*u,this.opacity)},rgb(){return this},clamp(){return new Cl(Wy(this.r),Wy(this.g),Wy(this.b),l4(this.opacity))},displayable(){return-0.5<=this.r&&this.r<255.5&&(-0.5<=this.g&&this.g<255.5)&&(-0.5<=this.b&&this.b<255.5)&&(0<=this.opacity&&this.opacity<=1)},hex:tW,formatHex:tW,formatHex8:YO,formatRgb:SW,toString:SW}));function tW(){return`#${qy(this.r)}${qy(this.g)}${qy(this.b)}`}function YO(){return`#${qy(this.r)}${qy(this.g)}${qy(this.b)}${qy((isNaN(this.opacity)?1:this.opacity)*255)}`}function SW(){let u=l4(this.opacity);return`${u===1?"rgb(":"rgba("}${Wy(this.r)}, ${Wy(this.g)}, ${Wy(this.b)}${u===1?")":`, ${u})`}`}function l4(u){return isNaN(u)?1:Math.max(0,Math.min(1,u))}function Wy(u){return Math.max(0,Math.min(255,Math.round(u)||0))}function qy(u){return u=Wy(u),(u<16?"0":"")+u.toString(16)}function PW(u,f,l,r){if(r<=0)u=f=l=NaN;else if(l<=0||l>=1)u=f=NaN;else if(f<=0)u=NaN;return new mr(u,f,l,r)}function mW(u){if(u instanceof mr)return new mr(u.h,u.s,u.l,u.opacity);if(!(u instanceof In))u=pr(u);if(!u)return new mr;if(u instanceof mr)return u;u=u.rgb();var f=u.r/255,l=u.g/255,r=u.b/255,y=Math.min(f,l,r),i=Math.max(f,l,r),_=NaN,n=i-y,$=(i+y)/2;if(n){if(f===i)_=(l-r)/n+(l0&&$<1?0:_;return new mr(_,n,$,u.opacity)}function pW(u,f,l,r){return arguments.length===1?mW(u):new mr(u,f,l,r==null?1:r)}function mr(u,f,l,r){this.h=+u,this.s=+f,this.l=+l,this.opacity=+r}hn(mr,pW,D9(In,{brighter(u){return u=u==null?f4:Math.pow(f4,u),new mr(this.h,this.s,this.l*u,this.opacity)},darker(u){return u=u==null?bn:Math.pow(bn,u),new mr(this.h,this.s,this.l*u,this.opacity)},rgb(){var u=this.h%360+(this.h<0)*360,f=isNaN(u)||isNaN(this.s)?0:this.s,l=this.l,r=l+(l<0.5?l:1-l)*f,y=2*l-r;return new Cl(t9(u>=240?u-240:u+120,y,r),t9(u,y,r),t9(u<120?u+240:u-120,y,r),this.opacity)},clamp(){return new mr(MW(this.h),u4(this.s),u4(this.l),l4(this.opacity))},displayable(){return(0<=this.s&&this.s<=1||isNaN(this.s))&&(0<=this.l&&this.l<=1)&&(0<=this.opacity&&this.opacity<=1)},formatHsl(){let u=l4(this.opacity);return`${u===1?"hsl(":"hsla("}${MW(this.h)}, ${u4(this.s)*100}%, ${u4(this.l)*100}%${u===1?")":`, ${u})`}`}}));function MW(u){return u=(u||0)%360,u<0?u+360:u}function u4(u){return Math.max(0,Math.min(1,u||0))}function t9(u,f,l){return(u<60?f+(l-f)*u/60:u<180?l:u<240?f+(l-f)*(240-u)/60:f)*255}function S9(u,f,l,r,y){var i=u*u,_=i*u;return((1-3*u+3*i-_)*f+(4-6*i+3*_)*l+(1+3*u+3*i-3*_)*r+_*y)/6}function P9(u){var f=u.length-1;return function(l){var r=l<=0?l=0:l>=1?(l=1,f-1):Math.floor(l*f),y=u[r],i=u[r+1],_=r>0?u[r-1]:2*y-i,n=r()=>u;function tO(u,f){return function(l){return u+l*f}}function SO(u,f,l){return u=Math.pow(u,l),f=Math.pow(f,l)-u,l=1/l,function(r){return Math.pow(u+r*f,l)}}function CW(u){return(u=+u)===1?y4:function(f,l){return l-f?SO(f,l,u):kn(isNaN(f)?l:f)}}function y4(u,f){var l=f-u;return l?tO(u,l):kn(isNaN(u)?f:u)}var cy=function u(f){var l=CW(f);function r(y,i){var _=l((y=Di(y)).r,(i=Di(i)).r),n=l(y.g,i.g),$=l(y.b,i.b),j=y4(y.opacity,i.opacity);return function(F){return y.r=_(F),y.g=n(F),y.b=$(F),y.opacity=j(F),y+""}}return r.gamma=u,r}(1);function xW(u){return function(f){var l=f.length,r=Array(l),y=Array(l),i=Array(l),_,n;for(_=0;_l)if(i=f.slice(l,i),n[_])n[_]+=i;else n[++_]=i;if((r=r[0])===(y=y[0]))if(n[_])n[_]+=y;else n[++_]=y;else n[++_]=null,$.push({i:_,x:cl(r,y)});l=x9.lastIndex}if(l180)F+=360;else if(F-j>180)j+=360;U.push({i:J.push(y(J)+"rotate(",null,r)-2,x:cl(j,F)})}else if(F)J.push(y(J)+"rotate("+F+r)}function n(j,F,J,U){if(j!==F)U.push({i:J.push(y(J)+"skewX(",null,r)-2,x:cl(j,F)});else if(F)J.push(y(J)+"skewX("+F+r)}function $(j,F,J,U,q,W){if(j!==J||F!==U){var G=q.push(y(q)+"scale(",null,",",null,")");W.push({i:G-4,x:cl(j,J)},{i:G-2,x:cl(F,U)})}else if(J!==1||U!==1)q.push(y(q)+"scale("+J+","+U+")")}return function(j,F){var J=[],U=[];return j=u(j),F=u(F),i(j.translateX,j.translateY,F.translateX,F.translateY,J,U),_(j.rotate,F.rotate,J,U),n(j.skewX,F.skewX,J,U),$(j.scaleX,j.scaleY,F.scaleX,F.scaleY,J,U),j=F=null,function(q){var W=-1,G=U.length,K;while(++W=0)u._call.call(void 0,f);u=u._next}--Si}function dW(){zy=(A4=on.now())+j4,Si=sn=0;try{fc()}finally{Si=0,rB(),zy=0}}function lB(){var u=on.now(),f=u-A4;if(f>eW)j4-=f,A4=u}function rB(){var u,f=$4,l,r=1/0;while(f)if(f._call){if(r>f._time)r=f._time;u=f,f=f._next}else l=f._next,f._next=null,f=u?u._next=l:$4=l;an=u,v9(r)}function v9(u){if(Si)return;if(sn)sn=clearTimeout(sn);var f=u-zy;if(f>24){if(u<1/0)sn=setTimeout(dW,u-on.now()-j4);if(gn)gn=clearInterval(gn)}else{if(!gn)A4=on.now(),gn=setInterval(lB,eW);Si=1,uc(dW)}}function u$(u,f,l){var r=new dn;return f=f==null?0:+f,r.restart((y)=>{r.stop(),u(y+f)},f,l),r}var iB=Uy("start","end","cancel","interrupt"),_B=[],yc=0,lc=1,U4=2,J4=3,rc=4,Q4=5,f$=6;function X0(u,f,l,r,y,i){var _=u.__transition;if(!_)u.__transition={};else if(l in _)return;nB(u,l,{name:f,index:r,group:y,on:iB,tween:_B,time:i.time,delay:i.delay,duration:i.duration,ease:i.ease,timer:null,state:yc})}function l$(u,f){var l=kf(u,f);if(l.state>yc)throw Error("too late; already scheduled");return l}function $l(u,f){var l=kf(u,f);if(l.state>J4)throw Error("too late; already running");return l}function kf(u,f){var l=u.__transition;if(!l||!(l=l[f]))throw Error("transition not found");return l}function nB(u,f,l){var r=u.__transition,y;r[f]=l,l.timer=F4(i,0,l.time);function i(j){if(l.state=lc,l.timer.restart(_,l.delay,l.time),l.delay<=j)_(j-l.delay)}function _(j){var F,J,U,q;if(l.state!==lc)return $();for(F in r){if(q=r[F],q.name!==l.name)continue;if(q.state===J4)return u$(_);if(q.state===rc)q.state=f$,q.timer.stop(),q.on.call("interrupt",u,u.__data__,q.index,q.group),delete r[F];else if(+FU4&&r.state=0)f=f.slice(0,l);return!f||f==="start"})}function HB(u,f,l){var r,y,i=ZB(f)?l$:$l;return function(){var _=i(this,u),n=_.on;if(n!==r)(y=(r=n).copy()).on(f,l);_.on=y}}function l7(u,f){var l=this._id;return arguments.length<2?kf(this.node(),l).on.on(u):this.each(HB(l,u,f))}function OB(u){return function(){var f=this.parentNode;for(var l in this.__transition)if(+l!==u)return;if(f)f.removeChild(this)}}function r7(){return this.on("end.remove",OB(this._id))}function y7(u){var f=this._name,l=this._id;if(typeof u!=="function")u=z1(u);for(var r=this._groups,y=r.length,i=Array(y),_=0;_()=>u;function Q7(u,{sourceEvent:f,target:l,transform:r,dispatch:y}){Object.defineProperties(this,{type:{value:u,enumerable:!0,configurable:!0},sourceEvent:{value:f,enumerable:!0,configurable:!0},target:{value:l,enumerable:!0,configurable:!0},transform:{value:r,enumerable:!0,configurable:!0},_:{value:y}})}function Cr(u,f,l){this.k=u,this.x=f,this.y=l}Cr.prototype={constructor:Cr,scale:function(u){return u===1?this:new Cr(this.k*u,this.x,this.y)},translate:function(u,f){return u===0&f===0?this:new Cr(this.k,this.x+this.k*u,this.y+this.k*f)},apply:function(u){return[u[0]*this.k+this.x,u[1]*this.k+this.y]},applyX:function(u){return u*this.k+this.x},applyY:function(u){return u*this.k+this.y},invert:function(u){return[(u[0]-this.x)/this.k,(u[1]-this.y)/this.k]},invertX:function(u){return(u-this.x)/this.k},invertY:function(u){return(u-this.y)/this.k},rescaleX:function(u){return u.copy().domain(u.range().map(this.invertX,this).map(u.invert,u))},rescaleY:function(u){return u.copy().domain(u.range().map(this.invertY,this).map(u.invert,u))},toString:function(){return"translate("+this.x+","+this.y+") scale("+this.k+")"}};var Gy=new Cr(1,0,0);i$.prototype=Cr.prototype;function i$(u){while(!u.__zoom)if(!(u=u.parentNode))return Gy;return u.__zoom}function T4(u){u.stopImmediatePropagation()}function Ky(u){u.preventDefault(),u.stopImmediatePropagation()}function bB(u){return(!u.ctrlKey||u.type==="wheel")&&!u.button}function vB(){var u=this;if(u instanceof SVGElement){if(u=u.ownerSVGElement||u,u.hasAttribute("viewBox"))return u=u.viewBox.baseVal,[[u.x,u.y],[u.x+u.width,u.y+u.height]];return[[0,0],[u.width.baseVal.value,u.height.baseVal.value]]}return[[0,0],[u.clientWidth,u.clientHeight]]}function nc(){return this.__zoom||Gy}function IB(u){return-u.deltaY*(u.deltaMode===1?0.05:u.deltaMode?1:0.002)*(u.ctrlKey?10:1)}function kB(){return navigator.maxTouchPoints||"ontouchstart"in this}function gB(u,f,l){var r=u.invertX(f[0][0])-l[0][0],y=u.invertX(f[1][0])-l[1][0],i=u.invertY(f[0][1])-l[0][1],_=u.invertY(f[1][1])-l[1][1];return u.translate(y>r?(r+y)/2:Math.min(0,r)||Math.max(0,y),_>i?(i+_)/2:Math.min(0,i)||Math.max(0,_))}function _$(){var u=bB,f=vB,l=gB,r=IB,y=kB,i=[0,1/0],_=[[-1/0,-1/0],[1/0,1/0]],n=250,$=Ny,j=Uy("start","zoom","end"),F,J,U,q=500,W=150,G=0,K=10;function Q(O){O.property("__zoom",nc).on("wheel.zoom",T,{passive:!1}).on("mousedown.zoom",X).on("dblclick.zoom",R).filter(y).on("touchstart.zoom",Y).on("touchmove.zoom",P).on("touchend.zoom touchcancel.zoom",t).style("-webkit-tap-highlight-color","rgba(0,0,0,0)")}Q.transform=function(O,M,S,b){var Z=O.selection?O.selection():O;if(Z.property("__zoom",nc),O!==Z)w(O,M,S,b);else Z.interrupt().each(function(){H(this,arguments).event(b).start().zoom(null,typeof M==="function"?M.apply(this,arguments):M).end()})},Q.scaleBy=function(O,M,S,b){Q.scaleTo(O,function(){var Z=this.__zoom.k,D=typeof M==="function"?M.apply(this,arguments):M;return Z*D},S,b)},Q.scaleTo=function(O,M,S,b){Q.transform(O,function(){var Z=f.apply(this,arguments),D=this.__zoom,I=S==null?z(Z):typeof S==="function"?S.apply(this,arguments):S,k=D.invert(I),h=typeof M==="function"?M.apply(this,arguments):M;return l(c(N(D,h),I,k),Z,_)},S,b)},Q.translateBy=function(O,M,S,b){Q.transform(O,function(){return l(this.__zoom.translate(typeof M==="function"?M.apply(this,arguments):M,typeof S==="function"?S.apply(this,arguments):S),f.apply(this,arguments),_)},null,b)},Q.translateTo=function(O,M,S,b,Z){Q.transform(O,function(){var D=f.apply(this,arguments),I=this.__zoom,k=b==null?z(D):typeof b==="function"?b.apply(this,arguments):b;return l(Gy.translate(k[0],k[1]).scale(I.k).translate(typeof M==="function"?-M.apply(this,arguments):-M,typeof S==="function"?-S.apply(this,arguments):-S),D,_)},b,Z)};function N(O,M){return M=Math.max(i[0],Math.min(i[1],M)),M===O.k?O:new Cr(M,O.x,O.y)}function c(O,M,S){var b=M[0]-S[0]*O.k,Z=M[1]-S[1]*O.k;return b===O.x&&Z===O.y?O:new Cr(O.k,b,Z)}function z(O){return[(+O[0][0]+ +O[1][0])/2,(+O[0][1]+ +O[1][1])/2]}function w(O,M,S,b){O.on("start.zoom",function(){H(this,arguments).event(b).start()}).on("interrupt.zoom end.zoom",function(){H(this,arguments).event(b).end()}).tween("zoom",function(){var Z=this,D=arguments,I=H(Z,D).event(b),k=f.apply(Z,D),h=S==null?z(k):typeof S==="function"?S.apply(Z,D):S,o=Math.max(k[1][0]-k[0][0],k[1][1]-k[0][1]),s=Z.__zoom,x=typeof M==="function"?M.apply(Z,D):M,uu=$(s.invert(h).concat(o/s.k),x.invert(h).concat(o/x.k));return function(nu){if(nu===1)nu=x;else{var $u=uu(nu),Fu=o/$u[2];nu=new Cr(Fu,h[0]-$u[0]*Fu,h[1]-$u[1]*Fu)}I.zoom(null,nu)}})}function H(O,M,S){return!S&&O.__zooming||new B(O,M)}function B(O,M){this.that=O,this.args=M,this.active=0,this.sourceEvent=null,this.extent=f.apply(O,M),this.taps=0}B.prototype={event:function(O){if(O)this.sourceEvent=O;return this},start:function(){if(++this.active===1)this.that.__zooming=this,this.emit("start");return this},zoom:function(O,M){if(this.mouse&&O!=="mouse")this.mouse[1]=M.invert(this.mouse[0]);if(this.touch0&&O!=="touch")this.touch0[1]=M.invert(this.touch0[0]);if(this.touch1&&O!=="touch")this.touch1[1]=M.invert(this.touch1[0]);return this.that.__zoom=M,this.emit("zoom"),this},end:function(){if(--this.active===0)delete this.that.__zooming,this.emit("end");return this},emit:function(O){var M=If(this.that).datum();j.call(O,this.that,new Q7(O,{sourceEvent:this.sourceEvent,target:Q,type:O,transform:this.that.__zoom,dispatch:j}),M)}};function T(O,...M){if(!u.apply(this,arguments))return;var S=H(this,M).event(O),b=this.__zoom,Z=Math.max(i[0],Math.min(i[1],b.k*Math.pow(2,r.apply(this,arguments)))),D=Wl(O);if(S.wheel){if(S.mouse[0][0]!==D[0]||S.mouse[0][1]!==D[1])S.mouse[1]=b.invert(S.mouse[0]=D);clearTimeout(S.wheel)}else if(b.k===Z)return;else S.mouse=[D,b.invert(D)],K1(this),S.start();Ky(O),S.wheel=setTimeout(I,W),S.zoom("mouse",l(c(N(b,Z),S.mouse[0],S.mouse[1]),S.extent,_));function I(){S.wheel=null,S.end()}}function X(O,...M){if(U||!u.apply(this,arguments))return;var S=O.currentTarget,b=H(this,M,!0).event(O),Z=If(O.view).on("mousemove.zoom",h,!0).on("mouseup.zoom",o,!0),D=Wl(O,S),I=O.clientX,k=O.clientY;Xi(O.view),T4(O),b.mouse=[D,this.__zoom.invert(D)],K1(this),b.start();function h(s){if(Ky(s),!b.moved){var x=s.clientX-I,uu=s.clientY-k;b.moved=x*x+uu*uu>G}b.event(s).zoom("mouse",l(c(b.that.__zoom,b.mouse[0]=Wl(s,S),b.mouse[1]),b.extent,_))}function o(s){Z.on("mousemove.zoom mouseup.zoom",null),pn(s.view,b.moved),Ky(s),b.event(s).end()}}function R(O,...M){if(!u.apply(this,arguments))return;var S=this.__zoom,b=Wl(O.changedTouches?O.changedTouches[0]:O,this),Z=S.invert(b),D=S.k*(O.shiftKey?0.5:2),I=l(c(N(S,D),b,Z),f.apply(this,M),_);if(Ky(O),n>0)If(this).transition().duration(n).call(w,I,b,O);else If(this).call(Q.transform,I,b,O)}function Y(O,...M){if(!u.apply(this,arguments))return;var S=O.touches,b=S.length,Z=H(this,M,O.changedTouches.length===b).event(O),D,I,k,h;T4(O);for(I=0;I"[React Flow]: Seems like you have not used zustand provider as an ancestor. Help: https://reactflow.dev/error#001",error002:()=>"It looks like you've created a new nodeTypes or edgeTypes object. If this wasn't on purpose please define the nodeTypes/edgeTypes outside of the component or memoize them.",error003:(u)=>`Node type "${u}" not found. Using fallback type "default".`,error004:()=>"The React Flow parent container needs a width and a height to render the graph.",error005:()=>"Only child nodes can use a parent extent.",error006:()=>"Can't create edge. An edge needs a source and a target.",error007:(u)=>`The old edge with id=${u} does not exist.`,error009:(u)=>`Marker type "${u}" doesn't exist.`,error008:(u,{id:f,sourceHandle:l,targetHandle:r})=>`Couldn't create edge for ${u} handle id: "${u==="source"?l:r}", edge id: ${f}.`,error010:()=>"Handle: No node id found. Make sure to only use a Handle inside a custom Node.",error011:(u)=>`Edge type "${u}" not found. Using fallback type "default".`,error012:(u)=>`Node with id "${u}" does not exist, it may have been removed. This can happen when a node is deleted before the "onNodeClick" handler is called.`,error013:(u="react")=>`It seems that you haven't loaded the styles. Please import '@xyflow/${u}/dist/style.css' or base.css to make sure everything is working properly.`,error014:()=>"useNodeConnections: No node ID found. Call useNodeConnections inside a custom Node or provide a node ID.",error015:()=>"It seems that you are trying to drag a node that is not initialized. Please use onNodesChange as explained in the docs."},xi=[[Number.NEGATIVE_INFINITY,Number.NEGATIVE_INFINITY],[Number.POSITIVE_INFINITY,Number.POSITIVE_INFINITY]],z7=["Enter"," ","Escape"],G7={"node.a11yDescription.default":"Press enter or space to select a node. Press delete to remove it and escape to cancel.","node.a11yDescription.keyboardDisabled":"Press enter or space to select a node. You can then use the arrow keys to move the node around. Press delete to remove it and escape to cancel.","node.a11yDescription.ariaLiveMessage":({direction:u,x:f,y:l})=>`Moved selected node ${u}. New position, x: ${f}, y: ${l}`,"edge.a11yDescription.default":"Press enter or space to select an edge. You can then press delete to remove it or escape to cancel.","controls.ariaLabel":"Control Panel","controls.zoomIn.ariaLabel":"Zoom In","controls.zoomOut.ariaLabel":"Zoom Out","controls.fitView.ariaLabel":"Fit View","controls.interactive.ariaLabel":"Toggle Interactivity","minimap.ariaLabel":"Mini Map","handle.ariaLabel":"Handle"},E1;(function(u){u.Strict="strict",u.Loose="loose"})(E1||(E1={}));var D0;(function(u){u.Free="free",u.Vertical="vertical",u.Horizontal="horizontal"})(D0||(D0={}));var Ly;(function(u){u.Partial="partial",u.Full="full"})(Ly||(Ly={}));var K7={inProgress:!1,isValid:null,from:null,fromHandle:null,fromPosition:null,fromNode:null,to:null,toHandle:null,toPosition:null,toNode:null,pointer:null},y0;(function(u){u.Bezier="default",u.Straight="straight",u.Step="step",u.SmoothStep="smoothstep",u.SimpleBezier="simplebezier"})(y0||(y0={}));var T1;(function(u){u.Arrow="arrow",u.ArrowClosed="arrowclosed"})(T1||(T1={}));var zu;(function(u){u.Left="left",u.Top="top",u.Right="right",u.Bottom="bottom"})(zu||(zu={}));var $c={[zu.Left]:zu.Right,[zu.Right]:zu.Left,[zu.Top]:zu.Bottom,[zu.Bottom]:zu.Top};function L7(u){return u===null?null:u?"valid":"invalid"}var w7=(u)=>("id"in u)&&("source"in u)&&("target"in u),Kc=(u)=>("id"in u)&&("position"in u)&&!("source"in u)&&!("target"in u),E7=(u)=>("id"in u)&&("internals"in u)&&!("source"in u)&&!("target"in u);var A$=(u,f=[0,0])=>{let{width:l,height:r}=i0(u),y=u.origin??f,i=l*y[0],_=r*y[1];return{x:u.position.x-i,y:u.position.y-_}},T7=(u,f={nodeOrigin:[0,0]})=>{if(u.length===0)return{x:0,y:0,width:0,height:0};let l=u.reduce((r,y)=>{let i=typeof y==="string",_=!f.nodeLookup&&!i?y:void 0;if(f.nodeLookup)_=i?f.nodeLookup.get(y):!E7(y)?f.nodeLookup.get(y.id):y;let n=_?O4(_,f.nodeOrigin):{x:0,y:0,x2:0,y2:0};return V4(r,n)},{x:1/0,y:1/0,x2:-1/0,y2:-1/0});return X4(l)},Ri=(u,f={})=>{let l={x:1/0,y:1/0,x2:-1/0,y2:-1/0},r=!1;return u.forEach((y)=>{if(f.filter===void 0||f.filter(y))l=V4(l,O4(y)),r=!0}),r?X4(l):{x:0,y:0,width:0,height:0}},B4=(u,f,[l,r,y]=[0,0,1],i=!1,_=!1)=>{let n={...vi(f,[l,r,y]),width:f.width/y,height:f.height/y},$=[];for(let j of u.values()){let{measured:F,selectable:J=!0,hidden:U=!1}=j;if(_&&!J||U)continue;let q=F.width??j.width??j.initialWidth??null,W=F.height??j.height??j.initialHeight??null,G=hi(n,Ey(j)),K=(q??0)*(W??0),Q=i&&G>0;if(!j.internals.handleBounds||Q||G>=K||j.dragging)$.push(j)}return $},Lc=(u,f)=>{let l=new Set;return u.forEach((r)=>{l.add(r.id)}),f.filter((r)=>l.has(r.source)||l.has(r.target))};function sB(u,f){let l=new Map,r=f?.nodes?new Set(f.nodes.map((y)=>y.id)):null;return u.forEach((y)=>{if(y.measured.width&&y.measured.height&&(f?.includeHiddenNodes||!y.hidden)&&(!r||r.has(y.id)))l.set(y.id,y)}),l}async function wc({nodes:u,width:f,height:l,panZoom:r,minZoom:y,maxZoom:i},_){if(u.size===0)return Promise.resolve(!0);let n=sB(u,_),$=Ri(n),j=j$($,f,l,_?.minZoom??y,_?.maxZoom??i,_?.padding??0.1);return await r.setViewport(j,{duration:_?.duration,ease:_?.ease,interpolate:_?.interpolate}),Promise.resolve(!0)}function Z7({nodeId:u,nextPosition:f,nodeLookup:l,nodeOrigin:r=[0,0],nodeExtent:y,onError:i}){let _=l.get(u),n=_.parentId?l.get(_.parentId):void 0,{x:$,y:j}=n?n.internals.positionAbsolute:{x:0,y:0},F=_.origin??r,J=_.extent||y;if(_.extent==="parent"&&!_.expandParent)if(!n)i?.("005",_r.error005());else{let q=n.measured.width,W=n.measured.height;if(q&&W)J=[[$,j],[$+q,j+W]]}else if(n&&Ci(_.extent))J=[[_.extent[0][0]+$,_.extent[0][1]+j],[_.extent[1][0]+$,_.extent[1][1]+j]];let U=Ci(J)?wy(f,J,_.measured):f;if(_.measured.width===void 0||_.measured.height===void 0)i?.("015",_r.error015());return{position:{x:U.x-$+(_.measured.width??0)*F[0],y:U.y-j+(_.measured.height??0)*F[1]},positionAbsolute:U}}async function Ec({nodesToRemove:u=[],edgesToRemove:f=[],nodes:l,edges:r,onBeforeDelete:y}){let i=new Set(u.map((U)=>U.id)),_=[];for(let U of l){if(U.deletable===!1)continue;let q=i.has(U.id),W=!q&&U.parentId&&_.find((G)=>G.id===U.parentId);if(q||W)_.push(U)}let n=new Set(f.map((U)=>U.id)),$=r.filter((U)=>U.deletable!==!1),F=Lc(_,$);for(let U of $)if(n.has(U.id)&&!F.find((W)=>W.id===U.id))F.push(U);if(!y)return{edges:F,nodes:_};let J=await y({nodes:_,edges:F});if(typeof J==="boolean")return J?{edges:F,nodes:_}:{edges:[],nodes:[]};return J}var pi=(u,f=0,l=1)=>Math.min(Math.max(u,f),l),wy=(u={x:0,y:0},f,l)=>({x:pi(u.x,f[0][0],f[1][0]-(l?.width??0)),y:pi(u.y,f[0][1],f[1][1]-(l?.height??0))});function Tc(u,f,l){let{width:r,height:y}=i0(l),{x:i,y:_}=l.internals.positionAbsolute;return wy(u,[[i,_],[i+r,_+y]],f)}var Ac=(u,f,l)=>{if(ul)return-pi(Math.abs(u-l),1,f)/f;return 0},Zc=(u,f,l=15,r=40)=>{let y=Ac(u.x,r,f.width-r)*l,i=Ac(u.y,r,f.height-r)*l;return[y,i]},V4=(u,f)=>({x:Math.min(u.x,f.x),y:Math.min(u.y,f.y),x2:Math.max(u.x2,f.x2),y2:Math.max(u.y2,f.y2)}),N7=({x:u,y:f,width:l,height:r})=>({x:u,y:f,x2:u+l,y2:f+r}),X4=({x:u,y:f,x2:l,y2:r})=>({x:u,y:f,width:l-u,height:r-f}),Ey=(u,f=[0,0])=>{let{x:l,y:r}=E7(u)?u.internals.positionAbsolute:A$(u,f);return{x:l,y:r,width:u.measured?.width??u.width??u.initialWidth??0,height:u.measured?.height??u.height??u.initialHeight??0}},O4=(u,f=[0,0])=>{let{x:l,y:r}=E7(u)?u.internals.positionAbsolute:A$(u,f);return{x:l,y:r,x2:l+(u.measured?.width??u.width??u.initialWidth??0),y2:r+(u.measured?.height??u.height??u.initialHeight??0)}},H7=(u,f)=>X4(V4(N7(u),N7(f))),hi=(u,f)=>{let l=Math.max(0,Math.min(u.x+u.width,f.x+f.width)-Math.max(u.x,f.x)),r=Math.max(0,Math.min(u.y+u.height,f.y+f.height)-Math.max(u.y,f.y));return Math.ceil(l*r)},O7=(u)=>Kr(u.width)&&Kr(u.height)&&Kr(u.x)&&Kr(u.y),Kr=(u)=>!isNaN(u)&&isFinite(u),B7=(u,f)=>{},bi=(u,f=[1,1])=>{return{x:f[0]*Math.round(u.x/f[0]),y:f[1]*Math.round(u.y/f[1])}},vi=({x:u,y:f},[l,r,y],i=!1,_=[1,1])=>{let n={x:(u-l)/y,y:(f-r)/y};return i?bi(n,_):n},$$=({x:u,y:f},[l,r,y])=>{return{x:u*y+l,y:f*y+r}};function Mi(u,f){if(typeof u==="number")return Math.floor((f-f/(1+u))*0.5);if(typeof u==="string"&&u.endsWith("px")){let l=parseFloat(u);if(!Number.isNaN(l))return Math.floor(l)}if(typeof u==="string"&&u.endsWith("%")){let l=parseFloat(u);if(!Number.isNaN(l))return Math.floor(f*l*0.01)}return console.error(`[React Flow] The padding value "${u}" is invalid. Please provide a number or a string with a valid unit (px or %).`),0}function aB(u,f,l){if(typeof u==="string"||typeof u==="number"){let r=Mi(u,l),y=Mi(u,f);return{top:r,right:y,bottom:r,left:y,x:y*2,y:r*2}}if(typeof u==="object"){let r=Mi(u.top??u.y??0,l),y=Mi(u.bottom??u.y??0,l),i=Mi(u.left??u.x??0,f),_=Mi(u.right??u.x??0,f);return{top:r,right:_,bottom:y,left:i,x:i+_,y:r+y}}return{top:0,right:0,bottom:0,left:0,x:0,y:0}}function oB(u,f,l,r,y,i){let{x:_,y:n}=$$(u,[f,l,r]),{x:$,y:j}=$$({x:u.x+u.width,y:u.y+u.height},[f,l,r]),F=y-$,J=i-j;return{left:Math.floor(_),top:Math.floor(n),right:Math.floor(F),bottom:Math.floor(J)}}var j$=(u,f,l,r,y,i)=>{let _=aB(i,f,l),n=(f-_.x)/u.width,$=(l-_.y)/u.height,j=Math.min(n,$),F=pi(j,r,y),J=u.x+u.width/2,U=u.y+u.height/2,q=f/2-J*F,W=l/2-U*F,G=oB(u,q,W,F,f,l),K={left:Math.min(G.left-_.left,0),top:Math.min(G.top-_.top,0),right:Math.min(G.right-_.right,0),bottom:Math.min(G.bottom-_.bottom,0)};return{x:q-K.left+K.right,y:W-K.top+K.bottom,zoom:F}},Ii=()=>typeof navigator<"u"&&navigator?.userAgent?.indexOf("Mac")>=0;function Ci(u){return u!==void 0&&u!==null&&u!=="parent"}function i0(u){return{width:u.measured?.width??u.width??u.initialWidth??0,height:u.measured?.height??u.height??u.initialHeight??0}}function V7(u){return(u.measured?.width??u.width??u.initialWidth)!==void 0&&(u.measured?.height??u.height??u.initialHeight)!==void 0}function X7(u,f={width:0,height:0},l,r,y){let i={...u},_=r.get(l);if(_){let n=_.origin||y;i.x+=_.internals.positionAbsolute.x-(f.width??0)*n[0],i.y+=_.internals.positionAbsolute.y-(f.height??0)*n[1]}return i}function Y7(u,f){if(u.size!==f.size)return!1;for(let l of u)if(!f.has(l))return!1;return!0}function Hc(){let u,f;return{promise:new Promise((r,y)=>{u=r,f=y}),resolve:u,reject:f}}function Oc(u){return{...G7,...u||{}}}function n$(u,{snapGrid:f=[0,0],snapToGrid:l=!1,transform:r,containerBounds:y}){let{x:i,y:_}=Lr(u),n=vi({x:i-(y?.left??0),y:_-(y?.top??0)},r),{x:$,y:j}=l?bi(n,f):n;return{xSnapped:$,ySnapped:j,...n}}var Y4=(u)=>({width:u.offsetWidth,height:u.offsetHeight}),D7=(u)=>u?.getRootNode?.()||window?.document,dB=["INPUT","SELECT","TEXTAREA"];function t7(u){let f=u.composedPath?.()?.[0]||u.target;if(f?.nodeType!==1)return!1;return dB.includes(f.nodeName)||f.hasAttribute("contenteditable")||!!f.closest(".nokey")}var S7=(u)=>("clientX"in u),Lr=(u,f)=>{let l=S7(u),r=l?u.clientX:u.touches?.[0].clientX,y=l?u.clientY:u.touches?.[0].clientY;return{x:r-(f?.left??0),y:y-(f?.top??0)}},jc=(u,f,l,r,y)=>{let i=f.querySelectorAll(`.${u}`);if(!i||!i.length)return null;return Array.from(i).map((_)=>{let n=_.getBoundingClientRect();return{id:_.getAttribute("data-handleid"),type:u,nodeId:y,position:_.getAttribute("data-handlepos"),x:(n.left-l.left)/r,y:(n.top-l.top)/r,...Y4(_)}})};function D4({sourceX:u,sourceY:f,targetX:l,targetY:r,sourceControlX:y,sourceControlY:i,targetControlX:_,targetControlY:n}){let $=u*0.125+y*0.375+_*0.375+l*0.125,j=f*0.125+i*0.375+n*0.375+r*0.125,F=Math.abs($-u),J=Math.abs(j-f);return[$,j,F,J]}function Z4(u,f){if(u>=0)return 0.5*u;return f*25*Math.sqrt(-u)}function Fc({pos:u,x1:f,y1:l,x2:r,y2:y,c:i}){switch(u){case zu.Left:return[f-Z4(f-r,i),l];case zu.Right:return[f+Z4(r-f,i),l];case zu.Top:return[f,l-Z4(l-y,i)];case zu.Bottom:return[f,l+Z4(y-l,i)]}}function t4({sourceX:u,sourceY:f,sourcePosition:l=zu.Bottom,targetX:r,targetY:y,targetPosition:i=zu.Top,curvature:_=0.25}){let[n,$]=Fc({pos:l,x1:u,y1:f,x2:r,y2:y,c:_}),[j,F]=Fc({pos:i,x1:r,y1:y,x2:u,y2:f,c:_}),[J,U,q,W]=D4({sourceX:u,sourceY:f,targetX:r,targetY:y,sourceControlX:n,sourceControlY:$,targetControlX:j,targetControlY:F});return[`M${u},${f} C${n},${$} ${j},${F} ${r},${y}`,J,U,q,W]}function P7({sourceX:u,sourceY:f,targetX:l,targetY:r}){let y=Math.abs(l-u)/2,i=l0}var eB=({source:u,sourceHandle:f,target:l,targetHandle:r})=>`xy-edge__${u}${f||""}-${l}${r||""}`,uV=(u,f)=>{return f.some((l)=>l.source===u.source&&l.target===u.target&&(l.sourceHandle===u.sourceHandle||!l.sourceHandle&&!u.sourceHandle)&&(l.targetHandle===u.targetHandle||!l.targetHandle&&!u.targetHandle))},M7=(u,f,l={})=>{if(!u.source||!u.target)return B7("006",_r.error006()),f;let r=l.getEdgeId||eB,y;if(w7(u))y={...u};else y={...u,id:r(u)};if(uV(y,f))return f;if(y.sourceHandle===null)delete y.sourceHandle;if(y.targetHandle===null)delete y.targetHandle;return f.concat(y)};function S4({sourceX:u,sourceY:f,targetX:l,targetY:r}){let[y,i,_,n]=P7({sourceX:u,sourceY:f,targetX:l,targetY:r});return[`M ${u},${f}L ${l},${r}`,y,i,_,n]}var Jc={[zu.Left]:{x:-1,y:0},[zu.Right]:{x:1,y:0},[zu.Top]:{x:0,y:-1},[zu.Bottom]:{x:0,y:1}},fV=({source:u,sourcePosition:f=zu.Bottom,target:l})=>{if(f===zu.Left||f===zu.Right)return u.xMath.sqrt(Math.pow(f.x-u.x,2)+Math.pow(f.y-u.y,2));function lV({source:u,sourcePosition:f=zu.Bottom,target:l,targetPosition:r=zu.Top,center:y,offset:i,stepPosition:_}){let n=Jc[f],$=Jc[r],j={x:u.x+n.x*i,y:u.y+n.y*i},F={x:l.x+$.x*i,y:l.y+$.y*i},J=fV({source:j,sourcePosition:f,target:F}),U=J.x!==0?"x":"y",q=J[U],W=[],G,K,Q={x:0,y:0},N={x:0,y:0},[,,c,z]=P7({sourceX:u.x,sourceY:u.y,targetX:l.x,targetY:l.y});if(n[U]*$[U]===-1){if(U==="x")G=y.x??j.x+(F.x-j.x)*_,K=y.y??(j.y+F.y)/2;else G=y.x??(j.x+F.x)/2,K=y.y??j.y+(F.y-j.y)*_;let T=[{x:G,y:j.y},{x:G,y:F.y}],X=[{x:j.x,y:K},{x:F.x,y:K}];if(n[U]===q)W=U==="x"?T:X;else W=U==="x"?X:T}else{let T=[{x:j.x,y:F.y}],X=[{x:F.x,y:j.y}];if(U==="x")W=n.x===q?X:T;else W=n.y===q?T:X;if(f===r){let O=Math.abs(u[U]-l[U]);if(O<=i){let M=Math.min(i-1,i-O);if(n[U]===q)Q[U]=(j[U]>u[U]?-1:1)*M;else N[U]=(F[U]>l[U]?-1:1)*M}}if(f!==r){let O=U==="x"?"y":"x",M=n[U]===$[O],S=j[O]>F[O],b=j[O]=t)G=(R.x+Y.x)/2,K=W[0].y;else G=W[0].x,K=(R.y+Y.y)/2}let w={x:j.x+Q.x,y:j.y+Q.y},H={x:F.x+N.x,y:F.y+N.y};return[[u,...w.x!==W[0].x||w.y!==W[0].y?[w]:[],...W,...H.x!==W[W.length-1].x||H.y!==W[W.length-1].y?[H]:[],l],G,K,c,z]}function rV(u,f,l,r){let y=Math.min(Uc(u,f)/2,Uc(f,l)/2,r),{x:i,y:_}=f;if(u.x===i&&i===l.x||u.y===_&&_===l.y)return`L${i} ${_}`;if(u.y===_){let j=u.xl.id===f))||null}function P4(u,f){if(!u)return"";if(typeof u==="string")return u;return`${f?`${f}__`:""}${Object.keys(u).sort().map((r)=>`${r}=${u[r]}`).join("&")}`}function Yc(u,{id:f,defaultColor:l,defaultMarkerStart:r,defaultMarkerEnd:y}){let i=new Set;return u.reduce((_,n)=>{return[n.markerStart||r,n.markerEnd||y].forEach(($)=>{if($&&typeof $==="object"){let j=P4($,f);if(!i.has(j))_.push({id:j,color:$.color||l,...$}),i.add(j)}}),_},[]).sort((_,n)=>_.id.localeCompare(n.id))}var Dc=1000,yV=10,m7={nodeOrigin:[0,0],nodeExtent:xi,elevateNodesOnSelect:!0,zIndexMode:"basic",defaults:{}},iV={...m7,checkEquality:!0};function p7(u,f){let l={...u};for(let r in f)if(f[r]!==void 0)l[r]=f[r];return l}function tc(u,f,l){let r=p7(m7,l);for(let y of u.values())if(y.parentId)x7(y,u,f,r);else{let i=A$(y,r.nodeOrigin),_=Ci(y.extent)?y.extent:r.nodeExtent,n=wy(i,_,i0(y));y.internals.positionAbsolute=n}}function _V(u,f){if(!u.handles)return!u.measured?void 0:f?.internals.handleBounds;let l=[],r=[];for(let y of u.handles){let i={id:y.id,width:y.width??1,height:y.height??1,nodeId:u.id,x:y.x,y:y.y,position:y.position,type:y.type};if(y.type==="source")l.push(i);else if(y.type==="target")r.push(i)}return{source:l,target:r}}function C7(u){return u==="manual"}function M4(u,f,l,r={}){let y=p7(iV,r),i={i:0},_=new Map(f),n=y?.elevateNodesOnSelect&&!C7(y.zIndexMode)?Dc:0,$=u.length>0,j=!1;f.clear(),l.clear();for(let F of u){let J=_.get(F.id);if(y.checkEquality&&F===J?.internals.userNode)f.set(F.id,J);else{let U=A$(F,y.nodeOrigin),q=Ci(F.extent)?F.extent:y.nodeExtent,W=wy(U,q,i0(F));J={...y.defaults,...F,measured:{width:F.measured?.width,height:F.measured?.height},internals:{positionAbsolute:W,handleBounds:_V(F,J),z:Sc(F,n,y.zIndexMode),userNode:F}},f.set(F.id,J)}if((J.measured===void 0||J.measured.width===void 0||J.measured.height===void 0)&&!J.hidden)$=!1;if(F.parentId)x7(J,f,l,r,i);j||=F.selected??!1}return{nodesInitialized:$,hasSelectedNodes:j}}function nV(u,f){if(!u.parentId)return;let l=f.get(u.parentId);if(l)l.set(u.id,u);else f.set(u.parentId,new Map([[u.id,u]]))}function x7(u,f,l,r,y){let{elevateNodesOnSelect:i,nodeOrigin:_,nodeExtent:n,zIndexMode:$}=p7(m7,r),j=u.parentId,F=f.get(j);if(!F){console.warn(`Parent node ${j} not found. Please make sure that parent nodes are in front of their child nodes in the nodes array.`);return}if(nV(u,l),y&&!F.parentId&&F.internals.rootParentIndex===void 0&&$==="auto")F.internals.rootParentIndex=++y.i,F.internals.z=F.internals.z+y.i*yV;if(y&&F.internals.rootParentIndex!==void 0)y.i=F.internals.rootParentIndex;let J=i&&!C7($)?Dc:0,{x:U,y:q,z:W}=$V(u,F,_,n,J,$),{positionAbsolute:G}=u.internals,K=U!==G.x||q!==G.y;if(K||W!==u.internals.z)f.set(u.id,{...u,internals:{...u.internals,positionAbsolute:K?{x:U,y:q}:G,z:W}})}function Sc(u,f,l){let r=Kr(u.zIndex)?u.zIndex:0;if(C7(l))return r;return r+(u.selected?f:0)}function $V(u,f,l,r,y,i){let{x:_,y:n}=f.internals.positionAbsolute,$=i0(u),j=A$(u,l),F=Ci(u.extent)?wy(j,u.extent,$):j,J=wy({x:_+F.x,y:n+F.y},r,$);if(u.extent==="parent")J=Tc(J,$,f);let U=Sc(u,y,i),q=f.internals.z??0;return{x:J.x,y:J.y,z:q>=U?q+1:U}}function m4(u,f,l,r=[0,0]){let y=[],i=new Map;for(let _ of u){let n=f.get(_.parentId);if(!n)continue;let $=i.get(_.parentId)?.expandedRect??Ey(n),j=H7($,_.rect);i.set(_.parentId,{expandedRect:j,parent:n})}if(i.size>0)i.forEach(({expandedRect:_,parent:n},$)=>{let j=n.internals.positionAbsolute,F=i0(n),J=n.origin??r,U=_.x0||q>0||K||Q)y.push({id:$,type:"position",position:{x:n.position.x-U+K,y:n.position.y-q+Q}}),l.get($)?.forEach((N)=>{if(!u.some((c)=>c.id===N.id))y.push({id:N.id,type:"position",position:{x:N.position.x+U,y:N.position.y+q}})});if(F.width<_.width||F.height<_.height||U||q)y.push({id:$,type:"dimensions",setAttributes:!0,dimensions:{width:W+(U?J[0]*U-K:0),height:G+(q?J[1]*q-Q:0)}})});return y}function Pc(u,f,l,r,y,i,_){let n=r?.querySelector(".xyflow__viewport"),$=!1;if(!n)return{changes:[],updatedInternals:$};let j=[],F=window.getComputedStyle(n),{m22:J}=new window.DOMMatrixReadOnly(F.transform),U=[];for(let q of u.values()){let W=f.get(q.id);if(!W)continue;if(W.hidden){f.set(W.id,{...W,internals:{...W.internals,handleBounds:void 0}}),$=!0;continue}let G=Y4(q.nodeElement),K=W.measured.width!==G.width||W.measured.height!==G.height;if(!!(G.width&&G.height&&(K||!W.internals.handleBounds||q.force))){let N=q.nodeElement.getBoundingClientRect(),c=Ci(W.extent)?W.extent:i,{positionAbsolute:z}=W.internals;if(W.parentId&&W.extent==="parent")z=Tc(z,G,f.get(W.parentId));else if(c)z=wy(z,c,G);let w={...W,measured:G,internals:{...W.internals,positionAbsolute:z,handleBounds:{source:jc("source",q.nodeElement,N,J,W.id),target:jc("target",q.nodeElement,N,J,W.id)}}};if(f.set(W.id,w),W.parentId)x7(w,f,l,{nodeOrigin:y,zIndexMode:_});if($=!0,K){if(j.push({id:W.id,type:"dimensions",dimensions:G}),W.expandParent&&W.parentId)U.push({id:W.id,parentId:W.parentId,rect:Ey(w,y)})}}}if(U.length>0){let q=m4(U,f,l,y);j.push(...q)}return{changes:j,updatedInternals:$}}async function Mc({delta:u,panZoom:f,transform:l,translateExtent:r,width:y,height:i}){if(!f||!u.x&&!u.y)return Promise.resolve(!1);let _=await f.setViewportConstrained({x:l[0]+u.x,y:l[1]+u.y,zoom:l[2]},[[0,0],[y,i]],r),n=!!_&&(_.x!==l[0]||_.y!==l[1]||_.k!==l[2]);return Promise.resolve(n)}function cc(u,f,l,r,y,i){let _=y,n=r.get(_)||new Map;r.set(_,n.set(l,f)),_=`${y}-${u}`;let $=r.get(_)||new Map;if(r.set(_,$.set(l,f)),i){_=`${y}-${u}-${i}`;let j=r.get(_)||new Map;r.set(_,j.set(l,f))}}function R7(u,f,l){u.clear(),f.clear();for(let r of l){let{source:y,target:i,sourceHandle:_=null,targetHandle:n=null}=r,$={edgeId:r.id,source:y,target:i,sourceHandle:_,targetHandle:n},j=`${y}-${_}--${i}-${n}`,F=`${i}-${n}--${y}-${_}`;cc("source",$,F,u,y,_),cc("target",$,j,u,i,n),f.set(r.id,r)}}function mc(u,f){if(!u.parentId)return!1;let l=f.get(u.parentId);if(!l)return!1;if(l.selected)return!0;return mc(l,f)}function Nc(u,f,l){let r=u;do{if(r?.matches?.(f))return!0;if(r===l)return!1;r=r?.parentElement}while(r);return!1}function AV(u,f,l,r){let y=new Map;for(let[i,_]of u)if((_.selected||_.id===r)&&(!_.parentId||!mc(_,u))&&(_.draggable||f&&typeof _.draggable>"u")){let n=u.get(i);if(n)y.set(i,{id:i,position:n.position||{x:0,y:0},distance:{x:l.x-n.internals.positionAbsolute.x,y:l.y-n.internals.positionAbsolute.y},extent:n.extent,parentId:n.parentId,origin:n.origin,expandParent:n.expandParent,internals:{positionAbsolute:n.internals.positionAbsolute||{x:0,y:0}},measured:{width:n.measured.width??0,height:n.measured.height??0}})}return y}function q7({nodeId:u,dragItems:f,nodeLookup:l,dragging:r=!0}){let y=[];for(let[_,n]of f){let $=l.get(_)?.internals.userNode;if($)y.push({...$,position:n.position,dragging:r})}if(!u)return[y[0],y];let i=l.get(u)?.internals.userNode;return[!i?y[0]:{...i,position:f.get(u)?.position||i.position,dragging:r},y]}function jV({dragItems:u,snapGrid:f,x:l,y:r}){let y=u.values().next().value;if(!y)return null;let i={x:l-y.distance.x,y:r-y.distance.y},_=bi(i,f);return{x:_.x-i.x,y:_.y-i.y}}function pc({onNodeMouseDown:u,getStoreItems:f,onDragStart:l,onDrag:r,onDragStop:y}){let i={x:null,y:null},_=0,n=new Map,$=!1,j={x:0,y:0},F=null,J=!1,U=null,q=!1,W=!1,G=null;function K({noDragClassName:N,handleSelector:c,domNode:z,isSelectable:w,nodeId:H,nodeClickDistance:B=0}){U=If(z);function T({x:P,y:t}){let{nodeLookup:O,nodeExtent:M,snapGrid:S,snapToGrid:b,nodeOrigin:Z,onNodeDrag:D,onSelectionDrag:I,onError:k,updateNodePositions:h}=f();i={x:P,y:t};let o=!1,s=n.size>1,x=s&&M?N7(Ri(n)):null,uu=s&&b?jV({dragItems:n,snapGrid:S,x:P,y:t}):null;for(let[nu,$u]of n){if(!O.has(nu))continue;let Fu={x:P-$u.distance.x,y:t-$u.distance.y};if(b)Fu=uu?{x:Math.round(Fu.x+uu.x),y:Math.round(Fu.y+uu.y)}:bi(Fu,S);let Ku=null;if(s&&M&&!$u.extent&&x){let{positionAbsolute:d}=$u.internals,e=d.x-x.x+M[0][0],cu=d.x+$u.measured.width-x.x2+M[1][0],g=d.y-x.y+M[0][1],Qu=d.y+$u.measured.height-x.y2+M[1][1];Ku=[[e,g],[cu,Qu]]}let{position:Wu,positionAbsolute:m}=Z7({nodeId:nu,nextPosition:Fu,nodeLookup:O,nodeExtent:Ku?Ku:M,nodeOrigin:Z,onError:k});o=o||$u.position.x!==Wu.x||$u.position.y!==Wu.y,$u.position=Wu,$u.internals.positionAbsolute=m}if(W=W||o,!o)return;if(h(n,!0),G&&(r||D||!H&&I)){let[nu,$u]=q7({nodeId:H,dragItems:n,nodeLookup:O});if(r?.(G,n,nu,$u),D?.(G,nu,$u),!H)I?.(G,$u)}}async function X(){if(!F)return;let{transform:P,panBy:t,autoPanSpeed:O,autoPanOnNodeDrag:M}=f();if(!M){$=!1,cancelAnimationFrame(_);return}let[S,b]=Zc(j,F,O);if(S!==0||b!==0){if(i.x=(i.x??0)-S/P[2],i.y=(i.y??0)-b/P[2],await t({x:S,y:b}))T(i)}_=requestAnimationFrame(X)}function R(P){let{nodeLookup:t,multiSelectionActive:O,nodesDraggable:M,transform:S,snapGrid:b,snapToGrid:Z,selectNodesOnDrag:D,onNodeDragStart:I,onSelectionDragStart:k,unselectNodesAndEdges:h}=f();if(J=!0,(!D||!w)&&!O&&H){if(!t.get(H)?.selected)h()}if(w&&D&&H)u?.(H);let o=n$(P.sourceEvent,{transform:S,snapGrid:b,snapToGrid:Z,containerBounds:F});if(i=o,n=AV(t,M,o,H),n.size>0&&(l||I||!H&&k)){let[s,x]=q7({nodeId:H,dragItems:n,nodeLookup:t});if(l?.(P.sourceEvent,n,s,x),I?.(P.sourceEvent,s,x),!H)k?.(P.sourceEvent,x)}}let Y=Rn().clickDistance(B).on("start",(P)=>{let{domNode:t,nodeDragThreshold:O,transform:M,snapGrid:S,snapToGrid:b}=f();if(F=t?.getBoundingClientRect()||null,q=!1,W=!1,G=P.sourceEvent,O===0)R(P);i=n$(P.sourceEvent,{transform:M,snapGrid:S,snapToGrid:b,containerBounds:F}),j=Lr(P.sourceEvent,F)}).on("drag",(P)=>{let{autoPanOnNodeDrag:t,transform:O,snapGrid:M,snapToGrid:S,nodeDragThreshold:b,nodeLookup:Z}=f(),D=n$(P.sourceEvent,{transform:O,snapGrid:M,snapToGrid:S,containerBounds:F});if(G=P.sourceEvent,P.sourceEvent.type==="touchmove"&&P.sourceEvent.touches.length>1||H&&!Z.has(H))q=!0;if(q)return;if(!$&&t&&J)$=!0,X();if(!J){let I=Lr(P.sourceEvent,F),k=I.x-j.x,h=I.y-j.y;if(Math.sqrt(k*k+h*h)>b)R(P)}if((i.x!==D.xSnapped||i.y!==D.ySnapped)&&n&&J)j=Lr(P.sourceEvent,F),T(D)}).on("end",(P)=>{if(!J||q)return;if($=!1,J=!1,cancelAnimationFrame(_),n.size>0){let{nodeLookup:t,updateNodePositions:O,onNodeDragStop:M,onSelectionDragStop:S}=f();if(W)O(n,!1),W=!1;if(y||M||!H&&S){let[b,Z]=q7({nodeId:H,dragItems:n,nodeLookup:t,dragging:!1});if(y?.(P.sourceEvent,n,b,Z),M?.(P.sourceEvent,b,Z),!H)S?.(P.sourceEvent,Z)}}}).filter((P)=>{let t=P.target;return!P.button&&(!N||!Nc(t,`.${N}`,z))&&(!c||Nc(t,c,z))});U.call(Y)}function Q(){U?.on(".drag",null)}return{update:K,destroy:Q}}function FV(u,f,l){let r=[],y={x:u.x-l,y:u.y-l,width:l*2,height:l*2};for(let i of f.values())if(hi(y,Ey(i))>0)r.push(i);return r}var JV=250;function UV(u,f,l,r){let y=[],i=1/0,_=FV(u,l,f+JV);for(let n of _){let $=[...n.internals.handleBounds?.source??[],...n.internals.handleBounds?.target??[]];for(let j of $){if(r.nodeId===j.nodeId&&r.type===j.type&&r.id===j.id)continue;let{x:F,y:J}=Z1(n,j,j.position,!0),U=Math.sqrt(Math.pow(F-u.x,2)+Math.pow(J-u.y,2));if(U>f)continue;if(U1){let n=r.type==="source"?"target":"source";return y.find(($)=>$.type===n)??y[0]}return y[0]}function Cc(u,f,l,r,y,i=!1){let _=r.get(u);if(!_)return null;let n=y==="strict"?_.internals.handleBounds?.[f]:[..._.internals.handleBounds?.source??[],..._.internals.handleBounds?.target??[]],$=(l?n?.find((j)=>j.id===l):n?.[0])??null;return $&&i?{...$,...Z1(_,$,$.position,!0)}:$}function xc(u,f){if(u)return u;else if(f?.classList.contains("target"))return"target";else if(f?.classList.contains("source"))return"source";return null}function QV(u,f){let l=null;if(f)l=!0;else if(u&&!f)l=!1;return l}var Rc=()=>!0;function qV(u,{connectionMode:f,connectionRadius:l,handleId:r,nodeId:y,edgeUpdaterType:i,isTarget:_,domNode:n,nodeLookup:$,lib:j,autoPanOnConnect:F,flowId:J,panBy:U,cancelConnection:q,onConnectStart:W,onConnect:G,onConnectEnd:K,isValidConnection:Q=Rc,onReconnectEnd:N,updateConnection:c,getTransform:z,getFromHandle:w,autoPanSpeed:H,dragThreshold:B=1,handleDomNode:T}){let X=D7(u.target),R=0,Y,{x:P,y:t}=Lr(u),O=xc(i,T),M=n?.getBoundingClientRect(),S=!1;if(!M||!O)return;let b=Cc(y,O,r,$,f);if(!b)return;let Z=Lr(u,M),D=!1,I=null,k=!1,h=null;function o(){if(!F||!M)return;let[Wu,m]=Zc(Z,M,H);U({x:Wu,y:m}),R=requestAnimationFrame(o)}let s={...b,nodeId:y,type:O,position:b.position},x=$.get(y),nu={inProgress:!0,isValid:null,from:Z1(x,s,zu.Left,!0),fromHandle:s,fromPosition:s.position,fromNode:x,to:Z,toHandle:null,toPosition:$c[s.position],toNode:null,pointer:Z};function $u(){S=!0,c(nu),W?.(u,{nodeId:y,handleId:r,handleType:O})}if(B===0)$u();function Fu(Wu){if(!S){let{x:Qu,y:Eu}=Lr(Wu),Tu=Qu-P,Du=Eu-t;if(!(Tu*Tu+Du*Du>B*B))return;$u()}if(!w()||!s){Ku(Wu);return}let m=z();if(Z=Lr(Wu,M),Y=UV(vi(Z,m,!1,[1,1]),l,$,s),!D)o(),D=!0;let d=hc(Wu,{handle:Y,connectionMode:f,fromNodeId:y,fromHandleId:r,fromType:_?"target":"source",isValidConnection:Q,doc:X,lib:j,flowId:J,nodeLookup:$});h=d.handleDomNode,I=d.connection,k=QV(!!Y,d.isValid);let e=$.get(y),cu=e?Z1(e,s,zu.Left,!0):nu.from,g={...nu,from:cu,isValid:k,to:d.toHandle&&k?$$({x:d.toHandle.x,y:d.toHandle.y},m):Z,toHandle:d.toHandle,toPosition:k&&d.toHandle?d.toHandle.position:$c[s.position],toNode:d.toHandle?$.get(d.toHandle.nodeId):null,pointer:Z};c(g),nu=g}function Ku(Wu){if("touches"in Wu&&Wu.touches.length>0)return;if(S){if((Y||h)&&I&&k)G?.(I);let{inProgress:m,...d}=nu,e={...d,toPosition:nu.toHandle?nu.toPosition:null};if(K?.(Wu,e),i)N?.(Wu,e)}q(),cancelAnimationFrame(R),D=!1,k=!1,I=null,h=null,X.removeEventListener("mousemove",Fu),X.removeEventListener("mouseup",Ku),X.removeEventListener("touchmove",Fu),X.removeEventListener("touchend",Ku)}X.addEventListener("mousemove",Fu),X.addEventListener("mouseup",Ku),X.addEventListener("touchmove",Fu),X.addEventListener("touchend",Ku)}function hc(u,{handle:f,connectionMode:l,fromNodeId:r,fromHandleId:y,fromType:i,doc:_,lib:n,flowId:$,isValidConnection:j=Rc,nodeLookup:F}){let J=i==="target",U=f?_.querySelector(`.${n}-flow__handle[data-id="${$}-${f?.nodeId}-${f?.id}-${f?.type}"]`):null,{x:q,y:W}=Lr(u),G=_.elementFromPoint(q,W),K=G?.classList.contains(`${n}-flow__handle`)?G:U,Q={handleDomNode:K,isValid:!1,connection:null,toHandle:null};if(K){let N=xc(void 0,K),c=K.getAttribute("data-nodeid"),z=K.getAttribute("data-handleid"),w=K.classList.contains("connectable"),H=K.classList.contains("connectableend");if(!c||!N)return Q;let B={source:J?c:r,sourceHandle:J?z:y,target:J?r:c,targetHandle:J?y:z};Q.connection=B;let X=w&&H&&(l===E1.Strict?J&&N==="source"||!J&&N==="target":c!==r||z!==y);Q.isValid=X&&j(B),Q.toHandle=Cc(c,N,z,F,l,!0)}return Q}var p4={onPointerDown:qV,isValid:hc};function bc({domNode:u,panZoom:f,getTransform:l,getViewScale:r}){let y=If(u);function i({translateExtent:n,width:$,height:j,zoomStep:F=1,pannable:J=!0,zoomable:U=!0,inversePan:q=!1}){let W=(c)=>{if(c.sourceEvent.type!=="wheel"||!f)return;let z=l(),w=c.sourceEvent.ctrlKey&&Ii()?10:1,H=-c.sourceEvent.deltaY*(c.sourceEvent.deltaMode===1?0.05:c.sourceEvent.deltaMode?1:0.002)*F,B=z[2]*Math.pow(2,H*w);f.scaleTo(B)},G=[0,0],K=(c)=>{if(c.sourceEvent.type==="mousedown"||c.sourceEvent.type==="touchstart")G=[c.sourceEvent.clientX??c.sourceEvent.touches[0].clientX,c.sourceEvent.clientY??c.sourceEvent.touches[0].clientY]},Q=(c)=>{let z=l();if(c.sourceEvent.type!=="mousemove"&&c.sourceEvent.type!=="touchmove"||!f)return;let w=[c.sourceEvent.clientX??c.sourceEvent.touches[0].clientX,c.sourceEvent.clientY??c.sourceEvent.touches[0].clientY],H=[w[0]-G[0],w[1]-G[1]];G=w;let B=r()*Math.max(z[2],Math.log(z[2]))*(q?-1:1),T={x:z[0]-H[0]*B,y:z[1]-H[1]*B},X=[[0,0],[$,j]];f.setViewportConstrained({x:T.x,y:T.y,zoom:z[2]},X,n)},N=_$().on("start",K).on("zoom",J?Q:null).on("zoom.wheel",U?W:null);y.call(N,{})}function _(){y.on("zoom",null)}return{update:i,destroy:_,pointer:Wl}}var C4=(u)=>({x:u.x,y:u.y,zoom:u.k}),W7=({x:u,y:f,zoom:l})=>Gy.translate(u,f).scale(l),mi=(u,f)=>u.target.closest(`.${f}`),vc=(u,f)=>f===2&&Array.isArray(u)&&u.includes(2),WV=(u)=>((u*=2)<=1?u*u*u:(u-=2)*u*u+2)/2,c7=(u,f=0,l=WV,r=()=>{})=>{let y=typeof f==="number"&&f>0;if(!y)r();return y?u.transition().duration(f).ease(l).on("end",r):u},Ic=(u)=>{let f=u.ctrlKey&&Ii()?10:1;return-u.deltaY*(u.deltaMode===1?0.05:u.deltaMode?1:0.002)*f};function cV({zoomPanValues:u,noWheelClassName:f,d3Selection:l,d3Zoom:r,panOnScrollMode:y,panOnScrollSpeed:i,zoomOnPinch:_,onPanZoomStart:n,onPanZoom:$,onPanZoomEnd:j}){return(F)=>{if(mi(F,f)){if(F.ctrlKey)F.preventDefault();return!1}F.preventDefault(),F.stopImmediatePropagation();let J=l.property("__zoom").k||1;if(F.ctrlKey&&_){let K=Wl(F),Q=Ic(F),N=J*Math.pow(2,Q);r.scaleTo(l,N,K,F);return}let U=F.deltaMode===1?20:1,q=y===D0.Vertical?0:F.deltaX*U,W=y===D0.Horizontal?0:F.deltaY*U;if(!Ii()&&F.shiftKey&&y!==D0.Vertical)q=F.deltaY*U,W=0;r.translateBy(l,-(q/J)*i,-(W/J)*i,{internal:!0});let G=C4(l.property("__zoom"));if(clearTimeout(u.panScrollTimeout),!u.isPanScrolling)u.isPanScrolling=!0,n?.(F,G);else $?.(F,G),u.panScrollTimeout=setTimeout(()=>{j?.(F,G),u.isPanScrolling=!1},150)}}function NV({noWheelClassName:u,preventScrolling:f,d3ZoomHandler:l}){return function(r,y){let i=r.type==="wheel",_=!f&&i&&!r.ctrlKey,n=mi(r,u);if(r.ctrlKey&&i&&n)r.preventDefault();if(_||n)return null;r.preventDefault(),l.call(this,r,y)}}function zV({zoomPanValues:u,onDraggingChange:f,onPanZoomStart:l}){return(r)=>{if(r.sourceEvent?.internal)return;let y=C4(r.transform);if(u.mouseButton=r.sourceEvent?.button||0,u.isZoomingOrPanning=!0,u.prevViewport=y,r.sourceEvent?.type==="mousedown")f(!0);if(l)l?.(r.sourceEvent,y)}}function GV({zoomPanValues:u,panOnDrag:f,onPaneContextMenu:l,onTransformChange:r,onPanZoom:y}){return(i)=>{if(u.usedRightMouseButton=!!(l&&vc(f,u.mouseButton??0)),!i.sourceEvent?.sync)r([i.transform.x,i.transform.y,i.transform.k]);if(y&&!i.sourceEvent?.internal)y?.(i.sourceEvent,C4(i.transform))}}function KV({zoomPanValues:u,panOnDrag:f,panOnScroll:l,onDraggingChange:r,onPanZoomEnd:y,onPaneContextMenu:i}){return(_)=>{if(_.sourceEvent?.internal)return;if(u.isZoomingOrPanning=!1,i&&vc(f,u.mouseButton??0)&&!u.usedRightMouseButton&&_.sourceEvent)i(_.sourceEvent);if(u.usedRightMouseButton=!1,r(!1),y){let n=C4(_.transform);u.prevViewport=n,clearTimeout(u.timerId),u.timerId=setTimeout(()=>{y?.(_.sourceEvent,n)},l?150:0)}}}function LV({zoomActivationKeyPressed:u,zoomOnScroll:f,zoomOnPinch:l,panOnDrag:r,panOnScroll:y,zoomOnDoubleClick:i,userSelectionActive:_,noWheelClassName:n,noPanClassName:$,lib:j,connectionInProgress:F}){return(J)=>{let U=u||f,q=l&&J.ctrlKey,W=J.type==="wheel";if(J.button===1&&J.type==="mousedown"&&(mi(J,`${j}-flow__node`)||mi(J,`${j}-flow__edge`)))return!0;if(!r&&!U&&!y&&!i&&!l)return!1;if(_)return!1;if(F&&!W)return!1;if(mi(J,n)&&W)return!1;if(mi(J,$)&&(!W||y&&W&&!u))return!1;if(!l&&J.ctrlKey&&W)return!1;if(!l&&J.type==="touchstart"&&J.touches?.length>1)return J.preventDefault(),!1;if(!U&&!y&&!q&&W)return!1;if(!r&&(J.type==="mousedown"||J.type==="touchstart"))return!1;if(Array.isArray(r)&&!r.includes(J.button)&&J.type==="mousedown")return!1;let G=Array.isArray(r)&&r.includes(J.button)||!J.button||J.button<=1;return(!J.ctrlKey||W)&&G}}function kc({domNode:u,minZoom:f,maxZoom:l,translateExtent:r,viewport:y,onPanZoom:i,onPanZoomStart:_,onPanZoomEnd:n,onDraggingChange:$}){let j={isZoomingOrPanning:!1,usedRightMouseButton:!1,prevViewport:{x:0,y:0,zoom:0},mouseButton:0,timerId:void 0,panScrollTimeout:void 0,isPanScrolling:!1},F=u.getBoundingClientRect(),J=_$().scaleExtent([f,l]).translateExtent(r),U=If(u).call(J);N({x:y.x,y:y.y,zoom:pi(y.zoom,f,l)},[[0,0],[F.width,F.height]],r);let q=U.on("wheel.zoom"),W=U.on("dblclick.zoom");J.wheelDelta(Ic);function G(Y,P){if(U)return new Promise((t)=>{J?.interpolate(P?.interpolate==="linear"?r0:Ny).transform(c7(U,P?.duration,P?.ease,()=>t(!0)),Y)});return Promise.resolve(!1)}function K({noWheelClassName:Y,noPanClassName:P,onPaneContextMenu:t,userSelectionActive:O,panOnScroll:M,panOnDrag:S,panOnScrollMode:b,panOnScrollSpeed:Z,preventScrolling:D,zoomOnPinch:I,zoomOnScroll:k,zoomOnDoubleClick:h,zoomActivationKeyPressed:o,lib:s,onTransformChange:x,connectionInProgress:uu,paneClickDistance:nu,selectionOnDrag:$u}){if(O&&!j.isZoomingOrPanning)Q();let Fu=M&&!o&&!O;J.clickDistance($u?1/0:!Kr(nu)||nu<0?0:nu);let Ku=Fu?cV({zoomPanValues:j,noWheelClassName:Y,d3Selection:U,d3Zoom:J,panOnScrollMode:b,panOnScrollSpeed:Z,zoomOnPinch:I,onPanZoomStart:_,onPanZoom:i,onPanZoomEnd:n}):NV({noWheelClassName:Y,preventScrolling:D,d3ZoomHandler:q});if(U.on("wheel.zoom",Ku,{passive:!1}),!O){let m=zV({zoomPanValues:j,onDraggingChange:$,onPanZoomStart:_});J.on("start",m);let d=GV({zoomPanValues:j,panOnDrag:S,onPaneContextMenu:!!t,onPanZoom:i,onTransformChange:x});J.on("zoom",d);let e=KV({zoomPanValues:j,panOnDrag:S,panOnScroll:M,onPaneContextMenu:t,onPanZoomEnd:n,onDraggingChange:$});J.on("end",e)}let Wu=LV({zoomActivationKeyPressed:o,panOnDrag:S,zoomOnScroll:k,panOnScroll:M,zoomOnDoubleClick:h,zoomOnPinch:I,userSelectionActive:O,noPanClassName:P,noWheelClassName:Y,lib:s,connectionInProgress:uu});if(J.filter(Wu),h)U.on("dblclick.zoom",W);else U.on("dblclick.zoom",null)}function Q(){J.on("zoom",null)}async function N(Y,P,t){let O=W7(Y),M=J?.constrain()(O,P,t);if(M)await G(M);return new Promise((S)=>S(M))}async function c(Y,P){let t=W7(Y);return await G(t,P),new Promise((O)=>O(t))}function z(Y){if(U){let P=W7(Y),t=U.property("__zoom");if(t.k!==Y.zoom||t.x!==Y.x||t.y!==Y.y)J?.transform(U,P,null,{sync:!0})}}function w(){let Y=U?i$(U.node()):{x:0,y:0,k:1};return{x:Y.x,y:Y.y,zoom:Y.k}}function H(Y,P){if(U)return new Promise((t)=>{J?.interpolate(P?.interpolate==="linear"?r0:Ny).scaleTo(c7(U,P?.duration,P?.ease,()=>t(!0)),Y)});return Promise.resolve(!1)}function B(Y,P){if(U)return new Promise((t)=>{J?.interpolate(P?.interpolate==="linear"?r0:Ny).scaleBy(c7(U,P?.duration,P?.ease,()=>t(!0)),Y)});return Promise.resolve(!1)}function T(Y){J?.scaleExtent(Y)}function X(Y){J?.translateExtent(Y)}function R(Y){let P=!Kr(Y)||Y<0?0:Y;J?.clickDistance(P)}return{update:K,destroy:Q,setViewport:c,setViewportConstrained:N,getViewport:w,scaleTo:H,scaleBy:B,setScaleExtent:T,setTranslateExtent:X,syncViewport:z,setClickDistance:R}}var H1;(function(u){u.Line="line",u.Handle="handle"})(H1||(H1={}));function wV({width:u,prevWidth:f,height:l,prevHeight:r,affectsX:y,affectsY:i}){let _=u-f,n=l-r,$=[_>0?1:_<0?-1:0,n>0?1:n<0?-1:0];if(_&&y)$[0]=$[0]*-1;if(n&&i)$[1]=$[1]*-1;return $}function zc(u){let f=u.includes("right")||u.includes("left"),l=u.includes("bottom")||u.includes("top"),r=u.includes("left"),y=u.includes("top");return{isHorizontal:f,isVertical:l,affectsX:r,affectsY:y}}function L1(u,f){return Math.max(0,f-u)}function w1(u,f){return Math.max(0,u-f)}function H4(u,f,l){return Math.max(0,f-u,u-l)}function Gc(u,f){return u?!f:f}function EV(u,f,l,r,y,i,_,n){let{affectsX:$,affectsY:j}=f,{isHorizontal:F,isVertical:J}=f,U=F&&J,{xSnapped:q,ySnapped:W}=l,{minWidth:G,maxWidth:K,minHeight:Q,maxHeight:N}=r,{x:c,y:z,width:w,height:H,aspectRatio:B}=u,T=Math.floor(F?q-u.pointerX:0),X=Math.floor(J?W-u.pointerY:0),R=w+($?-T:T),Y=H+(j?-X:X),P=-i[0]*w,t=-i[1]*H,O=H4(R,G,K),M=H4(Y,Q,N);if(_){let Z=0,D=0;if($&&T<0)Z=L1(c+T+P,_[0][0]);else if(!$&&T>0)Z=w1(c+R+P,_[1][0]);if(j&&X<0)D=L1(z+X+t,_[0][1]);else if(!j&&X>0)D=w1(z+Y+t,_[1][1]);O=Math.max(O,Z),M=Math.max(M,D)}if(n){let Z=0,D=0;if($&&T>0)Z=w1(c+T,n[0][0]);else if(!$&&T<0)Z=L1(c+R,n[1][0]);if(j&&X>0)D=w1(z+X,n[0][1]);else if(!j&&X<0)D=L1(z+Y,n[1][1]);O=Math.max(O,Z),M=Math.max(M,D)}if(y){if(F){let Z=H4(R/B,Q,N)*B;if(O=Math.max(O,Z),_){let D=0;if(!$&&!j||$&&!j&&U)D=w1(z+t+R/B,_[1][1])*B;else D=L1(z+t+($?T:-T)/B,_[0][1])*B;O=Math.max(O,D)}if(n){let D=0;if(!$&&!j||$&&!j&&U)D=L1(z+R/B,n[1][1])*B;else D=w1(z+($?T:-T)/B,n[0][1])*B;O=Math.max(O,D)}}if(J){let Z=H4(Y*B,G,K)/B;if(M=Math.max(M,Z),_){let D=0;if(!$&&!j||j&&!$&&U)D=w1(c+Y*B+P,_[1][0])/B;else D=L1(c+(j?X:-X)*B+P,_[0][0])/B;M=Math.max(M,D)}if(n){let D=0;if(!$&&!j||j&&!$&&U)D=L1(c+Y*B,n[1][0])/B;else D=w1(c+(j?X:-X)*B,n[0][0])/B;M=Math.max(M,D)}}}if(X=X+(X<0?M:-M),T=T+(T<0?O:-O),y)if(U)if(R>Y*B)X=(Gc($,j)?-T:T)/B;else T=(Gc($,j)?-X:X)*B;else if(F)X=T/B,j=$;else T=X*B,$=j;let S=$?c+T:c,b=j?z+X:z;return{width:w+($?-T:T),height:H+(j?-X:X),x:i[0]*T*(!$?1:-1)+S,y:i[1]*X*(!j?1:-1)+b}}var gc={width:0,height:0,x:0,y:0},TV={...gc,pointerX:0,pointerY:0,aspectRatio:1};function ZV(u){return[[0,0],[u.measured.width,u.measured.height]]}function HV(u,f,l){let r=f.position.x+u.position.x,y=f.position.y+u.position.y,i=u.measured.width??0,_=u.measured.height??0,n=l[0]*i,$=l[1]*_;return[[r-n,y-$],[r+i-n,y+_-$]]}function sc({domNode:u,nodeId:f,getStoreItems:l,onChange:r,onEnd:y}){let i=If(u),_={controlDirection:zc("bottom-right"),boundaries:{minWidth:0,minHeight:0,maxWidth:Number.MAX_VALUE,maxHeight:Number.MAX_VALUE},resizeDirection:void 0,keepAspectRatio:!1};function n({controlPosition:j,boundaries:F,keepAspectRatio:J,resizeDirection:U,onResizeStart:q,onResize:W,onResizeEnd:G,shouldResize:K}){let Q={...gc},N={...TV};_={boundaries:F,resizeDirection:U,keepAspectRatio:J,controlDirection:zc(j)};let c=void 0,z=null,w=[],H=void 0,B=void 0,T=void 0,X=!1,R=Rn().on("start",(Y)=>{let{nodeLookup:P,transform:t,snapGrid:O,snapToGrid:M,nodeOrigin:S,paneDomNode:b}=l();if(c=P.get(f),!c)return;z=b?.getBoundingClientRect()??null;let{xSnapped:Z,ySnapped:D}=n$(Y.sourceEvent,{transform:t,snapGrid:O,snapToGrid:M,containerBounds:z});if(Q={width:c.measured.width??0,height:c.measured.height??0,x:c.position.x??0,y:c.position.y??0},N={...Q,pointerX:Z,pointerY:D,aspectRatio:Q.width/Q.height},H=void 0,c.parentId&&(c.extent==="parent"||c.expandParent))H=P.get(c.parentId),B=H&&c.extent==="parent"?ZV(H):void 0;w=[],T=void 0;for(let[I,k]of P)if(k.parentId===f){if(w.push({id:I,position:{...k.position},extent:k.extent}),k.extent==="parent"||k.expandParent){let h=HV(k,c,k.origin??S);if(T)T=[[Math.min(h[0][0],T[0][0]),Math.min(h[0][1],T[0][1])],[Math.max(h[1][0],T[1][0]),Math.max(h[1][1],T[1][1])]];else T=h}}q?.(Y,{...Q})}).on("drag",(Y)=>{let{transform:P,snapGrid:t,snapToGrid:O,nodeOrigin:M}=l(),S=n$(Y.sourceEvent,{transform:P,snapGrid:t,snapToGrid:O,containerBounds:z}),b=[];if(!c)return;let{x:Z,y:D,width:I,height:k}=Q,h={},o=c.origin??M,{width:s,height:x,x:uu,y:nu}=EV(N,_.controlDirection,S,_.boundaries,_.keepAspectRatio,o,B,T),$u=s!==I,Fu=x!==k,Ku=uu!==Z&&$u,Wu=nu!==D&&Fu;if(!Ku&&!Wu&&!$u&&!Fu)return;if(Ku||Wu||o[0]===1||o[1]===1){if(h.x=Ku?uu:Q.x,h.y=Wu?nu:Q.y,Q.x=h.x,Q.y=h.y,w.length>0){let cu=uu-Z,g=nu-D;for(let Qu of w)Qu.position={x:Qu.position.x-cu+o[0]*(s-I),y:Qu.position.y-g+o[1]*(x-k)},b.push(Qu)}}if($u||Fu)h.width=$u&&(!_.resizeDirection||_.resizeDirection==="horizontal")?s:Q.width,h.height=Fu&&(!_.resizeDirection||_.resizeDirection==="vertical")?x:Q.height,Q.width=h.width,Q.height=h.height;if(H&&c.expandParent){let cu=o[0]*(h.width??0);if(h.x&&h.x{if(!X)return;G?.(Y,{...Q}),y?.({...Q}),X=!1});i.call(R)}function $(){i.on(".drag",null)}return{update:n,destroy:$}}var nN=Pu(wf(),1),$N=Pu(rN(),1);var yN=(u)=>{let f,l=new Set,r=(F,J)=>{let U=typeof F==="function"?F(f):F;if(!Object.is(U,f)){let q=f;f=(J!=null?J:typeof U!=="object"||U===null)?U:Object.assign({},f,U),l.forEach((W)=>W(f,q))}},y=()=>f,$={setState:r,getState:y,getInitialState:()=>j,subscribe:(F)=>{return l.add(F),()=>l.delete(F)},destroy:()=>{l.clear()}},j=f=u(r,y,$);return $},iN=(u)=>u?yN(u):yN;var{useDebugValue:vV}=nN.default,{useSyncExternalStoreWithSelector:IV}=$N.default,kV=(u)=>u;function b7(u,f=kV,l){let r=IV(u.subscribe,u.getState,u.getServerState||u.getInitialState,f,l);return vV(r),r}var _N=(u,f)=>{let l=iN(u),r=(y,i=f)=>b7(l,y,i);return Object.assign(r,l),r},AN=(u,f)=>u?_N(u,f):_N;function Kf(u,f){if(Object.is(u,f))return!0;if(typeof u!=="object"||u===null||typeof f!=="object"||f===null)return!1;if(u instanceof Map&&f instanceof Map){if(u.size!==f.size)return!1;for(let[r,y]of u)if(!Object.is(y,f.get(r)))return!1;return!0}if(u instanceof Set&&f instanceof Set){if(u.size!==f.size)return!1;for(let r of u)if(!f.has(r))return!1;return!0}let l=Object.keys(u);if(l.length!==Object.keys(f).length)return!1;for(let r of l)if(!Object.prototype.hasOwnProperty.call(f,r)||!Object.is(u[r],f[r]))return!1;return!0}var gV=Pu(e5(),1),v4=iu.createContext(null),sV=v4.Provider,DN=_r.error001();function uf(u,f){let l=iu.useContext(v4);if(l===null)throw Error(DN);return b7(l,u,f)}function Tf(){let u=iu.useContext(v4);if(u===null)throw Error(DN);return iu.useMemo(()=>({getState:u.getState,setState:u.setState,subscribe:u.subscribe}),[u])}var jN={display:"none"},aV={position:"absolute",width:1,height:1,margin:-1,border:0,padding:0,overflow:"hidden",clip:"rect(0px, 0px, 0px, 0px)",clipPath:"inset(100%)"},tN="react-flow__node-desc",SN="react-flow__edge-desc",oV="react-flow__aria-live",dV=(u)=>u.ariaLiveMessage,eV=(u)=>u.ariaLabelConfig;function uX({rfId:u}){let f=uf(dV);return ru.jsx("div",{id:`${oV}-${u}`,"aria-live":"assertive","aria-atomic":"true",style:aV,children:f})}function fX({rfId:u,disableKeyboardA11y:f}){let l=uf(eV);return ru.jsxs(ru.Fragment,{children:[ru.jsx("div",{id:`${tN}-${u}`,style:jN,children:f?l["node.a11yDescription.default"]:l["node.a11yDescription.keyboardDisabled"]}),ru.jsx("div",{id:`${SN}-${u}`,style:jN,children:l["edge.a11yDescription.default"]}),!f&&ru.jsx(uX,{rfId:u})]})}var I4=iu.forwardRef(({position:u="top-left",children:f,className:l,style:r,...y},i)=>{let _=`${u}`.split("-");return ru.jsx("div",{className:Yf(["react-flow__panel",l,..._]),style:r,ref:i,...y,children:f})});I4.displayName="Panel";function lX({proOptions:u,position:f="bottom-right"}){if(u?.hideAttribution)return null;return ru.jsx(I4,{position:f,className:"react-flow__attribution","data-message":"Please only hide this attribution when you are subscribed to React Flow Pro: https://pro.reactflow.dev",children:ru.jsx("a",{href:"https://reactflow.dev",target:"_blank",rel:"noopener noreferrer","aria-label":"React Flow attribution",children:"React Flow"})})}var rX=(u)=>{let f=[],l=[];for(let[,r]of u.nodeLookup)if(r.selected)f.push(r.internals.userNode);for(let[,r]of u.edgeLookup)if(r.selected)l.push(r);return{selectedNodes:f,selectedEdges:l}},R4=(u)=>u.id;function yX(u,f){return Kf(u.selectedNodes.map(R4),f.selectedNodes.map(R4))&&Kf(u.selectedEdges.map(R4),f.selectedEdges.map(R4))}function iX({onSelectionChange:u}){let f=Tf(),{selectedNodes:l,selectedEdges:r}=uf(rX,yX);return iu.useEffect(()=>{let y={nodes:l,edges:r};u?.(y),f.getState().onSelectionChangeHandlers.forEach((i)=>i(y))},[l,r,u]),null}var _X=(u)=>!!u.onSelectionChangeHandlers;function nX({onSelectionChange:u}){let f=uf(_X);if(u||f)return ru.jsx(iX,{onSelectionChange:u});return null}var k7=typeof window<"u"?iu.useLayoutEffect:iu.useEffect,PN=[0,0],$X={x:0,y:0,zoom:1},AX=["nodes","edges","defaultNodes","defaultEdges","onConnect","onConnectStart","onConnectEnd","onClickConnectStart","onClickConnectEnd","nodesDraggable","autoPanOnNodeFocus","nodesConnectable","nodesFocusable","edgesFocusable","edgesReconnectable","elevateNodesOnSelect","elevateEdgesOnSelect","minZoom","maxZoom","nodeExtent","onNodesChange","onEdgesChange","elementsSelectable","connectionMode","snapGrid","snapToGrid","translateExtent","connectOnClick","defaultEdgeOptions","fitView","fitViewOptions","onNodesDelete","onEdgesDelete","onDelete","onNodeDrag","onNodeDragStart","onNodeDragStop","onSelectionDrag","onSelectionDragStart","onSelectionDragStop","onMoveStart","onMove","onMoveEnd","noPanClassName","nodeOrigin","autoPanOnConnect","autoPanOnNodeDrag","onError","connectionRadius","isValidConnection","selectNodesOnDrag","nodeDragThreshold","connectionDragThreshold","onBeforeDelete","debug","autoPanSpeed","ariaLabelConfig","zIndexMode"],FN=[...AX,"rfId"],jX=(u)=>({setNodes:u.setNodes,setEdges:u.setEdges,setMinZoom:u.setMinZoom,setMaxZoom:u.setMaxZoom,setTranslateExtent:u.setTranslateExtent,setNodeExtent:u.setNodeExtent,reset:u.reset,setDefaultNodesAndEdges:u.setDefaultNodesAndEdges}),JN={translateExtent:xi,nodeOrigin:PN,minZoom:0.5,maxZoom:2,elementsSelectable:!0,noPanClassName:"nopan",rfId:"1"};function FX(u){let{setNodes:f,setEdges:l,setMinZoom:r,setMaxZoom:y,setTranslateExtent:i,setNodeExtent:_,reset:n,setDefaultNodesAndEdges:$}=uf(jX,Kf),j=Tf();k7(()=>{return $(u.defaultNodes,u.defaultEdges),()=>{F.current=JN,n()}},[]);let F=iu.useRef(JN);return k7(()=>{for(let J of FN){let U=u[J],q=F.current[J];if(U===q)continue;if(typeof u[J]>"u")continue;if(J==="nodes")f(U);else if(J==="edges")l(U);else if(J==="minZoom")r(U);else if(J==="maxZoom")y(U);else if(J==="translateExtent")i(U);else if(J==="nodeExtent")_(U);else if(J==="ariaLabelConfig")j.setState({ariaLabelConfig:Oc(U)});else if(J==="fitView")j.setState({fitViewQueued:U});else if(J==="fitViewOptions")j.setState({fitViewOptions:U});else j.setState({[J]:U})}F.current=u},FN.map((J)=>u[J])),null}function UN(){if(typeof window>"u"||!window.matchMedia)return null;return window.matchMedia("(prefers-color-scheme: dark)")}function JX(u){let[f,l]=iu.useState(u==="system"?null:u);return iu.useEffect(()=>{if(u!=="system"){l(u);return}let r=UN(),y=()=>l(r?.matches?"dark":"light");return y(),r?.addEventListener("change",y),()=>{r?.removeEventListener("change",y)}},[u]),f!==null?f:UN()?.matches?"dark":"light"}var QN=typeof document<"u"?document:null;function J$(u=null,f={target:QN,actInsideInputWithModifier:!0}){let[l,r]=iu.useState(!1),y=iu.useRef(!1),i=iu.useRef(new Set([])),[_,n]=iu.useMemo(()=>{if(u!==null){let j=(Array.isArray(u)?u:[u]).filter((J)=>typeof J==="string").map((J)=>J.replace("+",` `).replace(` `,` +`).split(` -`)),U=J.reduce((Q,W)=>Q.concat(...W),[]);return[J,U]}return[[],[]]},[f]);return _f.useEffect(()=>{let A=u?.target??QZ,J=u?.actInsideInputWithModifier??!0;if(f!==null){let U=(G)=>{if(y.current=G.ctrlKey||G.metaKey||G.shiftKey||G.altKey,(!y.current||y.current&&!J)&&SF(G))return!1;let H=zZ(G.code,j);if($.current.add(G[H]),WZ(r,$.current,!1)){let O=G.composedPath?.()?.[0]||G.target,z=O?.nodeName==="BUTTON"||O?.nodeName==="A";if(u.preventDefault!==!1&&(y.current||!z))G.preventDefault();_(!0)}},Q=(G)=>{let K=zZ(G.code,j);if(WZ(r,$.current,!0))_(!1),$.current.clear();else $.current.delete(G[K]);if(G.key==="Meta")$.current.clear();y.current=!1},W=()=>{$.current.clear(),_(!1)};return A?.addEventListener("keydown",U),A?.addEventListener("keyup",Q),window.addEventListener("blur",W),window.addEventListener("contextmenu",W),()=>{A?.removeEventListener("keydown",U),A?.removeEventListener("keyup",Q),window.removeEventListener("blur",W),window.removeEventListener("contextmenu",W)}}},[f,_]),l}function WZ(f,u,l){return f.filter((_)=>l||_.length===u.size).some((_)=>_.every((y)=>u.has(y)))}function zZ(f,u){return u.includes(f)?"code":"key"}var aT=()=>{let f=q0();return _f.useMemo(()=>{return{zoomIn:(u)=>{let{panZoom:l}=f.getState();return l?l.scaleBy(1.2,u):Promise.resolve(!1)},zoomOut:(u)=>{let{panZoom:l}=f.getState();return l?l.scaleBy(0.8333333333333334,u):Promise.resolve(!1)},zoomTo:(u,l)=>{let{panZoom:_}=f.getState();return _?_.scaleTo(u,l):Promise.resolve(!1)},getZoom:()=>f.getState().transform[2],setViewport:async(u,l)=>{let{transform:[_,y,$],panZoom:r}=f.getState();if(!r)return Promise.resolve(!1);return await r.setViewport({x:u.x??_,y:u.y??y,zoom:u.zoom??$},l),Promise.resolve(!0)},getViewport:()=>{let[u,l,_]=f.getState().transform;return{x:u,y:l,zoom:_}},setCenter:async(u,l,_)=>{return f.getState().setCenter(u,l,_)},fitBounds:async(u,l)=>{let{width:_,height:y,minZoom:$,maxZoom:r,panZoom:j}=f.getState(),A=F4(u,_,y,$,r,l?.padding??0.1);if(!j)return Promise.resolve(!1);return await j.setViewport(A,{duration:l?.duration,ease:l?.ease,interpolate:l?.interpolate}),Promise.resolve(!0)},screenToFlowPosition:(u,l={})=>{let{transform:_,snapGrid:y,snapToGrid:$,domNode:r}=f.getState();if(!r)return u;let{x:j,y:A}=r.getBoundingClientRect(),J={x:u.x-j,y:u.y-A},U=l.snapGrid??y,Q=l.snapToGrid??$;return k$(J,_,Q,U)},flowToScreenPosition:(u)=>{let{transform:l,domNode:_}=f.getState();if(!_)return u;let{x:y,y:$}=_.getBoundingClientRect(),r=j4(u,l);return{x:r.x+y,y:r.y+$}}}},[])};function CZ(f,u){let l=[],_=new Map,y=[];for(let $ of f)if($.type==="add"){y.push($);continue}else if($.type==="remove"||$.type==="replace")_.set($.id,[$]);else{let r=_.get($.id);if(r)r.push($);else _.set($.id,[$])}for(let $ of u){let r=_.get($.id);if(!r){l.push($);continue}if(r[0].type==="remove")continue;if(r[0].type==="replace"){l.push({...r[0].item});continue}let j={...$};for(let A of r)dT(A,j);l.push(j)}if(y.length)y.forEach(($)=>{if($.index!==void 0)l.splice($.index,0,{...$.item});else l.push({...$.item})});return l}function dT(f,u){switch(f.type){case"select":{u.selected=f.selected;break}case"position":{if(typeof f.position<"u")u.position=f.position;if(typeof f.dragging<"u")u.dragging=f.dragging;break}case"dimensions":{if(typeof f.dimensions<"u"){if(u.measured={...f.dimensions},f.setAttributes){if(f.setAttributes===!0||f.setAttributes==="width")u.width=f.dimensions.width;if(f.setAttributes===!0||f.setAttributes==="height")u.height=f.dimensions.height}}if(typeof f.resizing==="boolean")u.resizing=f.resizing;break}}}function eT(f,u){return CZ(f,u)}function fM(f,u){return CZ(f,u)}function wy(f,u){return{id:f,type:"select",selected:u}}function o$(f,u=new Set,l=!1){let _=[];for(let[y,$]of f){let r=u.has(y);if(!($.selected===void 0&&!r)&&$.selected!==r){if(l)$.selected=r;_.push(wy($.id,r))}}return _}function GZ({items:f=[],lookup:u}){let l=[],_=new Map(f.map((y)=>[y.id,y]));for(let[y,$]of f.entries()){let r=u.get($.id),j=r?.internals?.userNode??r;if(j!==void 0&&j!==$)l.push({id:$.id,item:$,type:"replace"});if(j===void 0)l.push({item:$,type:"add",index:y})}for(let[y]of u)if(_.get(y)===void 0)l.push({id:y,type:"remove"});return l}function KZ(f){return{id:f.id,type:"remove"}}var NZ=(f)=>EN(f),uM=(f)=>qF(f);function iZ(f){return _f.forwardRef(f)}function ZZ(f){let[u,l]=_f.useState(BigInt(0)),[_]=_f.useState(()=>lM(()=>l((y)=>y+BigInt(1))));return kF(()=>{let y=_.get();if(y.length)f(y),_.reset()},[u]),_}function lM(f){let u=[];return{get:()=>u,reset:()=>{u=[]},push:(l)=>{u.push(l),f()}}}var cZ=_f.createContext(null);function _M({children:f}){let u=q0(),l=_f.useCallback((j)=>{let{nodes:A=[],setNodes:J,hasDefaultNodes:U,onNodesChange:Q,nodeLookup:W,fitViewQueued:G,onNodesChangeMiddlewareMap:K}=u.getState(),H=A;for(let z of j)H=typeof z==="function"?z(H):z;let O=GZ({items:H,lookup:W});for(let z of K.values())O=z(O);if(U)J(H);if(O.length>0)Q?.(O);else if(G)window.requestAnimationFrame(()=>{let{fitViewQueued:z,nodes:Z,setNodes:N}=u.getState();if(z)N(Z)})},[]),_=ZZ(l),y=_f.useCallback((j)=>{let{edges:A=[],setEdges:J,hasDefaultEdges:U,onEdgesChange:Q,edgeLookup:W}=u.getState(),G=A;for(let K of j)G=typeof K==="function"?K(G):K;if(U)J(G);else if(Q)Q(GZ({items:G,lookup:W}))},[]),$=ZZ(y),r=_f.useMemo(()=>({nodeQueue:_,edgeQueue:$}),[]);return lf.jsx(cZ.Provider,{value:r,children:f})}function yM(){let f=_f.useContext(cZ);if(!f)throw Error("useBatchContext must be used within a BatchProvider");return f}var $M=(f)=>!!f.panZoom;function sF(){let f=aT(),u=q0(),l=yM(),_=f0($M),y=_f.useMemo(()=>{let $=(Q)=>u.getState().nodeLookup.get(Q),r=(Q)=>{l.nodeQueue.push(Q)},j=(Q)=>{l.edgeQueue.push(Q)},A=(Q)=>{let{nodeLookup:W,nodeOrigin:G}=u.getState(),K=NZ(Q)?Q:W.get(Q.id),H=K.parentId?MF(K.position,K.measured,K.parentId,W,G):K.position,O={...K,position:H,width:K.measured?.width??K.width,height:K.measured?.height??K.height};return Yy(O)},J=(Q,W,G={replace:!1})=>{r((K)=>K.map((H)=>{if(H.id===Q){let O=typeof W==="function"?W(H):W;return G.replace&&NZ(O)?O:{...H,...O}}return H}))},U=(Q,W,G={replace:!1})=>{j((K)=>K.map((H)=>{if(H.id===Q){let O=typeof W==="function"?W(H):W;return G.replace&&uM(O)?O:{...H,...O}}return H}))};return{getNodes:()=>u.getState().nodes.map((Q)=>({...Q})),getNode:(Q)=>$(Q)?.internals.userNode,getInternalNode:$,getEdges:()=>{let{edges:Q=[]}=u.getState();return Q.map((W)=>({...W}))},getEdge:(Q)=>u.getState().edgeLookup.get(Q),setNodes:r,setEdges:j,addNodes:(Q)=>{let W=Array.isArray(Q)?Q:[Q];l.nodeQueue.push((G)=>[...G,...W])},addEdges:(Q)=>{let W=Array.isArray(Q)?Q:[Q];l.edgeQueue.push((G)=>[...G,...W])},toObject:()=>{let{nodes:Q=[],edges:W=[],transform:G}=u.getState(),[K,H,O]=G;return{nodes:Q.map((z)=>({...z})),edges:W.map((z)=>({...z})),viewport:{x:K,y:H,zoom:O}}},deleteElements:async({nodes:Q=[],edges:W=[]})=>{let{nodes:G,edges:K,onNodesDelete:H,onEdgesDelete:O,triggerNodeChanges:z,triggerEdgeChanges:Z,onDelete:N,onBeforeDelete:E}=u.getState(),{nodes:q,edges:Y}=await VN({nodesToRemove:Q,edgesToRemove:W,nodes:G,edges:K,onBeforeDelete:E}),w=Y.length>0,B=q.length>0;if(w){let P=Y.map(KZ);O?.(Y),Z(P)}if(B){let P=q.map(KZ);H?.(q),z(P)}if(B||w)N?.({nodes:q,edges:Y});return{deletedNodes:q,deletedEdges:Y}},getIntersectingNodes:(Q,W=!0,G)=>{let K=wF(Q),H=K?Q:A(Q),O=G!==void 0;if(!H)return[];return(G||u.getState().nodes).filter((z)=>{let Z=u.getState().nodeLookup.get(z.id);if(Z&&!K&&(z.id===Q.id||!Z.internals.positionAbsolute))return!1;let N=Yy(O?z:Z),E=m$(N,H);return W&&E>0||E>=N.width*N.height||E>=H.width*H.height})},isNodeIntersecting:(Q,W,G=!0)=>{let H=wF(Q)?Q:A(Q);if(!H)return!1;let O=m$(H,W);return G&&O>0||O>=W.width*W.height||O>=H.width*H.height},updateNode:J,updateNodeData:(Q,W,G={replace:!1})=>{J(Q,(K)=>{let H=typeof W==="function"?W(K):W;return G.replace?{...K,data:H}:{...K,data:{...K.data,...H}}},G)},updateEdge:U,updateEdgeData:(Q,W,G={replace:!1})=>{U(Q,(K)=>{let H=typeof W==="function"?W(K):W;return G.replace?{...K,data:H}:{...K,data:{...K.data,...H}}},G)},getNodesBounds:(Q)=>{let{nodeLookup:W,nodeOrigin:G}=u.getState();return XF(Q,{nodeLookup:W,nodeOrigin:G})},getHandleConnections:({type:Q,id:W,nodeId:G})=>Array.from(u.getState().connectionLookup.get(`${G}-${Q}${W?`-${W}`:""}`)?.values()??[]),getNodeConnections:({type:Q,handleId:W,nodeId:G})=>Array.from(u.getState().connectionLookup.get(`${G}${Q?W?`-${Q}-${W}`:`-${Q}`:""}`)?.values()??[]),fitView:async(Q)=>{let W=u.getState().fitViewResolver??XN();return u.setState({fitViewQueued:!0,fitViewOptions:Q,fitViewResolver:W}),l.nodeQueue.push((G)=>[...G]),W.promise}}},[]);return _f.useMemo(()=>{return{...y,...f,viewportInitialized:_}},[_])}var EZ=(f)=>f.selected,rM=typeof window<"u"?window:void 0;function jM({deleteKeyCode:f,multiSelectionKeyCode:u}){let l=q0(),{deleteElements:_}=sF(),y=U4(f,{actInsideInputWithModifier:!1}),$=U4(u,{target:rM});_f.useEffect(()=>{if(y){let{edges:r,nodes:j}=l.getState();_({nodes:j.filter(EZ),edges:r.filter(EZ)}),l.setState({nodesSelectionActive:!1})}},[y]),_f.useEffect(()=>{l.setState({multiSelectionActive:$})},[$])}function AM(f){let u=q0();_f.useEffect(()=>{let l=()=>{if(!f.current||!(f.current.checkVisibility?.()??!0))return!1;let _=T5(f.current);if(_.height===0||_.width===0)u.getState().onError?.("004",$l.error004());u.setState({width:_.width||500,height:_.height||500})};if(f.current){l(),window.addEventListener("resize",l);let _=new ResizeObserver(()=>l());return _.observe(f.current),()=>{if(window.removeEventListener("resize",l),_&&f.current)_.unobserve(f.current)}}},[])}var m5={position:"absolute",width:"100%",height:"100%",top:0,left:0},FM=(f)=>({userSelectionActive:f.userSelectionActive,lib:f.lib,connectionInProgress:f.connection.inProgress});function JM({onPaneContextMenu:f,zoomOnScroll:u=!0,zoomOnPinch:l=!0,panOnScroll:_=!1,panOnScrollSpeed:y=0.5,panOnScrollMode:$=c1.Free,zoomOnDoubleClick:r=!0,panOnDrag:j=!0,defaultViewport:A,translateExtent:J,minZoom:U,maxZoom:Q,zoomActivationKeyCode:W,preventScrolling:G=!0,children:K,noWheelClassName:H,noPanClassName:O,onViewportChange:z,isControlledViewport:Z,paneClickDistance:N,selectionOnDrag:E}){let q=q0(),Y=_f.useRef(null),{userSelectionActive:w,lib:B,connectionInProgress:P}=f0(FM,H0),h=U4(W),M=_f.useRef();AM(Y);let n=_f.useCallback((S)=>{if(z?.({x:S[0],y:S[1],zoom:S[2]}),!Z)q.setState({transform:S})},[z,Z]);return _f.useEffect(()=>{if(Y.current){M.current=mN({domNode:Y.current,minZoom:U,maxZoom:Q,translateExtent:J,viewport:A,onDraggingChange:(C)=>q.setState((v)=>v.paneDragging===C?v:{paneDragging:C}),onPanZoomStart:(C,v)=>{let{onViewportChangeStart:X,onMoveStart:D}=q.getState();D?.(C,v),X?.(v)},onPanZoom:(C,v)=>{let{onViewportChange:X,onMove:D}=q.getState();D?.(C,v),X?.(v)},onPanZoomEnd:(C,v)=>{let{onViewportChangeEnd:X,onMoveEnd:D}=q.getState();D?.(C,v),X?.(v)}});let{x:S,y:T,zoom:i}=M.current.getViewport();return q.setState({panZoom:M.current,transform:[S,T,i],domNode:Y.current.closest(".react-flow")}),()=>{M.current?.destroy()}}},[]),_f.useEffect(()=>{M.current?.update({onPaneContextMenu:f,zoomOnScroll:u,zoomOnPinch:l,panOnScroll:_,panOnScrollSpeed:y,panOnScrollMode:$,zoomOnDoubleClick:r,panOnDrag:j,zoomActivationKeyPressed:h,preventScrolling:G,noPanClassName:O,userSelectionActive:w,noWheelClassName:H,lib:B,onTransformChange:n,connectionInProgress:P,selectionOnDrag:E,paneClickDistance:N})},[f,u,l,_,y,$,r,j,h,G,O,w,H,B,n,P,E,N]),lf.jsx("div",{className:"react-flow__renderer",ref:Y,style:m5,children:K})}var UM=(f)=>({userSelectionActive:f.userSelectionActive,userSelectionRect:f.userSelectionRect});function QM(){let{userSelectionActive:f,userSelectionRect:u}=f0(UM,H0);if(!(f&&u))return null;return lf.jsx("div",{className:"react-flow__selection react-flow__container",style:{width:u.width,height:u.height,transform:`translate(${u.x}px, ${u.y}px)`}})}var mF=(f,u)=>{return(l)=>{if(l.target!==u.current)return;f?.(l)}},WM=(f)=>({userSelectionActive:f.userSelectionActive,elementsSelectable:f.elementsSelectable,connectionInProgress:f.connection.inProgress,dragging:f.paneDragging});function zM({isSelecting:f,selectionKeyPressed:u,selectionMode:l=Xy.Full,panOnDrag:_,paneClickDistance:y,selectionOnDrag:$,onSelectionStart:r,onSelectionEnd:j,onPaneClick:A,onPaneContextMenu:J,onPaneScroll:U,onPaneMouseEnter:Q,onPaneMouseMove:W,onPaneMouseLeave:G,children:K}){let H=q0(),{userSelectionActive:O,elementsSelectable:z,dragging:Z,connectionInProgress:N}=f0(WM,H0),E=z&&(f||O),q=_f.useRef(null),Y=_f.useRef(),w=_f.useRef(new Set),B=_f.useRef(new Set),P=_f.useRef(!1),h=(X)=>{if(P.current||N){P.current=!1;return}A?.(X),H.getState().resetSelectedElements(),H.setState({nodesSelectionActive:!1})},M=(X)=>{if(Array.isArray(_)&&_?.includes(2)){X.preventDefault();return}J?.(X)},n=U?(X)=>U(X):void 0,S=(X)=>{if(P.current)X.stopPropagation(),P.current=!1},T=(X)=>{let{domNode:D}=H.getState();if(Y.current=D?.getBoundingClientRect(),!Y.current)return;let p=X.target===q.current;if(!p&&!!X.target.closest(".nokey")||!f||!($&&p||u)||X.button!==0||!X.isPrimary)return;X.target?.setPointerCapture?.(X.pointerId),P.current=!1;let{x:d,y:a}=Ol(X.nativeEvent,Y.current);if(H.setState({userSelectionRect:{width:0,height:0,startX:d,startY:a,x:d,y:a}}),!p)X.stopPropagation(),X.preventDefault()},i=(X)=>{let{userSelectionRect:D,transform:p,nodeLookup:m,edgeLookup:s,connectionLookup:d,triggerNodeChanges:a,triggerEdgeChanges:I,defaultEdgeOptions:ff,resetSelectedElements:yf}=H.getState();if(!Y.current||!D)return;let{x:rf,y:Wf}=Ol(X.nativeEvent,Y.current),{startX:Ef,startY:Gf}=D;if(!P.current){let k=u?0:y;if(Math.hypot(rf-Ef,Wf-Gf)<=k)return;yf(),r?.(X)}P.current=!0;let c={startX:Ef,startY:Gf,x:rfk.id)),B.current=new Set;let Kf=ff?.selectable??!0;for(let k of w.current){let Af=d.get(k);if(!Af)continue;for(let{edgeId:Yf}of Af.values()){let Bf=s.get(Yf);if(Bf&&(Bf.selectable??Kf))B.current.add(Yf)}}if(!PF(o,w.current)){let k=o$(m,w.current,!0);a(k)}if(!PF(e,B.current)){let k=o$(s,B.current);I(k)}H.setState({userSelectionRect:c,userSelectionActive:!0,nodesSelectionActive:!1})},C=(X)=>{if(X.button!==0)return;if(X.target?.releasePointerCapture?.(X.pointerId),!O&&X.target===q.current&&H.getState().userSelectionRect)h?.(X);if(H.setState({userSelectionActive:!1,userSelectionRect:null}),P.current)j?.(X),H.setState({nodesSelectionActive:w.current.size>0})},v=_===!0||Array.isArray(_)&&_.includes(0);return lf.jsxs("div",{className:M0(["react-flow__pane",{draggable:v,dragging:Z,selection:f}]),onClick:E?void 0:mF(h,q),onContextMenu:mF(M,q),onWheel:mF(n,q),onPointerEnter:E?void 0:Q,onPointerMove:E?i:W,onPointerUp:E?C:void 0,onPointerDownCapture:E?T:void 0,onClickCapture:E?S:void 0,onPointerLeave:G,ref:q,style:m5,children:[K,lf.jsx(QM,{})]})}function tF({id:f,store:u,unselect:l=!1,nodeRef:_}){let{addSelectedNodes:y,unselectNodesAndEdges:$,multiSelectionActive:r,nodeLookup:j,onError:A}=u.getState(),J=j.get(f);if(!J){A?.("012",$l.error012(f));return}if(u.setState({nodesSelectionActive:!1}),!J.selected)y([f]);else if(l||J.selected&&r)$({nodes:[J],edges:[]}),requestAnimationFrame(()=>_?.current?.blur())}function RZ({nodeRef:f,disabled:u=!1,noDragClassName:l,handleSelector:_,nodeId:y,isSelectable:$,nodeClickDistance:r}){let j=q0(),[A,J]=_f.useState(!1),U=_f.useRef();return _f.useEffect(()=>{U.current=cN({getStoreItems:()=>j.getState(),onNodeMouseDown:(Q)=>{tF({id:Q,store:j,nodeRef:f})},onDragStart:()=>{J(!0)},onDragStop:()=>{J(!1)}})},[]),_f.useEffect(()=>{if(u||!f.current||!U.current)return;return U.current.update({noDragClassName:l,handleSelector:_,domNode:f.current,isSelectable:$,nodeId:y,nodeClickDistance:r}),()=>{U.current?.destroy()}},[l,_,u,$,f,y,r]),A}var GM=(f)=>(u)=>u.selected&&(u.draggable||f&&typeof u.draggable>"u");function xZ(){let f=q0();return _f.useCallback((l)=>{let{nodeExtent:_,snapToGrid:y,snapGrid:$,nodesDraggable:r,onError:j,updateNodePositions:A,nodeLookup:J,nodeOrigin:U}=f.getState(),Q=new Map,W=GM(r),G=y?$[0]:5,K=y?$[1]:5,H=l.direction.x*G*l.factor,O=l.direction.y*K*l.factor;for(let[,z]of J){if(!W(z))continue;let Z={x:z.internals.positionAbsolute.x+H,y:z.internals.positionAbsolute.y+O};if(y)Z=g$(Z,$);let{position:N,positionAbsolute:E}=BF({nodeId:z.id,nextPosition:Z,nodeLookup:J,nodeExtent:_,nodeOrigin:U,onError:j});z.position=N,z.internals.positionAbsolute=E,Q.set(z.id,z)}A(Q)},[])}var oF=_f.createContext(null),KM=oF.Provider;oF.Consumer;var bZ=()=>{return _f.useContext(oF)},NM=(f)=>({connectOnClick:f.connectOnClick,noPanClassName:f.noPanClassName,rfId:f.rfId}),ZM=(f,u,l)=>(_)=>{let{connectionClickStartHandle:y,connectionMode:$,connection:r}=_,{fromHandle:j,toHandle:A,isValid:J}=r,U=A?.nodeId===f&&A?.id===u&&A?.type===l;return{connectingFrom:j?.nodeId===f&&j?.id===u&&j?.type===l,connectingTo:U,clickConnecting:y?.nodeId===f&&y?.id===u&&y?.type===l,isPossibleEndHandle:$===q_.Strict?j?.type!==l:f!==j?.nodeId||u!==j?.id,connectionInProcess:!!j,clickConnectionInProcess:!!y,valid:U&&J}};function EM({type:f="source",position:u=Zf.Top,isValidConnection:l,isConnectable:_=!0,isConnectableStart:y=!0,isConnectableEnd:$=!0,id:r,onConnect:j,children:A,className:J,onMouseDown:U,onTouchStart:Q,...W},G){let K=r||null,H=f==="target",O=q0(),z=bZ(),{connectOnClick:Z,noPanClassName:N,rfId:E}=f0(NM,H0),{connectingFrom:q,connectingTo:Y,clickConnecting:w,isPossibleEndHandle:B,connectionInProcess:P,clickConnectionInProcess:h,valid:M}=f0(ZM(z,K,f),H0);if(!z)O.getState().onError?.("010",$l.error010());let n=(i)=>{let{defaultEdgeOptions:C,onConnect:v,hasDefaultEdges:X}=O.getState(),D={...C,...i};if(X){let{edges:p,setEdges:m}=O.getState();m(cF(D,p))}v?.(D),j?.(D)},S=(i)=>{if(!z)return;let C=CF(i.nativeEvent);if(y&&(C&&i.button===0||!C)){let v=O.getState();c5.onPointerDown(i.nativeEvent,{handleDomNode:i.currentTarget,autoPanOnConnect:v.autoPanOnConnect,connectionMode:v.connectionMode,connectionRadius:v.connectionRadius,domNode:v.domNode,nodeLookup:v.nodeLookup,lib:v.lib,isTarget:H,handleId:K,nodeId:z,flowId:v.rfId,panBy:v.panBy,cancelConnection:v.cancelConnection,onConnectStart:v.onConnectStart,onConnectEnd:(...X)=>O.getState().onConnectEnd?.(...X),updateConnection:v.updateConnection,onConnect:n,isValidConnection:l||((...X)=>O.getState().isValidConnection?.(...X)??!0),getTransform:()=>O.getState().transform,getFromHandle:()=>O.getState().connection.fromHandle,autoPanSpeed:v.autoPanSpeed,dragThreshold:v.connectionDragThreshold})}if(C)U?.(i);else Q?.(i)},T=(i)=>{let{onClickConnectStart:C,onClickConnectEnd:v,connectionClickStartHandle:X,connectionMode:D,isValidConnection:p,lib:m,rfId:s,nodeLookup:d,connection:a}=O.getState();if(!z||!X&&!y)return;if(!X){C?.(i.nativeEvent,{nodeId:z,handleId:K,handleType:f}),O.setState({connectionClickStartHandle:{nodeId:z,type:f,id:K}});return}let I=nF(i.target),ff=l||p,{connection:yf,isValid:rf}=c5.isValid(i.nativeEvent,{handle:{nodeId:z,id:K,type:f},connectionMode:D,fromNodeId:X.nodeId,fromHandleId:X.id||null,fromType:X.type,isValidConnection:ff,flowId:s,doc:I,lib:m,nodeLookup:d});if(rf&&yf)n(yf);let Wf=structuredClone(a);delete Wf.inProgress,Wf.toPosition=Wf.toHandle?Wf.toHandle.position:null,v?.(i,Wf),O.setState({connectionClickStartHandle:null})};return lf.jsx("div",{"data-handleid":K,"data-nodeid":z,"data-handlepos":u,"data-id":`${E}-${z}-${K}-${f}`,className:M0(["react-flow__handle",`react-flow__handle-${u}`,"nodrag",N,J,{source:!H,target:H,connectable:_,connectablestart:y,connectableend:$,clickconnecting:w,connectingfrom:q,connectingto:Y,valid:M,connectionindicator:_&&(!P||B)&&(P||h?$:y)}]),onMouseDown:S,onTouchStart:S,onClick:Z?T:void 0,ref:G,...W,children:A})}var Dy=_f.memo(iZ(EM));function HM({data:f,isConnectable:u,sourcePosition:l=Zf.Bottom}){return lf.jsxs(lf.Fragment,{children:[f?.label,lf.jsx(Dy,{type:"source",position:l,isConnectable:u})]})}function OM({data:f,isConnectable:u,targetPosition:l=Zf.Top,sourcePosition:_=Zf.Bottom}){return lf.jsxs(lf.Fragment,{children:[lf.jsx(Dy,{type:"target",position:l,isConnectable:u}),f?.label,lf.jsx(Dy,{type:"source",position:_,isConnectable:u})]})}function VM(){return null}function qM({data:f,isConnectable:u,targetPosition:l=Zf.Top}){return lf.jsxs(lf.Fragment,{children:[lf.jsx(Dy,{type:"target",position:l,isConnectable:u}),f?.label]})}var h5={ArrowUp:{x:0,y:-1},ArrowDown:{x:0,y:1},ArrowLeft:{x:-1,y:0},ArrowRight:{x:1,y:0}},HZ={input:HM,default:OM,output:qM,group:VM};function LM(f){if(f.internals.handleBounds===void 0)return{width:f.width??f.initialWidth??f.style?.width,height:f.height??f.initialHeight??f.style?.height};return{width:f.width??f.style?.width,height:f.height??f.style?.height}}var XM=(f)=>{let{width:u,height:l,x:_,y}=p$(f.nodeLookup,{filter:($)=>!!$.selected});return{width:Hl(u)?u:null,height:Hl(l)?l:null,userSelectionActive:f.userSelectionActive,transformString:`translate(${f.transform[0]}px,${f.transform[1]}px) scale(${f.transform[2]}) translate(${_}px,${y}px)`}};function BM({onSelectionContextMenu:f,noPanClassName:u,disableKeyboardA11y:l}){let _=q0(),{width:y,height:$,transformString:r,userSelectionActive:j}=f0(XM,H0),A=xZ(),J=_f.useRef(null);_f.useEffect(()=>{if(!l)J.current?.focus({preventScroll:!0})},[l]);let U=!j&&y!==null&&$!==null;if(RZ({nodeRef:J,disabled:!U}),!U)return null;let Q=f?(G)=>{let K=_.getState().nodes.filter((H)=>H.selected);f(G,K)}:void 0,W=(G)=>{if(Object.prototype.hasOwnProperty.call(h5,G.key))G.preventDefault(),A({direction:h5[G.key],factor:G.shiftKey?4:1})};return lf.jsx("div",{className:M0(["react-flow__nodesselection","react-flow__container",u]),style:{transform:r},children:lf.jsx("div",{ref:J,className:"react-flow__nodesselection-rect",onContextMenu:Q,tabIndex:l?void 0:-1,onKeyDown:l?void 0:W,style:{width:y,height:$}})})}var OZ=typeof window<"u"?window:void 0,YM=(f)=>{return{nodesSelectionActive:f.nodesSelectionActive,userSelectionActive:f.userSelectionActive}};function vZ({children:f,onPaneClick:u,onPaneMouseEnter:l,onPaneMouseMove:_,onPaneMouseLeave:y,onPaneContextMenu:$,onPaneScroll:r,paneClickDistance:j,deleteKeyCode:A,selectionKeyCode:J,selectionOnDrag:U,selectionMode:Q,onSelectionStart:W,onSelectionEnd:G,multiSelectionKeyCode:K,panActivationKeyCode:H,zoomActivationKeyCode:O,elementsSelectable:z,zoomOnScroll:Z,zoomOnPinch:N,panOnScroll:E,panOnScrollSpeed:q,panOnScrollMode:Y,zoomOnDoubleClick:w,panOnDrag:B,defaultViewport:P,translateExtent:h,minZoom:M,maxZoom:n,preventScrolling:S,onSelectionContextMenu:T,noWheelClassName:i,noPanClassName:C,disableKeyboardA11y:v,onViewportChange:X,isControlledViewport:D}){let{nodesSelectionActive:p,userSelectionActive:m}=f0(YM,H0),s=U4(J,{target:OZ}),d=U4(H,{target:OZ}),a=d||B,I=d||E,ff=U&&a!==!0,yf=s||m||ff;return jM({deleteKeyCode:A,multiSelectionKeyCode:K}),lf.jsx(JM,{onPaneContextMenu:$,elementsSelectable:z,zoomOnScroll:Z,zoomOnPinch:N,panOnScroll:I,panOnScrollSpeed:q,panOnScrollMode:Y,zoomOnDoubleClick:w,panOnDrag:!s&&a,defaultViewport:P,translateExtent:h,minZoom:M,maxZoom:n,zoomActivationKeyCode:O,preventScrolling:S,noWheelClassName:i,noPanClassName:C,onViewportChange:X,isControlledViewport:D,paneClickDistance:j,selectionOnDrag:ff,children:lf.jsxs(zM,{onSelectionStart:W,onSelectionEnd:G,onPaneClick:u,onPaneMouseEnter:l,onPaneMouseMove:_,onPaneMouseLeave:y,onPaneContextMenu:$,onPaneScroll:r,panOnDrag:a,isSelecting:!!yf,selectionMode:Q,selectionKeyPressed:s,paneClickDistance:j,selectionOnDrag:ff,children:[f,p&&lf.jsx(BM,{onSelectionContextMenu:T,noPanClassName:C,disableKeyboardA11y:v})]})})}vZ.displayName="FlowRenderer";var wM=_f.memo(vZ),DM=(f)=>(u)=>{return f?Y5(u.nodeLookup,{x:0,y:0,width:u.width,height:u.height},u.transform,!0).map((l)=>l.id):Array.from(u.nodeLookup.keys())};function TM(f){return f0(_f.useCallback(DM(f),[f]),H0)}var MM=(f)=>f.updateNodeInternals;function PM(){let f=f0(MM),[u]=_f.useState(()=>{if(typeof ResizeObserver>"u")return null;return new ResizeObserver((l)=>{let _=new Map;l.forEach((y)=>{let $=y.target.getAttribute("data-id");_.set($,{id:$,nodeElement:y.target,force:!0})}),f(_)})});return _f.useEffect(()=>{return()=>{u?.disconnect()}},[u]),u}function nM({node:f,nodeType:u,hasDimensions:l,resizeObserver:_}){let y=q0(),$=_f.useRef(null),r=_f.useRef(null),j=_f.useRef(f.sourcePosition),A=_f.useRef(f.targetPosition),J=_f.useRef(u),U=l&&!!f.internals.handleBounds;return _f.useEffect(()=>{if($.current&&!f.hidden&&(!U||r.current!==$.current)){if(r.current)_?.unobserve(r.current);_?.observe($.current),r.current=$.current}},[U,f.hidden]),_f.useEffect(()=>{return()=>{if(r.current)_?.unobserve(r.current),r.current=null}},[]),_f.useEffect(()=>{if($.current){let Q=J.current!==u,W=j.current!==f.sourcePosition,G=A.current!==f.targetPosition;if(Q||W||G)J.current=u,j.current=f.sourcePosition,A.current=f.targetPosition,y.getState().updateNodeInternals(new Map([[f.id,{id:f.id,nodeElement:$.current,force:!0}]]))}},[f.id,u,f.sourcePosition,f.targetPosition]),$}function SM({id:f,onClick:u,onMouseEnter:l,onMouseMove:_,onMouseLeave:y,onContextMenu:$,onDoubleClick:r,nodesDraggable:j,elementsSelectable:A,nodesConnectable:J,nodesFocusable:U,resizeObserver:Q,noDragClassName:W,noPanClassName:G,disableKeyboardA11y:K,rfId:H,nodeTypes:O,nodeClickDistance:z,onError:Z}){let{node:N,internals:E,isParent:q}=f0((rf)=>{let Wf=rf.nodeLookup.get(f),Ef=rf.parentLookup.has(f);return{node:Wf,internals:Wf.internals,isParent:Ef}},H0),Y=N.type||"default",w=O?.[Y]||HZ[Y];if(w===void 0)Z?.("003",$l.error003(Y)),Y="default",w=O?.default||HZ.default;let B=!!(N.draggable||j&&typeof N.draggable>"u"),P=!!(N.selectable||A&&typeof N.selectable>"u"),h=!!(N.connectable||J&&typeof N.connectable>"u"),M=!!(N.focusable||U&&typeof N.focusable>"u"),n=q0(),S=TF(N),T=nM({node:N,nodeType:Y,hasDimensions:S,resizeObserver:Q}),i=RZ({nodeRef:T,disabled:N.hidden||!B,noDragClassName:W,handleSelector:N.dragHandle,nodeId:f,isSelectable:P,nodeClickDistance:z}),C=xZ();if(N.hidden)return null;let v=r1(N),X=LM(N),D=P||B||u||l||_||y,p=l?(rf)=>l(rf,{...E.userNode}):void 0,m=_?(rf)=>_(rf,{...E.userNode}):void 0,s=y?(rf)=>y(rf,{...E.userNode}):void 0,d=$?(rf)=>$(rf,{...E.userNode}):void 0,a=r?(rf)=>r(rf,{...E.userNode}):void 0,I=(rf)=>{let{selectNodesOnDrag:Wf,nodeDragThreshold:Ef}=n.getState();if(P&&(!Wf||!B||Ef>0))tF({id:f,store:n,nodeRef:T});if(u)u(rf,{...E.userNode})},ff=(rf)=>{if(SF(rf.nativeEvent)||K)return;if(EF.includes(rf.key)&&P){let Wf=rf.key==="Escape";tF({id:f,store:n,unselect:Wf,nodeRef:T})}else if(B&&N.selected&&Object.prototype.hasOwnProperty.call(h5,rf.key)){rf.preventDefault();let{ariaLabelConfig:Wf}=n.getState();n.setState({ariaLiveMessage:Wf["node.a11yDescription.ariaLiveMessage"]({direction:rf.key.replace("Arrow","").toLowerCase(),x:~~E.positionAbsolute.x,y:~~E.positionAbsolute.y})}),C({direction:h5[rf.key],factor:rf.shiftKey?4:1})}},yf=()=>{if(K||!T.current?.matches(":focus-visible"))return;let{transform:rf,width:Wf,height:Ef,autoPanOnNodeFocus:Gf,setCenter:c}=n.getState();if(!Gf)return;if(!(Y5(new Map([[f,N]]),{x:0,y:0,width:Wf,height:Ef},rf,!0).length>0))c(N.position.x+v.width/2,N.position.y+v.height/2,{zoom:rf[2]})};return lf.jsx("div",{className:M0(["react-flow__node",`react-flow__node-${Y}`,{[G]:B},N.className,{selected:N.selected,selectable:P,parent:q,draggable:B,dragging:i}]),ref:T,style:{zIndex:E.z,transform:`translate(${E.positionAbsolute.x}px,${E.positionAbsolute.y}px)`,pointerEvents:D?"all":"none",visibility:S?"visible":"hidden",...N.style,...X},"data-id":f,"data-testid":`rf__node-${f}`,onMouseEnter:p,onMouseMove:m,onMouseLeave:s,onContextMenu:d,onClick:I,onDoubleClick:a,onKeyDown:M?ff:void 0,tabIndex:M?0:void 0,onFocus:M?yf:void 0,role:N.ariaRole??(M?"group":void 0),"aria-roledescription":"node","aria-describedby":K?void 0:`${PZ}-${H}`,"aria-label":N.ariaLabel,...N.domAttributes,children:lf.jsx(KM,{value:f,children:lf.jsx(w,{id:f,data:N.data,type:Y,positionAbsoluteX:E.positionAbsolute.x,positionAbsoluteY:E.positionAbsolute.y,selected:N.selected??!1,selectable:P,draggable:B,deletable:N.deletable??!0,isConnectable:h,sourcePosition:N.sourcePosition,targetPosition:N.targetPosition,dragging:i,dragHandle:N.dragHandle,zIndex:E.z,parentId:N.parentId,...v})})})}var CM=_f.memo(SM),iM=(f)=>({nodesDraggable:f.nodesDraggable,nodesConnectable:f.nodesConnectable,nodesFocusable:f.nodesFocusable,elementsSelectable:f.elementsSelectable,onError:f.onError});function hZ(f){let{nodesDraggable:u,nodesConnectable:l,nodesFocusable:_,elementsSelectable:y,onError:$}=f0(iM,H0),r=TM(f.onlyRenderVisibleElements),j=PM();return lf.jsx("div",{className:"react-flow__nodes",style:m5,children:r.map((A)=>{return lf.jsx(CM,{id:A,nodeTypes:f.nodeTypes,nodeExtent:f.nodeExtent,onClick:f.onNodeClick,onMouseEnter:f.onNodeMouseEnter,onMouseMove:f.onNodeMouseMove,onMouseLeave:f.onNodeMouseLeave,onContextMenu:f.onNodeContextMenu,onDoubleClick:f.onNodeDoubleClick,noDragClassName:f.noDragClassName,noPanClassName:f.noPanClassName,rfId:f.rfId,disableKeyboardA11y:f.disableKeyboardA11y,resizeObserver:j,nodesDraggable:u,nodesConnectable:l,nodesFocusable:_,elementsSelectable:y,nodeClickDistance:f.nodeClickDistance,onError:$},A)})})}hZ.displayName="NodeRenderer";var cM=_f.memo(hZ);function RM(f){return f0(_f.useCallback((l)=>{if(!f)return l.edges.map((y)=>y.id);let _=[];if(l.width&&l.height)for(let y of l.edges){let $=l.nodeLookup.get(y.source),r=l.nodeLookup.get(y.target);if($&&r&&wN({sourceNode:$,targetNode:r,width:l.width,height:l.height,transform:l.transform}))_.push(y.id)}return _},[f]),H0)}var xM=({color:f="none",strokeWidth:u=1})=>{let l={strokeWidth:u,...f&&{stroke:f}};return lf.jsx("polyline",{className:"arrow",style:l,strokeLinecap:"round",fill:"none",strokeLinejoin:"round",points:"-5,-4 0,0 -5,4"})},bM=({color:f="none",strokeWidth:u=1})=>{let l={strokeWidth:u,...f&&{stroke:f,fill:f}};return lf.jsx("polyline",{className:"arrowclosed",style:l,strokeLinecap:"round",strokeLinejoin:"round",points:"-5,-4 0,0 -5,4 -5,-4"})},VZ={[L_.Arrow]:xM,[L_.ArrowClosed]:bM};function vM(f){let u=q0();return _f.useMemo(()=>{if(!Object.prototype.hasOwnProperty.call(VZ,f))return u.getState().onError?.("009",$l.error009(f)),null;return VZ[f]},[f])}var hM=({id:f,type:u,color:l,width:_=12.5,height:y=12.5,markerUnits:$="strokeWidth",strokeWidth:r,orient:j="auto-start-reverse"})=>{let A=vM(u);if(!A)return null;return lf.jsx("marker",{className:"react-flow__arrowhead",id:f,markerWidth:`${_}`,markerHeight:`${y}`,viewBox:"-10 -10 20 20",markerUnits:$,orient:j,refX:"0",refY:"0",children:lf.jsx(A,{color:l,strokeWidth:r})})},IZ=({defaultColor:f,rfId:u})=>{let l=f0(($)=>$.edges),_=f0(($)=>$.defaultEdgeOptions),y=_f.useMemo(()=>{return TN(l,{id:u,defaultColor:f,defaultMarkerStart:_?.markerStart,defaultMarkerEnd:_?.markerEnd})},[l,_,u,f]);if(!y.length)return null;return lf.jsx("svg",{className:"react-flow__marker","aria-hidden":"true",children:lf.jsx("defs",{children:y.map(($)=>lf.jsx(hM,{id:$.id,type:$.type,color:$.color,width:$.width,height:$.height,markerUnits:$.markerUnits,strokeWidth:$.strokeWidth,orient:$.orient},$.id))})})};IZ.displayName="MarkerDefinitions";var IM=_f.memo(IZ);function pZ({x:f,y:u,label:l,labelStyle:_,labelShowBg:y=!0,labelBgStyle:$,labelBgPadding:r=[2,4],labelBgBorderRadius:j=2,children:A,className:J,...U}){let[Q,W]=_f.useState({x:1,y:0,width:0,height:0}),G=M0(["react-flow__edge-textwrapper",J]),K=_f.useRef(null);if(_f.useEffect(()=>{if(K.current){let H=K.current.getBBox();W({x:H.x,y:H.y,width:H.width,height:H.height})}},[l]),!l)return null;return lf.jsxs("g",{transform:`translate(${f-Q.width/2} ${u-Q.height/2})`,className:G,visibility:Q.width?"visible":"hidden",...U,children:[y&&lf.jsx("rect",{width:Q.width+2*r[0],x:-r[0],y:-r[1],height:Q.height+2*r[1],className:"react-flow__edge-textbg",style:$,rx:j,ry:j}),lf.jsx("text",{className:"react-flow__edge-text",y:Q.height/2,dy:"0.3em",ref:K,style:_,children:l}),A]})}pZ.displayName="EdgeText";var pM=_f.memo(pZ);function a$({path:f,labelX:u,labelY:l,label:_,labelStyle:y,labelShowBg:$,labelBgStyle:r,labelBgPadding:j,labelBgBorderRadius:A,interactionWidth:J=20,...U}){return lf.jsxs(lf.Fragment,{children:[lf.jsx("path",{...U,d:f,fill:"none",className:M0(["react-flow__edge-path",U.className])}),J?lf.jsx("path",{d:f,fill:"none",strokeOpacity:0,strokeWidth:J,className:"react-flow__edge-interaction"}):null,_&&Hl(u)&&Hl(l)?lf.jsx(pM,{x:u,y:l,label:_,labelStyle:y,labelShowBg:$,labelBgStyle:r,labelBgPadding:j,labelBgBorderRadius:A}):null]})}function qZ({pos:f,x1:u,y1:l,x2:_,y2:y}){if(f===Zf.Left||f===Zf.Right)return[0.5*(u+_),l];return[u,0.5*(l+y)]}function mZ({sourceX:f,sourceY:u,sourcePosition:l=Zf.Bottom,targetX:_,targetY:y,targetPosition:$=Zf.Top}){let[r,j]=qZ({pos:l,x1:f,y1:u,x2:_,y2:y}),[A,J]=qZ({pos:$,x1:_,y1:y,x2:f,y2:u}),[U,Q,W,G]=M5({sourceX:f,sourceY:u,targetX:_,targetY:y,sourceControlX:r,sourceControlY:j,targetControlX:A,targetControlY:J});return[`M${f},${u} C${r},${j} ${A},${J} ${_},${y}`,U,Q,W,G]}function gZ(f){return _f.memo(({id:u,sourceX:l,sourceY:_,targetX:y,targetY:$,sourcePosition:r,targetPosition:j,label:A,labelStyle:J,labelShowBg:U,labelBgStyle:Q,labelBgPadding:W,labelBgBorderRadius:G,style:K,markerEnd:H,markerStart:O,interactionWidth:z})=>{let[Z,N,E]=mZ({sourceX:l,sourceY:_,sourcePosition:r,targetX:y,targetY:$,targetPosition:j}),q=f.isInternal?void 0:u;return lf.jsx(a$,{id:q,path:Z,labelX:N,labelY:E,label:A,labelStyle:J,labelShowBg:U,labelBgStyle:Q,labelBgPadding:W,labelBgBorderRadius:G,style:K,markerEnd:H,markerStart:O,interactionWidth:z})})}var mM=gZ({isInternal:!1}),kZ=gZ({isInternal:!0});mM.displayName="SimpleBezierEdge";kZ.displayName="SimpleBezierEdgeInternal";function tZ(f){return _f.memo(({id:u,sourceX:l,sourceY:_,targetX:y,targetY:$,label:r,labelStyle:j,labelShowBg:A,labelBgStyle:J,labelBgPadding:U,labelBgBorderRadius:Q,style:W,sourcePosition:G=Zf.Bottom,targetPosition:K=Zf.Top,markerEnd:H,markerStart:O,pathOptions:z,interactionWidth:Z})=>{let[N,E,q]=J4({sourceX:l,sourceY:_,sourcePosition:G,targetX:y,targetY:$,targetPosition:K,borderRadius:z?.borderRadius,offset:z?.offset,stepPosition:z?.stepPosition}),Y=f.isInternal?void 0:u;return lf.jsx(a$,{id:Y,path:N,labelX:E,labelY:q,label:r,labelStyle:j,labelShowBg:A,labelBgStyle:J,labelBgPadding:U,labelBgBorderRadius:Q,style:W,markerEnd:H,markerStart:O,interactionWidth:Z})})}var sZ=tZ({isInternal:!1}),oZ=tZ({isInternal:!0});sZ.displayName="SmoothStepEdge";oZ.displayName="SmoothStepEdgeInternal";function aZ(f){return _f.memo(({id:u,...l})=>{let _=f.isInternal?void 0:u;return lf.jsx(sZ,{...l,id:_,pathOptions:_f.useMemo(()=>({borderRadius:0,offset:l.pathOptions?.offset}),[l.pathOptions?.offset])})})}var gM=aZ({isInternal:!1}),dZ=aZ({isInternal:!0});gM.displayName="StepEdge";dZ.displayName="StepEdgeInternal";function eZ(f){return _f.memo(({id:u,sourceX:l,sourceY:_,targetX:y,targetY:$,label:r,labelStyle:j,labelShowBg:A,labelBgStyle:J,labelBgPadding:U,labelBgBorderRadius:Q,style:W,markerEnd:G,markerStart:K,interactionWidth:H})=>{let[O,z,Z]=n5({sourceX:l,sourceY:_,targetX:y,targetY:$}),N=f.isInternal?void 0:u;return lf.jsx(a$,{id:N,path:O,labelX:z,labelY:Z,label:r,labelStyle:j,labelShowBg:A,labelBgStyle:J,labelBgPadding:U,labelBgBorderRadius:Q,style:W,markerEnd:G,markerStart:K,interactionWidth:H})})}var kM=eZ({isInternal:!1}),fE=eZ({isInternal:!0});kM.displayName="StraightEdge";fE.displayName="StraightEdgeInternal";function uE(f){return _f.memo(({id:u,sourceX:l,sourceY:_,targetX:y,targetY:$,sourcePosition:r=Zf.Bottom,targetPosition:j=Zf.Top,label:A,labelStyle:J,labelShowBg:U,labelBgStyle:Q,labelBgPadding:W,labelBgBorderRadius:G,style:K,markerEnd:H,markerStart:O,pathOptions:z,interactionWidth:Z})=>{let[N,E,q]=P5({sourceX:l,sourceY:_,sourcePosition:r,targetX:y,targetY:$,targetPosition:j,curvature:z?.curvature}),Y=f.isInternal?void 0:u;return lf.jsx(a$,{id:Y,path:N,labelX:E,labelY:q,label:A,labelStyle:J,labelShowBg:U,labelBgStyle:Q,labelBgPadding:W,labelBgBorderRadius:G,style:K,markerEnd:H,markerStart:O,interactionWidth:Z})})}var tM=uE({isInternal:!1}),lE=uE({isInternal:!0});tM.displayName="BezierEdge";lE.displayName="BezierEdgeInternal";var LZ={default:lE,straight:fE,step:dZ,smoothstep:oZ,simplebezier:kZ},XZ={sourceX:null,sourceY:null,targetX:null,targetY:null,sourcePosition:null,targetPosition:null},sM=(f,u,l)=>{if(l===Zf.Left)return f-u;if(l===Zf.Right)return f+u;return f},oM=(f,u,l)=>{if(l===Zf.Top)return f-u;if(l===Zf.Bottom)return f+u;return f},BZ="react-flow__edgeupdater";function YZ({position:f,centerX:u,centerY:l,radius:_=10,onMouseDown:y,onMouseEnter:$,onMouseOut:r,type:j}){return lf.jsx("circle",{onMouseDown:y,onMouseEnter:$,onMouseOut:r,className:M0([BZ,`${BZ}-${j}`]),cx:sM(u,_,f),cy:oM(l,_,f),r:_,stroke:"transparent",fill:"transparent"})}function aM({isReconnectable:f,reconnectRadius:u,edge:l,sourceX:_,sourceY:y,targetX:$,targetY:r,sourcePosition:j,targetPosition:A,onReconnect:J,onReconnectStart:U,onReconnectEnd:Q,setReconnecting:W,setUpdateHover:G}){let K=q0(),H=(E,q)=>{if(E.button!==0)return;let{autoPanOnConnect:Y,domNode:w,connectionMode:B,connectionRadius:P,lib:h,onConnectStart:M,cancelConnection:n,nodeLookup:S,rfId:T,panBy:i,updateConnection:C}=K.getState(),v=q.type==="target",X=(m,s)=>{W(!1),Q?.(m,l,q.type,s)},D=(m)=>J?.(l,m),p=(m,s)=>{W(!0),U?.(E,l,q.type),M?.(m,s)};c5.onPointerDown(E.nativeEvent,{autoPanOnConnect:Y,connectionMode:B,connectionRadius:P,domNode:w,handleId:q.id,nodeId:q.nodeId,nodeLookup:S,isTarget:v,edgeUpdaterType:q.type,lib:h,flowId:T,cancelConnection:n,panBy:i,isValidConnection:(...m)=>K.getState().isValidConnection?.(...m)??!0,onConnect:D,onConnectStart:p,onConnectEnd:(...m)=>K.getState().onConnectEnd?.(...m),onReconnectEnd:X,updateConnection:C,getTransform:()=>K.getState().transform,getFromHandle:()=>K.getState().connection.fromHandle,dragThreshold:K.getState().connectionDragThreshold,handleDomNode:E.currentTarget})},O=(E)=>H(E,{nodeId:l.target,id:l.targetHandle??null,type:"target"}),z=(E)=>H(E,{nodeId:l.source,id:l.sourceHandle??null,type:"source"}),Z=()=>G(!0),N=()=>G(!1);return lf.jsxs(lf.Fragment,{children:[(f===!0||f==="source")&&lf.jsx(YZ,{position:j,centerX:_,centerY:y,radius:u,onMouseDown:O,onMouseEnter:Z,onMouseOut:N,type:"source"}),(f===!0||f==="target")&&lf.jsx(YZ,{position:A,centerX:$,centerY:r,radius:u,onMouseDown:z,onMouseEnter:Z,onMouseOut:N,type:"target"})]})}function dM({id:f,edgesFocusable:u,edgesReconnectable:l,elementsSelectable:_,onClick:y,onDoubleClick:$,onContextMenu:r,onMouseEnter:j,onMouseMove:A,onMouseLeave:J,reconnectRadius:U,onReconnect:Q,onReconnectStart:W,onReconnectEnd:G,rfId:K,edgeTypes:H,noPanClassName:O,onError:z,disableKeyboardA11y:Z}){let N=f0((c)=>c.edgeLookup.get(f)),E=f0((c)=>c.defaultEdgeOptions);N=E?{...E,...N}:N;let q=N.type||"default",Y=H?.[q]||LZ[q];if(Y===void 0)z?.("011",$l.error011(q)),q="default",Y=H?.default||LZ.default;let w=!!(N.focusable||u&&typeof N.focusable>"u"),B=typeof Q<"u"&&(N.reconnectable||l&&typeof N.reconnectable>"u"),P=!!(N.selectable||_&&typeof N.selectable>"u"),h=_f.useRef(null),[M,n]=_f.useState(!1),[S,T]=_f.useState(!1),i=q0(),{zIndex:C,sourceX:v,sourceY:X,targetX:D,targetY:p,sourcePosition:m,targetPosition:s}=f0(_f.useCallback((c)=>{let o=c.nodeLookup.get(N.source),e=c.nodeLookup.get(N.target);if(!o||!e)return{zIndex:N.zIndex,...XZ};let Kf=DN({id:f,sourceNode:o,targetNode:e,sourceHandle:N.sourceHandle||null,targetHandle:N.targetHandle||null,connectionMode:c.connectionMode,onError:z});return{zIndex:YN({selected:N.selected,zIndex:N.zIndex,sourceNode:o,targetNode:e,elevateOnSelect:c.elevateEdgesOnSelect,zIndexMode:c.zIndexMode}),...Kf||XZ}},[N.source,N.target,N.sourceHandle,N.targetHandle,N.selected,N.zIndex]),H0),d=_f.useMemo(()=>N.markerStart?`url('#${S5(N.markerStart,K)}')`:void 0,[N.markerStart,K]),a=_f.useMemo(()=>N.markerEnd?`url('#${S5(N.markerEnd,K)}')`:void 0,[N.markerEnd,K]);if(N.hidden||v===null||X===null||D===null||p===null)return null;let I=(c)=>{let{addSelectedEdges:o,unselectNodesAndEdges:e,multiSelectionActive:Kf}=i.getState();if(P)if(i.setState({nodesSelectionActive:!1}),N.selected&&Kf)e({nodes:[],edges:[N]}),h.current?.blur();else o([f]);if(y)y(c,N)},ff=$?(c)=>{$(c,{...N})}:void 0,yf=r?(c)=>{r(c,{...N})}:void 0,rf=j?(c)=>{j(c,{...N})}:void 0,Wf=A?(c)=>{A(c,{...N})}:void 0,Ef=J?(c)=>{J(c,{...N})}:void 0,Gf=(c)=>{if(!Z&&EF.includes(c.key)&&P){let{unselectNodesAndEdges:o,addSelectedEdges:e}=i.getState();if(c.key==="Escape")h.current?.blur(),o({edges:[N]});else e([f])}};return lf.jsx("svg",{style:{zIndex:C},children:lf.jsxs("g",{className:M0(["react-flow__edge",`react-flow__edge-${q}`,N.className,O,{selected:N.selected,animated:N.animated,inactive:!P&&!y,updating:M,selectable:P}]),onClick:I,onDoubleClick:ff,onContextMenu:yf,onMouseEnter:rf,onMouseMove:Wf,onMouseLeave:Ef,onKeyDown:w?Gf:void 0,tabIndex:w?0:void 0,role:N.ariaRole??(w?"group":"img"),"aria-roledescription":"edge","data-id":f,"data-testid":`rf__edge-${f}`,"aria-label":N.ariaLabel===null?void 0:N.ariaLabel||`Edge from ${N.source} to ${N.target}`,"aria-describedby":w?`${nZ}-${K}`:void 0,ref:h,...N.domAttributes,children:[!S&&lf.jsx(Y,{id:f,source:N.source,target:N.target,type:N.type,selected:N.selected,animated:N.animated,selectable:P,deletable:N.deletable??!0,label:N.label,labelStyle:N.labelStyle,labelShowBg:N.labelShowBg,labelBgStyle:N.labelBgStyle,labelBgPadding:N.labelBgPadding,labelBgBorderRadius:N.labelBgBorderRadius,sourceX:v,sourceY:X,targetX:D,targetY:p,sourcePosition:m,targetPosition:s,data:N.data,style:N.style,sourceHandleId:N.sourceHandle,targetHandleId:N.targetHandle,markerStart:d,markerEnd:a,pathOptions:"pathOptions"in N?N.pathOptions:void 0,interactionWidth:N.interactionWidth}),B&&lf.jsx(aM,{edge:N,isReconnectable:B,reconnectRadius:U,onReconnect:Q,onReconnectStart:W,onReconnectEnd:G,sourceX:v,sourceY:X,targetX:D,targetY:p,sourcePosition:m,targetPosition:s,setUpdateHover:n,setReconnecting:T})]})})}var eM=_f.memo(dM),fP=(f)=>({edgesFocusable:f.edgesFocusable,edgesReconnectable:f.edgesReconnectable,elementsSelectable:f.elementsSelectable,connectionMode:f.connectionMode,onError:f.onError});function _E({defaultMarkerColor:f,onlyRenderVisibleElements:u,rfId:l,edgeTypes:_,noPanClassName:y,onReconnect:$,onEdgeContextMenu:r,onEdgeMouseEnter:j,onEdgeMouseMove:A,onEdgeMouseLeave:J,onEdgeClick:U,reconnectRadius:Q,onEdgeDoubleClick:W,onReconnectStart:G,onReconnectEnd:K,disableKeyboardA11y:H}){let{edgesFocusable:O,edgesReconnectable:z,elementsSelectable:Z,onError:N}=f0(fP,H0),E=RM(u);return lf.jsxs("div",{className:"react-flow__edges",children:[lf.jsx(IM,{defaultColor:f,rfId:l}),E.map((q)=>{return lf.jsx(eM,{id:q,edgesFocusable:O,edgesReconnectable:z,elementsSelectable:Z,noPanClassName:y,onReconnect:$,onContextMenu:r,onMouseEnter:j,onMouseMove:A,onMouseLeave:J,onClick:U,reconnectRadius:Q,onDoubleClick:W,onReconnectStart:G,onReconnectEnd:K,rfId:l,onError:N,edgeTypes:_,disableKeyboardA11y:H},q)})]})}_E.displayName="EdgeRenderer";var uP=_f.memo(_E),lP=(f)=>`translate(${f.transform[0]}px,${f.transform[1]}px) scale(${f.transform[2]})`;function _P({children:f}){let u=f0(lP);return lf.jsx("div",{className:"react-flow__viewport xyflow__viewport react-flow__container",style:{transform:u},children:f})}function yP(f){let u=sF(),l=_f.useRef(!1);_f.useEffect(()=>{if(!l.current&&u.viewportInitialized&&f)setTimeout(()=>f(u),1),l.current=!0},[f,u.viewportInitialized])}var $P=(f)=>f.panZoom?.syncViewport;function rP(f){let u=f0($P),l=q0();return _f.useEffect(()=>{if(f)u?.(f),l.setState({transform:[f.x,f.y,f.zoom]})},[f,u]),null}function wZ(f){return f.connection.inProgress?{...f.connection,to:k$(f.connection.to,f.transform)}:{...f.connection}}function jP(f){if(f)return(l)=>{let _=wZ(l);return f(_)};return wZ}function AP(f){let u=jP(f);return f0(u,H0)}var FP=(f)=>({nodesConnectable:f.nodesConnectable,isValid:f.connection.isValid,inProgress:f.connection.inProgress,width:f.width,height:f.height});function JP({containerStyle:f,style:u,type:l,component:_}){let{nodesConnectable:y,width:$,height:r,isValid:j,inProgress:A}=f0(FP,H0);if(!($&&y&&A))return null;return lf.jsx("svg",{style:f,width:$,height:r,className:"react-flow__connectionline react-flow__container",children:lf.jsx("g",{className:M0(["react-flow__connection",VF(j)]),children:lf.jsx(yE,{style:u,type:l,CustomComponent:_,isValid:j})})})}var yE=({style:f,type:u=$1.Bezier,CustomComponent:l,isValid:_})=>{let{inProgress:y,from:$,fromNode:r,fromHandle:j,fromPosition:A,to:J,toNode:U,toHandle:Q,toPosition:W,pointer:G}=AP();if(!y)return;if(l)return lf.jsx(l,{connectionLineType:u,connectionLineStyle:f,fromNode:r,fromHandle:j,fromX:$.x,fromY:$.y,toX:J.x,toY:J.y,fromPosition:A,toPosition:W,connectionStatus:VF(_),toNode:U,toHandle:Q,pointer:G});let K="",H={sourceX:$.x,sourceY:$.y,sourcePosition:A,targetX:J.x,targetY:J.y,targetPosition:W};switch(u){case $1.Bezier:[K]=P5(H);break;case $1.SimpleBezier:[K]=mZ(H);break;case $1.Step:[K]=J4({...H,borderRadius:0});break;case $1.SmoothStep:[K]=J4(H);break;default:[K]=n5(H)}return lf.jsx("path",{d:K,fill:"none",className:"react-flow__connection-path",style:f})};yE.displayName="ConnectionLine";var UP={};function DZ(f=UP){let u=_f.useRef(f),l=q0();_f.useEffect(()=>{},[f])}function QP(){let f=q0(),u=_f.useRef(!1);_f.useEffect(()=>{},[])}function $E({nodeTypes:f,edgeTypes:u,onInit:l,onNodeClick:_,onEdgeClick:y,onNodeDoubleClick:$,onEdgeDoubleClick:r,onNodeMouseEnter:j,onNodeMouseMove:A,onNodeMouseLeave:J,onNodeContextMenu:U,onSelectionContextMenu:Q,onSelectionStart:W,onSelectionEnd:G,connectionLineType:K,connectionLineStyle:H,connectionLineComponent:O,connectionLineContainerStyle:z,selectionKeyCode:Z,selectionOnDrag:N,selectionMode:E,multiSelectionKeyCode:q,panActivationKeyCode:Y,zoomActivationKeyCode:w,deleteKeyCode:B,onlyRenderVisibleElements:P,elementsSelectable:h,defaultViewport:M,translateExtent:n,minZoom:S,maxZoom:T,preventScrolling:i,defaultMarkerColor:C,zoomOnScroll:v,zoomOnPinch:X,panOnScroll:D,panOnScrollSpeed:p,panOnScrollMode:m,zoomOnDoubleClick:s,panOnDrag:d,onPaneClick:a,onPaneMouseEnter:I,onPaneMouseMove:ff,onPaneMouseLeave:yf,onPaneScroll:rf,onPaneContextMenu:Wf,paneClickDistance:Ef,nodeClickDistance:Gf,onEdgeContextMenu:c,onEdgeMouseEnter:o,onEdgeMouseMove:e,onEdgeMouseLeave:Kf,reconnectRadius:k,onReconnect:Af,onReconnectStart:Yf,onReconnectEnd:Bf,noDragClassName:df,noWheelClassName:_0,noPanClassName:y0,disableKeyboardA11y:N0,nodeExtent:a0,rfId:pu,viewport:mu,onViewportChange:C0}){return DZ(f),DZ(u),QP(),yP(l),rP(mu),lf.jsx(wM,{onPaneClick:a,onPaneMouseEnter:I,onPaneMouseMove:ff,onPaneMouseLeave:yf,onPaneContextMenu:Wf,onPaneScroll:rf,paneClickDistance:Ef,deleteKeyCode:B,selectionKeyCode:Z,selectionOnDrag:N,selectionMode:E,onSelectionStart:W,onSelectionEnd:G,multiSelectionKeyCode:q,panActivationKeyCode:Y,zoomActivationKeyCode:w,elementsSelectable:h,zoomOnScroll:v,zoomOnPinch:X,zoomOnDoubleClick:s,panOnScroll:D,panOnScrollSpeed:p,panOnScrollMode:m,panOnDrag:d,defaultViewport:M,translateExtent:n,minZoom:S,maxZoom:T,onSelectionContextMenu:Q,preventScrolling:i,noDragClassName:df,noWheelClassName:_0,noPanClassName:y0,disableKeyboardA11y:N0,onViewportChange:C0,isControlledViewport:!!mu,children:lf.jsxs(_P,{children:[lf.jsx(uP,{edgeTypes:u,onEdgeClick:y,onEdgeDoubleClick:r,onReconnect:Af,onReconnectStart:Yf,onReconnectEnd:Bf,onlyRenderVisibleElements:P,onEdgeContextMenu:c,onEdgeMouseEnter:o,onEdgeMouseMove:e,onEdgeMouseLeave:Kf,reconnectRadius:k,defaultMarkerColor:C,noPanClassName:y0,disableKeyboardA11y:N0,rfId:pu}),lf.jsx(JP,{style:H,type:K,component:O,containerStyle:z}),lf.jsx("div",{className:"react-flow__edgelabel-renderer"}),lf.jsx(cM,{nodeTypes:f,onNodeClick:_,onNodeDoubleClick:$,onNodeMouseEnter:j,onNodeMouseMove:A,onNodeMouseLeave:J,onNodeContextMenu:U,nodeClickDistance:Gf,onlyRenderVisibleElements:P,noPanClassName:y0,noDragClassName:df,disableKeyboardA11y:N0,nodeExtent:a0,rfId:pu}),lf.jsx("div",{className:"react-flow__viewport-portal"})]})})}$E.displayName="GraphView";var WP=_f.memo($E),TZ=({nodes:f,edges:u,defaultNodes:l,defaultEdges:_,width:y,height:$,fitView:r,fitViewOptions:j,minZoom:A=0.5,maxZoom:J=2,nodeOrigin:U,nodeExtent:Q,zIndexMode:W="basic"}={})=>{let G=new Map,K=new Map,H=new Map,O=new Map,z=_??u??[],Z=l??f??[],N=U??[0,0],E=Q??I$;hF(H,O,z);let{nodesInitialized:q}=C5(Z,G,K,{nodeOrigin:N,nodeExtent:E,zIndexMode:W}),Y=[0,0,1];if(r&&y&&$){let w=p$(G,{filter:(M)=>!!((M.width||M.initialWidth)&&(M.height||M.initialHeight))}),{x:B,y:P,zoom:h}=F4(w,y,$,A,J,j?.padding??0.1);Y=[B,P,h]}return{rfId:"1",width:y??0,height:$??0,transform:Y,nodes:Z,nodesInitialized:q,nodeLookup:G,parentLookup:K,edges:z,edgeLookup:O,connectionLookup:H,onNodesChange:null,onEdgesChange:null,hasDefaultNodes:l!==void 0,hasDefaultEdges:_!==void 0,panZoom:null,minZoom:A,maxZoom:J,translateExtent:I$,nodeExtent:E,nodesSelectionActive:!1,userSelectionActive:!1,userSelectionRect:null,connectionMode:q_.Strict,domNode:null,paneDragging:!1,noPanClassName:"nopan",nodeOrigin:N,nodeDragThreshold:1,connectionDragThreshold:1,snapGrid:[15,15],snapToGrid:!1,nodesDraggable:!0,nodesConnectable:!0,nodesFocusable:!0,edgesFocusable:!0,edgesReconnectable:!0,elementsSelectable:!0,elevateNodesOnSelect:!0,elevateEdgesOnSelect:!0,selectNodesOnDrag:!0,multiSelectionActive:!1,fitViewQueued:r??!1,fitViewOptions:j,fitViewResolver:null,connection:{...OF},connectionClickStartHandle:null,connectOnClick:!0,ariaLiveMessage:"",autoPanOnConnect:!0,autoPanOnNodeDrag:!0,autoPanOnNodeFocus:!0,autoPanSpeed:15,connectionRadius:20,onError:DF,isValidConnection:void 0,onSelectionChangeHandlers:[],lib:"react",debug:!1,ariaLabelConfig:HF,zIndexMode:W,onNodesChangeMiddlewareMap:new Map,onEdgesChangeMiddlewareMap:new Map}},zP=({nodes:f,edges:u,defaultNodes:l,defaultEdges:_,width:y,height:$,fitView:r,fitViewOptions:j,minZoom:A,maxZoom:J,nodeOrigin:U,nodeExtent:Q,zIndexMode:W})=>jZ((G,K)=>{async function H(){let{nodeLookup:O,panZoom:z,fitViewOptions:Z,fitViewResolver:N,width:E,height:q,minZoom:Y,maxZoom:w}=K();if(!z)return;await ON({nodes:O,width:E,height:q,panZoom:z,minZoom:Y,maxZoom:w},Z),N?.resolve(!0),G({fitViewResolver:null})}return{...TZ({nodes:f,edges:u,width:y,height:$,fitView:r,fitViewOptions:j,minZoom:A,maxZoom:J,nodeOrigin:U,nodeExtent:Q,defaultNodes:l,defaultEdges:_,zIndexMode:W}),setNodes:(O)=>{let{nodeLookup:z,parentLookup:Z,nodeOrigin:N,elevateNodesOnSelect:E,fitViewQueued:q,zIndexMode:Y,nodesSelectionActive:w}=K(),{nodesInitialized:B,hasSelectedNodes:P}=C5(O,z,Z,{nodeOrigin:N,nodeExtent:Q,elevateNodesOnSelect:E,checkEquality:!0,zIndexMode:Y}),h=w&&P;if(q&&B)H(),G({nodes:O,nodesInitialized:B,fitViewQueued:!1,fitViewOptions:void 0,nodesSelectionActive:h});else G({nodes:O,nodesInitialized:B,nodesSelectionActive:h})},setEdges:(O)=>{let{connectionLookup:z,edgeLookup:Z}=K();hF(z,Z,O),G({edges:O})},setDefaultNodesAndEdges:(O,z)=>{if(O){let{setNodes:Z}=K();Z(O),G({hasDefaultNodes:!0})}if(z){let{setEdges:Z}=K();Z(z),G({hasDefaultEdges:!0})}},updateNodeInternals:(O)=>{let{triggerNodeChanges:z,nodeLookup:Z,parentLookup:N,domNode:E,nodeOrigin:q,nodeExtent:Y,debug:w,fitViewQueued:B,zIndexMode:P}=K(),{changes:h,updatedInternals:M}=SN(O,Z,N,E,q,Y,P);if(!M)return;if(PN(Z,N,{nodeOrigin:q,nodeExtent:Y,zIndexMode:P}),B)H(),G({fitViewQueued:!1,fitViewOptions:void 0});else G({});if(h?.length>0){if(w)console.log("React Flow: trigger node changes",h);z?.(h)}},updateNodePositions:(O,z=!1)=>{let Z=[],N=[],{nodeLookup:E,triggerNodeChanges:q,connection:Y,updateConnection:w,onNodesChangeMiddlewareMap:B}=K();for(let[P,h]of O){let M=E.get(P),n=!!(M?.expandParent&&M?.parentId&&h?.position),S={id:P,type:"position",position:n?{x:Math.max(0,h.position.x),y:Math.max(0,h.position.y)}:h.position,dragging:z};if(M&&Y.inProgress&&Y.fromNode.id===M.id){let T=X_(M,Y.fromHandle,Zf.Left,!0);w({...Y,from:T})}if(n&&M.parentId)Z.push({id:P,parentId:M.parentId,rect:{...h.internals.positionAbsolute,width:h.measured.width??0,height:h.measured.height??0}});N.push(S)}if(Z.length>0){let{parentLookup:P,nodeOrigin:h}=K(),M=i5(Z,E,P,h);N.push(...M)}for(let P of B.values())N=P(N);q(N)},triggerNodeChanges:(O)=>{let{onNodesChange:z,setNodes:Z,nodes:N,hasDefaultNodes:E,debug:q}=K();if(O?.length){if(E){let Y=eT(O,N);Z(Y)}if(q)console.log("React Flow: trigger node changes",O);z?.(O)}},triggerEdgeChanges:(O)=>{let{onEdgesChange:z,setEdges:Z,edges:N,hasDefaultEdges:E,debug:q}=K();if(O?.length){if(E){let Y=fM(O,N);Z(Y)}if(q)console.log("React Flow: trigger edge changes",O);z?.(O)}},addSelectedNodes:(O)=>{let{multiSelectionActive:z,edgeLookup:Z,nodeLookup:N,triggerNodeChanges:E,triggerEdgeChanges:q}=K();if(z){let Y=O.map((w)=>wy(w,!0));E(Y);return}E(o$(N,new Set([...O]),!0)),q(o$(Z))},addSelectedEdges:(O)=>{let{multiSelectionActive:z,edgeLookup:Z,nodeLookup:N,triggerNodeChanges:E,triggerEdgeChanges:q}=K();if(z){let Y=O.map((w)=>wy(w,!0));q(Y);return}q(o$(Z,new Set([...O]))),E(o$(N,new Set,!0))},unselectNodesAndEdges:({nodes:O,edges:z}={})=>{let{edges:Z,nodes:N,nodeLookup:E,triggerNodeChanges:q,triggerEdgeChanges:Y}=K(),w=O?O:N,B=z?z:Z,P=[];for(let M of w){if(!M.selected)continue;let n=E.get(M.id);if(n)n.selected=!1;P.push(wy(M.id,!1))}let h=[];for(let M of B){if(!M.selected)continue;h.push(wy(M.id,!1))}q(P),Y(h)},setMinZoom:(O)=>{let{panZoom:z,maxZoom:Z}=K();z?.setScaleExtent([O,Z]),G({minZoom:O})},setMaxZoom:(O)=>{let{panZoom:z,minZoom:Z}=K();z?.setScaleExtent([Z,O]),G({maxZoom:O})},setTranslateExtent:(O)=>{K().panZoom?.setTranslateExtent(O),G({translateExtent:O})},resetSelectedElements:()=>{let{edges:O,nodes:z,triggerNodeChanges:Z,triggerEdgeChanges:N,elementsSelectable:E}=K();if(!E)return;let q=z.reduce((w,B)=>B.selected?[...w,wy(B.id,!1)]:w,[]),Y=O.reduce((w,B)=>B.selected?[...w,wy(B.id,!1)]:w,[]);Z(q),N(Y)},setNodeExtent:(O)=>{let{nodes:z,nodeLookup:Z,parentLookup:N,nodeOrigin:E,elevateNodesOnSelect:q,nodeExtent:Y,zIndexMode:w}=K();if(O[0][0]===Y[0][0]&&O[0][1]===Y[0][1]&&O[1][0]===Y[1][0]&&O[1][1]===Y[1][1])return;C5(z,Z,N,{nodeOrigin:E,nodeExtent:O,elevateNodesOnSelect:q,checkEquality:!1,zIndexMode:w}),G({nodeExtent:O})},panBy:(O)=>{let{transform:z,width:Z,height:N,panZoom:E,translateExtent:q}=K();return CN({delta:O,panZoom:E,transform:z,translateExtent:q,width:Z,height:N})},setCenter:async(O,z,Z)=>{let{width:N,height:E,maxZoom:q,panZoom:Y}=K();if(!Y)return Promise.resolve(!1);let w=typeof Z?.zoom<"u"?Z.zoom:q;return await Y.setViewport({x:N/2-O*w,y:E/2-z*w,zoom:w},{duration:Z?.duration,ease:Z?.ease,interpolate:Z?.interpolate}),Promise.resolve(!0)},cancelConnection:()=>{G({connection:{...OF}})},updateConnection:(O)=>{G({connection:O})},reset:()=>G({...TZ()})}},Object.is);function GP({initialNodes:f,initialEdges:u,defaultNodes:l,defaultEdges:_,initialWidth:y,initialHeight:$,initialMinZoom:r,initialMaxZoom:j,initialFitViewOptions:A,fitView:J,nodeOrigin:U,nodeExtent:Q,zIndexMode:W,children:G}){let[K]=_f.useState(()=>zP({nodes:f,edges:u,defaultNodes:l,defaultEdges:_,width:y,height:$,fitView:J,minZoom:r,maxZoom:j,fitViewOptions:A,nodeOrigin:U,nodeExtent:Q,zIndexMode:W}));return lf.jsx(nT,{value:K,children:lf.jsx(_M,{children:G})})}function KP({children:f,nodes:u,edges:l,defaultNodes:_,defaultEdges:y,width:$,height:r,fitView:j,fitViewOptions:A,minZoom:J,maxZoom:U,nodeOrigin:Q,nodeExtent:W,zIndexMode:G}){if(_f.useContext(I5))return lf.jsx(lf.Fragment,{children:f});return lf.jsx(GP,{initialNodes:u,initialEdges:l,defaultNodes:_,defaultEdges:y,initialWidth:$,initialHeight:r,fitView:j,initialFitViewOptions:A,initialMinZoom:J,initialMaxZoom:U,nodeOrigin:Q,nodeExtent:W,zIndexMode:G,children:f})}var NP={width:"100%",height:"100%",overflow:"hidden",position:"relative",zIndex:0};function ZP({nodes:f,edges:u,defaultNodes:l,defaultEdges:_,className:y,nodeTypes:$,edgeTypes:r,onNodeClick:j,onEdgeClick:A,onInit:J,onMove:U,onMoveStart:Q,onMoveEnd:W,onConnect:G,onConnectStart:K,onConnectEnd:H,onClickConnectStart:O,onClickConnectEnd:z,onNodeMouseEnter:Z,onNodeMouseMove:N,onNodeMouseLeave:E,onNodeContextMenu:q,onNodeDoubleClick:Y,onNodeDragStart:w,onNodeDrag:B,onNodeDragStop:P,onNodesDelete:h,onEdgesDelete:M,onDelete:n,onSelectionChange:S,onSelectionDragStart:T,onSelectionDrag:i,onSelectionDragStop:C,onSelectionContextMenu:v,onSelectionStart:X,onSelectionEnd:D,onBeforeDelete:p,connectionMode:m,connectionLineType:s=$1.Bezier,connectionLineStyle:d,connectionLineComponent:a,connectionLineContainerStyle:I,deleteKeyCode:ff="Backspace",selectionKeyCode:yf="Shift",selectionOnDrag:rf=!1,selectionMode:Wf=Xy.Full,panActivationKeyCode:Ef="Space",multiSelectionKeyCode:Gf=t$()?"Meta":"Control",zoomActivationKeyCode:c=t$()?"Meta":"Control",snapToGrid:o,snapGrid:e,onlyRenderVisibleElements:Kf=!1,selectNodesOnDrag:k,nodesDraggable:Af,autoPanOnNodeFocus:Yf,nodesConnectable:Bf,nodesFocusable:df,nodeOrigin:_0=SZ,edgesFocusable:y0,edgesReconnectable:N0,elementsSelectable:a0=!0,defaultViewport:pu=gT,minZoom:mu=0.5,maxZoom:C0=2,translateExtent:Q1=I$,preventScrolling:ru=!0,nodeExtent:Uf,defaultMarkerColor:nf="#b1b1b7",zoomOnScroll:Nu=!0,zoomOnPinch:Cf=!0,panOnScroll:d0=!1,panOnScrollSpeed:e0=0.5,panOnScrollMode:Zu=c1.Free,zoomOnDoubleClick:i0=!0,panOnDrag:Du=!0,onPaneClick:W1,onPaneMouseEnter:pl,onPaneMouseMove:R_,onPaneMouseLeave:x_,onPaneScroll:v0,onPaneContextMenu:uf,paneClickDistance:wf=1,nodeClickDistance:Hf=0,children:gf,onReconnect:pf,onReconnectStart:Q0,onReconnectEnd:u0,onEdgeContextMenu:fu,onEdgeDoubleClick:Bl,onEdgeMouseEnter:w4,onEdgeMouseMove:$3,onEdgeMouseLeave:D4,reconnectRadius:Tu=10,onNodesChange:ml,onEdgesChange:T4,noDragClassName:M4="nodrag",noWheelClassName:r3="nowheel",noPanClassName:j3="nopan",fitView:Yl,fitViewOptions:A3,connectOnClick:h0,attributionPosition:Nr,proOptions:P4,defaultEdgeOptions:z1,elevateNodesOnSelect:ny=!0,elevateEdgesOnSelect:b_=!1,disableKeyboardA11y:Sy=!1,autoPanOnConnect:cJ,autoPanOnNodeDrag:Cy,autoPanSpeed:RJ,connectionRadius:n4,isValidConnection:Zr,onError:Er,style:Hr,id:G1,nodeDragThreshold:iy,connectionDragThreshold:v_,viewport:Mu,onViewportChange:S4,width:F3,height:Fl,colorMode:C4="light",debug:Or,onScroll:i4,ariaLabelConfig:c4,zIndexMode:K1="basic",...R4},J3){let U3=G1||"1",Vr=oT(C4),Q3=_f.useCallback((Jl)=>{Jl.currentTarget.scrollTo({top:0,left:0,behavior:"instant"}),i4?.(Jl)},[i4]);return lf.jsx("div",{"data-testid":"rf__wrapper",...R4,onScroll:Q3,style:{...Hr,...NP},ref:J3,className:M0(["react-flow",y,Vr]),id:G1,role:"application",children:lf.jsxs(KP,{nodes:f,edges:u,width:F3,height:Fl,fitView:Yl,fitViewOptions:A3,minZoom:mu,maxZoom:C0,nodeOrigin:_0,nodeExtent:Uf,zIndexMode:K1,children:[lf.jsx(sT,{nodes:f,edges:u,defaultNodes:l,defaultEdges:_,onConnect:G,onConnectStart:K,onConnectEnd:H,onClickConnectStart:O,onClickConnectEnd:z,nodesDraggable:Af,autoPanOnNodeFocus:Yf,nodesConnectable:Bf,nodesFocusable:df,edgesFocusable:y0,edgesReconnectable:N0,elementsSelectable:a0,elevateNodesOnSelect:ny,elevateEdgesOnSelect:b_,minZoom:mu,maxZoom:C0,nodeExtent:Uf,onNodesChange:ml,onEdgesChange:T4,snapToGrid:o,snapGrid:e,connectionMode:m,translateExtent:Q1,connectOnClick:h0,defaultEdgeOptions:z1,fitView:Yl,fitViewOptions:A3,onNodesDelete:h,onEdgesDelete:M,onDelete:n,onNodeDragStart:w,onNodeDrag:B,onNodeDragStop:P,onSelectionDrag:i,onSelectionDragStart:T,onSelectionDragStop:C,onMove:U,onMoveStart:Q,onMoveEnd:W,noPanClassName:j3,nodeOrigin:_0,rfId:U3,autoPanOnConnect:cJ,autoPanOnNodeDrag:Cy,autoPanSpeed:RJ,onError:Er,connectionRadius:n4,isValidConnection:Zr,selectNodesOnDrag:k,nodeDragThreshold:iy,connectionDragThreshold:v_,onBeforeDelete:p,debug:Or,ariaLabelConfig:c4,zIndexMode:K1}),lf.jsx(WP,{onInit:J,onNodeClick:j,onEdgeClick:A,onNodeMouseEnter:Z,onNodeMouseMove:N,onNodeMouseLeave:E,onNodeContextMenu:q,onNodeDoubleClick:Y,nodeTypes:$,edgeTypes:r,connectionLineType:s,connectionLineStyle:d,connectionLineComponent:a,connectionLineContainerStyle:I,selectionKeyCode:yf,selectionOnDrag:rf,selectionMode:Wf,deleteKeyCode:ff,multiSelectionKeyCode:Gf,panActivationKeyCode:Ef,zoomActivationKeyCode:c,onlyRenderVisibleElements:Kf,defaultViewport:pu,translateExtent:Q1,minZoom:mu,maxZoom:C0,preventScrolling:ru,zoomOnScroll:Nu,zoomOnPinch:Cf,zoomOnDoubleClick:i0,panOnScroll:d0,panOnScrollSpeed:e0,panOnScrollMode:Zu,panOnDrag:Du,onPaneClick:W1,onPaneMouseEnter:pl,onPaneMouseMove:R_,onPaneMouseLeave:x_,onPaneScroll:v0,onPaneContextMenu:uf,paneClickDistance:wf,nodeClickDistance:Hf,onSelectionContextMenu:v,onSelectionStart:X,onSelectionEnd:D,onReconnect:pf,onReconnectStart:Q0,onReconnectEnd:u0,onEdgeContextMenu:fu,onEdgeDoubleClick:Bl,onEdgeMouseEnter:w4,onEdgeMouseMove:$3,onEdgeMouseLeave:D4,reconnectRadius:Tu,defaultMarkerColor:nf,noDragClassName:M4,noWheelClassName:r3,noPanClassName:j3,rfId:U3,disableKeyboardA11y:Sy,nodeExtent:Uf,viewport:Mu,onViewportChange:S4}),lf.jsx(mT,{onSelectionChange:S}),gf,lf.jsx(bT,{proOptions:P4,position:Nr}),lf.jsx(xT,{rfId:U3,disableKeyboardA11y:Sy})]})})}var rE=iZ(ZP);var Ih=$l.error014();function EP({dimensions:f,lineWidth:u,variant:l,className:_}){return lf.jsx("path",{strokeWidth:u,d:`M${f[0]/2} 0 V${f[1]} M0 ${f[1]/2} H${f[0]}`,className:M0(["react-flow__background-pattern",l,_])})}function HP({radius:f,className:u}){return lf.jsx("circle",{cx:f,cy:f,r:f,className:M0(["react-flow__background-pattern","dots",u])})}var Y_;(function(f){f.Lines="lines",f.Dots="dots",f.Cross="cross"})(Y_||(Y_={}));var OP={[Y_.Dots]:1,[Y_.Lines]:1,[Y_.Cross]:6},VP=(f)=>({transform:f.transform,patternId:`pattern-${f.rfId}`});function jE({id:f,variant:u=Y_.Dots,gap:l=20,size:_,lineWidth:y=1,offset:$=0,color:r,bgColor:j,style:A,className:J,patternClassName:U}){let Q=_f.useRef(null),{transform:W,patternId:G}=f0(VP,H0),K=_||OP[u],H=u===Y_.Dots,O=u===Y_.Cross,z=Array.isArray(l)?l:[l,l],Z=[z[0]*W[2]||1,z[1]*W[2]||1],N=K*W[2],E=Array.isArray($)?$:[$,$],q=O?[N,N]:Z,Y=[E[0]*W[2]||1+q[0]/2,E[1]*W[2]||1+q[1]/2],w=`${G}${f?f:""}`;return lf.jsxs("svg",{className:M0(["react-flow__background",J]),style:{...A,...m5,"--xy-background-color-props":j,"--xy-background-pattern-color-props":r},ref:Q,"data-testid":"rf__background",children:[lf.jsx("pattern",{id:w,x:W[0]%Z[0],y:W[1]%Z[1],width:Z[0],height:Z[1],patternUnits:"userSpaceOnUse",patternTransform:`translate(-${Y[0]},-${Y[1]})`,children:H?lf.jsx(HP,{radius:N/2,className:U}):lf.jsx(EP,{dimensions:q,lineWidth:y,variant:u,className:U})}),lf.jsx("rect",{x:"0",y:"0",width:"100%",height:"100%",fill:`url(#${w})`})]})}jE.displayName="Background";var AE=_f.memo(jE);function qP(){return lf.jsx("svg",{xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 32 32",children:lf.jsx("path",{d:"M32 18.133H18.133V32h-4.266V18.133H0v-4.266h13.867V0h4.266v13.867H32z"})})}function LP(){return lf.jsx("svg",{xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 32 5",children:lf.jsx("path",{d:"M0 0h32v4.2H0z"})})}function XP(){return lf.jsx("svg",{xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 32 30",children:lf.jsx("path",{d:"M3.692 4.63c0-.53.4-.938.939-.938h5.215V0H4.708C2.13 0 0 2.054 0 4.63v5.216h3.692V4.631zM27.354 0h-5.2v3.692h5.17c.53 0 .984.4.984.939v5.215H32V4.631A4.624 4.624 0 0027.354 0zm.954 24.83c0 .532-.4.94-.939.94h-5.215v3.768h5.215c2.577 0 4.631-2.13 4.631-4.707v-5.139h-3.692v5.139zm-23.677.94c-.531 0-.939-.4-.939-.94v-5.138H0v5.139c0 2.577 2.13 4.707 4.708 4.707h5.138V25.77H4.631z"})})}function BP(){return lf.jsx("svg",{xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 25 32",children:lf.jsx("path",{d:"M21.333 10.667H19.81V7.619C19.81 3.429 16.38 0 12.19 0 8 0 4.571 3.429 4.571 7.619v3.048H3.048A3.056 3.056 0 000 13.714v15.238A3.056 3.056 0 003.048 32h18.285a3.056 3.056 0 003.048-3.048V13.714a3.056 3.056 0 00-3.048-3.047zM12.19 24.533a3.056 3.056 0 01-3.047-3.047 3.056 3.056 0 013.047-3.048 3.056 3.056 0 013.048 3.048 3.056 3.056 0 01-3.048 3.047zm4.724-13.866H7.467V7.619c0-2.59 2.133-4.724 4.723-4.724 2.591 0 4.724 2.133 4.724 4.724v3.048z"})})}function YP(){return lf.jsx("svg",{xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 25 32",children:lf.jsx("path",{d:"M21.333 10.667H19.81V7.619C19.81 3.429 16.38 0 12.19 0c-4.114 1.828-1.37 2.133.305 2.438 1.676.305 4.42 2.59 4.42 5.181v3.048H3.047A3.056 3.056 0 000 13.714v15.238A3.056 3.056 0 003.048 32h18.285a3.056 3.056 0 003.048-3.048V13.714a3.056 3.056 0 00-3.048-3.047zM12.19 24.533a3.056 3.056 0 01-3.047-3.047 3.056 3.056 0 013.047-3.048 3.056 3.056 0 013.048 3.048 3.056 3.056 0 01-3.048 3.047z"})})}function v5({children:f,className:u,...l}){return lf.jsx("button",{type:"button",className:M0(["react-flow__controls-button",u]),...l,children:f})}var wP=(f)=>({isInteractive:f.nodesDraggable||f.nodesConnectable||f.elementsSelectable,minZoomReached:f.transform[2]<=f.minZoom,maxZoomReached:f.transform[2]>=f.maxZoom,ariaLabelConfig:f.ariaLabelConfig});function FE({style:f,showZoom:u=!0,showFitView:l=!0,showInteractive:_=!0,fitViewOptions:y,onZoomIn:$,onZoomOut:r,onFitView:j,onInteractiveChange:A,className:J,children:U,position:Q="bottom-left",orientation:W="vertical","aria-label":G}){let K=q0(),{isInteractive:H,minZoomReached:O,maxZoomReached:z,ariaLabelConfig:Z}=f0(wP,H0),{zoomIn:N,zoomOut:E,fitView:q}=sF(),Y=()=>{N(),$?.()},w=()=>{E(),r?.()},B=()=>{q(y),j?.()},P=()=>{K.setState({nodesDraggable:!H,nodesConnectable:!H,elementsSelectable:!H}),A?.(!H)};return lf.jsxs(p5,{className:M0(["react-flow__controls",W==="horizontal"?"horizontal":"vertical",J]),position:Q,style:f,"data-testid":"rf__controls","aria-label":G??Z["controls.ariaLabel"],children:[u&&lf.jsxs(lf.Fragment,{children:[lf.jsx(v5,{onClick:Y,className:"react-flow__controls-zoomin",title:Z["controls.zoomIn.ariaLabel"],"aria-label":Z["controls.zoomIn.ariaLabel"],disabled:z,children:lf.jsx(qP,{})}),lf.jsx(v5,{onClick:w,className:"react-flow__controls-zoomout",title:Z["controls.zoomOut.ariaLabel"],"aria-label":Z["controls.zoomOut.ariaLabel"],disabled:O,children:lf.jsx(LP,{})})]}),l&&lf.jsx(v5,{className:"react-flow__controls-fitview",onClick:B,title:Z["controls.fitView.ariaLabel"],"aria-label":Z["controls.fitView.ariaLabel"],children:lf.jsx(XP,{})}),_&&lf.jsx(v5,{className:"react-flow__controls-interactive",onClick:P,title:Z["controls.interactive.ariaLabel"],"aria-label":Z["controls.interactive.ariaLabel"],children:H?lf.jsx(YP,{}):lf.jsx(BP,{})}),U]})}FE.displayName="Controls";var JE=_f.memo(FE);function DP({id:f,x:u,y:l,width:_,height:y,style:$,color:r,strokeColor:j,strokeWidth:A,className:J,borderRadius:U,shapeRendering:Q,selected:W,onClick:G}){let{background:K,backgroundColor:H}=$||{},O=r||K||H;return lf.jsx("rect",{className:M0(["react-flow__minimap-node",{selected:W},J]),x:u,y:l,rx:U,ry:U,width:_,height:y,style:{fill:O,stroke:j,strokeWidth:A},shapeRendering:Q,onClick:G?(z)=>G(z,f):void 0})}var TP=_f.memo(DP),MP=(f)=>f.nodes.map((u)=>u.id),gF=(f)=>f instanceof Function?f:()=>f;function PP({nodeStrokeColor:f,nodeColor:u,nodeClassName:l="",nodeBorderRadius:_=5,nodeStrokeWidth:y,nodeComponent:$=TP,onClick:r}){let j=f0(MP,H0),A=gF(u),J=gF(f),U=gF(l),Q=typeof window>"u"||!!window.chrome?"crispEdges":"geometricPrecision";return lf.jsx(lf.Fragment,{children:j.map((W)=>lf.jsx(SP,{id:W,nodeColorFunc:A,nodeStrokeColorFunc:J,nodeClassNameFunc:U,nodeBorderRadius:_,nodeStrokeWidth:y,NodeComponent:$,onClick:r,shapeRendering:Q},W))})}function nP({id:f,nodeColorFunc:u,nodeStrokeColorFunc:l,nodeClassNameFunc:_,nodeBorderRadius:y,nodeStrokeWidth:$,shapeRendering:r,NodeComponent:j,onClick:A}){let{node:J,x:U,y:Q,width:W,height:G}=f0((K)=>{let H=K.nodeLookup.get(f);if(!H)return{node:void 0,x:0,y:0,width:0,height:0};let O=H.internals.userNode,{x:z,y:Z}=H.internals.positionAbsolute,{width:N,height:E}=r1(O);return{node:O,x:z,y:Z,width:N,height:E}},H0);if(!J||J.hidden||!TF(J))return null;return lf.jsx(j,{x:U,y:Q,width:W,height:G,style:J.style,selected:!!J.selected,className:_(J),color:u(J),borderRadius:y,strokeColor:l(J),strokeWidth:$,shapeRendering:r,onClick:A,id:J.id})}var SP=_f.memo(nP),CP=_f.memo(PP),iP=200,cP=150,RP=(f)=>!f.hidden,xP=(f)=>{let u={x:-f.transform[0]/f.transform[2],y:-f.transform[1]/f.transform[2],width:f.width/f.transform[2],height:f.height/f.transform[2]};return{viewBB:u,boundingRect:f.nodeLookup.size>0?YF(p$(f.nodeLookup,{filter:RP}),u):u,rfId:f.rfId,panZoom:f.panZoom,translateExtent:f.translateExtent,flowWidth:f.width,flowHeight:f.height,ariaLabelConfig:f.ariaLabelConfig}},bP="react-flow__minimap-desc";function UE({style:f,className:u,nodeStrokeColor:l,nodeColor:_,nodeClassName:y="",nodeBorderRadius:$=5,nodeStrokeWidth:r,nodeComponent:j,bgColor:A,maskColor:J,maskStrokeColor:U,maskStrokeWidth:Q,position:W="bottom-right",onClick:G,onNodeClick:K,pannable:H=!1,zoomable:O=!1,ariaLabel:z,inversePan:Z,zoomStep:N=1,offsetScale:E=5}){let q=q0(),Y=_f.useRef(null),{boundingRect:w,viewBB:B,rfId:P,panZoom:h,translateExtent:M,flowWidth:n,flowHeight:S,ariaLabelConfig:T}=f0(xP,H0),i=f?.width??iP,C=f?.height??cP,v=w.width/i,X=w.height/C,D=Math.max(v,X),p=D*i,m=D*C,s=E*D,d=w.x-(p-w.width)/2-s,a=w.y-(m-w.height)/2-s,I=p+s*2,ff=m+s*2,yf=`${bP}-${P}`,rf=_f.useRef(0),Wf=_f.useRef();rf.current=D,_f.useEffect(()=>{if(Y.current&&h)return Wf.current=hN({domNode:Y.current,panZoom:h,getTransform:()=>q.getState().transform,getViewScale:()=>rf.current}),()=>{Wf.current?.destroy()}},[h]),_f.useEffect(()=>{Wf.current?.update({translateExtent:M,width:n,height:S,inversePan:Z,pannable:H,zoomStep:N,zoomable:O})},[H,O,Z,N,M,n,S]);let Ef=G?(o)=>{let[e,Kf]=Wf.current?.pointer(o)||[0,0];G(o,{x:e,y:Kf})}:void 0,Gf=K?_f.useCallback((o,e)=>{let Kf=q.getState().nodeLookup.get(e).internals.userNode;K(o,Kf)},[]):void 0,c=z??T["minimap.ariaLabel"];return lf.jsx(p5,{position:W,style:{...f,"--xy-minimap-background-color-props":typeof A==="string"?A:void 0,"--xy-minimap-mask-background-color-props":typeof J==="string"?J:void 0,"--xy-minimap-mask-stroke-color-props":typeof U==="string"?U:void 0,"--xy-minimap-mask-stroke-width-props":typeof Q==="number"?Q*D:void 0,"--xy-minimap-node-background-color-props":typeof _==="string"?_:void 0,"--xy-minimap-node-stroke-color-props":typeof l==="string"?l:void 0,"--xy-minimap-node-stroke-width-props":typeof r==="number"?r:void 0},className:M0(["react-flow__minimap",u]),"data-testid":"rf__minimap",children:lf.jsxs("svg",{width:i,height:C,viewBox:`${d} ${a} ${I} ${ff}`,className:"react-flow__minimap-svg",role:"img","aria-labelledby":yf,ref:Y,onClick:Ef,children:[c&&lf.jsx("title",{id:yf,children:c}),lf.jsx(CP,{onClick:Gf,nodeColor:_,nodeStrokeColor:l,nodeBorderRadius:$,nodeClassName:y,nodeStrokeWidth:r,nodeComponent:j}),lf.jsx("path",{className:"react-flow__minimap-mask",d:`M${d-s},${a-s}h${I+s*2}v${ff+s*2}h${-I-s*2}z - M${B.x},${B.y}h${B.width}v${B.height}h${-B.width}z`,fillRule:"evenodd",pointerEvents:"none"})]})})}UE.displayName="MiniMap";var ph=_f.memo(UE),vP=(f)=>(u)=>f?`${Math.max(1/u.transform[2],1)}`:void 0,hP={[B_.Line]:"right",[B_.Handle]:"bottom-right"};function IP({nodeId:f,position:u,variant:l=B_.Handle,className:_,style:y=void 0,children:$,color:r,minWidth:j=10,minHeight:A=10,maxWidth:J=Number.MAX_VALUE,maxHeight:U=Number.MAX_VALUE,keepAspectRatio:Q=!1,resizeDirection:W,autoScale:G=!0,shouldResize:K,onResizeStart:H,onResize:O,onResizeEnd:z}){let Z=bZ(),N=typeof f==="string"?f:Z,E=q0(),q=_f.useRef(null),Y=l===B_.Handle,w=f0(_f.useCallback(vP(Y&&G),[Y,G]),H0),B=_f.useRef(null),P=u??hP[l];_f.useEffect(()=>{if(!q.current||!N)return;if(!B.current)B.current=kN({domNode:q.current,nodeId:N,getStoreItems:()=>{let{nodeLookup:M,transform:n,snapGrid:S,snapToGrid:T,nodeOrigin:i,domNode:C}=E.getState();return{nodeLookup:M,transform:n,snapGrid:S,snapToGrid:T,nodeOrigin:i,paneDomNode:C}},onChange:(M,n)=>{let{triggerNodeChanges:S,nodeLookup:T,parentLookup:i,nodeOrigin:C}=E.getState(),v=[],X={x:M.x,y:M.y},D=T.get(N);if(D&&D.expandParent&&D.parentId){let p=D.origin??C,m=M.width??D.measured.width??0,s=M.height??D.measured.height??0,d={id:D.id,parentId:D.parentId,rect:{width:m,height:s,...MF({x:M.x??D.position.x,y:M.y??D.position.y},{width:m,height:s},D.parentId,T,p)}},a=i5([d],T,i,C);v.push(...a),X.x=M.x?Math.max(p[0]*m,M.x):void 0,X.y=M.y?Math.max(p[1]*s,M.y):void 0}if(X.x!==void 0&&X.y!==void 0){let p={id:N,type:"position",position:{...X}};v.push(p)}if(M.width!==void 0&&M.height!==void 0){let m={id:N,type:"dimensions",resizing:!0,setAttributes:!W?!0:W==="horizontal"?"width":"height",dimensions:{width:M.width,height:M.height}};v.push(m)}for(let p of n){let m={...p,type:"position"};v.push(m)}S(v)},onEnd:({width:M,height:n})=>{let S={id:N,type:"dimensions",resizing:!1,dimensions:{width:M,height:n}};E.getState().triggerNodeChanges([S])}});return B.current.update({controlPosition:P,boundaries:{minWidth:j,minHeight:A,maxWidth:J,maxHeight:U},keepAspectRatio:Q,resizeDirection:W,onResizeStart:H,onResize:O,onResizeEnd:z,shouldResize:K}),()=>{B.current?.destroy()}},[P,j,A,J,U,Q,H,O,z,K]);let h=P.split("-");return lf.jsx("div",{className:M0(["react-flow__resize-control","nodrag",...h,l,_]),ref:q,style:{...y,scale:w,...r&&{[Y?"backgroundColor":"borderColor"]:r}},children:$})}var mh=_f.memo(IP);var V=M_.default.createElement,{useEffect:F1}=M_.default,bu=M_.default.useState,T_=M_.default.useRef,Z4=[{id:"in-left",side:"left",position:Zf.Left,style:{top:"50%"}},{id:"in-top-left",side:"top",slot:"left",slotIndex:-1,position:Zf.Top,style:{left:"28%"}},{id:"in-top-mid",side:"top",slot:"mid",slotIndex:0,position:Zf.Top,style:{left:"50%"}},{id:"in-top-right",side:"top",slot:"right",slotIndex:1,position:Zf.Top,style:{left:"72%"}},{id:"in-bottom-left",side:"bottom",slot:"left",slotIndex:-1,position:Zf.Bottom,style:{left:"28%"}},{id:"in-bottom-mid",side:"bottom",slot:"mid",slotIndex:0,position:Zf.Bottom,style:{left:"50%"}},{id:"in-bottom-right",side:"bottom",slot:"right",slotIndex:1,position:Zf.Bottom,style:{left:"72%"}}],z4=[{id:"out-right",position:Zf.Right,style:{top:"50%"}}],QE=["#4eb7a8","#d7a13a","#69aee8","#e0835f","#b7d86b","#d98bd2","#5fc6bf"],d$=236,e$=88,WE=15000,pP=10,aF=96,j1=72,dF=64,zE=12;function g5(){return typeof document>"u"||document.visibilityState!=="hidden"}function GE(f,u){let l=Number.parseFloat(String(f||""));return Number.isFinite(l)?l/100:u}function mP(f,u,l){let _=String(f.side||"");if(_!=="top"&&_!=="bottom")return 0;let y=Number(f.slotIndex||0),$=_==="top"?"in-top-mid":"in-bottom-mid",r=u.get(f.id)||0,j=u.get($)||0;if(y===0)return j===0?-26:28+r*74;let A=l===0?Math.abs(y)*2:Math.sign(l)===Math.sign(y)?-3:3;if(j>0&&r===0)return-14+A;return 8+r*74+A}function k5(f){let u=f.filter(($,r)=>{let j=f[r-1];return!j||Math.abs(j.x-$.x)>0.5||Math.abs(j.y-$.y)>0.5});if(u.length<2)return"";let l=`M ${u[0].x},${u[0].y}`,_=u[0];for(let $=1;$0.5||Math.abs(W.y-_.y)>0.5)l+=` L ${W.x},${W.y}`;l+=` Q ${j.x},${j.y} ${G.x},${G.y}`,_=G}let y=u[u.length-1];return`${l} L ${y.x},${y.y}`}function iE(f,u,l,_,y,$,r=""){let j=l>=f,A=Math.max(1,Math.abs(l-f)),J=Math.abs(_-u),U=Math.max(34,Math.min(118,A*0.26)),Q=Math.min(280,Math.abs($));if(j&&y===Zf.Left&&Q<4&&J<28&&A<420)return`M ${f},${u} C ${f+U},${u} ${l-U},${_} ${l},${_}`;if(j&&y===Zf.Left&&(r==="direct-forward-left"||A<=260&&J<=210)){let z=Math.max(42,Math.min(140,A*0.48)),Z=Math.max(-28,Math.min(28,$*0.18));return`M ${f},${u} C ${f+z},${u+Z} ${l-z},${_} ${l},${_}`}if(j){let z=f+U;if(y===Zf.Top||y===Zf.Bottom){let E=y===Zf.Top?-1:1,q=_+E*(54+Q*0.42);return k5([{x:f,y:u},{x:z,y:u},{x:z+Math.min(120,A*0.18),y:q},{x:l,y:q},{x:l,y:_+E*34},{x:l,y:_}])}let Z=l-U,N=(u+_)/2+$;return k5([{x:f,y:u},{x:z,y:u},{x:z+Math.min(110,A*0.16),y:N},{x:Z-Math.min(90,A*0.12),y:N},{x:Z,y:_},{x:l,y:_}])}let K=y===Zf.Bottom?1:y===Zf.Top?-1:$>=0?1:-1,H=Math.max(f,l)+92+Math.min(180,Q*0.52),O=K<0?Math.min(u,_)-84-Q*0.62:Math.max(u,_)+84+Q*0.62;if(y===Zf.Top||y===Zf.Bottom)return k5([{x:f,y:u},{x:f+U,y:u},{x:H,y:O},{x:l,y:O},{x:l,y:_+K*38},{x:l,y:_}]);return k5([{x:f,y:u},{x:f+U,y:u},{x:H,y:O},{x:l-U,y:O},{x:l-U,y:_},{x:l,y:_}])}function gP({data:f}){return V("div",{className:"pipeline-flow-node-body"},Z4.map((u)=>V(Dy,{key:u.id,id:u.id,type:"target",position:u.position,isConnectable:!1,className:`pipeline-flow-handle input ${u.side} slot-${u.slot||"mid"}`,style:u.style})),z4.map((u)=>V(Dy,{key:u.id,id:u.id,type:"source",position:u.position,isConnectable:!1,className:"pipeline-flow-handle output right",style:u.style})),f?.label)}function kP({id:f,sourceX:u,sourceY:l,targetX:_,targetY:y,targetPosition:$,markerEnd:r,markerStart:j,style:A,data:J}){let U=Number(J?.laneOffset||0),Q=iE(u,l,_,y,$,U,String(J?.routeMode||""));return V(a$,{id:f,path:Q,markerEnd:r,markerStart:j,style:A,interactionWidth:28})}var tP={pipelineCurve:kP},sP={pipelineNode:gP};function a5(f){if(!f)return"--";let u=new Date(f);if(Number.isNaN(u.getTime()))return"--";return W0(u)}function ql(f){let u=Number(f);if(!Number.isFinite(u)||u<0)return"--";let l=Math.round(u/1000);if(l<60)return`${l}s`;if(l<3600)return`${Math.floor(l/60)}m ${l%60}s`;return`${Math.floor(l/3600)}h ${Math.floor(l%3600/60)}m`}function eF(f){let u=Number(f);if(!Number.isFinite(u))return"--";return u.toLocaleString("zh-CN")}function KE(f){let u=Number(f);if(!Number.isFinite(u))return"--";return`${Math.round(Math.max(0,Math.min(1,u))*100)}%`}function Pf(f){return typeof f==="object"&&f!==null&&!Array.isArray(f)}function Xf(f){return Array.isArray(f)?f:[]}function vf(f){if(!f)return null;let u=new Date(f);return Number.isNaN(u.getTime())?null:u.getTime()}function E4(f){return Number.isFinite(Number(f))?new Date(Number(f)).toISOString():""}function V4(...f){for(let u of f){let l=vf(u);if(l!==null)return new Date(l).toISOString()}return""}function WJ(...f){let u=f.map(vf).filter((l)=>l!==null);return u.length>0?new Date(Math.max(...u)).toISOString():""}function zJ(f){return["succeeded","failed","skipped","cancelled","canceled","completed"].includes(String(f||"").toLowerCase())}function cE(f){let u=bE(f).toLowerCase();return["running","active","in-progress","in_progress"].includes(u)}function NE(f,u="status"){return f.reduce((l,_)=>{let y=String(_?.[u]||"unknown").toLowerCase();return l[y]=(l[y]||0)+1,l},{})}function RE(f){if(!f||typeof f!=="string")return null;try{let u=JSON.parse(f);return Pf(u)?u:null}catch{return null}}function fJ(f){let u=f.map(RE).filter(($)=>Boolean($)),l=u.flatMap(($)=>[$.timestamp,$.createdAt,$.updatedAt]).filter(Boolean),_=WJ(...l),y=Array.from(new Set(u.map(($)=>String($.event||$.action||$.type||"")).filter(Boolean))).slice(0,3);return{total:f.length,parsed:u.length,lastAt:_,eventKinds:y}}function d5(f){if(f===null||f===void 0)return"--";if(typeof f==="boolean")return f?"是":"否";if(typeof f==="number")return String(f);if(typeof f==="string")return f.length>80?`${f.slice(0,77)}...`:f;if(Array.isArray(f))return`${f.length} 项`;if(typeof f==="object")return`${Object.keys(f).length} 字段`;return String(f)}function xE(f,u=280){if(f===null||f===void 0)return"";let _=(typeof f==="string"?f:String(f)).replace(/\r\n/gu,` -`).trim();return _.length>u?`${_.slice(0,Math.max(0,u-1))}...`:_}function bE(f){if(typeof f==="string")return f;if(Pf(f))return String(f.status||f.state||f.phase||"unknown");return"unknown"}function oP(f){return f.filter((u)=>u&&u.value!==void 0&&u.value!==null&&String(u.value)!=="")}function rJ({items:f}){let u=oP(Xf(f));return V("div",{className:"pipeline-kv-grid"},u.map((l)=>V("span",{key:l.label},V("b",null,l.label),V("span",null,l.value))))}function GJ({items:f}){let u=Xf(f).map((l)=>String(l||"")).filter(Boolean);if(u.length===0)return null;return V("div",{className:"pipeline-chip-row"},u.map((l,_)=>V("span",{key:`${_}-${l}`},l)))}function jJ(f,u){let l=String(u?.procedureRunId||""),_=Xf(f?.procedureRuns);return _.find((y)=>String(Ll(y))===l)||_.at(-1)||null}function aP(f,u){let l=String(u||"");if(!l)return null;return Xf(f?.procedureRuns).find((_)=>Ll(_)===l)||null}function uJ(f){return Xf(f?.attempts).length}function ZE(f){return Xf(f?.attempts).reduce((u,l)=>u+$r(l).length,0)}function $r(f){return Xf(f?.opencodeMessages?.steps).filter(Pf)}function vE(f){let u=String(f?.status||"").toLowerCase();if(["error","failed","failure"].includes(u))return"failed";if(["completed","succeeded","success"].includes(u))return"succeeded";if(["running","started","in_progress"].includes(u))return"running";return"unknown"}function dP(f,u){let l=AJ(f.map(($)=>$?.agent)).slice(0,3),_=AJ(f.map(($)=>$?.model)).slice(0,3),y=u.length<=2?u.map(($)=>`session ${$}`):[`sessions ${u.length}`,...u.slice(0,2).map(($)=>`session ${$}`)];return[...l.map(($)=>`agent ${$}`),..._.map(($)=>`model ${$}`),...y]}function G4(f,u=0){return String(f?.messageId||f?.index||"")||`step-${u}`}function eP({steps:f,sessionIds:u,sessionFacts:l,matchedStepKey:_}){let y=Xf(f),$=y.findIndex((O,z)=>G4(O,z)===_),r=$>=0?y[$]:null,j=y.flatMap((O)=>[vf(O?.createdAt),vf(O?.completedAt)]).filter((O)=>O!==null),A=j.length>0?Math.min(...j):null,J=j.length>0?Math.max(...j):null,U=A!==null&&J!==null?Math.max(0,J-A):null,Q=y.reduce((O,z)=>O+Xf(z?.parts).filter((Z)=>String(Z?.type||"").toLowerCase()==="tool").length,0),W=y.reduce((O,z)=>O+Xf(z?.parts).filter((Z)=>["text","reasoning"].includes(String(Z?.type||"").toLowerCase())).length,0),G=y.reduce((O,z)=>O+Xf(z?.parts).filter((Z)=>String(Z?.type||"").toLowerCase()==="tool"&&vE(Z)==="failed").length,0),K=[`${y.length} steps`,`${u.length} sessions`,`${W} messages`,`${Q} tools`,U!==null?`duration ${ql(U)}`:"",G>0?`${G} failed tools`:""].filter(Boolean),H=r?[`Step ${r?.index??$+1}`,String(r?.role||"role --"),r?.model?`model ${r.model}`:"",r?.finish?`finish ${r.finish}`:"",r?.durationMs!==void 0&&r?.durationMs!==null?`duration ${ql(r.durationMs)}`:""].filter(Boolean):[];return V("section",{className:"pipeline-trace-timeline","data-testid":"pipeline-step-timeline"},V("div",{className:"pipeline-trace-head"},V("div",null,V("b",null,"OpenCode Trace"),V("span",null,"Trace 使用 Code Queue 统一样式展示完整 agent loop;Pipeline 旧 step/message/tool 卡片样式已废弃。")),V("div",{className:"pipeline-trace-session-head","data-testid":"pipeline-step-timeline-session"},V("span",null,K.join(" / ")||"Trace"),l.length>0?V(GJ,{items:l}):null)),r?V("div",{className:"pipeline-trace-focus","data-testid":"pipeline-trace-matched-step"},V("span",{className:"codex-output-channel"},"Matched"),V("strong",null,`Gantt selection -> ${H.join(" / ")}`),V("time",null,`${a5(r?.createdAt)} -> ${a5(r?.completedAt)}`)):null,V(O2,{port:GG,input:y,className:"codex-transcript pipeline-trace",testId:"pipeline-opencode-step-trace",emptyText:"暂无 OpenCode Trace 输出",keepRecentToolCalls:3}))}function K4(f){return Xf(f).flatMap((u)=>{if(Pf(u))return[u];let l=RE(u);return l?[l]:[]})}function hl(f){return String(f?.event||f?.action||f?.requestedAction||f?.type||"").toLowerCase()}function Ty(f){return V4(f?.timestamp,f?.createdAt,f?.updatedAt,f?.startedAt,f?.finishedAt)}function fn(f){return vf(Ty(f))}function rr(f){return String(f?.attempt||f?.id||"")}function AJ(f){let u=new Set,l=[];for(let _ of f){let y=String(_||"");if(!y||u.has(y))continue;u.add(y),l.push(y)}return l}function EE(f){switch(String(f||"").toLowerCase()){case"monitor":return"monitor";case"webui":return"webui";case"cli":return"cli";case"system":return"runner";default:return String(f||"--")}}function My(f){return String(f?.requestedAction||f?.action||"").toLowerCase()}function N4(f){switch(My(f)){case"guide":return"引导";case"modify":return"修改";case"approve":return"审核通过";case"restart":return"重启";case"redo":return"重做";default:return String(f?.requestedAction||f?.action||"控制")}}function HE(f){switch(hl(f)){case"initial-prompt-delivered":return"初始 prompt";case"append-prompt-delivered":return"追加 prompt";case"append-prompt-queued":return"追加 prompt 已排队";case"monitor-prompt-delivered":return"Monitor prompt";case"node-long-running-observation":return"长任务观察";case"node-finished":return"节点完成";case"oa-policy-downstream-evaluated":return"OA 下游策略";case"control-command-queued":return`${N4(f)} 已发起`;case"control-command-applied":return`${N4(f)} 已生效`;case"control-command-ignored":return`${N4(f)} 已忽略`;default:return String(f?.event||f?.action||f?.requestedAction||"event")}}function OE(f){return xE(f?.promptPreview||f?.reasonPreview||f?.prompt||f?.reason||"",240)}function un(f){let u=String(f?.prompt||""),l=String(f?.reason||f?.restartReason||""),_=u?"":String(f?.promptPreview||""),y=l?"":String(f?.reasonPreview||"");return[u||_?{label:u?"prompt":"prompt preview",value:u||_}:null,l||y?{label:l?"reason":"reason preview",value:l||y}:null,Xf(f?.resetNodeIds).length>0?{label:"reset nodes",value:Xf(f.resetNodeIds).join(", ")}:null,Xf(f?.runningResetNodeIds).length>0?{label:"interrupted running nodes",value:Xf(f.runningResetNodeIds).join(", ")}:null,Xf(f?.interruptedProcedureRunIds).length>0?{label:"interrupted procedures",value:Xf(f.interruptedProcedureRunIds).join(", ")}:null,f?.interruptedProcedureRunId?{label:"interrupted procedure",value:String(f.interruptedProcedureRunId)}:null].filter(Boolean)}function lJ(f){let u=$r(f),l=u.map((A)=>vf(A?.createdAt)).filter((A)=>A!==null),_=u.map((A)=>vf(A?.completedAt)??vf(A?.createdAt)).filter((A)=>A!==null),y=K4(f?.controlEventRecords).map((A)=>fn(A)).filter((A)=>A!==null),$=Xf(f?.assistantOutputs).map((A)=>vf(A?.updatedAt)).filter((A)=>A!==null),r=l[0]??y[0]??$[0]??null,j=_.at(-1)??y.at(-1)??$.at(-1)??r;return{startMs:r,endMs:j}}function ln(f,u,l,_,y=""){let $=Xf(f?.procedureRuns).filter((j)=>jr(j,u)===l);if($.length===0)return null;if(y){let j=$.find((A)=>Ll(A)===y);if(j)return j}if(_===null)return $.at(-1)||null;let r=$.find((j)=>{let A=vf(t5(j,f)),J=vf(s5(j,f))??A;return A!==null&&J!==null&&_>=A-1000&&_<=J+1000});if(r)return r;return $.slice().sort((j,A)=>{let J=vf(t5(j,f))??_,U=vf(s5(j,f))??J,Q=vf(t5(A,f))??_,W=vf(s5(A,f))??Q,G=Math.min(Math.abs(J-_),Math.abs(U-_)),K=Math.min(Math.abs(Q-_),Math.abs(W-_));return G-K})[0]||null}function hE(f,u){let l=Xf(f?.attempts).filter(Pf);if(l.length===0)return null;let _=String(u?.attempt||"");if(_){let r=l.find((j)=>rr(j)===_);if(r)return r}let y=Number.isFinite(Number(u?.ms))?Number(u.ms):null;if(y===null)return l.at(-1)||null;let $=l.find((r)=>{let j=lJ(r);return Number.isFinite(j.startMs)&&Number.isFinite(j.endMs)&&y>=Number(j.startMs)-1000&&y<=Number(j.endMs)+1000});if($)return $;return l.slice().sort((r,j)=>{let A=lJ(r),J=lJ(j),U=Math.min(Math.abs(Number(A.startMs??y)-y),Math.abs(Number(A.endMs??y)-y)),Q=Math.min(Math.abs(Number(J.startMs??y)-y),Math.abs(Number(J.endMs??y)-y));return U-Q})[0]||l.at(-1)||null}function IE(f,u){let l=$r(f);if(l.length===0)return{step:null,stepIndex:-1,stepKey:""};if(u===null){let $=l[0];return{step:$,stepIndex:0,stepKey:G4($,0)}}for(let $=0;$=j-1000&&u<=A+1000)return{step:r,stepIndex:$,stepKey:G4(r,$)}}let _=l.findIndex(($)=>{let r=vf($?.createdAt)??vf($?.completedAt);return r!==null&&r>=u});if(_>=0){let $=l[_];return{step:$,stepIndex:_,stepKey:G4($,_)}}let y=Math.max(0,l.length-1);return{step:l[y],stepIndex:y,stepKey:G4(l[y],y)}}function _n(f,u){let l=String(u?.runId||f?.runId||"");if(String(u?.mode||"")==="interval"){let J=u?.interval||{},U=jJ(f,J)||J.raw||{};return{mode:"interval",runId:l,interval:J,marker:null,nodeId:String(J?.nodeId||jr(U,l)||""),procedure:U,attempt:null,matchedStep:null,matchedStepIndex:-1,matchedStepKey:""}}let _=Pf(u?.marker)?u.marker:{},y=Number.isFinite(Number(_?.ms))?Number(_.ms):null,$=String(_?.nodeId||""),r=$?ln(f,l,$,y,String(_?.procedureRunId||"")):null,j=r?hE(r,_):null,A=j?IE(j,y):{step:null,stepIndex:-1,stepKey:""};return{mode:"event",runId:l,interval:null,marker:_,nodeId:$,procedure:r,attempt:j,matchedStep:A.step,matchedStepIndex:A.stepIndex,matchedStepKey:A.stepKey}}function yn({procedure:f,matchedStepKey:u="",matchedAttemptId:l=""}){let _=Xf(f?.attempts);if(_.length===0)return V(jl,{title:"暂无 attempt 详情",text:"当前 procedure 还没有可展示的 attempt / OpenCode Trace;若刚点击甘特线,请等待 node 详情抓取完成。"});return _.map((y,$)=>{let r=y?.opencodeMessages||{},j=$r(y),A=Xf(r.sessionIds).map((W)=>String(W)).filter(Boolean),J=dP(j,A),U=rr(y)||`attempt-${$+1}`,Q=j.reduce((W,G)=>W+Xf(G?.parts).filter((K)=>String(K?.type||"").toLowerCase()==="tool"&&vE(K)==="failed").length,0);return V("article",{key:U,className:`pipeline-attempt-card ${l===U?"matched":""}`},V("div",{className:"pipeline-attempt-head"},V("div",null,V("strong",null,U),V("span",null,r.source||"opencode")),V("div",{className:"pipeline-attempt-badges"},V("span",null,`${j.length} steps`),V("span",null,`${r.toolCallCount??"--"} tools`),Q>0?V("span",{className:"danger"},`${Q} failed`):null)),V(rJ,{items:[{label:"messages",value:r.messageCount??"--"},{label:"steps",value:r.stepCount??j.length},{label:"tools",value:r.toolCallCount??"--"},{label:"updated",value:Nf(r.updatedAt)},{label:"sessions",value:A.join(", ")||"--"}]}),j.length===0?V("p",{className:"muted paragraph"},"当前 attempt 尚未返回 OpenCode Trace;请确认 D601 pipeline-control 已重建并重新抓取。"):V(eP,{steps:j,sessionIds:A,sessionFacts:J,matchedStepKey:u}))})}function _J(f,u){return`${f}::${u}`}function e5(f,u,l){if(!Pf(f))return null;return String(f.runId||"")===u&&String(f.nodeId||"")===l?f:null}function $n(f,u){let l=Pf(f)?f:{};if(!Pf(u))return l;let _=Xf(u.attempts),y=Xf(l.attempts);return{...l,...u,attempts:_.length>0?_:y}}function rn(f,u,l,_){if(!e5(u,l,_))return f;let y=Xf(u.procedureRuns),$=Pf(f)?f:{};return{...$,...u,controlCommands:Xf(u.controlCommands).length>0?u.controlCommands:$.controlCommands,controlEvents:Xf(u.controlEvents).length>0?u.controlEvents:$.controlEvents,procedureRuns:y.length>0?y:$.procedureRuns}}function jn({selection:f,runDetails:u,nodeDetails:l,nodeDetailsState:_,onRaw:y,onCollapse:$}){if(!f?.mode)return V("aside",{className:"pipeline-gantt-detail-panel empty","data-testid":"pipeline-gantt-detail-panel"},V("div",{className:"pipeline-gantt-detail-head"},V("div",null,V("span",{className:"panel-eyebrow"},"Gantt Detail"),V(j0,{title:"未选择元素",level:3})),V("button",{type:"button",className:"ghost-btn mini",onClick:$,"data-testid":"pipeline-gantt-sidebar-collapse"},"收起")),V(jl,{title:"选择一条执行线或一个控制点",text:"点击甘特图中的 node 执行线、prompt 点或控制点,在这里查看结构化过程和 OpenCode step。"}));let r=String(f?.runId||""),j=String(f?.interval?.nodeId||f?.marker?.nodeId||""),A=u?.runId===r?u.details:null,J=e5(l,r,j),U=String(_?.runId||"")===r&&String(_?.nodeId||"")===j,Q=rn(A,J,r,j),W=(String(u?.runId||"")!==r||Boolean(u?.loading))&&!Q,G=String(u?.runId||"")===r?String(u?.error||""):"",K=U?String(_?.error||""):"",H=Q?_n(Q,f):null,O=H?.interval||f?.interval||null,z=H?.marker||f?.marker||null,Z=String(O?.procedureRunId||z?.procedureRunId||""),N=J?aP(J,Z)||jJ(J,O||{procedureRunId:Z}):null,E=H?.procedure||(Q?jJ(Q,O||{procedureRunId:Z}):null)||O?.raw||{};if(N&&(uJ(E)===0||ZE(N)>=ZE(E)))E=$n(E,N);let q=H?.attempt||null,Y=String(H?.matchedStepKey||"");if(!q&&z&&uJ(E)>0)q=hE(E,z),Y=String(IE(q,Number.isFinite(Number(z?.ms))?Number(z.ms):null).stepKey||"");let w=rr(q),B=uJ(E)>0,P=U&&Boolean(_?.loading)&&!B,h=Boolean(W||P),M=[B?"":G,K].filter(Boolean).join(" / "),n=U&&_?.fetchedAt?_.fetchedAt:u?.fetchedAt,S=bE(E?.status||O?.status||z?.status||z?.event),T=f?.mode==="event"?z?.label||HE(z?.raw||z)||"event":H?.nodeId||O?.nodeId||"node",i=z?un(z?.raw||z):[],C=z?[hl(z?.raw||z)?`event ${hl(z?.raw||z)}`:"",z?.promptEvent?`prompt ${z.promptEvent}`:"",z?.action?`action ${z.action}`:"",z?.sourceKind?`source ${EE(z.sourceKind)}`:"",z?.sourceNodeId?`from ${z.sourceNodeId}`:"",z?.targetNodeId?`to ${z.targetNodeId}`:"",z?.snapReason?`draw ${z.snapReason}`:""].filter(Boolean):[];return V("aside",{className:"pipeline-gantt-detail-panel","data-testid":"pipeline-gantt-detail-panel"},V("div",{className:"pipeline-gantt-detail-head"},V("div",null,V("span",{className:"panel-eyebrow"},f?.mode==="event"?"Gantt Event Detail":"Gantt Line Detail"),V(j0,{title:T,level:3,loading:h})),V("div",{className:"pipeline-gantt-detail-head-actions"},V(P_,{status:S},S),V("button",{type:"button",className:"ghost-btn mini",onClick:$,"data-testid":"pipeline-gantt-sidebar-collapse"},"收起"))),z?V("article",{className:"pipeline-event-card"},V("div",{className:"pipeline-event-card-head"},V("strong",null,z?.label||HE(z?.raw||z)),V(GJ,{items:C})),V(rJ,{items:[{label:"event time",value:Nf(z?.timestampIso||z?.timestamp||"--")},z?.snapped?{label:"drawn time",value:Nf(z?.renderedTimestampIso||z?.ms)}:null,{label:"node",value:z?.nodeId||"--"},{label:"procedure",value:z?.procedureRunId||Ll(E)||"--"},{label:"attempt",value:z?.attempt||w||"--"},{label:"source kind",value:z?.sourceKind?EE(z.sourceKind):"--"},{label:"source node",value:z?.sourceNodeId||"--"},{label:"target node",value:z?.targetNodeId||"--"},{label:"command",value:z?.commandId||z?.eventId||"--"},z?.snapReason?{label:"placement",value:z.snapReason}:null]}),i.length>0?V("div",{className:"pipeline-event-blocks"},i.map((v,X)=>V("section",{key:`${v.label}-${X}`,className:"pipeline-event-text-block"},V("b",null,v.label),V("p",null,v.value)))):null,OE(z?.raw||z)?V("p",{className:"pipeline-text-preview"},OE(z?.raw||z)):null):null,V(rJ,{items:[{label:"epoch",value:r||O?.runId||"--"},{label:"node",value:H?.nodeId||O?.nodeId||z?.nodeId||"--"},{label:"procedure",value:O?.procedureRunId||z?.procedureRunId||Ll(E)||"--"},{label:"started",value:Nf(O?.startedAt||E?.startedAt)},{label:"finished",value:Nf(O?.finishedAt||E?.finishedAt)},{label:"duration",value:ql(O?.durationMs||E?.durationMs)},{label:"fetched",value:n?W0(n):"--"},H?.matchedStep?{label:"matched step",value:`Step ${H.matchedStep.index??H.matchedStepIndex+1}`}:null]}),V(A0,{error:M}),V("div",{className:"pipeline-gantt-detail-actions"},V(Il,{title:`Procedure ${O?.procedureRunId||z?.procedureRunId||H?.nodeId||"node"}`,data:E,onOpen:y,testId:"raw-pipeline-gantt-procedure"}),z?V(Il,{title:`Pipeline event ${z?.id||z?.commandId||z?.eventId||H?.nodeId||"event"}`,data:z?.raw||z,onOpen:y,testId:"raw-pipeline-gantt-event"}):null,Q?V(Il,{title:`Pipeline run ${r||"--"}`,data:Q,onOpen:y,testId:"raw-pipeline-gantt-node-details"}):null),!h&&!Ll(E)&&!z?V(jl,{title:"暂无过程详情",text:"当前选择还没有可匹配的 procedure 运行记录。"}):null,!h&&Ll(E)?V(yn,{procedure:E,matchedStepKey:Y,matchedAttemptId:w}):null)}function An({value:f}){let l=String(f||"--").split(/([_-])/u);return V(M_.default.Fragment,null,l.map((_,y)=>_==="-"||_==="_"?V(M_.default.Fragment,{key:y},_,V("wbr",null)):V(M_.default.Fragment,{key:y},_)))}async function w_(f,u={}){return Mf(f,{invalidJsonPrefix:"Pipeline 返回了无效 JSON",...u})}function P_({status:f,children:u}){let l=String(f||"unknown").toLowerCase();return V("span",{className:`status-badge ${l}`},u||f||"unknown")}function wu({label:f,value:u,hint:l,tone:_}){return V("article",{className:`metric-card ${_||""}`},V("div",{className:"metric-label"},f),V("div",{className:"metric-value"},u),V("div",{className:"metric-hint"},l))}function A1({title:f,eyebrow:u,actions:l,children:_,className:y,loading:$}){return V("section",{className:`panel ${y||""}`},V("div",{className:"panel-head"},V("div",null,u?V("p",{className:"panel-eyebrow"},u):null,V(j0,{title:f,loading:$})),l?V("div",{className:"panel-actions"},l):null),V("div",{className:"panel-body"},_))}function Il({title:f,data:u,onOpen:l,testId:_}){return V("button",{type:"button",className:"ghost-btn","data-testid":_,onClick:()=>l(f,u)},"查看原始JSON")}function Vl({title:f,subtitle:u,facts:l,data:_,onRaw:y,testId:$}){let r=Xf(l).map((j)=>String(j||"")).filter(Boolean);return V("article",{className:"pipeline-evidence-row"},V("div",{className:"pipeline-evidence-main"},V("strong",null,f),u?V("span",null,u):null),V("div",{className:"pipeline-evidence-facts"},r.map((j,A)=>V("span",{key:`${A}-${j.slice(0,16)}`},j))),_!==void 0?V(Il,{title:f,data:_,onOpen:y,testId:$}):null)}function jl({title:f,text:u}){return V("div",{className:"empty-state"},V("strong",null,f),V("span",null,u))}function Fn(f){return f?.runtime&&typeof f.runtime==="object"&&!Array.isArray(f.runtime)?f.runtime:{}}function Jn(f){return f?.backend&&typeof f.backend==="object"&&!Array.isArray(f.backend)?f.backend:{}}function Un(f){return f?.repository&&typeof f.repository==="object"&&!Array.isArray(f.repository)?f.repository:{}}function Qn(f){return{components:Array.isArray(f?.registry?.components)?f.registry.components:[],pipelines:Array.isArray(f?.pipelines)?f.pipelines:[],runs:Array.isArray(f?.runs)?f.runs:[]}}function VE(f,u,l){let _=f?._unidesk?.arrayLimits?.[u],y=Number(_?.originalLength);return Number.isFinite(y)?y:l}function pE(f){if(!f||typeof f!=="object"||Array.isArray(f))return"--";return`${f.componentClass||"--"}/${f.id||"--"}`}function fr(f){if(!f||typeof f!=="object"||Array.isArray(f))return"";let u=String(f.componentClass||"").trim(),l=String(f.id||"").trim();return u&&l?`${u}/${l}`:""}function KJ(f){return f?.config&&typeof f.config==="object"&&!Array.isArray(f.config)?f.config:{}}function mE(f){let u=KJ(f),l=Array.isArray(u.nodes)?u.nodes:Array.isArray(f?.nodes)?f.nodes:[],_=new Map;for(let r of l){let j=String(r?.id||r?.nodeId||"");if(j)_.set(j,{...r,id:j})}let y=NJ(f),$=(r)=>{if(r&&!_.has(r))_.set(r,{id:r})};for(let r of ZJ(f))H4(r).forEach($);for(let r of y)$(String(r?.from||r?.source||"")),$(String(r?.to||r?.target||""));return Array.from(_.values())}function NJ(f){let u=KJ(f);return Array.isArray(u.edges)?u.edges:Array.isArray(f?.edges)?f.edges:[]}function ZJ(f){let u=KJ(f);return Array.isArray(u.topologicalBatches)?u.topologicalBatches:Array.isArray(f?.topologicalBatches)?f.topologicalBatches:[]}function Wn(f){let u=new Map;for(let l of f){let _=fr(l);if(_)u.set(_,l);let y=Array.isArray(l?.refs)?l.refs:[];for(let $ of y){let r=fr($);if(r)u.set(r,l)}}return u}function qE(f,u){let l=u.get(fr(f?.componentRef));if(l)return l;let _=fr({componentClass:f?.kind,id:f?.id});return _?u.get(_)||null:null}function LE(f,u){let l=gE(f,u);return String(l?.status||"pending")}function gE(f,u){return(Array.isArray(f?.nodes)?f.nodes:[]).find((_)=>_?.nodeId===u||_?.id===u)||null}function zn(f){return f.reduce((u,l)=>{let _=String(l?.status||"unknown").toLowerCase();return u[_]=(u[_]||0)+1,u},{})}function Gn(f){if(Array.isArray(f?.scorers))return f.scorers.filter(Pf);if(Array.isArray(f?.summary?.scorers))return f.summary.scorers.filter(Pf);if(Array.isArray(f?.artifact?.summary?.scorers))return f.artifact.summary.scorers.filter(Pf);return[]}function Kn(f){if(Pf(f?.run))return f.run;if(Pf(f?.runSummary))return f.runSummary;return null}function Nn(f,u){if(!Pf(f)&&!Pf(u))return null;if(!Pf(f))return u;if(!Pf(u))return f;return{...f,...u,request:Pf(f.request)||Pf(u.request)?{...Pf(f.request)?f.request:{},...Pf(u.request)?u.request:{}}:u.request??f.request,artifact:Pf(f.artifact)||Pf(u.artifact)?{...Pf(f.artifact)?f.artifact:{},...Pf(u.artifact)?u.artifact:{}}:u.artifact??f.artifact,summary:Pf(f.summary)||Pf(u.summary)?{...Pf(f.summary)?f.summary:{},...Pf(u.summary)?u.summary:{}}:u.summary??f.summary}}function ur(f){let u=Gn(f),l=u.find((U)=>Pf(U?.score))||u[0]||null,_=Pf(l?.score)?l.score:{},y=Number(_.passed),$=Number(_.total),r=Number(_.ratio),j=Number.isFinite(r)?r:Number.isFinite(y)&&Number.isFinite($)&&$>0?y/$:null,A=j===null?null:Math.round(Math.max(0,Math.min(100,j<=1?j*100:j))),J=String(_.text||(Number.isFinite(y)&&Number.isFinite($)?`${y}/${$}`:""));return{scorer:l,scorers:u,score:_,passed:Number.isFinite(y)?y:null,total:Number.isFinite($)?$:null,percent:A,text:J}}function FJ(f){let u=ur(f);return u.text||(u.scorers.length>0?String(u.scorer?.status||"pending"):"--")}function EJ(f){let u=ur(f);if(u.total>0&&u.passed===u.total)return"succeeded";if(u.total>0&&u.passed>0)return"running";if(u.scorers.length>0)return"failed";return"pending"}function Zn(f){return Array.isArray(f?.items)?f.items.filter(Pf):[]}function En({run:f}){let u=FJ(f);return V("span",{className:`pipeline-score-badge ${EJ(f)}`},`score ${u}`)}function Hn({run:f,onRaw:u}){let _=ur(f).scorers;if(!f)return V(jl,{title:"暂无评分",text:"选择一个 epoch 后会显示 scorer 结果。"});if(_.length===0)return V("div",{className:"pipeline-score-empty"},V("strong",null,"评分器等待中"),V("span",null,"DAG 完成后,Pipeline control backend 会把 scorer summary 追加到 run artifact,并通过 UniDesk 显示。"));return V("div",{className:"pipeline-score-board","data-testid":"pipeline-score-board"},_.map((y,$)=>{let r=ur({scorers:[y]}),j=Zn(y),A=r.percent??0;return V("article",{key:`${y.scorerId||y.component||$}`,className:`pipeline-score-card ${EJ({scorers:[y]})}`},V("div",{className:"pipeline-score-head"},V("div",null,V("span",null,y.scorerId||y.component||"scorer"),V("strong",null,r.text||y.status||"--")),V(P_,{status:y.status||"unknown"},y.status||"unknown")),V("div",{className:"pipeline-score-meter","aria-label":`score ${A}%`},V("span",{style:{width:`${A}%`}})),V("div",{className:"pipeline-score-facts"},V("span",null,`${A}%`),V("span",null,y.component||"--"),V("span",null,y.applicationCheckoutRef||"--")),j.length>0?V("div",{className:"pipeline-score-items"},j.map((J)=>V("span",{key:`${J.id||J.filter}`,className:`pipeline-score-item ${String(J.status||"").toLowerCase()}`,title:`${J.filter||"--"} / ran=${J.ran??"?"}`},V("b",null,J.id||"--"),V("small",null,J.status||"--")))):V("p",{className:"muted paragraph"},"当前 scorer 尚未返回 item 级结果。"),y.error?V("p",{className:"pipeline-score-error"},xE(y.error,360)):null,V("div",{className:"panel-actions inline-actions"},V(Il,{title:`Scorer ${y.scorerId||$}`,data:y,onOpen:u,testId:"raw-pipeline-score"})))}))}function On(f){let u=f.reduce((l,_)=>{let y=String(_?.componentClass||"unknown");return l[y]=(l[y]||0)+1,l},{});return Object.entries(u).map(([l,_])=>({name:l,count:Number(_)})).sort((l,_)=>_.count-l.count||l.name.localeCompare(_.name))}function H4(f){if(Array.isArray(f))return f.map((u)=>typeof u==="string"?u:String(u?.id||u?.nodeId||"")).filter(Boolean);if(Array.isArray(f?.nodes))return H4(f.nodes);if(Array.isArray(f?.nodeIds))return H4(f.nodeIds);return[]}function Vn(f){return Pf(f?.instanceInputs?.monitor)?f.instanceInputs.monitor:{}}function kE(f,u){if(String(f?.kind||"").toLowerCase()!=="procedure")return!1;let l=Vn(f);if(f?.instanceInputs?.monitorMode===!0||l.enabled===!0)return!0;let _=pE(f?.componentRef);return String(u?.id||u?.config?.id||_||"").toLowerCase().includes("monitor")}function qn(f){return f.filter((u)=>kE(u)).map((u)=>String(u?.id||"")).filter(Boolean)}function Ln(f,u){if(u.length===0)return f;let l=new Set(u),_=u.filter((y)=>f.includes(y));if(_.length===0)return f;return[..._,...f.filter((y)=>!l.has(y))]}function Xn(f,u){if(u.length===0)return f;let l=new Set(u),_=u.filter(($)=>f.some((r)=>r.includes($)));if(_.length===0)return f;let y=f.map(($)=>$.filter((r)=>!l.has(r))).filter(($)=>$.length>0);return[_,...y]}function Bn(f,u,l){let y=ZJ(f).map(H4).filter((W)=>W.length>0);if(y.length>0)return y;let $=u.map((W)=>String(W?.id||"")).filter(Boolean),r=new Set($),j=new Map($.map((W)=>[W,0])),A=new Map($.map((W)=>[W,[]]));for(let W of l){let G=String(W?.from||W?.source||""),K=String(W?.to||W?.target||"");if(!r.has(G)||!r.has(K))continue;A.get(G)?.push(K),j.set(K,(j.get(K)||0)+1)}let J=new Map,U=$.filter((W)=>(j.get(W)||0)===0);for(let W of U)J.set(W,0);while(U.length>0){let W=U.shift(),G=(J.get(W)||0)+1;for(let K of A.get(W)||[])if(j.set(K,Math.max(0,(j.get(K)||0)-1)),J.set(K,Math.max(J.get(K)||0,G)),(j.get(K)||0)===0)U.push(K)}$.forEach((W)=>{if(!J.has(W))J.set(W,0)});let Q=Math.max(0,...Array.from(J.values()));return Array.from({length:Q+1},(W,G)=>$.filter((K)=>J.get(K)===G)).filter((W)=>W.length>0)}function Yn(f,u,l){let y=ZJ(f).map(H4).filter((j)=>j.length>0),$=y.length>0?y.flatMap((j)=>j):(()=>{let j=u.map((H)=>String(H?.id||"")).filter(Boolean),A=new Set(j),J=l.filter((H)=>String(H?.edgeType||"").toLowerCase()!=="rework"),U=new Map(j.map((H)=>[H,0])),Q=new Map(j.map((H)=>[H,[]]));for(let H of J){let O=String(H?.from||H?.source||""),z=String(H?.to||H?.target||"");if(!A.has(O)||!A.has(z))continue;Q.get(O)?.push(z),U.set(z,(U.get(z)||0)+1)}let W=new Map,G=j.filter((H)=>(U.get(H)||0)===0);for(let H of G)W.set(H,0);while(G.length>0){let H=G.shift(),O=(W.get(H)||0)+1;for(let z of Q.get(H)||[])if(U.set(z,Math.max(0,(U.get(z)||0)-1)),W.set(z,Math.max(W.get(z)||0,O)),(U.get(z)||0)===0)G.push(z)}j.forEach((H)=>{if(!W.has(H))W.set(H,0)});let K=Math.max(0,...Array.from(W.values()));return Array.from({length:K+1},(H,O)=>j.filter((z)=>W.get(z)===O)).flatMap((H)=>H)})(),r=new Set($);for(let j of u){let A=String(j?.id||"");if(!A||r.has(A))continue;$.push(A),r.add(A)}return Ln($,qn(u))}function Q4(f){return`${f.source}->${f.target}-${f.index}`}function XE(f,u,l){let _=mE(f),y=NJ(f),$=Wn(l),r=new Map(_.map((S)=>[String(S?.id||""),S])),j=_.filter((S)=>kE(S,qE(S,$))).map((S)=>String(S?.id||"")).filter(Boolean),A=Xn(Bn(f,_,y),j),J=[],U=new Map,Q=330,W=122;A.forEach((S,T)=>{let i=S.length*122;S.forEach((C,v)=>{let X=r.get(C)||{id:C},D=qE(X,$),p=LE(u,C).toLowerCase(),m=String(X.kind||D?.componentClass||"node").toLowerCase(),s=pE(X.componentRef||D),d=String(D?.config?.version||D?.version||""),a=String(D?.config?.description||D?.description||""),I=v*122-Math.floor(i/2);U.set(C,{column:T,row:v,y:I}),J.push({id:C,type:"pipelineNode",position:{x:T*330,y:I},data:{exportLabel:{id:C,kind:m,componentRef:s,componentVersion:d,componentDescription:a,status:p},label:V("div",{className:"flow-node-label"},V("strong",null,C),V("span",null,m),V("code",{title:a||s},d?`${s}@${d}`:s),V(P_,{status:p},p))},className:`pipeline-flow-node ${m} ${p}`})})});let G=y.flatMap((S,T)=>{let i=String(S?.from||S?.source||""),C=String(S?.to||S?.target||"");if(!r.has(i)||!r.has(C))return[];return[{source:i,target:C,index:T,condition:S?.condition,edgeType:S?.edgeType}]}),K=G.reduce((S,T)=>S.set(T.source,(S.get(T.source)||0)+1),new Map),H=G.reduce((S,T)=>S.set(T.target,(S.get(T.target)||0)+1),new Map),O=G.reduce((S,T)=>{let i=`${T.source}->${T.target}`;return S.set(i,(S.get(i)||0)+1)},new Map),z=new Map,Z=new Map,N=new Map,E=new Map,q=new Map,Y=new Map,w=G.reduce((S,T)=>{let i=U.get(T.source),C=U.get(T.target),v=(C?.column||0)-(i?.column||0);if(v<=0||String(T.edgeType||"").toLowerCase()==="rework"||v!==1)return S;let D=`${T.source}->column:${C?.column??""}`,p=S.get(D)||[];return p.push(T),S.set(D,p),S},new Map);for(let S of w.values()){if(S.length<2)continue;S.slice().sort((T,i)=>{let C=U.get(T.target),v=U.get(i.target);return(C?.y||0)-(v?.y||0)||T.index-i.index}).forEach((T,i,C)=>{Y.set(Q4(T),{slot:i-(C.length-1)/2,count:C.length})})}[...G].sort((S,T)=>{let i=U.get(S.source),C=U.get(S.target),v=U.get(T.source),X=U.get(T.target),D=Math.abs((C?.column||0)-(i?.column||0))*330+Math.abs((C?.y||0)-(i?.y||0)),p=Math.abs((X?.column||0)-(v?.column||0))*330+Math.abs((X?.y||0)-(v?.y||0));return D-p||S.index-T.index}).forEach((S)=>{let T=U.get(S.source)||{column:0,row:0,y:0},i=U.get(S.target)||{column:0,row:0,y:0},C=i.column-T.column,v=Math.max(0,C),X=C<=0||String(S.edgeType||"").toLowerCase()==="rework",D=T.y-i.y,p=H.get(S.target)||1,m=Y.has(Q4(S)),s=!X&&v<=1&&(m||p===1),d=q.get(S.target)||new Map;q.set(S.target,d);let a=Z4.slice().sort((I,ff)=>{let yf=(Gf)=>{let c=String(Gf.side),o=0;if(X){if(c==="left")o+=86;if(c==="top")o+=i.y<=0?-22:12;if(c==="bottom")o+=i.y>=0?-22:12;if(Math.abs(i.y)<12&&c!=="left")o+=S.index%2===0?c==="top"?-6:6:c==="bottom"?-6:6;return o}if(s){if(c==="left")o-=m?72:44;if(c!=="left")o+=m?72:44;return o+Math.abs(D)*0.02}if(c==="left")o+=v<=1?0:24;if(c==="top")o+=D<-36?-18:42;if(c==="bottom")o+=D>36?-18:42;if(v<=1&&Math.abs(D)<=82&&c!=="left")o+=38;if(v>1&&c!=="left")o-=10;return o},rf=T.y-i.y,Wf=rf!==0?rf:S.index%2===0?-1:1,Ef=(Gf)=>{let c=d.get(Gf.id)||0;return yf(Gf)+c*64+mP(Gf,d,Wf)};return Ef(I)-Ef(ff)||String(I.id).localeCompare(String(ff.id))})[0];d.set(a.id,(d.get(a.id)||0)+1),E.set(Q4(S),a)});let P=G.map((S)=>{let T=LE(u,S.target).toLowerCase(),i=`${S.source}->${S.target}`,C=z.get(S.source)||0,v=Z.get(S.target)||0,X=N.get(i)||0;z.set(S.source,C+1),Z.set(S.target,v+1),N.set(i,X+1);let D=C-((K.get(S.source)||1)-1)/2,p=v-((H.get(S.target)||1)-1)/2,m=X-((O.get(i)||1)-1)/2,s=U.get(S.source),d=U.get(S.target),a=(d?.column||0)-(s?.column||0),I=Math.max(1,Math.abs(a)),ff=a<=0||String(S.edgeType||"").toLowerCase()==="rework",yf=Math.abs((d?.y||0)-(s?.y||0)),rf=Y.get(Q4(S)),Wf=!ff&&a===1&&(H.get(S.target)||0)>1,Ef=rf?rf.slot:m*2+D+p*0.45,Gf=Ef===0?S.index%2===0?-1:1:Math.sign(Ef),c=E.get(Q4(S))||Z4[1],o=c.side==="top"?-1:c.side==="bottom"?1:Gf,e=ff||I>1||yf>96||Math.abs(Ef)>0.2||c.side!=="left",Kf=ff?118+I*18:22+I*16,k=c.side==="left"?0:28,Af=e?Math.max(-280,Math.min(280,o*Math.min(180,Kf+k+yf*0.22)+Ef*28)):0,Yf=Math.max(0,Math.min(z4.length-1,Math.round(D+(z4.length-1)/2))),Bf=z4[Yf]||z4[1],df=T==="succeeded"?"var(--accent-2)":T==="running"?"var(--accent)":T==="failed"?"var(--danger)":"rgba(129, 147, 159, 0.78)",_0=s?.column||0,y0=d?.column||0,N0=Af===0?0:Math.sign(Af),a0=ff?`feedback:${_0}->${y0}:${N0}`:rf?`fanout:${_0}->${y0}:${S.source}`:Wf?`fanin:${_0}->${y0}:${S.target}`:c.side!=="left"||I>1?`corridor:${_0}->${y0}:${c.side}:${N0}:${Math.round(Math.abs(Af)/56)}`:"";return{id:`${S.source}->${S.target}-${S.index}`,source:S.source,target:S.target,sourceHandle:Bf.id,targetHandle:c.id,type:"pipelineCurve",zIndex:12,animated:T==="running",data:{baseEdgeColor:df,laneOffset:Af,routeMode:rf&&c.side==="left"?"direct-forward-left":"",targetSide:c.side,isFeedback:ff,overlapGroup:a0},targetStatus:T}}),h=P.reduce((S,T)=>{let i=String(T.data?.overlapGroup||"");return i?S.set(i,(S.get(i)||0)+1):S},new Map),M=new Map,n=P.map((S)=>{let T=String(S.targetStatus||"pending"),i={...S};delete i.targetStatus;let C=String(S.data?.overlapGroup||""),v=C?h.get(C)||0:0,X=v>1?M.get(C)||0:-1;if(v>1)M.set(C,X+1);let D=X>=0?QE[X%QE.length]:String(S.data.baseEdgeColor),p={stroke:D};if(S.data.isFeedback)p.strokeDasharray="9 7";return{...i,data:{...S.data,edgeColor:D,overlapSlot:X,overlapCount:v},style:p,markerEnd:{type:L_.ArrowClosed,color:D},className:`pipeline-flow-edge ${T} ${S.data.isFeedback?"feedback":""} ${X>=0?"overlap-colored":""}`}});return{nodes:J,edges:n}}function vu(f){return String(f??"").replace(/&/g,"&").replace(//g,">").replace(/"/g,""")}function BE(f){let u=String(f||"");if(u.includes("--accent-2"))return"#4eb7a8";if(u.includes("--accent"))return"#d7a13a";if(u.includes("--danger"))return"#cf6a54";return u.startsWith("#")?u:"#81939f"}function lr(f){return`arrow-${f.replace(/[^a-zA-Z0-9_-]+/g,"")}`}function tE(f,u="pipeline"){return String(f||u).replace(/[^a-zA-Z0-9_-]+/g,"-").replace(/^-|-$/g,"")||u}function YE(f,u){let l=f.position.x,_=f.position.y,y=Z4.find(($)=>$.id===u);if(y?.side==="top")return{x:l+d$*GE(y.style?.left,0.5),y:_,position:Zf.Top};if(y?.side==="bottom")return{x:l+d$*GE(y.style?.left,0.5),y:_+e$,position:Zf.Bottom};return{x:l,y:_+e$/2,position:Zf.Left}}function wn(f){return{x:f.position.x+d$,y:f.position.y+e$/2}}function Dn(f,u){let l=Math.min(...f.nodes.map((H)=>H.position.x),0)-220,_=Math.min(...f.nodes.map((H)=>H.position.y),0)-220,y=Math.max(...f.nodes.map((H)=>H.position.x+d$),1)+220,$=Math.max(...f.nodes.map((H)=>H.position.y+e$),1)+220,r=Math.ceil(y-l),j=Math.ceil($-_),A=new Map(f.nodes.map((H)=>[H.id,H])),J=f.edges.map((H)=>BE(H.data?.edgeColor||H.style?.stroke)),Q=Array.from(new Set(["#4eb7a8","#d7a13a","#cf6a54","#81939f",...J])).map((H)=>``).join(""),W=f.edges.flatMap((H)=>{let O=A.get(H.source),z=A.get(H.target);if(!O||!z)return[];let Z=wn(O),N=YE(z,String(H.targetHandle||"in-left")),E=iE(Z.x,Z.y,N.x,N.y,N.position,Number(H.data?.laneOffset||0),String(H.data?.routeMode||"")),q=BE(H.data?.edgeColor||H.style?.stroke),Y=H.data?.isFeedback?' stroke-dasharray="9 7"':"";return``}).join(` -`),G=f.nodes.map((H)=>{let O=H.data?.exportLabel||{},z=String(O.status||"pending").toLowerCase(),Z=z==="succeeded"?"#4eb7a8":z==="running"?"#d7a13a":z==="failed"?"#cf6a54":"#81939f",N=H.position.x,E=H.position.y,q=Z4.map((Y)=>{let w=YE(H,Y.id);if(Y.side==="top"||Y.side==="bottom")return``;return``}).join(` +`)),F=j.reduce((J,U)=>J.concat(...U),[]);return[j,F]}return[[],[]]},[u]);return iu.useEffect(()=>{let $=f?.target??QN,j=f?.actInsideInputWithModifier??!0;if(u!==null){let F=(q)=>{if(y.current=q.ctrlKey||q.metaKey||q.shiftKey||q.altKey,(!y.current||y.current&&!j)&&t7(q))return!1;let G=WN(q.code,n);if(i.current.add(q[G]),qN(_,i.current,!1)){let K=q.composedPath?.()?.[0]||q.target,Q=K?.nodeName==="BUTTON"||K?.nodeName==="A";if(f.preventDefault!==!1&&(y.current||!Q))q.preventDefault();r(!0)}},J=(q)=>{let W=WN(q.code,n);if(qN(_,i.current,!0))r(!1),i.current.clear();else i.current.delete(q[W]);if(q.key==="Meta")i.current.clear();y.current=!1},U=()=>{i.current.clear(),r(!1)};return $?.addEventListener("keydown",F),$?.addEventListener("keyup",J),window.addEventListener("blur",U),window.addEventListener("contextmenu",U),()=>{$?.removeEventListener("keydown",F),$?.removeEventListener("keyup",J),window.removeEventListener("blur",U),window.removeEventListener("contextmenu",U)}}},[u,r]),l}function qN(u,f,l){return u.filter((r)=>l||r.length===f.size).some((r)=>r.every((y)=>f.has(y)))}function WN(u,f){return f.includes(u)?"code":"key"}var UX=()=>{let u=Tf();return iu.useMemo(()=>{return{zoomIn:(f)=>{let{panZoom:l}=u.getState();return l?l.scaleBy(1.2,f):Promise.resolve(!1)},zoomOut:(f)=>{let{panZoom:l}=u.getState();return l?l.scaleBy(0.8333333333333334,f):Promise.resolve(!1)},zoomTo:(f,l)=>{let{panZoom:r}=u.getState();return r?r.scaleTo(f,l):Promise.resolve(!1)},getZoom:()=>u.getState().transform[2],setViewport:async(f,l)=>{let{transform:[r,y,i],panZoom:_}=u.getState();if(!_)return Promise.resolve(!1);return await _.setViewport({x:f.x??r,y:f.y??y,zoom:f.zoom??i},l),Promise.resolve(!0)},getViewport:()=>{let[f,l,r]=u.getState().transform;return{x:f,y:l,zoom:r}},setCenter:async(f,l,r)=>{return u.getState().setCenter(f,l,r)},fitBounds:async(f,l)=>{let{width:r,height:y,minZoom:i,maxZoom:_,panZoom:n}=u.getState(),$=j$(f,r,y,i,_,l?.padding??0.1);if(!n)return Promise.resolve(!1);return await n.setViewport($,{duration:l?.duration,ease:l?.ease,interpolate:l?.interpolate}),Promise.resolve(!0)},screenToFlowPosition:(f,l={})=>{let{transform:r,snapGrid:y,snapToGrid:i,domNode:_}=u.getState();if(!_)return f;let{x:n,y:$}=_.getBoundingClientRect(),j={x:f.x-n,y:f.y-$},F=l.snapGrid??y,J=l.snapToGrid??i;return vi(j,r,J,F)},flowToScreenPosition:(f)=>{let{transform:l,domNode:r}=u.getState();if(!r)return f;let{x:y,y:i}=r.getBoundingClientRect(),_=$$(f,l);return{x:_.x+y,y:_.y+i}}}},[])};function MN(u,f){let l=[],r=new Map,y=[];for(let i of u)if(i.type==="add"){y.push(i);continue}else if(i.type==="remove"||i.type==="replace")r.set(i.id,[i]);else{let _=r.get(i.id);if(_)_.push(i);else r.set(i.id,[i])}for(let i of f){let _=r.get(i.id);if(!_){l.push(i);continue}if(_[0].type==="remove")continue;if(_[0].type==="replace"){l.push({..._[0].item});continue}let n={...i};for(let $ of _)QX($,n);l.push(n)}if(y.length)y.forEach((i)=>{if(i.index!==void 0)l.splice(i.index,0,{...i.item});else l.push({...i.item})});return l}function QX(u,f){switch(u.type){case"select":{f.selected=u.selected;break}case"position":{if(typeof u.position<"u")f.position=u.position;if(typeof u.dragging<"u")f.dragging=u.dragging;break}case"dimensions":{if(typeof u.dimensions<"u"){if(f.measured={...u.dimensions},u.setAttributes){if(u.setAttributes===!0||u.setAttributes==="width")f.width=u.dimensions.width;if(u.setAttributes===!0||u.setAttributes==="height")f.height=u.dimensions.height}}if(typeof u.resizing==="boolean")f.resizing=u.resizing;break}}}function qX(u,f){return MN(u,f)}function WX(u,f){return MN(u,f)}function Ty(u,f){return{id:u,type:"select",selected:f}}function gi(u,f=new Set,l=!1){let r=[];for(let[y,i]of u){let _=f.has(y);if(!(i.selected===void 0&&!_)&&i.selected!==_){if(l)i.selected=_;r.push(Ty(i.id,_))}}return r}function cN({items:u=[],lookup:f}){let l=[],r=new Map(u.map((y)=>[y.id,y]));for(let[y,i]of u.entries()){let _=f.get(i.id),n=_?.internals?.userNode??_;if(n!==void 0&&n!==i)l.push({id:i.id,item:i,type:"replace"});if(n===void 0)l.push({item:i,type:"add",index:y})}for(let[y]of f)if(r.get(y)===void 0)l.push({id:y,type:"remove"});return l}function NN(u){return{id:u.id,type:"remove"}}var zN=(u)=>Kc(u),cX=(u)=>w7(u);function mN(u){return iu.forwardRef(u)}function GN(u){let[f,l]=iu.useState(BigInt(0)),[r]=iu.useState(()=>NX(()=>l((y)=>y+BigInt(1))));return k7(()=>{let y=r.get();if(y.length)u(y),r.reset()},[f]),r}function NX(u){let f=[];return{get:()=>f,reset:()=>{f=[]},push:(l)=>{f.push(l),u()}}}var pN=iu.createContext(null);function zX({children:u}){let f=Tf(),l=iu.useCallback((n)=>{let{nodes:$=[],setNodes:j,hasDefaultNodes:F,onNodesChange:J,nodeLookup:U,fitViewQueued:q,onNodesChangeMiddlewareMap:W}=f.getState(),G=$;for(let Q of n)G=typeof Q==="function"?Q(G):Q;let K=cN({items:G,lookup:U});for(let Q of W.values())K=Q(K);if(F)j(G);if(K.length>0)J?.(K);else if(q)window.requestAnimationFrame(()=>{let{fitViewQueued:Q,nodes:N,setNodes:c}=f.getState();if(Q)c(N)})},[]),r=GN(l),y=iu.useCallback((n)=>{let{edges:$=[],setEdges:j,hasDefaultEdges:F,onEdgesChange:J,edgeLookup:U}=f.getState(),q=$;for(let W of n)q=typeof W==="function"?W(q):W;if(F)j(q);else if(J)J(cN({items:q,lookup:U}))},[]),i=GN(y),_=iu.useMemo(()=>({nodeQueue:r,edgeQueue:i}),[]);return ru.jsx(pN.Provider,{value:_,children:u})}function GX(){let u=iu.useContext(pN);if(!u)throw Error("useBatchContext must be used within a BatchProvider");return u}var KX=(u)=>!!u.panZoom;function s7(){let u=UX(),f=Tf(),l=GX(),r=uf(KX),y=iu.useMemo(()=>{let i=(J)=>f.getState().nodeLookup.get(J),_=(J)=>{l.nodeQueue.push(J)},n=(J)=>{l.edgeQueue.push(J)},$=(J)=>{let{nodeLookup:U,nodeOrigin:q}=f.getState(),W=zN(J)?J:U.get(J.id),G=W.parentId?X7(W.position,W.measured,W.parentId,U,q):W.position,K={...W,position:G,width:W.measured?.width??W.width,height:W.measured?.height??W.height};return Ey(K)},j=(J,U,q={replace:!1})=>{_((W)=>W.map((G)=>{if(G.id===J){let K=typeof U==="function"?U(G):U;return q.replace&&zN(K)?K:{...G,...K}}return G}))},F=(J,U,q={replace:!1})=>{n((W)=>W.map((G)=>{if(G.id===J){let K=typeof U==="function"?U(G):U;return q.replace&&cX(K)?K:{...G,...K}}return G}))};return{getNodes:()=>f.getState().nodes.map((J)=>({...J})),getNode:(J)=>i(J)?.internals.userNode,getInternalNode:i,getEdges:()=>{let{edges:J=[]}=f.getState();return J.map((U)=>({...U}))},getEdge:(J)=>f.getState().edgeLookup.get(J),setNodes:_,setEdges:n,addNodes:(J)=>{let U=Array.isArray(J)?J:[J];l.nodeQueue.push((q)=>[...q,...U])},addEdges:(J)=>{let U=Array.isArray(J)?J:[J];l.edgeQueue.push((q)=>[...q,...U])},toObject:()=>{let{nodes:J=[],edges:U=[],transform:q}=f.getState(),[W,G,K]=q;return{nodes:J.map((Q)=>({...Q})),edges:U.map((Q)=>({...Q})),viewport:{x:W,y:G,zoom:K}}},deleteElements:async({nodes:J=[],edges:U=[]})=>{let{nodes:q,edges:W,onNodesDelete:G,onEdgesDelete:K,triggerNodeChanges:Q,triggerEdgeChanges:N,onDelete:c,onBeforeDelete:z}=f.getState(),{nodes:w,edges:H}=await Ec({nodesToRemove:J,edgesToRemove:U,nodes:q,edges:W,onBeforeDelete:z}),B=H.length>0,T=w.length>0;if(B){let X=H.map(NN);K?.(H),N(X)}if(T){let X=w.map(NN);G?.(w),Q(X)}if(T||B)c?.({nodes:w,edges:H});return{deletedNodes:w,deletedEdges:H}},getIntersectingNodes:(J,U=!0,q)=>{let W=O7(J),G=W?J:$(J),K=q!==void 0;if(!G)return[];return(q||f.getState().nodes).filter((Q)=>{let N=f.getState().nodeLookup.get(Q.id);if(N&&!W&&(Q.id===J.id||!N.internals.positionAbsolute))return!1;let c=Ey(K?Q:N),z=hi(c,G);return U&&z>0||z>=c.width*c.height||z>=G.width*G.height})},isNodeIntersecting:(J,U,q=!0)=>{let G=O7(J)?J:$(J);if(!G)return!1;let K=hi(G,U);return q&&K>0||K>=U.width*U.height||K>=G.width*G.height},updateNode:j,updateNodeData:(J,U,q={replace:!1})=>{j(J,(W)=>{let G=typeof U==="function"?U(W):U;return q.replace?{...W,data:G}:{...W,data:{...W.data,...G}}},q)},updateEdge:F,updateEdgeData:(J,U,q={replace:!1})=>{F(J,(W)=>{let G=typeof U==="function"?U(W):U;return q.replace?{...W,data:G}:{...W,data:{...W.data,...G}}},q)},getNodesBounds:(J)=>{let{nodeLookup:U,nodeOrigin:q}=f.getState();return T7(J,{nodeLookup:U,nodeOrigin:q})},getHandleConnections:({type:J,id:U,nodeId:q})=>Array.from(f.getState().connectionLookup.get(`${q}-${J}${U?`-${U}`:""}`)?.values()??[]),getNodeConnections:({type:J,handleId:U,nodeId:q})=>Array.from(f.getState().connectionLookup.get(`${q}${J?U?`-${J}-${U}`:`-${J}`:""}`)?.values()??[]),fitView:async(J)=>{let U=f.getState().fitViewResolver??Hc();return f.setState({fitViewQueued:!0,fitViewOptions:J,fitViewResolver:U}),l.nodeQueue.push((q)=>[...q]),U.promise}}},[]);return iu.useMemo(()=>{return{...y,...u,viewportInitialized:r}},[r])}var KN=(u)=>u.selected,LX=typeof window<"u"?window:void 0;function wX({deleteKeyCode:u,multiSelectionKeyCode:f}){let l=Tf(),{deleteElements:r}=s7(),y=J$(u,{actInsideInputWithModifier:!1}),i=J$(f,{target:LX});iu.useEffect(()=>{if(y){let{edges:_,nodes:n}=l.getState();r({nodes:n.filter(KN),edges:_.filter(KN)}),l.setState({nodesSelectionActive:!1})}},[y]),iu.useEffect(()=>{l.setState({multiSelectionActive:i})},[i])}function EX(u){let f=Tf();iu.useEffect(()=>{let l=()=>{if(!u.current||!(u.current.checkVisibility?.()??!0))return!1;let r=Y4(u.current);if(r.height===0||r.width===0)f.getState().onError?.("004",_r.error004());f.setState({width:r.width||500,height:r.height||500})};if(u.current){l(),window.addEventListener("resize",l);let r=new ResizeObserver(()=>l());return r.observe(u.current),()=>{if(window.removeEventListener("resize",l),r&&u.current)r.unobserve(u.current)}}},[])}var k4={position:"absolute",width:"100%",height:"100%",top:0,left:0},TX=(u)=>({userSelectionActive:u.userSelectionActive,lib:u.lib,connectionInProgress:u.connection.inProgress});function ZX({onPaneContextMenu:u,zoomOnScroll:f=!0,zoomOnPinch:l=!0,panOnScroll:r=!1,panOnScrollSpeed:y=0.5,panOnScrollMode:i=D0.Free,zoomOnDoubleClick:_=!0,panOnDrag:n=!0,defaultViewport:$,translateExtent:j,minZoom:F,maxZoom:J,zoomActivationKeyCode:U,preventScrolling:q=!0,children:W,noWheelClassName:G,noPanClassName:K,onViewportChange:Q,isControlledViewport:N,paneClickDistance:c,selectionOnDrag:z}){let w=Tf(),H=iu.useRef(null),{userSelectionActive:B,lib:T,connectionInProgress:X}=uf(TX,Kf),R=J$(U),Y=iu.useRef();EX(H);let P=iu.useCallback((t)=>{if(Q?.({x:t[0],y:t[1],zoom:t[2]}),!N)w.setState({transform:t})},[Q,N]);return iu.useEffect(()=>{if(H.current){Y.current=kc({domNode:H.current,minZoom:F,maxZoom:J,translateExtent:j,viewport:$,onDraggingChange:(S)=>w.setState((b)=>b.paneDragging===S?b:{paneDragging:S}),onPanZoomStart:(S,b)=>{let{onViewportChangeStart:Z,onMoveStart:D}=w.getState();D?.(S,b),Z?.(b)},onPanZoom:(S,b)=>{let{onViewportChange:Z,onMove:D}=w.getState();D?.(S,b),Z?.(b)},onPanZoomEnd:(S,b)=>{let{onViewportChangeEnd:Z,onMoveEnd:D}=w.getState();D?.(S,b),Z?.(b)}});let{x:t,y:O,zoom:M}=Y.current.getViewport();return w.setState({panZoom:Y.current,transform:[t,O,M],domNode:H.current.closest(".react-flow")}),()=>{Y.current?.destroy()}}},[]),iu.useEffect(()=>{Y.current?.update({onPaneContextMenu:u,zoomOnScroll:f,zoomOnPinch:l,panOnScroll:r,panOnScrollSpeed:y,panOnScrollMode:i,zoomOnDoubleClick:_,panOnDrag:n,zoomActivationKeyPressed:R,preventScrolling:q,noPanClassName:K,userSelectionActive:B,noWheelClassName:G,lib:T,onTransformChange:P,connectionInProgress:X,selectionOnDrag:z,paneClickDistance:c})},[u,f,l,r,y,i,_,n,R,q,K,B,G,T,P,X,z,c]),ru.jsx("div",{className:"react-flow__renderer",ref:H,style:k4,children:W})}var HX=(u)=>({userSelectionActive:u.userSelectionActive,userSelectionRect:u.userSelectionRect});function OX(){let{userSelectionActive:u,userSelectionRect:f}=uf(HX,Kf);if(!(u&&f))return null;return ru.jsx("div",{className:"react-flow__selection react-flow__container",style:{width:f.width,height:f.height,transform:`translate(${f.x}px, ${f.y}px)`}})}var v7=(u,f)=>{return(l)=>{if(l.target!==f.current)return;u?.(l)}},BX=(u)=>({userSelectionActive:u.userSelectionActive,elementsSelectable:u.elementsSelectable,connectionInProgress:u.connection.inProgress,dragging:u.paneDragging});function VX({isSelecting:u,selectionKeyPressed:f,selectionMode:l=Ly.Full,panOnDrag:r,paneClickDistance:y,selectionOnDrag:i,onSelectionStart:_,onSelectionEnd:n,onPaneClick:$,onPaneContextMenu:j,onPaneScroll:F,onPaneMouseEnter:J,onPaneMouseMove:U,onPaneMouseLeave:q,children:W}){let G=Tf(),{userSelectionActive:K,elementsSelectable:Q,dragging:N,connectionInProgress:c}=uf(BX,Kf),z=Q&&(u||K),w=iu.useRef(null),H=iu.useRef(),B=iu.useRef(new Set),T=iu.useRef(new Set),X=iu.useRef(!1),R=(Z)=>{if(X.current||c){X.current=!1;return}$?.(Z),G.getState().resetSelectedElements(),G.setState({nodesSelectionActive:!1})},Y=(Z)=>{if(Array.isArray(r)&&r?.includes(2)){Z.preventDefault();return}j?.(Z)},P=F?(Z)=>F(Z):void 0,t=(Z)=>{if(X.current)Z.stopPropagation(),X.current=!1},O=(Z)=>{let{domNode:D}=G.getState();if(H.current=D?.getBoundingClientRect(),!H.current)return;let I=Z.target===w.current;if(!I&&!!Z.target.closest(".nokey")||!u||!(i&&I||f)||Z.button!==0||!Z.isPrimary)return;Z.target?.setPointerCapture?.(Z.pointerId),X.current=!1;let{x:o,y:s}=Lr(Z.nativeEvent,H.current);if(G.setState({userSelectionRect:{width:0,height:0,startX:o,startY:s,x:o,y:s}}),!I)Z.stopPropagation(),Z.preventDefault()},M=(Z)=>{let{userSelectionRect:D,transform:I,nodeLookup:k,edgeLookup:h,connectionLookup:o,triggerNodeChanges:s,triggerEdgeChanges:x,defaultEdgeOptions:uu,resetSelectedElements:nu}=G.getState();if(!H.current||!D)return;let{x:$u,y:Fu}=Lr(Z.nativeEvent,H.current),{startX:Ku,startY:Wu}=D;if(!X.current){let g=f?0:y;if(Math.hypot($u-Ku,Fu-Wu)<=g)return;nu(),_?.(Z)}X.current=!0;let m={startX:Ku,startY:Wu,x:$ug.id)),T.current=new Set;let cu=uu?.selectable??!0;for(let g of B.current){let Qu=o.get(g);if(!Qu)continue;for(let{edgeId:Eu}of Qu.values()){let Tu=h.get(Eu);if(Tu&&(Tu.selectable??cu))T.current.add(Eu)}}if(!Y7(d,B.current)){let g=gi(k,B.current,!0);s(g)}if(!Y7(e,T.current)){let g=gi(h,T.current);x(g)}G.setState({userSelectionRect:m,userSelectionActive:!0,nodesSelectionActive:!1})},S=(Z)=>{if(Z.button!==0)return;if(Z.target?.releasePointerCapture?.(Z.pointerId),!K&&Z.target===w.current&&G.getState().userSelectionRect)R?.(Z);if(G.setState({userSelectionActive:!1,userSelectionRect:null}),X.current)n?.(Z),G.setState({nodesSelectionActive:B.current.size>0})},b=r===!0||Array.isArray(r)&&r.includes(0);return ru.jsxs("div",{className:Yf(["react-flow__pane",{draggable:b,dragging:N,selection:u}]),onClick:z?void 0:v7(R,w),onContextMenu:v7(Y,w),onWheel:v7(P,w),onPointerEnter:z?void 0:J,onPointerMove:z?M:U,onPointerUp:z?S:void 0,onPointerDownCapture:z?O:void 0,onClickCapture:z?t:void 0,onPointerLeave:q,ref:w,style:k4,children:[W,ru.jsx(OX,{})]})}function g7({id:u,store:f,unselect:l=!1,nodeRef:r}){let{addSelectedNodes:y,unselectNodesAndEdges:i,multiSelectionActive:_,nodeLookup:n,onError:$}=f.getState(),j=n.get(u);if(!j){$?.("012",_r.error012(u));return}if(f.setState({nodesSelectionActive:!1}),!j.selected)y([u]);else if(l||j.selected&&_)i({nodes:[j],edges:[]}),requestAnimationFrame(()=>r?.current?.blur())}function CN({nodeRef:u,disabled:f=!1,noDragClassName:l,handleSelector:r,nodeId:y,isSelectable:i,nodeClickDistance:_}){let n=Tf(),[$,j]=iu.useState(!1),F=iu.useRef();return iu.useEffect(()=>{F.current=pc({getStoreItems:()=>n.getState(),onNodeMouseDown:(J)=>{g7({id:J,store:n,nodeRef:u})},onDragStart:()=>{j(!0)},onDragStop:()=>{j(!1)}})},[]),iu.useEffect(()=>{if(f||!u.current||!F.current)return;return F.current.update({noDragClassName:l,handleSelector:r,domNode:u.current,isSelectable:i,nodeId:y,nodeClickDistance:_}),()=>{F.current?.destroy()}},[l,r,f,i,u,y,_]),$}var XX=(u)=>(f)=>f.selected&&(f.draggable||u&&typeof f.draggable>"u");function xN(){let u=Tf();return iu.useCallback((l)=>{let{nodeExtent:r,snapToGrid:y,snapGrid:i,nodesDraggable:_,onError:n,updateNodePositions:$,nodeLookup:j,nodeOrigin:F}=u.getState(),J=new Map,U=XX(_),q=y?i[0]:5,W=y?i[1]:5,G=l.direction.x*q*l.factor,K=l.direction.y*W*l.factor;for(let[,Q]of j){if(!U(Q))continue;let N={x:Q.internals.positionAbsolute.x+G,y:Q.internals.positionAbsolute.y+K};if(y)N=bi(N,i);let{position:c,positionAbsolute:z}=Z7({nodeId:Q.id,nextPosition:N,nodeLookup:j,nodeExtent:r,nodeOrigin:F,onError:n});Q.position=c,Q.internals.positionAbsolute=z,J.set(Q.id,Q)}$(J)},[])}var a7=iu.createContext(null),YX=a7.Provider;a7.Consumer;var RN=()=>{return iu.useContext(a7)},DX=(u)=>({connectOnClick:u.connectOnClick,noPanClassName:u.noPanClassName,rfId:u.rfId}),tX=(u,f,l)=>(r)=>{let{connectionClickStartHandle:y,connectionMode:i,connection:_}=r,{fromHandle:n,toHandle:$,isValid:j}=_,F=$?.nodeId===u&&$?.id===f&&$?.type===l;return{connectingFrom:n?.nodeId===u&&n?.id===f&&n?.type===l,connectingTo:F,clickConnecting:y?.nodeId===u&&y?.id===f&&y?.type===l,isPossibleEndHandle:i===E1.Strict?n?.type!==l:u!==n?.nodeId||f!==n?.id,connectionInProcess:!!n,clickConnectionInProcess:!!y,valid:F&&j}};function SX({type:u="source",position:f=zu.Top,isValidConnection:l,isConnectable:r=!0,isConnectableStart:y=!0,isConnectableEnd:i=!0,id:_,onConnect:n,children:$,className:j,onMouseDown:F,onTouchStart:J,...U},q){let W=_||null,G=u==="target",K=Tf(),Q=RN(),{connectOnClick:N,noPanClassName:c,rfId:z}=uf(DX,Kf),{connectingFrom:w,connectingTo:H,clickConnecting:B,isPossibleEndHandle:T,connectionInProcess:X,clickConnectionInProcess:R,valid:Y}=uf(tX(Q,W,u),Kf);if(!Q)K.getState().onError?.("010",_r.error010());let P=(M)=>{let{defaultEdgeOptions:S,onConnect:b,hasDefaultEdges:Z}=K.getState(),D={...S,...M};if(Z){let{edges:I,setEdges:k}=K.getState();k(M7(D,I))}b?.(D),n?.(D)},t=(M)=>{if(!Q)return;let S=S7(M.nativeEvent);if(y&&(S&&M.button===0||!S)){let b=K.getState();p4.onPointerDown(M.nativeEvent,{handleDomNode:M.currentTarget,autoPanOnConnect:b.autoPanOnConnect,connectionMode:b.connectionMode,connectionRadius:b.connectionRadius,domNode:b.domNode,nodeLookup:b.nodeLookup,lib:b.lib,isTarget:G,handleId:W,nodeId:Q,flowId:b.rfId,panBy:b.panBy,cancelConnection:b.cancelConnection,onConnectStart:b.onConnectStart,onConnectEnd:(...Z)=>K.getState().onConnectEnd?.(...Z),updateConnection:b.updateConnection,onConnect:P,isValidConnection:l||((...Z)=>K.getState().isValidConnection?.(...Z)??!0),getTransform:()=>K.getState().transform,getFromHandle:()=>K.getState().connection.fromHandle,autoPanSpeed:b.autoPanSpeed,dragThreshold:b.connectionDragThreshold})}if(S)F?.(M);else J?.(M)},O=(M)=>{let{onClickConnectStart:S,onClickConnectEnd:b,connectionClickStartHandle:Z,connectionMode:D,isValidConnection:I,lib:k,rfId:h,nodeLookup:o,connection:s}=K.getState();if(!Q||!Z&&!y)return;if(!Z){S?.(M.nativeEvent,{nodeId:Q,handleId:W,handleType:u}),K.setState({connectionClickStartHandle:{nodeId:Q,type:u,id:W}});return}let x=D7(M.target),uu=l||I,{connection:nu,isValid:$u}=p4.isValid(M.nativeEvent,{handle:{nodeId:Q,id:W,type:u},connectionMode:D,fromNodeId:Z.nodeId,fromHandleId:Z.id||null,fromType:Z.type,isValidConnection:uu,flowId:h,doc:x,lib:k,nodeLookup:o});if($u&&nu)P(nu);let Fu=structuredClone(s);delete Fu.inProgress,Fu.toPosition=Fu.toHandle?Fu.toHandle.position:null,b?.(M,Fu),K.setState({connectionClickStartHandle:null})};return ru.jsx("div",{"data-handleid":W,"data-nodeid":Q,"data-handlepos":f,"data-id":`${z}-${Q}-${W}-${u}`,className:Yf(["react-flow__handle",`react-flow__handle-${f}`,"nodrag",c,j,{source:!G,target:G,connectable:r,connectablestart:y,connectableend:i,clickconnecting:B,connectingfrom:w,connectingto:H,valid:Y,connectionindicator:r&&(!X||T)&&(X||R?i:y)}]),onMouseDown:t,onTouchStart:t,onClick:N?O:void 0,ref:q,...U,children:$})}var Zy=iu.memo(mN(SX));function PX({data:u,isConnectable:f,sourcePosition:l=zu.Bottom}){return ru.jsxs(ru.Fragment,{children:[u?.label,ru.jsx(Zy,{type:"source",position:l,isConnectable:f})]})}function MX({data:u,isConnectable:f,targetPosition:l=zu.Top,sourcePosition:r=zu.Bottom}){return ru.jsxs(ru.Fragment,{children:[ru.jsx(Zy,{type:"target",position:l,isConnectable:f}),u?.label,ru.jsx(Zy,{type:"source",position:r,isConnectable:f})]})}function mX(){return null}function pX({data:u,isConnectable:f,targetPosition:l=zu.Top}){return ru.jsxs(ru.Fragment,{children:[ru.jsx(Zy,{type:"target",position:l,isConnectable:f}),u?.label]})}var b4={ArrowUp:{x:0,y:-1},ArrowDown:{x:0,y:1},ArrowLeft:{x:-1,y:0},ArrowRight:{x:1,y:0}},LN={input:PX,default:MX,output:pX,group:mX};function CX(u){if(u.internals.handleBounds===void 0)return{width:u.width??u.initialWidth??u.style?.width,height:u.height??u.initialHeight??u.style?.height};return{width:u.width??u.style?.width,height:u.height??u.style?.height}}var xX=(u)=>{let{width:f,height:l,x:r,y}=Ri(u.nodeLookup,{filter:(i)=>!!i.selected});return{width:Kr(f)?f:null,height:Kr(l)?l:null,userSelectionActive:u.userSelectionActive,transformString:`translate(${u.transform[0]}px,${u.transform[1]}px) scale(${u.transform[2]}) translate(${r}px,${y}px)`}};function RX({onSelectionContextMenu:u,noPanClassName:f,disableKeyboardA11y:l}){let r=Tf(),{width:y,height:i,transformString:_,userSelectionActive:n}=uf(xX,Kf),$=xN(),j=iu.useRef(null);iu.useEffect(()=>{if(!l)j.current?.focus({preventScroll:!0})},[l]);let F=!n&&y!==null&&i!==null;if(CN({nodeRef:j,disabled:!F}),!F)return null;let J=u?(q)=>{let W=r.getState().nodes.filter((G)=>G.selected);u(q,W)}:void 0,U=(q)=>{if(Object.prototype.hasOwnProperty.call(b4,q.key))q.preventDefault(),$({direction:b4[q.key],factor:q.shiftKey?4:1})};return ru.jsx("div",{className:Yf(["react-flow__nodesselection","react-flow__container",f]),style:{transform:_},children:ru.jsx("div",{ref:j,className:"react-flow__nodesselection-rect",onContextMenu:J,tabIndex:l?void 0:-1,onKeyDown:l?void 0:U,style:{width:y,height:i}})})}var wN=typeof window<"u"?window:void 0,hX=(u)=>{return{nodesSelectionActive:u.nodesSelectionActive,userSelectionActive:u.userSelectionActive}};function hN({children:u,onPaneClick:f,onPaneMouseEnter:l,onPaneMouseMove:r,onPaneMouseLeave:y,onPaneContextMenu:i,onPaneScroll:_,paneClickDistance:n,deleteKeyCode:$,selectionKeyCode:j,selectionOnDrag:F,selectionMode:J,onSelectionStart:U,onSelectionEnd:q,multiSelectionKeyCode:W,panActivationKeyCode:G,zoomActivationKeyCode:K,elementsSelectable:Q,zoomOnScroll:N,zoomOnPinch:c,panOnScroll:z,panOnScrollSpeed:w,panOnScrollMode:H,zoomOnDoubleClick:B,panOnDrag:T,defaultViewport:X,translateExtent:R,minZoom:Y,maxZoom:P,preventScrolling:t,onSelectionContextMenu:O,noWheelClassName:M,noPanClassName:S,disableKeyboardA11y:b,onViewportChange:Z,isControlledViewport:D}){let{nodesSelectionActive:I,userSelectionActive:k}=uf(hX,Kf),h=J$(j,{target:wN}),o=J$(G,{target:wN}),s=o||T,x=o||z,uu=F&&s!==!0,nu=h||k||uu;return wX({deleteKeyCode:$,multiSelectionKeyCode:W}),ru.jsx(ZX,{onPaneContextMenu:i,elementsSelectable:Q,zoomOnScroll:N,zoomOnPinch:c,panOnScroll:x,panOnScrollSpeed:w,panOnScrollMode:H,zoomOnDoubleClick:B,panOnDrag:!h&&s,defaultViewport:X,translateExtent:R,minZoom:Y,maxZoom:P,zoomActivationKeyCode:K,preventScrolling:t,noWheelClassName:M,noPanClassName:S,onViewportChange:Z,isControlledViewport:D,paneClickDistance:n,selectionOnDrag:uu,children:ru.jsxs(VX,{onSelectionStart:U,onSelectionEnd:q,onPaneClick:f,onPaneMouseEnter:l,onPaneMouseMove:r,onPaneMouseLeave:y,onPaneContextMenu:i,onPaneScroll:_,panOnDrag:s,isSelecting:!!nu,selectionMode:J,selectionKeyPressed:h,paneClickDistance:n,selectionOnDrag:uu,children:[u,I&&ru.jsx(RX,{onSelectionContextMenu:O,noPanClassName:S,disableKeyboardA11y:b})]})})}hN.displayName="FlowRenderer";var bX=iu.memo(hN),vX=(u)=>(f)=>{return u?B4(f.nodeLookup,{x:0,y:0,width:f.width,height:f.height},f.transform,!0).map((l)=>l.id):Array.from(f.nodeLookup.keys())};function IX(u){return uf(iu.useCallback(vX(u),[u]),Kf)}var kX=(u)=>u.updateNodeInternals;function gX(){let u=uf(kX),[f]=iu.useState(()=>{if(typeof ResizeObserver>"u")return null;return new ResizeObserver((l)=>{let r=new Map;l.forEach((y)=>{let i=y.target.getAttribute("data-id");r.set(i,{id:i,nodeElement:y.target,force:!0})}),u(r)})});return iu.useEffect(()=>{return()=>{f?.disconnect()}},[f]),f}function sX({node:u,nodeType:f,hasDimensions:l,resizeObserver:r}){let y=Tf(),i=iu.useRef(null),_=iu.useRef(null),n=iu.useRef(u.sourcePosition),$=iu.useRef(u.targetPosition),j=iu.useRef(f),F=l&&!!u.internals.handleBounds;return iu.useEffect(()=>{if(i.current&&!u.hidden&&(!F||_.current!==i.current)){if(_.current)r?.unobserve(_.current);r?.observe(i.current),_.current=i.current}},[F,u.hidden]),iu.useEffect(()=>{return()=>{if(_.current)r?.unobserve(_.current),_.current=null}},[]),iu.useEffect(()=>{if(i.current){let J=j.current!==f,U=n.current!==u.sourcePosition,q=$.current!==u.targetPosition;if(J||U||q)j.current=f,n.current=u.sourcePosition,$.current=u.targetPosition,y.getState().updateNodeInternals(new Map([[u.id,{id:u.id,nodeElement:i.current,force:!0}]]))}},[u.id,f,u.sourcePosition,u.targetPosition]),i}function aX({id:u,onClick:f,onMouseEnter:l,onMouseMove:r,onMouseLeave:y,onContextMenu:i,onDoubleClick:_,nodesDraggable:n,elementsSelectable:$,nodesConnectable:j,nodesFocusable:F,resizeObserver:J,noDragClassName:U,noPanClassName:q,disableKeyboardA11y:W,rfId:G,nodeTypes:K,nodeClickDistance:Q,onError:N}){let{node:c,internals:z,isParent:w}=uf(($u)=>{let Fu=$u.nodeLookup.get(u),Ku=$u.parentLookup.has(u);return{node:Fu,internals:Fu.internals,isParent:Ku}},Kf),H=c.type||"default",B=K?.[H]||LN[H];if(B===void 0)N?.("003",_r.error003(H)),H="default",B=K?.default||LN.default;let T=!!(c.draggable||n&&typeof c.draggable>"u"),X=!!(c.selectable||$&&typeof c.selectable>"u"),R=!!(c.connectable||j&&typeof c.connectable>"u"),Y=!!(c.focusable||F&&typeof c.focusable>"u"),P=Tf(),t=V7(c),O=sX({node:c,nodeType:H,hasDimensions:t,resizeObserver:J}),M=CN({nodeRef:O,disabled:c.hidden||!T,noDragClassName:U,handleSelector:c.dragHandle,nodeId:u,isSelectable:X,nodeClickDistance:Q}),S=xN();if(c.hidden)return null;let b=i0(c),Z=CX(c),D=X||T||f||l||r||y,I=l?($u)=>l($u,{...z.userNode}):void 0,k=r?($u)=>r($u,{...z.userNode}):void 0,h=y?($u)=>y($u,{...z.userNode}):void 0,o=i?($u)=>i($u,{...z.userNode}):void 0,s=_?($u)=>_($u,{...z.userNode}):void 0,x=($u)=>{let{selectNodesOnDrag:Fu,nodeDragThreshold:Ku}=P.getState();if(X&&(!Fu||!T||Ku>0))g7({id:u,store:P,nodeRef:O});if(f)f($u,{...z.userNode})},uu=($u)=>{if(t7($u.nativeEvent)||W)return;if(z7.includes($u.key)&&X){let Fu=$u.key==="Escape";g7({id:u,store:P,unselect:Fu,nodeRef:O})}else if(T&&c.selected&&Object.prototype.hasOwnProperty.call(b4,$u.key)){$u.preventDefault();let{ariaLabelConfig:Fu}=P.getState();P.setState({ariaLiveMessage:Fu["node.a11yDescription.ariaLiveMessage"]({direction:$u.key.replace("Arrow","").toLowerCase(),x:~~z.positionAbsolute.x,y:~~z.positionAbsolute.y})}),S({direction:b4[$u.key],factor:$u.shiftKey?4:1})}},nu=()=>{if(W||!O.current?.matches(":focus-visible"))return;let{transform:$u,width:Fu,height:Ku,autoPanOnNodeFocus:Wu,setCenter:m}=P.getState();if(!Wu)return;if(!(B4(new Map([[u,c]]),{x:0,y:0,width:Fu,height:Ku},$u,!0).length>0))m(c.position.x+b.width/2,c.position.y+b.height/2,{zoom:$u[2]})};return ru.jsx("div",{className:Yf(["react-flow__node",`react-flow__node-${H}`,{[q]:T},c.className,{selected:c.selected,selectable:X,parent:w,draggable:T,dragging:M}]),ref:O,style:{zIndex:z.z,transform:`translate(${z.positionAbsolute.x}px,${z.positionAbsolute.y}px)`,pointerEvents:D?"all":"none",visibility:t?"visible":"hidden",...c.style,...Z},"data-id":u,"data-testid":`rf__node-${u}`,onMouseEnter:I,onMouseMove:k,onMouseLeave:h,onContextMenu:o,onClick:x,onDoubleClick:s,onKeyDown:Y?uu:void 0,tabIndex:Y?0:void 0,onFocus:Y?nu:void 0,role:c.ariaRole??(Y?"group":void 0),"aria-roledescription":"node","aria-describedby":W?void 0:`${tN}-${G}`,"aria-label":c.ariaLabel,...c.domAttributes,children:ru.jsx(YX,{value:u,children:ru.jsx(B,{id:u,data:c.data,type:H,positionAbsoluteX:z.positionAbsolute.x,positionAbsoluteY:z.positionAbsolute.y,selected:c.selected??!1,selectable:X,draggable:T,deletable:c.deletable??!0,isConnectable:R,sourcePosition:c.sourcePosition,targetPosition:c.targetPosition,dragging:M,dragHandle:c.dragHandle,zIndex:z.z,parentId:c.parentId,...b})})})}var oX=iu.memo(aX),dX=(u)=>({nodesDraggable:u.nodesDraggable,nodesConnectable:u.nodesConnectable,nodesFocusable:u.nodesFocusable,elementsSelectable:u.elementsSelectable,onError:u.onError});function bN(u){let{nodesDraggable:f,nodesConnectable:l,nodesFocusable:r,elementsSelectable:y,onError:i}=uf(dX,Kf),_=IX(u.onlyRenderVisibleElements),n=gX();return ru.jsx("div",{className:"react-flow__nodes",style:k4,children:_.map(($)=>{return ru.jsx(oX,{id:$,nodeTypes:u.nodeTypes,nodeExtent:u.nodeExtent,onClick:u.onNodeClick,onMouseEnter:u.onNodeMouseEnter,onMouseMove:u.onNodeMouseMove,onMouseLeave:u.onNodeMouseLeave,onContextMenu:u.onNodeContextMenu,onDoubleClick:u.onNodeDoubleClick,noDragClassName:u.noDragClassName,noPanClassName:u.noPanClassName,rfId:u.rfId,disableKeyboardA11y:u.disableKeyboardA11y,resizeObserver:n,nodesDraggable:f,nodesConnectable:l,nodesFocusable:r,elementsSelectable:y,nodeClickDistance:u.nodeClickDistance,onError:i},$)})})}bN.displayName="NodeRenderer";var eX=iu.memo(bN);function uY(u){return uf(iu.useCallback((l)=>{if(!u)return l.edges.map((y)=>y.id);let r=[];if(l.width&&l.height)for(let y of l.edges){let i=l.nodeLookup.get(y.source),_=l.nodeLookup.get(y.target);if(i&&_&&Vc({sourceNode:i,targetNode:_,width:l.width,height:l.height,transform:l.transform}))r.push(y.id)}return r},[u]),Kf)}var fY=({color:u="none",strokeWidth:f=1})=>{let l={strokeWidth:f,...u&&{stroke:u}};return ru.jsx("polyline",{className:"arrow",style:l,strokeLinecap:"round",fill:"none",strokeLinejoin:"round",points:"-5,-4 0,0 -5,4"})},lY=({color:u="none",strokeWidth:f=1})=>{let l={strokeWidth:f,...u&&{stroke:u,fill:u}};return ru.jsx("polyline",{className:"arrowclosed",style:l,strokeLinecap:"round",strokeLinejoin:"round",points:"-5,-4 0,0 -5,4 -5,-4"})},EN={[T1.Arrow]:fY,[T1.ArrowClosed]:lY};function rY(u){let f=Tf();return iu.useMemo(()=>{if(!Object.prototype.hasOwnProperty.call(EN,u))return f.getState().onError?.("009",_r.error009(u)),null;return EN[u]},[u])}var yY=({id:u,type:f,color:l,width:r=12.5,height:y=12.5,markerUnits:i="strokeWidth",strokeWidth:_,orient:n="auto-start-reverse"})=>{let $=rY(f);if(!$)return null;return ru.jsx("marker",{className:"react-flow__arrowhead",id:u,markerWidth:`${r}`,markerHeight:`${y}`,viewBox:"-10 -10 20 20",markerUnits:i,orient:n,refX:"0",refY:"0",children:ru.jsx($,{color:l,strokeWidth:_})})},vN=({defaultColor:u,rfId:f})=>{let l=uf((i)=>i.edges),r=uf((i)=>i.defaultEdgeOptions),y=iu.useMemo(()=>{return Yc(l,{id:f,defaultColor:u,defaultMarkerStart:r?.markerStart,defaultMarkerEnd:r?.markerEnd})},[l,r,f,u]);if(!y.length)return null;return ru.jsx("svg",{className:"react-flow__marker","aria-hidden":"true",children:ru.jsx("defs",{children:y.map((i)=>ru.jsx(yY,{id:i.id,type:i.type,color:i.color,width:i.width,height:i.height,markerUnits:i.markerUnits,strokeWidth:i.strokeWidth,orient:i.orient},i.id))})})};vN.displayName="MarkerDefinitions";var iY=iu.memo(vN);function IN({x:u,y:f,label:l,labelStyle:r,labelShowBg:y=!0,labelBgStyle:i,labelBgPadding:_=[2,4],labelBgBorderRadius:n=2,children:$,className:j,...F}){let[J,U]=iu.useState({x:1,y:0,width:0,height:0}),q=Yf(["react-flow__edge-textwrapper",j]),W=iu.useRef(null);if(iu.useEffect(()=>{if(W.current){let G=W.current.getBBox();U({x:G.x,y:G.y,width:G.width,height:G.height})}},[l]),!l)return null;return ru.jsxs("g",{transform:`translate(${u-J.width/2} ${f-J.height/2})`,className:q,visibility:J.width?"visible":"hidden",...F,children:[y&&ru.jsx("rect",{width:J.width+2*_[0],x:-_[0],y:-_[1],height:J.height+2*_[1],className:"react-flow__edge-textbg",style:i,rx:n,ry:n}),ru.jsx("text",{className:"react-flow__edge-text",y:J.height/2,dy:"0.3em",ref:W,style:r,children:l}),$]})}IN.displayName="EdgeText";var _Y=iu.memo(IN);function si({path:u,labelX:f,labelY:l,label:r,labelStyle:y,labelShowBg:i,labelBgStyle:_,labelBgPadding:n,labelBgBorderRadius:$,interactionWidth:j=20,...F}){return ru.jsxs(ru.Fragment,{children:[ru.jsx("path",{...F,d:u,fill:"none",className:Yf(["react-flow__edge-path",F.className])}),j?ru.jsx("path",{d:u,fill:"none",strokeOpacity:0,strokeWidth:j,className:"react-flow__edge-interaction"}):null,r&&Kr(f)&&Kr(l)?ru.jsx(_Y,{x:f,y:l,label:r,labelStyle:y,labelShowBg:i,labelBgStyle:_,labelBgPadding:n,labelBgBorderRadius:$}):null]})}function TN({pos:u,x1:f,y1:l,x2:r,y2:y}){if(u===zu.Left||u===zu.Right)return[0.5*(f+r),l];return[f,0.5*(l+y)]}function kN({sourceX:u,sourceY:f,sourcePosition:l=zu.Bottom,targetX:r,targetY:y,targetPosition:i=zu.Top}){let[_,n]=TN({pos:l,x1:u,y1:f,x2:r,y2:y}),[$,j]=TN({pos:i,x1:r,y1:y,x2:u,y2:f}),[F,J,U,q]=D4({sourceX:u,sourceY:f,targetX:r,targetY:y,sourceControlX:_,sourceControlY:n,targetControlX:$,targetControlY:j});return[`M${u},${f} C${_},${n} ${$},${j} ${r},${y}`,F,J,U,q]}function gN(u){return iu.memo(({id:f,sourceX:l,sourceY:r,targetX:y,targetY:i,sourcePosition:_,targetPosition:n,label:$,labelStyle:j,labelShowBg:F,labelBgStyle:J,labelBgPadding:U,labelBgBorderRadius:q,style:W,markerEnd:G,markerStart:K,interactionWidth:Q})=>{let[N,c,z]=kN({sourceX:l,sourceY:r,sourcePosition:_,targetX:y,targetY:i,targetPosition:n}),w=u.isInternal?void 0:f;return ru.jsx(si,{id:w,path:N,labelX:c,labelY:z,label:$,labelStyle:j,labelShowBg:F,labelBgStyle:J,labelBgPadding:U,labelBgBorderRadius:q,style:W,markerEnd:G,markerStart:K,interactionWidth:Q})})}var nY=gN({isInternal:!1}),sN=gN({isInternal:!0});nY.displayName="SimpleBezierEdge";sN.displayName="SimpleBezierEdgeInternal";function aN(u){return iu.memo(({id:f,sourceX:l,sourceY:r,targetX:y,targetY:i,label:_,labelStyle:n,labelShowBg:$,labelBgStyle:j,labelBgPadding:F,labelBgBorderRadius:J,style:U,sourcePosition:q=zu.Bottom,targetPosition:W=zu.Top,markerEnd:G,markerStart:K,pathOptions:Q,interactionWidth:N})=>{let[c,z,w]=F$({sourceX:l,sourceY:r,sourcePosition:q,targetX:y,targetY:i,targetPosition:W,borderRadius:Q?.borderRadius,offset:Q?.offset,stepPosition:Q?.stepPosition}),H=u.isInternal?void 0:f;return ru.jsx(si,{id:H,path:c,labelX:z,labelY:w,label:_,labelStyle:n,labelShowBg:$,labelBgStyle:j,labelBgPadding:F,labelBgBorderRadius:J,style:U,markerEnd:G,markerStart:K,interactionWidth:N})})}var oN=aN({isInternal:!1}),dN=aN({isInternal:!0});oN.displayName="SmoothStepEdge";dN.displayName="SmoothStepEdgeInternal";function eN(u){return iu.memo(({id:f,...l})=>{let r=u.isInternal?void 0:f;return ru.jsx(oN,{...l,id:r,pathOptions:iu.useMemo(()=>({borderRadius:0,offset:l.pathOptions?.offset}),[l.pathOptions?.offset])})})}var $Y=eN({isInternal:!1}),uz=eN({isInternal:!0});$Y.displayName="StepEdge";uz.displayName="StepEdgeInternal";function fz(u){return iu.memo(({id:f,sourceX:l,sourceY:r,targetX:y,targetY:i,label:_,labelStyle:n,labelShowBg:$,labelBgStyle:j,labelBgPadding:F,labelBgBorderRadius:J,style:U,markerEnd:q,markerStart:W,interactionWidth:G})=>{let[K,Q,N]=S4({sourceX:l,sourceY:r,targetX:y,targetY:i}),c=u.isInternal?void 0:f;return ru.jsx(si,{id:c,path:K,labelX:Q,labelY:N,label:_,labelStyle:n,labelShowBg:$,labelBgStyle:j,labelBgPadding:F,labelBgBorderRadius:J,style:U,markerEnd:q,markerStart:W,interactionWidth:G})})}var AY=fz({isInternal:!1}),lz=fz({isInternal:!0});AY.displayName="StraightEdge";lz.displayName="StraightEdgeInternal";function rz(u){return iu.memo(({id:f,sourceX:l,sourceY:r,targetX:y,targetY:i,sourcePosition:_=zu.Bottom,targetPosition:n=zu.Top,label:$,labelStyle:j,labelShowBg:F,labelBgStyle:J,labelBgPadding:U,labelBgBorderRadius:q,style:W,markerEnd:G,markerStart:K,pathOptions:Q,interactionWidth:N})=>{let[c,z,w]=t4({sourceX:l,sourceY:r,sourcePosition:_,targetX:y,targetY:i,targetPosition:n,curvature:Q?.curvature}),H=u.isInternal?void 0:f;return ru.jsx(si,{id:H,path:c,labelX:z,labelY:w,label:$,labelStyle:j,labelShowBg:F,labelBgStyle:J,labelBgPadding:U,labelBgBorderRadius:q,style:W,markerEnd:G,markerStart:K,interactionWidth:N})})}var jY=rz({isInternal:!1}),yz=rz({isInternal:!0});jY.displayName="BezierEdge";yz.displayName="BezierEdgeInternal";var ZN={default:yz,straight:lz,step:uz,smoothstep:dN,simplebezier:sN},HN={sourceX:null,sourceY:null,targetX:null,targetY:null,sourcePosition:null,targetPosition:null},FY=(u,f,l)=>{if(l===zu.Left)return u-f;if(l===zu.Right)return u+f;return u},JY=(u,f,l)=>{if(l===zu.Top)return u-f;if(l===zu.Bottom)return u+f;return u},ON="react-flow__edgeupdater";function BN({position:u,centerX:f,centerY:l,radius:r=10,onMouseDown:y,onMouseEnter:i,onMouseOut:_,type:n}){return ru.jsx("circle",{onMouseDown:y,onMouseEnter:i,onMouseOut:_,className:Yf([ON,`${ON}-${n}`]),cx:FY(f,r,u),cy:JY(l,r,u),r,stroke:"transparent",fill:"transparent"})}function UY({isReconnectable:u,reconnectRadius:f,edge:l,sourceX:r,sourceY:y,targetX:i,targetY:_,sourcePosition:n,targetPosition:$,onReconnect:j,onReconnectStart:F,onReconnectEnd:J,setReconnecting:U,setUpdateHover:q}){let W=Tf(),G=(z,w)=>{if(z.button!==0)return;let{autoPanOnConnect:H,domNode:B,connectionMode:T,connectionRadius:X,lib:R,onConnectStart:Y,cancelConnection:P,nodeLookup:t,rfId:O,panBy:M,updateConnection:S}=W.getState(),b=w.type==="target",Z=(k,h)=>{U(!1),J?.(k,l,w.type,h)},D=(k)=>j?.(l,k),I=(k,h)=>{U(!0),F?.(z,l,w.type),Y?.(k,h)};p4.onPointerDown(z.nativeEvent,{autoPanOnConnect:H,connectionMode:T,connectionRadius:X,domNode:B,handleId:w.id,nodeId:w.nodeId,nodeLookup:t,isTarget:b,edgeUpdaterType:w.type,lib:R,flowId:O,cancelConnection:P,panBy:M,isValidConnection:(...k)=>W.getState().isValidConnection?.(...k)??!0,onConnect:D,onConnectStart:I,onConnectEnd:(...k)=>W.getState().onConnectEnd?.(...k),onReconnectEnd:Z,updateConnection:S,getTransform:()=>W.getState().transform,getFromHandle:()=>W.getState().connection.fromHandle,dragThreshold:W.getState().connectionDragThreshold,handleDomNode:z.currentTarget})},K=(z)=>G(z,{nodeId:l.target,id:l.targetHandle??null,type:"target"}),Q=(z)=>G(z,{nodeId:l.source,id:l.sourceHandle??null,type:"source"}),N=()=>q(!0),c=()=>q(!1);return ru.jsxs(ru.Fragment,{children:[(u===!0||u==="source")&&ru.jsx(BN,{position:n,centerX:r,centerY:y,radius:f,onMouseDown:K,onMouseEnter:N,onMouseOut:c,type:"source"}),(u===!0||u==="target")&&ru.jsx(BN,{position:$,centerX:i,centerY:_,radius:f,onMouseDown:Q,onMouseEnter:N,onMouseOut:c,type:"target"})]})}function QY({id:u,edgesFocusable:f,edgesReconnectable:l,elementsSelectable:r,onClick:y,onDoubleClick:i,onContextMenu:_,onMouseEnter:n,onMouseMove:$,onMouseLeave:j,reconnectRadius:F,onReconnect:J,onReconnectStart:U,onReconnectEnd:q,rfId:W,edgeTypes:G,noPanClassName:K,onError:Q,disableKeyboardA11y:N}){let c=uf((m)=>m.edgeLookup.get(u)),z=uf((m)=>m.defaultEdgeOptions);c=z?{...z,...c}:c;let w=c.type||"default",H=G?.[w]||ZN[w];if(H===void 0)Q?.("011",_r.error011(w)),w="default",H=G?.default||ZN.default;let B=!!(c.focusable||f&&typeof c.focusable>"u"),T=typeof J<"u"&&(c.reconnectable||l&&typeof c.reconnectable>"u"),X=!!(c.selectable||r&&typeof c.selectable>"u"),R=iu.useRef(null),[Y,P]=iu.useState(!1),[t,O]=iu.useState(!1),M=Tf(),{zIndex:S,sourceX:b,sourceY:Z,targetX:D,targetY:I,sourcePosition:k,targetPosition:h}=uf(iu.useCallback((m)=>{let d=m.nodeLookup.get(c.source),e=m.nodeLookup.get(c.target);if(!d||!e)return{zIndex:c.zIndex,...HN};let cu=Xc({id:u,sourceNode:d,targetNode:e,sourceHandle:c.sourceHandle||null,targetHandle:c.targetHandle||null,connectionMode:m.connectionMode,onError:Q});return{zIndex:Bc({selected:c.selected,zIndex:c.zIndex,sourceNode:d,targetNode:e,elevateOnSelect:m.elevateEdgesOnSelect,zIndexMode:m.zIndexMode}),...cu||HN}},[c.source,c.target,c.sourceHandle,c.targetHandle,c.selected,c.zIndex]),Kf),o=iu.useMemo(()=>c.markerStart?`url('#${P4(c.markerStart,W)}')`:void 0,[c.markerStart,W]),s=iu.useMemo(()=>c.markerEnd?`url('#${P4(c.markerEnd,W)}')`:void 0,[c.markerEnd,W]);if(c.hidden||b===null||Z===null||D===null||I===null)return null;let x=(m)=>{let{addSelectedEdges:d,unselectNodesAndEdges:e,multiSelectionActive:cu}=M.getState();if(X)if(M.setState({nodesSelectionActive:!1}),c.selected&&cu)e({nodes:[],edges:[c]}),R.current?.blur();else d([u]);if(y)y(m,c)},uu=i?(m)=>{i(m,{...c})}:void 0,nu=_?(m)=>{_(m,{...c})}:void 0,$u=n?(m)=>{n(m,{...c})}:void 0,Fu=$?(m)=>{$(m,{...c})}:void 0,Ku=j?(m)=>{j(m,{...c})}:void 0,Wu=(m)=>{if(!N&&z7.includes(m.key)&&X){let{unselectNodesAndEdges:d,addSelectedEdges:e}=M.getState();if(m.key==="Escape")R.current?.blur(),d({edges:[c]});else e([u])}};return ru.jsx("svg",{style:{zIndex:S},children:ru.jsxs("g",{className:Yf(["react-flow__edge",`react-flow__edge-${w}`,c.className,K,{selected:c.selected,animated:c.animated,inactive:!X&&!y,updating:Y,selectable:X}]),onClick:x,onDoubleClick:uu,onContextMenu:nu,onMouseEnter:$u,onMouseMove:Fu,onMouseLeave:Ku,onKeyDown:B?Wu:void 0,tabIndex:B?0:void 0,role:c.ariaRole??(B?"group":"img"),"aria-roledescription":"edge","data-id":u,"data-testid":`rf__edge-${u}`,"aria-label":c.ariaLabel===null?void 0:c.ariaLabel||`Edge from ${c.source} to ${c.target}`,"aria-describedby":B?`${SN}-${W}`:void 0,ref:R,...c.domAttributes,children:[!t&&ru.jsx(H,{id:u,source:c.source,target:c.target,type:c.type,selected:c.selected,animated:c.animated,selectable:X,deletable:c.deletable??!0,label:c.label,labelStyle:c.labelStyle,labelShowBg:c.labelShowBg,labelBgStyle:c.labelBgStyle,labelBgPadding:c.labelBgPadding,labelBgBorderRadius:c.labelBgBorderRadius,sourceX:b,sourceY:Z,targetX:D,targetY:I,sourcePosition:k,targetPosition:h,data:c.data,style:c.style,sourceHandleId:c.sourceHandle,targetHandleId:c.targetHandle,markerStart:o,markerEnd:s,pathOptions:"pathOptions"in c?c.pathOptions:void 0,interactionWidth:c.interactionWidth}),T&&ru.jsx(UY,{edge:c,isReconnectable:T,reconnectRadius:F,onReconnect:J,onReconnectStart:U,onReconnectEnd:q,sourceX:b,sourceY:Z,targetX:D,targetY:I,sourcePosition:k,targetPosition:h,setUpdateHover:P,setReconnecting:O})]})})}var qY=iu.memo(QY),WY=(u)=>({edgesFocusable:u.edgesFocusable,edgesReconnectable:u.edgesReconnectable,elementsSelectable:u.elementsSelectable,connectionMode:u.connectionMode,onError:u.onError});function iz({defaultMarkerColor:u,onlyRenderVisibleElements:f,rfId:l,edgeTypes:r,noPanClassName:y,onReconnect:i,onEdgeContextMenu:_,onEdgeMouseEnter:n,onEdgeMouseMove:$,onEdgeMouseLeave:j,onEdgeClick:F,reconnectRadius:J,onEdgeDoubleClick:U,onReconnectStart:q,onReconnectEnd:W,disableKeyboardA11y:G}){let{edgesFocusable:K,edgesReconnectable:Q,elementsSelectable:N,onError:c}=uf(WY,Kf),z=uY(f);return ru.jsxs("div",{className:"react-flow__edges",children:[ru.jsx(iY,{defaultColor:u,rfId:l}),z.map((w)=>{return ru.jsx(qY,{id:w,edgesFocusable:K,edgesReconnectable:Q,elementsSelectable:N,noPanClassName:y,onReconnect:i,onContextMenu:_,onMouseEnter:n,onMouseMove:$,onMouseLeave:j,onClick:F,reconnectRadius:J,onDoubleClick:U,onReconnectStart:q,onReconnectEnd:W,rfId:l,onError:c,edgeTypes:r,disableKeyboardA11y:G},w)})]})}iz.displayName="EdgeRenderer";var cY=iu.memo(iz),NY=(u)=>`translate(${u.transform[0]}px,${u.transform[1]}px) scale(${u.transform[2]})`;function zY({children:u}){let f=uf(NY);return ru.jsx("div",{className:"react-flow__viewport xyflow__viewport react-flow__container",style:{transform:f},children:u})}function GY(u){let f=s7(),l=iu.useRef(!1);iu.useEffect(()=>{if(!l.current&&f.viewportInitialized&&u)setTimeout(()=>u(f),1),l.current=!0},[u,f.viewportInitialized])}var KY=(u)=>u.panZoom?.syncViewport;function LY(u){let f=uf(KY),l=Tf();return iu.useEffect(()=>{if(u)f?.(u),l.setState({transform:[u.x,u.y,u.zoom]})},[u,f]),null}function VN(u){return u.connection.inProgress?{...u.connection,to:vi(u.connection.to,u.transform)}:{...u.connection}}function wY(u){if(u)return(l)=>{let r=VN(l);return u(r)};return VN}function EY(u){let f=wY(u);return uf(f,Kf)}var TY=(u)=>({nodesConnectable:u.nodesConnectable,isValid:u.connection.isValid,inProgress:u.connection.inProgress,width:u.width,height:u.height});function ZY({containerStyle:u,style:f,type:l,component:r}){let{nodesConnectable:y,width:i,height:_,isValid:n,inProgress:$}=uf(TY,Kf);if(!(i&&y&&$))return null;return ru.jsx("svg",{style:u,width:i,height:_,className:"react-flow__connectionline react-flow__container",children:ru.jsx("g",{className:Yf(["react-flow__connection",L7(n)]),children:ru.jsx(_z,{style:f,type:l,CustomComponent:r,isValid:n})})})}var _z=({style:u,type:f=y0.Bezier,CustomComponent:l,isValid:r})=>{let{inProgress:y,from:i,fromNode:_,fromHandle:n,fromPosition:$,to:j,toNode:F,toHandle:J,toPosition:U,pointer:q}=EY();if(!y)return;if(l)return ru.jsx(l,{connectionLineType:f,connectionLineStyle:u,fromNode:_,fromHandle:n,fromX:i.x,fromY:i.y,toX:j.x,toY:j.y,fromPosition:$,toPosition:U,connectionStatus:L7(r),toNode:F,toHandle:J,pointer:q});let W="",G={sourceX:i.x,sourceY:i.y,sourcePosition:$,targetX:j.x,targetY:j.y,targetPosition:U};switch(f){case y0.Bezier:[W]=t4(G);break;case y0.SimpleBezier:[W]=kN(G);break;case y0.Step:[W]=F$({...G,borderRadius:0});break;case y0.SmoothStep:[W]=F$(G);break;default:[W]=S4(G)}return ru.jsx("path",{d:W,fill:"none",className:"react-flow__connection-path",style:u})};_z.displayName="ConnectionLine";var HY={};function XN(u=HY){let f=iu.useRef(u),l=Tf();iu.useEffect(()=>{},[u])}function OY(){let u=Tf(),f=iu.useRef(!1);iu.useEffect(()=>{},[])}function nz({nodeTypes:u,edgeTypes:f,onInit:l,onNodeClick:r,onEdgeClick:y,onNodeDoubleClick:i,onEdgeDoubleClick:_,onNodeMouseEnter:n,onNodeMouseMove:$,onNodeMouseLeave:j,onNodeContextMenu:F,onSelectionContextMenu:J,onSelectionStart:U,onSelectionEnd:q,connectionLineType:W,connectionLineStyle:G,connectionLineComponent:K,connectionLineContainerStyle:Q,selectionKeyCode:N,selectionOnDrag:c,selectionMode:z,multiSelectionKeyCode:w,panActivationKeyCode:H,zoomActivationKeyCode:B,deleteKeyCode:T,onlyRenderVisibleElements:X,elementsSelectable:R,defaultViewport:Y,translateExtent:P,minZoom:t,maxZoom:O,preventScrolling:M,defaultMarkerColor:S,zoomOnScroll:b,zoomOnPinch:Z,panOnScroll:D,panOnScrollSpeed:I,panOnScrollMode:k,zoomOnDoubleClick:h,panOnDrag:o,onPaneClick:s,onPaneMouseEnter:x,onPaneMouseMove:uu,onPaneMouseLeave:nu,onPaneScroll:$u,onPaneContextMenu:Fu,paneClickDistance:Ku,nodeClickDistance:Wu,onEdgeContextMenu:m,onEdgeMouseEnter:d,onEdgeMouseMove:e,onEdgeMouseLeave:cu,reconnectRadius:g,onReconnect:Qu,onReconnectStart:Eu,onReconnectEnd:Tu,noDragClassName:Du,noWheelClassName:ff,noPanClassName:rf,disableKeyboardA11y:Lf,nodeExtent:gf,rfId:jr,viewport:Ol,onViewportChange:ef}){return XN(u),XN(f),OY(),GY(l),LY(Ol),ru.jsx(bX,{onPaneClick:s,onPaneMouseEnter:x,onPaneMouseMove:uu,onPaneMouseLeave:nu,onPaneContextMenu:Fu,onPaneScroll:$u,paneClickDistance:Ku,deleteKeyCode:T,selectionKeyCode:N,selectionOnDrag:c,selectionMode:z,onSelectionStart:U,onSelectionEnd:q,multiSelectionKeyCode:w,panActivationKeyCode:H,zoomActivationKeyCode:B,elementsSelectable:R,zoomOnScroll:b,zoomOnPinch:Z,zoomOnDoubleClick:h,panOnScroll:D,panOnScrollSpeed:I,panOnScrollMode:k,panOnDrag:o,defaultViewport:Y,translateExtent:P,minZoom:t,maxZoom:O,onSelectionContextMenu:J,preventScrolling:M,noDragClassName:Du,noWheelClassName:ff,noPanClassName:rf,disableKeyboardA11y:Lf,onViewportChange:ef,isControlledViewport:!!Ol,children:ru.jsxs(zY,{children:[ru.jsx(cY,{edgeTypes:f,onEdgeClick:y,onEdgeDoubleClick:_,onReconnect:Qu,onReconnectStart:Eu,onReconnectEnd:Tu,onlyRenderVisibleElements:X,onEdgeContextMenu:m,onEdgeMouseEnter:d,onEdgeMouseMove:e,onEdgeMouseLeave:cu,reconnectRadius:g,defaultMarkerColor:S,noPanClassName:rf,disableKeyboardA11y:Lf,rfId:jr}),ru.jsx(ZY,{style:G,type:W,component:K,containerStyle:Q}),ru.jsx("div",{className:"react-flow__edgelabel-renderer"}),ru.jsx(eX,{nodeTypes:u,onNodeClick:r,onNodeDoubleClick:i,onNodeMouseEnter:n,onNodeMouseMove:$,onNodeMouseLeave:j,onNodeContextMenu:F,nodeClickDistance:Wu,onlyRenderVisibleElements:X,noPanClassName:rf,noDragClassName:Du,disableKeyboardA11y:Lf,nodeExtent:gf,rfId:jr}),ru.jsx("div",{className:"react-flow__viewport-portal"})]})})}nz.displayName="GraphView";var BY=iu.memo(nz),YN=({nodes:u,edges:f,defaultNodes:l,defaultEdges:r,width:y,height:i,fitView:_,fitViewOptions:n,minZoom:$=0.5,maxZoom:j=2,nodeOrigin:F,nodeExtent:J,zIndexMode:U="basic"}={})=>{let q=new Map,W=new Map,G=new Map,K=new Map,Q=r??f??[],N=l??u??[],c=F??[0,0],z=J??xi;R7(G,K,Q);let{nodesInitialized:w}=M4(N,q,W,{nodeOrigin:c,nodeExtent:z,zIndexMode:U}),H=[0,0,1];if(_&&y&&i){let B=Ri(q,{filter:(Y)=>!!((Y.width||Y.initialWidth)&&(Y.height||Y.initialHeight))}),{x:T,y:X,zoom:R}=j$(B,y,i,$,j,n?.padding??0.1);H=[T,X,R]}return{rfId:"1",width:y??0,height:i??0,transform:H,nodes:N,nodesInitialized:w,nodeLookup:q,parentLookup:W,edges:Q,edgeLookup:K,connectionLookup:G,onNodesChange:null,onEdgesChange:null,hasDefaultNodes:l!==void 0,hasDefaultEdges:r!==void 0,panZoom:null,minZoom:$,maxZoom:j,translateExtent:xi,nodeExtent:z,nodesSelectionActive:!1,userSelectionActive:!1,userSelectionRect:null,connectionMode:E1.Strict,domNode:null,paneDragging:!1,noPanClassName:"nopan",nodeOrigin:c,nodeDragThreshold:1,connectionDragThreshold:1,snapGrid:[15,15],snapToGrid:!1,nodesDraggable:!0,nodesConnectable:!0,nodesFocusable:!0,edgesFocusable:!0,edgesReconnectable:!0,elementsSelectable:!0,elevateNodesOnSelect:!0,elevateEdgesOnSelect:!0,selectNodesOnDrag:!0,multiSelectionActive:!1,fitViewQueued:_??!1,fitViewOptions:n,fitViewResolver:null,connection:{...K7},connectionClickStartHandle:null,connectOnClick:!0,ariaLiveMessage:"",autoPanOnConnect:!0,autoPanOnNodeDrag:!0,autoPanOnNodeFocus:!0,autoPanSpeed:15,connectionRadius:20,onError:B7,isValidConnection:void 0,onSelectionChangeHandlers:[],lib:"react",debug:!1,ariaLabelConfig:G7,zIndexMode:U,onNodesChangeMiddlewareMap:new Map,onEdgesChangeMiddlewareMap:new Map}},VY=({nodes:u,edges:f,defaultNodes:l,defaultEdges:r,width:y,height:i,fitView:_,fitViewOptions:n,minZoom:$,maxZoom:j,nodeOrigin:F,nodeExtent:J,zIndexMode:U})=>AN((q,W)=>{async function G(){let{nodeLookup:K,panZoom:Q,fitViewOptions:N,fitViewResolver:c,width:z,height:w,minZoom:H,maxZoom:B}=W();if(!Q)return;await wc({nodes:K,width:z,height:w,panZoom:Q,minZoom:H,maxZoom:B},N),c?.resolve(!0),q({fitViewResolver:null})}return{...YN({nodes:u,edges:f,width:y,height:i,fitView:_,fitViewOptions:n,minZoom:$,maxZoom:j,nodeOrigin:F,nodeExtent:J,defaultNodes:l,defaultEdges:r,zIndexMode:U}),setNodes:(K)=>{let{nodeLookup:Q,parentLookup:N,nodeOrigin:c,elevateNodesOnSelect:z,fitViewQueued:w,zIndexMode:H,nodesSelectionActive:B}=W(),{nodesInitialized:T,hasSelectedNodes:X}=M4(K,Q,N,{nodeOrigin:c,nodeExtent:J,elevateNodesOnSelect:z,checkEquality:!0,zIndexMode:H}),R=B&&X;if(w&&T)G(),q({nodes:K,nodesInitialized:T,fitViewQueued:!1,fitViewOptions:void 0,nodesSelectionActive:R});else q({nodes:K,nodesInitialized:T,nodesSelectionActive:R})},setEdges:(K)=>{let{connectionLookup:Q,edgeLookup:N}=W();R7(Q,N,K),q({edges:K})},setDefaultNodesAndEdges:(K,Q)=>{if(K){let{setNodes:N}=W();N(K),q({hasDefaultNodes:!0})}if(Q){let{setEdges:N}=W();N(Q),q({hasDefaultEdges:!0})}},updateNodeInternals:(K)=>{let{triggerNodeChanges:Q,nodeLookup:N,parentLookup:c,domNode:z,nodeOrigin:w,nodeExtent:H,debug:B,fitViewQueued:T,zIndexMode:X}=W(),{changes:R,updatedInternals:Y}=Pc(K,N,c,z,w,H,X);if(!Y)return;if(tc(N,c,{nodeOrigin:w,nodeExtent:H,zIndexMode:X}),T)G(),q({fitViewQueued:!1,fitViewOptions:void 0});else q({});if(R?.length>0){if(B)console.log("React Flow: trigger node changes",R);Q?.(R)}},updateNodePositions:(K,Q=!1)=>{let N=[],c=[],{nodeLookup:z,triggerNodeChanges:w,connection:H,updateConnection:B,onNodesChangeMiddlewareMap:T}=W();for(let[X,R]of K){let Y=z.get(X),P=!!(Y?.expandParent&&Y?.parentId&&R?.position),t={id:X,type:"position",position:P?{x:Math.max(0,R.position.x),y:Math.max(0,R.position.y)}:R.position,dragging:Q};if(Y&&H.inProgress&&H.fromNode.id===Y.id){let O=Z1(Y,H.fromHandle,zu.Left,!0);B({...H,from:O})}if(P&&Y.parentId)N.push({id:X,parentId:Y.parentId,rect:{...R.internals.positionAbsolute,width:R.measured.width??0,height:R.measured.height??0}});c.push(t)}if(N.length>0){let{parentLookup:X,nodeOrigin:R}=W(),Y=m4(N,z,X,R);c.push(...Y)}for(let X of T.values())c=X(c);w(c)},triggerNodeChanges:(K)=>{let{onNodesChange:Q,setNodes:N,nodes:c,hasDefaultNodes:z,debug:w}=W();if(K?.length){if(z){let H=qX(K,c);N(H)}if(w)console.log("React Flow: trigger node changes",K);Q?.(K)}},triggerEdgeChanges:(K)=>{let{onEdgesChange:Q,setEdges:N,edges:c,hasDefaultEdges:z,debug:w}=W();if(K?.length){if(z){let H=WX(K,c);N(H)}if(w)console.log("React Flow: trigger edge changes",K);Q?.(K)}},addSelectedNodes:(K)=>{let{multiSelectionActive:Q,edgeLookup:N,nodeLookup:c,triggerNodeChanges:z,triggerEdgeChanges:w}=W();if(Q){let H=K.map((B)=>Ty(B,!0));z(H);return}z(gi(c,new Set([...K]),!0)),w(gi(N))},addSelectedEdges:(K)=>{let{multiSelectionActive:Q,edgeLookup:N,nodeLookup:c,triggerNodeChanges:z,triggerEdgeChanges:w}=W();if(Q){let H=K.map((B)=>Ty(B,!0));w(H);return}w(gi(N,new Set([...K]))),z(gi(c,new Set,!0))},unselectNodesAndEdges:({nodes:K,edges:Q}={})=>{let{edges:N,nodes:c,nodeLookup:z,triggerNodeChanges:w,triggerEdgeChanges:H}=W(),B=K?K:c,T=Q?Q:N,X=[];for(let Y of B){if(!Y.selected)continue;let P=z.get(Y.id);if(P)P.selected=!1;X.push(Ty(Y.id,!1))}let R=[];for(let Y of T){if(!Y.selected)continue;R.push(Ty(Y.id,!1))}w(X),H(R)},setMinZoom:(K)=>{let{panZoom:Q,maxZoom:N}=W();Q?.setScaleExtent([K,N]),q({minZoom:K})},setMaxZoom:(K)=>{let{panZoom:Q,minZoom:N}=W();Q?.setScaleExtent([N,K]),q({maxZoom:K})},setTranslateExtent:(K)=>{W().panZoom?.setTranslateExtent(K),q({translateExtent:K})},resetSelectedElements:()=>{let{edges:K,nodes:Q,triggerNodeChanges:N,triggerEdgeChanges:c,elementsSelectable:z}=W();if(!z)return;let w=Q.reduce((B,T)=>T.selected?[...B,Ty(T.id,!1)]:B,[]),H=K.reduce((B,T)=>T.selected?[...B,Ty(T.id,!1)]:B,[]);N(w),c(H)},setNodeExtent:(K)=>{let{nodes:Q,nodeLookup:N,parentLookup:c,nodeOrigin:z,elevateNodesOnSelect:w,nodeExtent:H,zIndexMode:B}=W();if(K[0][0]===H[0][0]&&K[0][1]===H[0][1]&&K[1][0]===H[1][0]&&K[1][1]===H[1][1])return;M4(Q,N,c,{nodeOrigin:z,nodeExtent:K,elevateNodesOnSelect:w,checkEquality:!1,zIndexMode:B}),q({nodeExtent:K})},panBy:(K)=>{let{transform:Q,width:N,height:c,panZoom:z,translateExtent:w}=W();return Mc({delta:K,panZoom:z,transform:Q,translateExtent:w,width:N,height:c})},setCenter:async(K,Q,N)=>{let{width:c,height:z,maxZoom:w,panZoom:H}=W();if(!H)return Promise.resolve(!1);let B=typeof N?.zoom<"u"?N.zoom:w;return await H.setViewport({x:c/2-K*B,y:z/2-Q*B,zoom:B},{duration:N?.duration,ease:N?.ease,interpolate:N?.interpolate}),Promise.resolve(!0)},cancelConnection:()=>{q({connection:{...K7}})},updateConnection:(K)=>{q({connection:K})},reset:()=>q({...YN()})}},Object.is);function XY({initialNodes:u,initialEdges:f,defaultNodes:l,defaultEdges:r,initialWidth:y,initialHeight:i,initialMinZoom:_,initialMaxZoom:n,initialFitViewOptions:$,fitView:j,nodeOrigin:F,nodeExtent:J,zIndexMode:U,children:q}){let[W]=iu.useState(()=>VY({nodes:u,edges:f,defaultNodes:l,defaultEdges:r,width:y,height:i,fitView:j,minZoom:_,maxZoom:n,fitViewOptions:$,nodeOrigin:F,nodeExtent:J,zIndexMode:U}));return ru.jsx(sV,{value:W,children:ru.jsx(zX,{children:q})})}function YY({children:u,nodes:f,edges:l,defaultNodes:r,defaultEdges:y,width:i,height:_,fitView:n,fitViewOptions:$,minZoom:j,maxZoom:F,nodeOrigin:J,nodeExtent:U,zIndexMode:q}){if(iu.useContext(v4))return ru.jsx(ru.Fragment,{children:u});return ru.jsx(XY,{initialNodes:f,initialEdges:l,defaultNodes:r,defaultEdges:y,initialWidth:i,initialHeight:_,fitView:n,initialFitViewOptions:$,initialMinZoom:j,initialMaxZoom:F,nodeOrigin:J,nodeExtent:U,zIndexMode:q,children:u})}var DY={width:"100%",height:"100%",overflow:"hidden",position:"relative",zIndex:0};function tY({nodes:u,edges:f,defaultNodes:l,defaultEdges:r,className:y,nodeTypes:i,edgeTypes:_,onNodeClick:n,onEdgeClick:$,onInit:j,onMove:F,onMoveStart:J,onMoveEnd:U,onConnect:q,onConnectStart:W,onConnectEnd:G,onClickConnectStart:K,onClickConnectEnd:Q,onNodeMouseEnter:N,onNodeMouseMove:c,onNodeMouseLeave:z,onNodeContextMenu:w,onNodeDoubleClick:H,onNodeDragStart:B,onNodeDrag:T,onNodeDragStop:X,onNodesDelete:R,onEdgesDelete:Y,onDelete:P,onSelectionChange:t,onSelectionDragStart:O,onSelectionDrag:M,onSelectionDragStop:S,onSelectionContextMenu:b,onSelectionStart:Z,onSelectionEnd:D,onBeforeDelete:I,connectionMode:k,connectionLineType:h=y0.Bezier,connectionLineStyle:o,connectionLineComponent:s,connectionLineContainerStyle:x,deleteKeyCode:uu="Backspace",selectionKeyCode:nu="Shift",selectionOnDrag:$u=!1,selectionMode:Fu=Ly.Full,panActivationKeyCode:Ku="Space",multiSelectionKeyCode:Wu=Ii()?"Meta":"Control",zoomActivationKeyCode:m=Ii()?"Meta":"Control",snapToGrid:d,snapGrid:e,onlyRenderVisibleElements:cu=!1,selectNodesOnDrag:g,nodesDraggable:Qu,autoPanOnNodeFocus:Eu,nodesConnectable:Tu,nodesFocusable:Du,nodeOrigin:ff=PN,edgesFocusable:rf,edgesReconnectable:Lf,elementsSelectable:gf=!0,defaultViewport:jr=$X,minZoom:Ol=0.5,maxZoom:ef=2,translateExtent:hr=xi,preventScrolling:vl=!0,nodeExtent:ju,defaultMarkerColor:bu="#b1b1b7",zoomOnScroll:ul=!0,zoomOnPinch:tu=!0,panOnScroll:ou=!1,panOnScrollSpeed:Al=0.5,panOnScrollMode:Bl=D0.Free,zoomOnDoubleClick:sf=!0,panOnDrag:Il=!0,onPaneClick:Fr,onPaneMouseEnter:kl,onPaneMouseMove:M0,onPaneMouseLeave:r_,onPaneScroll:y_,onPaneContextMenu:fu,paneClickDistance:Zu=1,nodeClickDistance:Lu=0,children:ku,onReconnect:Uf,onReconnectStart:vu,onReconnectEnd:yf,onEdgeContextMenu:_f,onEdgeDoubleClick:xf,onEdgeMouseEnter:i_,onEdgeMouseMove:B$,onEdgeMouseLeave:__,reconnectRadius:V$=10,onNodesChange:n_,onEdgesChange:X$,noDragClassName:Vl="nodrag",noWheelClassName:br="nowheel",noPanClassName:$_="nopan",fitView:A_,fitViewOptions:Vy,connectOnClick:Y$,attributionPosition:vr,proOptions:D$,defaultEdgeOptions:Rf,elevateNodesOnSelect:z8=!0,elevateEdgesOnSelect:t$=!1,disableKeyboardA11y:Jr=!1,autoPanOnConnect:Xy,autoPanOnNodeDrag:p1,autoPanSpeed:j_,connectionRadius:Mj,isValidConnection:Yy,onError:mj,style:S$,id:P$,nodeDragThreshold:G8,connectionDragThreshold:K8,viewport:m0,onViewportChange:Dy,width:C1,height:Xl,colorMode:M$="light",debug:F_,onScroll:gl,ariaLabelConfig:m$,zIndexMode:p$="basic",...L8},C$){let Ir=P$||"1",x$=JX(M$),J_=iu.useCallback((R$)=>{R$.currentTarget.scrollTo({top:0,left:0,behavior:"instant"}),gl?.(R$)},[gl]);return ru.jsx("div",{"data-testid":"rf__wrapper",...L8,onScroll:J_,style:{...S$,...DY},ref:C$,className:Yf(["react-flow",y,x$]),id:P$,role:"application",children:ru.jsxs(YY,{nodes:u,edges:f,width:C1,height:Xl,fitView:A_,fitViewOptions:Vy,minZoom:Ol,maxZoom:ef,nodeOrigin:ff,nodeExtent:ju,zIndexMode:p$,children:[ru.jsx(FX,{nodes:u,edges:f,defaultNodes:l,defaultEdges:r,onConnect:q,onConnectStart:W,onConnectEnd:G,onClickConnectStart:K,onClickConnectEnd:Q,nodesDraggable:Qu,autoPanOnNodeFocus:Eu,nodesConnectable:Tu,nodesFocusable:Du,edgesFocusable:rf,edgesReconnectable:Lf,elementsSelectable:gf,elevateNodesOnSelect:z8,elevateEdgesOnSelect:t$,minZoom:Ol,maxZoom:ef,nodeExtent:ju,onNodesChange:n_,onEdgesChange:X$,snapToGrid:d,snapGrid:e,connectionMode:k,translateExtent:hr,connectOnClick:Y$,defaultEdgeOptions:Rf,fitView:A_,fitViewOptions:Vy,onNodesDelete:R,onEdgesDelete:Y,onDelete:P,onNodeDragStart:B,onNodeDrag:T,onNodeDragStop:X,onSelectionDrag:M,onSelectionDragStart:O,onSelectionDragStop:S,onMove:F,onMoveStart:J,onMoveEnd:U,noPanClassName:$_,nodeOrigin:ff,rfId:Ir,autoPanOnConnect:Xy,autoPanOnNodeDrag:p1,autoPanSpeed:j_,onError:mj,connectionRadius:Mj,isValidConnection:Yy,selectNodesOnDrag:g,nodeDragThreshold:G8,connectionDragThreshold:K8,onBeforeDelete:I,debug:F_,ariaLabelConfig:m$,zIndexMode:p$}),ru.jsx(BY,{onInit:j,onNodeClick:n,onEdgeClick:$,onNodeMouseEnter:N,onNodeMouseMove:c,onNodeMouseLeave:z,onNodeContextMenu:w,onNodeDoubleClick:H,nodeTypes:i,edgeTypes:_,connectionLineType:h,connectionLineStyle:o,connectionLineComponent:s,connectionLineContainerStyle:x,selectionKeyCode:nu,selectionOnDrag:$u,selectionMode:Fu,deleteKeyCode:uu,multiSelectionKeyCode:Wu,panActivationKeyCode:Ku,zoomActivationKeyCode:m,onlyRenderVisibleElements:cu,defaultViewport:jr,translateExtent:hr,minZoom:Ol,maxZoom:ef,preventScrolling:vl,zoomOnScroll:ul,zoomOnPinch:tu,zoomOnDoubleClick:sf,panOnScroll:ou,panOnScrollSpeed:Al,panOnScrollMode:Bl,panOnDrag:Il,onPaneClick:Fr,onPaneMouseEnter:kl,onPaneMouseMove:M0,onPaneMouseLeave:r_,onPaneScroll:y_,onPaneContextMenu:fu,paneClickDistance:Zu,nodeClickDistance:Lu,onSelectionContextMenu:b,onSelectionStart:Z,onSelectionEnd:D,onReconnect:Uf,onReconnectStart:vu,onReconnectEnd:yf,onEdgeContextMenu:_f,onEdgeDoubleClick:xf,onEdgeMouseEnter:i_,onEdgeMouseMove:B$,onEdgeMouseLeave:__,reconnectRadius:V$,defaultMarkerColor:bu,noDragClassName:Vl,noWheelClassName:br,noPanClassName:$_,rfId:Ir,disableKeyboardA11y:Jr,nodeExtent:ju,viewport:m0,onViewportChange:Dy}),ru.jsx(nX,{onSelectionChange:t}),ku,ru.jsx(lX,{proOptions:D$,position:vr}),ru.jsx(fX,{rfId:Ir,disableKeyboardA11y:Jr})]})})}var $z=mN(tY);var yh=_r.error014();function SY({dimensions:u,lineWidth:f,variant:l,className:r}){return ru.jsx("path",{strokeWidth:f,d:`M${u[0]/2} 0 V${u[1]} M0 ${u[1]/2} H${u[0]}`,className:Yf(["react-flow__background-pattern",l,r])})}function PY({radius:u,className:f}){return ru.jsx("circle",{cx:u,cy:u,r:u,className:Yf(["react-flow__background-pattern","dots",f])})}var O1;(function(u){u.Lines="lines",u.Dots="dots",u.Cross="cross"})(O1||(O1={}));var MY={[O1.Dots]:1,[O1.Lines]:1,[O1.Cross]:6},mY=(u)=>({transform:u.transform,patternId:`pattern-${u.rfId}`});function Az({id:u,variant:f=O1.Dots,gap:l=20,size:r,lineWidth:y=1,offset:i=0,color:_,bgColor:n,style:$,className:j,patternClassName:F}){let J=iu.useRef(null),{transform:U,patternId:q}=uf(mY,Kf),W=r||MY[f],G=f===O1.Dots,K=f===O1.Cross,Q=Array.isArray(l)?l:[l,l],N=[Q[0]*U[2]||1,Q[1]*U[2]||1],c=W*U[2],z=Array.isArray(i)?i:[i,i],w=K?[c,c]:N,H=[z[0]*U[2]||1+w[0]/2,z[1]*U[2]||1+w[1]/2],B=`${q}${u?u:""}`;return ru.jsxs("svg",{className:Yf(["react-flow__background",j]),style:{...$,...k4,"--xy-background-color-props":n,"--xy-background-pattern-color-props":_},ref:J,"data-testid":"rf__background",children:[ru.jsx("pattern",{id:B,x:U[0]%N[0],y:U[1]%N[1],width:N[0],height:N[1],patternUnits:"userSpaceOnUse",patternTransform:`translate(-${H[0]},-${H[1]})`,children:G?ru.jsx(PY,{radius:c/2,className:F}):ru.jsx(SY,{dimensions:w,lineWidth:y,variant:f,className:F})}),ru.jsx("rect",{x:"0",y:"0",width:"100%",height:"100%",fill:`url(#${B})`})]})}Az.displayName="Background";var jz=iu.memo(Az);function pY(){return ru.jsx("svg",{xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 32 32",children:ru.jsx("path",{d:"M32 18.133H18.133V32h-4.266V18.133H0v-4.266h13.867V0h4.266v13.867H32z"})})}function CY(){return ru.jsx("svg",{xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 32 5",children:ru.jsx("path",{d:"M0 0h32v4.2H0z"})})}function xY(){return ru.jsx("svg",{xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 32 30",children:ru.jsx("path",{d:"M3.692 4.63c0-.53.4-.938.939-.938h5.215V0H4.708C2.13 0 0 2.054 0 4.63v5.216h3.692V4.631zM27.354 0h-5.2v3.692h5.17c.53 0 .984.4.984.939v5.215H32V4.631A4.624 4.624 0 0027.354 0zm.954 24.83c0 .532-.4.94-.939.94h-5.215v3.768h5.215c2.577 0 4.631-2.13 4.631-4.707v-5.139h-3.692v5.139zm-23.677.94c-.531 0-.939-.4-.939-.94v-5.138H0v5.139c0 2.577 2.13 4.707 4.708 4.707h5.138V25.77H4.631z"})})}function RY(){return ru.jsx("svg",{xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 25 32",children:ru.jsx("path",{d:"M21.333 10.667H19.81V7.619C19.81 3.429 16.38 0 12.19 0 8 0 4.571 3.429 4.571 7.619v3.048H3.048A3.056 3.056 0 000 13.714v15.238A3.056 3.056 0 003.048 32h18.285a3.056 3.056 0 003.048-3.048V13.714a3.056 3.056 0 00-3.048-3.047zM12.19 24.533a3.056 3.056 0 01-3.047-3.047 3.056 3.056 0 013.047-3.048 3.056 3.056 0 013.048 3.048 3.056 3.056 0 01-3.048 3.047zm4.724-13.866H7.467V7.619c0-2.59 2.133-4.724 4.723-4.724 2.591 0 4.724 2.133 4.724 4.724v3.048z"})})}function hY(){return ru.jsx("svg",{xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 25 32",children:ru.jsx("path",{d:"M21.333 10.667H19.81V7.619C19.81 3.429 16.38 0 12.19 0c-4.114 1.828-1.37 2.133.305 2.438 1.676.305 4.42 2.59 4.42 5.181v3.048H3.047A3.056 3.056 0 000 13.714v15.238A3.056 3.056 0 003.048 32h18.285a3.056 3.056 0 003.048-3.048V13.714a3.056 3.056 0 00-3.048-3.047zM12.19 24.533a3.056 3.056 0 01-3.047-3.047 3.056 3.056 0 013.047-3.048 3.056 3.056 0 013.048 3.048 3.056 3.056 0 01-3.048 3.047z"})})}function h4({children:u,className:f,...l}){return ru.jsx("button",{type:"button",className:Yf(["react-flow__controls-button",f]),...l,children:u})}var bY=(u)=>({isInteractive:u.nodesDraggable||u.nodesConnectable||u.elementsSelectable,minZoomReached:u.transform[2]<=u.minZoom,maxZoomReached:u.transform[2]>=u.maxZoom,ariaLabelConfig:u.ariaLabelConfig});function Fz({style:u,showZoom:f=!0,showFitView:l=!0,showInteractive:r=!0,fitViewOptions:y,onZoomIn:i,onZoomOut:_,onFitView:n,onInteractiveChange:$,className:j,children:F,position:J="bottom-left",orientation:U="vertical","aria-label":q}){let W=Tf(),{isInteractive:G,minZoomReached:K,maxZoomReached:Q,ariaLabelConfig:N}=uf(bY,Kf),{zoomIn:c,zoomOut:z,fitView:w}=s7(),H=()=>{c(),i?.()},B=()=>{z(),_?.()},T=()=>{w(y),n?.()},X=()=>{W.setState({nodesDraggable:!G,nodesConnectable:!G,elementsSelectable:!G}),$?.(!G)};return ru.jsxs(I4,{className:Yf(["react-flow__controls",U==="horizontal"?"horizontal":"vertical",j]),position:J,style:u,"data-testid":"rf__controls","aria-label":q??N["controls.ariaLabel"],children:[f&&ru.jsxs(ru.Fragment,{children:[ru.jsx(h4,{onClick:H,className:"react-flow__controls-zoomin",title:N["controls.zoomIn.ariaLabel"],"aria-label":N["controls.zoomIn.ariaLabel"],disabled:Q,children:ru.jsx(pY,{})}),ru.jsx(h4,{onClick:B,className:"react-flow__controls-zoomout",title:N["controls.zoomOut.ariaLabel"],"aria-label":N["controls.zoomOut.ariaLabel"],disabled:K,children:ru.jsx(CY,{})})]}),l&&ru.jsx(h4,{className:"react-flow__controls-fitview",onClick:T,title:N["controls.fitView.ariaLabel"],"aria-label":N["controls.fitView.ariaLabel"],children:ru.jsx(xY,{})}),r&&ru.jsx(h4,{className:"react-flow__controls-interactive",onClick:X,title:N["controls.interactive.ariaLabel"],"aria-label":N["controls.interactive.ariaLabel"],children:G?ru.jsx(hY,{}):ru.jsx(RY,{})}),F]})}Fz.displayName="Controls";var Jz=iu.memo(Fz);function vY({id:u,x:f,y:l,width:r,height:y,style:i,color:_,strokeColor:n,strokeWidth:$,className:j,borderRadius:F,shapeRendering:J,selected:U,onClick:q}){let{background:W,backgroundColor:G}=i||{},K=_||W||G;return ru.jsx("rect",{className:Yf(["react-flow__minimap-node",{selected:U},j]),x:f,y:l,rx:F,ry:F,width:r,height:y,style:{fill:K,stroke:n,strokeWidth:$},shapeRendering:J,onClick:q?(Q)=>q(Q,u):void 0})}var IY=iu.memo(vY),kY=(u)=>u.nodes.map((f)=>f.id),I7=(u)=>u instanceof Function?u:()=>u;function gY({nodeStrokeColor:u,nodeColor:f,nodeClassName:l="",nodeBorderRadius:r=5,nodeStrokeWidth:y,nodeComponent:i=IY,onClick:_}){let n=uf(kY,Kf),$=I7(f),j=I7(u),F=I7(l),J=typeof window>"u"||!!window.chrome?"crispEdges":"geometricPrecision";return ru.jsx(ru.Fragment,{children:n.map((U)=>ru.jsx(aY,{id:U,nodeColorFunc:$,nodeStrokeColorFunc:j,nodeClassNameFunc:F,nodeBorderRadius:r,nodeStrokeWidth:y,NodeComponent:i,onClick:_,shapeRendering:J},U))})}function sY({id:u,nodeColorFunc:f,nodeStrokeColorFunc:l,nodeClassNameFunc:r,nodeBorderRadius:y,nodeStrokeWidth:i,shapeRendering:_,NodeComponent:n,onClick:$}){let{node:j,x:F,y:J,width:U,height:q}=uf((W)=>{let G=W.nodeLookup.get(u);if(!G)return{node:void 0,x:0,y:0,width:0,height:0};let K=G.internals.userNode,{x:Q,y:N}=G.internals.positionAbsolute,{width:c,height:z}=i0(K);return{node:K,x:Q,y:N,width:c,height:z}},Kf);if(!j||j.hidden||!V7(j))return null;return ru.jsx(n,{x:F,y:J,width:U,height:q,style:j.style,selected:!!j.selected,className:r(j),color:f(j),borderRadius:y,strokeColor:l(j),strokeWidth:i,shapeRendering:_,onClick:$,id:j.id})}var aY=iu.memo(sY),oY=iu.memo(gY),dY=200,eY=150,uD=(u)=>!u.hidden,fD=(u)=>{let f={x:-u.transform[0]/u.transform[2],y:-u.transform[1]/u.transform[2],width:u.width/u.transform[2],height:u.height/u.transform[2]};return{viewBB:f,boundingRect:u.nodeLookup.size>0?H7(Ri(u.nodeLookup,{filter:uD}),f):f,rfId:u.rfId,panZoom:u.panZoom,translateExtent:u.translateExtent,flowWidth:u.width,flowHeight:u.height,ariaLabelConfig:u.ariaLabelConfig}},lD="react-flow__minimap-desc";function Uz({style:u,className:f,nodeStrokeColor:l,nodeColor:r,nodeClassName:y="",nodeBorderRadius:i=5,nodeStrokeWidth:_,nodeComponent:n,bgColor:$,maskColor:j,maskStrokeColor:F,maskStrokeWidth:J,position:U="bottom-right",onClick:q,onNodeClick:W,pannable:G=!1,zoomable:K=!1,ariaLabel:Q,inversePan:N,zoomStep:c=1,offsetScale:z=5}){let w=Tf(),H=iu.useRef(null),{boundingRect:B,viewBB:T,rfId:X,panZoom:R,translateExtent:Y,flowWidth:P,flowHeight:t,ariaLabelConfig:O}=uf(fD,Kf),M=u?.width??dY,S=u?.height??eY,b=B.width/M,Z=B.height/S,D=Math.max(b,Z),I=D*M,k=D*S,h=z*D,o=B.x-(I-B.width)/2-h,s=B.y-(k-B.height)/2-h,x=I+h*2,uu=k+h*2,nu=`${lD}-${X}`,$u=iu.useRef(0),Fu=iu.useRef();$u.current=D,iu.useEffect(()=>{if(H.current&&R)return Fu.current=bc({domNode:H.current,panZoom:R,getTransform:()=>w.getState().transform,getViewScale:()=>$u.current}),()=>{Fu.current?.destroy()}},[R]),iu.useEffect(()=>{Fu.current?.update({translateExtent:Y,width:P,height:t,inversePan:N,pannable:G,zoomStep:c,zoomable:K})},[G,K,N,c,Y,P,t]);let Ku=q?(d)=>{let[e,cu]=Fu.current?.pointer(d)||[0,0];q(d,{x:e,y:cu})}:void 0,Wu=W?iu.useCallback((d,e)=>{let cu=w.getState().nodeLookup.get(e).internals.userNode;W(d,cu)},[]):void 0,m=Q??O["minimap.ariaLabel"];return ru.jsx(I4,{position:U,style:{...u,"--xy-minimap-background-color-props":typeof $==="string"?$:void 0,"--xy-minimap-mask-background-color-props":typeof j==="string"?j:void 0,"--xy-minimap-mask-stroke-color-props":typeof F==="string"?F:void 0,"--xy-minimap-mask-stroke-width-props":typeof J==="number"?J*D:void 0,"--xy-minimap-node-background-color-props":typeof r==="string"?r:void 0,"--xy-minimap-node-stroke-color-props":typeof l==="string"?l:void 0,"--xy-minimap-node-stroke-width-props":typeof _==="number"?_:void 0},className:Yf(["react-flow__minimap",f]),"data-testid":"rf__minimap",children:ru.jsxs("svg",{width:M,height:S,viewBox:`${o} ${s} ${x} ${uu}`,className:"react-flow__minimap-svg",role:"img","aria-labelledby":nu,ref:H,onClick:Ku,children:[m&&ru.jsx("title",{id:nu,children:m}),ru.jsx(oY,{onClick:Wu,nodeColor:r,nodeStrokeColor:l,nodeBorderRadius:i,nodeClassName:y,nodeStrokeWidth:_,nodeComponent:n}),ru.jsx("path",{className:"react-flow__minimap-mask",d:`M${o-h},${s-h}h${x+h*2}v${uu+h*2}h${-x-h*2}z + M${T.x},${T.y}h${T.width}v${T.height}h${-T.width}z`,fillRule:"evenodd",pointerEvents:"none"})]})})}Uz.displayName="MiniMap";var ih=iu.memo(Uz),rD=(u)=>(f)=>u?`${Math.max(1/f.transform[2],1)}`:void 0,yD={[H1.Line]:"right",[H1.Handle]:"bottom-right"};function iD({nodeId:u,position:f,variant:l=H1.Handle,className:r,style:y=void 0,children:i,color:_,minWidth:n=10,minHeight:$=10,maxWidth:j=Number.MAX_VALUE,maxHeight:F=Number.MAX_VALUE,keepAspectRatio:J=!1,resizeDirection:U,autoScale:q=!0,shouldResize:W,onResizeStart:G,onResize:K,onResizeEnd:Q}){let N=RN(),c=typeof u==="string"?u:N,z=Tf(),w=iu.useRef(null),H=l===H1.Handle,B=uf(iu.useCallback(rD(H&&q),[H,q]),Kf),T=iu.useRef(null),X=f??yD[l];iu.useEffect(()=>{if(!w.current||!c)return;if(!T.current)T.current=sc({domNode:w.current,nodeId:c,getStoreItems:()=>{let{nodeLookup:Y,transform:P,snapGrid:t,snapToGrid:O,nodeOrigin:M,domNode:S}=z.getState();return{nodeLookup:Y,transform:P,snapGrid:t,snapToGrid:O,nodeOrigin:M,paneDomNode:S}},onChange:(Y,P)=>{let{triggerNodeChanges:t,nodeLookup:O,parentLookup:M,nodeOrigin:S}=z.getState(),b=[],Z={x:Y.x,y:Y.y},D=O.get(c);if(D&&D.expandParent&&D.parentId){let I=D.origin??S,k=Y.width??D.measured.width??0,h=Y.height??D.measured.height??0,o={id:D.id,parentId:D.parentId,rect:{width:k,height:h,...X7({x:Y.x??D.position.x,y:Y.y??D.position.y},{width:k,height:h},D.parentId,O,I)}},s=m4([o],O,M,S);b.push(...s),Z.x=Y.x?Math.max(I[0]*k,Y.x):void 0,Z.y=Y.y?Math.max(I[1]*h,Y.y):void 0}if(Z.x!==void 0&&Z.y!==void 0){let I={id:c,type:"position",position:{...Z}};b.push(I)}if(Y.width!==void 0&&Y.height!==void 0){let k={id:c,type:"dimensions",resizing:!0,setAttributes:!U?!0:U==="horizontal"?"width":"height",dimensions:{width:Y.width,height:Y.height}};b.push(k)}for(let I of P){let k={...I,type:"position"};b.push(k)}t(b)},onEnd:({width:Y,height:P})=>{let t={id:c,type:"dimensions",resizing:!1,dimensions:{width:Y,height:P}};z.getState().triggerNodeChanges([t])}});return T.current.update({controlPosition:X,boundaries:{minWidth:n,minHeight:$,maxWidth:j,maxHeight:F},keepAspectRatio:J,resizeDirection:U,onResizeStart:G,onResize:K,onResizeEnd:Q,shouldResize:W}),()=>{T.current?.destroy()}},[X,n,$,j,F,J,G,K,Q,W]);let R=X.split("-");return ru.jsx("div",{className:Yf(["react-flow__resize-control","nodrag",...R,l,r]),ref:w,style:{...y,scale:B,..._&&{[H?"backgroundColor":"borderColor"]:_}},children:i})}var _h=iu.memo(iD);var L=Y1.default.createElement,{useEffect:$0}=Y1.default,xl=Y1.default.useState,X1=Y1.default.useRef,z$=[{id:"in-left",side:"left",position:zu.Left,style:{top:"50%"}},{id:"in-top-left",side:"top",slot:"left",slotIndex:-1,position:zu.Top,style:{left:"28%"}},{id:"in-top-mid",side:"top",slot:"mid",slotIndex:0,position:zu.Top,style:{left:"50%"}},{id:"in-top-right",side:"top",slot:"right",slotIndex:1,position:zu.Top,style:{left:"72%"}},{id:"in-bottom-left",side:"bottom",slot:"left",slotIndex:-1,position:zu.Bottom,style:{left:"28%"}},{id:"in-bottom-mid",side:"bottom",slot:"mid",slotIndex:0,position:zu.Bottom,style:{left:"50%"}},{id:"in-bottom-right",side:"bottom",slot:"right",slotIndex:1,position:zu.Bottom,style:{left:"72%"}}],q$=[{id:"out-right",position:zu.Right,style:{top:"50%"}}],Qz=["#4eb7a8","#d7a13a","#69aee8","#e0835f","#b7d86b","#d98bd2","#5fc6bf"],ai=236,oi=88,qz=15000,_D=10,o7=96,_0=72,d7=64,Wz=12;function g4(){return typeof document>"u"||document.visibilityState!=="hidden"}function cz(u,f){let l=Number.parseFloat(String(u||""));return Number.isFinite(l)?l/100:f}function nD(u,f,l){let r=String(u.side||"");if(r!=="top"&&r!=="bottom")return 0;let y=Number(u.slotIndex||0),i=r==="top"?"in-top-mid":"in-bottom-mid",_=f.get(u.id)||0,n=f.get(i)||0;if(y===0)return n===0?-26:28+_*74;let $=l===0?Math.abs(y)*2:Math.sign(l)===Math.sign(y)?-3:3;if(n>0&&_===0)return-14+$;return 8+_*74+$}function s4(u){let f=u.filter((i,_)=>{let n=u[_-1];return!n||Math.abs(n.x-i.x)>0.5||Math.abs(n.y-i.y)>0.5});if(f.length<2)return"";let l=`M ${f[0].x},${f[0].y}`,r=f[0];for(let i=1;i0.5||Math.abs(U.y-r.y)>0.5)l+=` L ${U.x},${U.y}`;l+=` Q ${n.x},${n.y} ${q.x},${q.y}`,r=q}let y=f[f.length-1];return`${l} L ${y.x},${y.y}`}function mz(u,f,l,r,y,i,_=""){let n=l>=u,$=Math.max(1,Math.abs(l-u)),j=Math.abs(r-f),F=Math.max(34,Math.min(118,$*0.26)),J=Math.min(280,Math.abs(i));if(n&&y===zu.Left&&J<4&&j<28&&$<420)return`M ${u},${f} C ${u+F},${f} ${l-F},${r} ${l},${r}`;if(n&&y===zu.Left&&(_==="direct-forward-left"||$<=260&&j<=210)){let Q=Math.max(42,Math.min(140,$*0.48)),N=Math.max(-28,Math.min(28,i*0.18));return`M ${u},${f} C ${u+Q},${f+N} ${l-Q},${r} ${l},${r}`}if(n){let Q=u+F;if(y===zu.Top||y===zu.Bottom){let z=y===zu.Top?-1:1,w=r+z*(54+J*0.42);return s4([{x:u,y:f},{x:Q,y:f},{x:Q+Math.min(120,$*0.18),y:w},{x:l,y:w},{x:l,y:r+z*34},{x:l,y:r}])}let N=l-F,c=(f+r)/2+i;return s4([{x:u,y:f},{x:Q,y:f},{x:Q+Math.min(110,$*0.16),y:c},{x:N-Math.min(90,$*0.12),y:c},{x:N,y:r},{x:l,y:r}])}let W=y===zu.Bottom?1:y===zu.Top?-1:i>=0?1:-1,G=Math.max(u,l)+92+Math.min(180,J*0.52),K=W<0?Math.min(f,r)-84-J*0.62:Math.max(f,r)+84+J*0.62;if(y===zu.Top||y===zu.Bottom)return s4([{x:u,y:f},{x:u+F,y:f},{x:G,y:K},{x:l,y:K},{x:l,y:r+W*38},{x:l,y:r}]);return s4([{x:u,y:f},{x:u+F,y:f},{x:G,y:K},{x:l-F,y:K},{x:l-F,y:r},{x:l,y:r}])}function $D({data:u}){return L("div",{className:"pipeline-flow-node-body"},z$.map((f)=>L(Zy,{key:f.id,id:f.id,type:"target",position:f.position,isConnectable:!1,className:`pipeline-flow-handle input ${f.side} slot-${f.slot||"mid"}`,style:f.style})),q$.map((f)=>L(Zy,{key:f.id,id:f.id,type:"source",position:f.position,isConnectable:!1,className:"pipeline-flow-handle output right",style:f.style})),u?.label)}function AD({id:u,sourceX:f,sourceY:l,targetX:r,targetY:y,targetPosition:i,markerEnd:_,markerStart:n,style:$,data:j}){let F=Number(j?.laneOffset||0),J=mz(f,l,r,y,i,F,String(j?.routeMode||""));return L(si,{id:u,path:J,markerEnd:_,markerStart:n,style:$,interactionWidth:28})}var jD={pipelineCurve:AD},FD={pipelineNode:$D};function e4(u){if(!u)return"--";let f=new Date(u);if(Number.isNaN(f.getTime()))return"--";return qf(f)}function Er(u){let f=Number(u);if(!Number.isFinite(f)||f<0)return"--";let l=Math.round(f/1000);if(l<60)return`${l}s`;if(l<3600)return`${Math.floor(l/60)}m ${l%60}s`;return`${Math.floor(l/3600)}h ${Math.floor(l%3600/60)}m`}function e7(u){let f=Number(u);if(!Number.isFinite(f))return"--";return f.toLocaleString("zh-CN")}function Nz(u){let f=Number(u);if(!Number.isFinite(f))return"--";return`${Math.round(Math.max(0,Math.min(1,f))*100)}%`}function Yu(u){return typeof u==="object"&&u!==null&&!Array.isArray(u)}function Hu(u){return Array.isArray(u)?u:[]}function hu(u){if(!u)return null;let f=new Date(u);return Number.isNaN(f.getTime())?null:f.getTime()}function G$(u){return Number.isFinite(Number(u))?new Date(Number(u)).toISOString():""}function w$(...u){for(let f of u){let l=hu(f);if(l!==null)return new Date(l).toISOString()}return""}function Uj(...u){let f=u.map(hu).filter((l)=>l!==null);return f.length>0?new Date(Math.max(...f)).toISOString():""}function Qj(u){return["succeeded","failed","skipped","cancelled","canceled","completed"].includes(String(u||"").toLowerCase())}function pz(u){let f=Rz(u).toLowerCase();return["running","active","in-progress","in_progress"].includes(f)}function zz(u,f="status"){return u.reduce((l,r)=>{let y=String(r?.[f]||"unknown").toLowerCase();return l[y]=(l[y]||0)+1,l},{})}function Cz(u){if(!u||typeof u!=="string")return null;try{let f=JSON.parse(u);return Yu(f)?f:null}catch{return null}}function uj(u){let f=u.map(Cz).filter((i)=>Boolean(i)),l=f.flatMap((i)=>[i.timestamp,i.createdAt,i.updatedAt]).filter(Boolean),r=Uj(...l),y=Array.from(new Set(f.map((i)=>String(i.event||i.action||i.type||"")).filter(Boolean))).slice(0,3);return{total:u.length,parsed:f.length,lastAt:r,eventKinds:y}}function u8(u){if(u===null||u===void 0)return"--";if(typeof u==="boolean")return u?"是":"否";if(typeof u==="number")return String(u);if(typeof u==="string")return u.length>80?`${u.slice(0,77)}...`:u;if(Array.isArray(u))return`${u.length} 项`;if(typeof u==="object")return`${Object.keys(u).length} 字段`;return String(u)}function xz(u,f=280){if(u===null||u===void 0)return"";let r=(typeof u==="string"?u:String(u)).replace(/\r\n/gu,` +`).trim();return r.length>f?`${r.slice(0,Math.max(0,f-1))}...`:r}function Rz(u){if(typeof u==="string")return u;if(Yu(u))return String(u.status||u.state||u.phase||"unknown");return"unknown"}function JD(u){return u.filter((f)=>f&&f.value!==void 0&&f.value!==null&&String(f.value)!=="")}function _j({items:u}){let f=JD(Hu(u));return L("div",{className:"pipeline-kv-grid"},f.map((l)=>L("span",{key:l.label},L("b",null,l.label),L("span",null,l.value))))}function qj({items:u}){let f=Hu(u).map((l)=>String(l||"")).filter(Boolean);if(f.length===0)return null;return L("div",{className:"pipeline-chip-row"},f.map((l,r)=>L("span",{key:`${r}-${l}`},l)))}function nj(u,f){let l=String(f?.procedureRunId||""),r=Hu(u?.procedureRuns);return r.find((y)=>String(Tr(y))===l)||r.at(-1)||null}function UD(u,f){let l=String(f||"");if(!l)return null;return Hu(u?.procedureRuns).find((r)=>Tr(r)===l)||null}function fj(u){return Hu(u?.attempts).length}function Gz(u){return Hu(u?.attempts).reduce((f,l)=>f+n8(l).length,0)}function n8(u){return Hu(u?.opencodeMessages?.steps).filter(Yu)}function hz(u){let f=String(u?.status||"").toLowerCase();if(["error","failed","failure"].includes(f))return"failed";if(["completed","succeeded","success"].includes(f))return"succeeded";if(["running","started","in_progress"].includes(f))return"running";return"unknown"}function QD(u,f){let l=$j(u.map((i)=>i?.agent)).slice(0,3),r=$j(u.map((i)=>i?.model)).slice(0,3),y=f.length<=2?f.map((i)=>`session ${i}`):[`sessions ${f.length}`,...f.slice(0,2).map((i)=>`session ${i}`)];return[...l.map((i)=>`agent ${i}`),...r.map((i)=>`model ${i}`),...y]}function W$(u,f=0){return String(u?.messageId||u?.index||"")||`step-${f}`}function qD({steps:u,sessionIds:f,sessionFacts:l,matchedStepKey:r}){let y=Hu(u),i=y.findIndex((K,Q)=>W$(K,Q)===r),_=i>=0?y[i]:null,n=y.flatMap((K)=>[hu(K?.createdAt),hu(K?.completedAt)]).filter((K)=>K!==null),$=n.length>0?Math.min(...n):null,j=n.length>0?Math.max(...n):null,F=$!==null&&j!==null?Math.max(0,j-$):null,J=y.reduce((K,Q)=>K+Hu(Q?.parts).filter((N)=>String(N?.type||"").toLowerCase()==="tool").length,0),U=y.reduce((K,Q)=>K+Hu(Q?.parts).filter((N)=>["text","reasoning"].includes(String(N?.type||"").toLowerCase())).length,0),q=y.reduce((K,Q)=>K+Hu(Q?.parts).filter((N)=>String(N?.type||"").toLowerCase()==="tool"&&hz(N)==="failed").length,0),W=[`${y.length} steps`,`${f.length} sessions`,`${U} messages`,`${J} tools`,F!==null?`duration ${Er(F)}`:"",q>0?`${q} failed tools`:""].filter(Boolean),G=_?[`Step ${_?.index??i+1}`,String(_?.role||"role --"),_?.model?`model ${_.model}`:"",_?.finish?`finish ${_.finish}`:"",_?.durationMs!==void 0&&_?.durationMs!==null?`duration ${Er(_.durationMs)}`:""].filter(Boolean):[];return L("section",{className:"pipeline-trace-timeline","data-testid":"pipeline-step-timeline"},L("div",{className:"pipeline-trace-head"},L("div",null,L("b",null,"OpenCode Trace"),L("span",null,"Trace 使用 Code Queue 统一样式展示完整 agent loop;Pipeline 旧 step/message/tool 卡片样式已废弃。")),L("div",{className:"pipeline-trace-session-head","data-testid":"pipeline-step-timeline-session"},L("span",null,W.join(" / ")||"Trace"),l.length>0?L(qj,{items:l}):null)),_?L("div",{className:"pipeline-trace-focus","data-testid":"pipeline-trace-matched-step"},L("span",{className:"codex-output-channel"},"Matched"),L("strong",null,`Gantt selection -> ${G.join(" / ")}`),L("time",null,`${e4(_?.createdAt)} -> ${e4(_?.completedAt)}`)):null,L(H6,{port:Wq,input:y,className:"codex-transcript pipeline-trace",testId:"pipeline-opencode-step-trace",emptyText:"暂无 OpenCode Trace 输出",keepRecentToolCalls:3}))}function c$(u){return Hu(u).flatMap((f)=>{if(Yu(f))return[f];let l=Cz(f);return l?[l]:[]})}function xr(u){return String(u?.event||u?.action||u?.requestedAction||u?.type||"").toLowerCase()}function Hy(u){return w$(u?.timestamp,u?.createdAt,u?.updatedAt,u?.startedAt,u?.finishedAt)}function WD(u){return hu(Hy(u))}function $8(u){return String(u?.attempt||u?.id||"")}function $j(u){let f=new Set,l=[];for(let r of u){let y=String(r||"");if(!y||f.has(y))continue;f.add(y),l.push(y)}return l}function Kz(u){switch(String(u||"").toLowerCase()){case"monitor":return"monitor";case"webui":return"webui";case"cli":return"cli";case"system":return"runner";default:return String(u||"--")}}function Oy(u){return String(u?.requestedAction||u?.action||"").toLowerCase()}function N$(u){switch(Oy(u)){case"guide":return"引导";case"modify":return"修改";case"approve":return"审核通过";case"restart":return"重启";case"redo":return"重做";default:return String(u?.requestedAction||u?.action||"控制")}}function Lz(u){switch(xr(u)){case"initial-prompt-delivered":return"初始 prompt";case"append-prompt-delivered":return"追加 prompt";case"append-prompt-queued":return"追加 prompt 已排队";case"monitor-prompt-delivered":return"Monitor prompt";case"node-long-running-observation":return"长任务观察";case"node-finished":return"节点完成";case"oa-policy-downstream-evaluated":return"OA 下游策略";case"control-command-queued":return`${N$(u)} 已发起`;case"control-command-applied":return`${N$(u)} 已生效`;case"control-command-ignored":return`${N$(u)} 已忽略`;default:return String(u?.event||u?.action||u?.requestedAction||"event")}}function wz(u){return xz(u?.promptPreview||u?.reasonPreview||u?.prompt||u?.reason||"",240)}function cD(u){let f=String(u?.prompt||""),l=String(u?.reason||u?.restartReason||""),r=f?"":String(u?.promptPreview||""),y=l?"":String(u?.reasonPreview||"");return[f||r?{label:f?"prompt":"prompt preview",value:f||r}:null,l||y?{label:l?"reason":"reason preview",value:l||y}:null,Hu(u?.resetNodeIds).length>0?{label:"reset nodes",value:Hu(u.resetNodeIds).join(", ")}:null,Hu(u?.runningResetNodeIds).length>0?{label:"interrupted running nodes",value:Hu(u.runningResetNodeIds).join(", ")}:null,Hu(u?.interruptedProcedureRunIds).length>0?{label:"interrupted procedures",value:Hu(u.interruptedProcedureRunIds).join(", ")}:null,u?.interruptedProcedureRunId?{label:"interrupted procedure",value:String(u.interruptedProcedureRunId)}:null].filter(Boolean)}function lj(u){let f=n8(u),l=f.map(($)=>hu($?.createdAt)).filter(($)=>$!==null),r=f.map(($)=>hu($?.completedAt)??hu($?.createdAt)).filter(($)=>$!==null),y=c$(u?.controlEventRecords).map(($)=>WD($)).filter(($)=>$!==null),i=Hu(u?.assistantOutputs).map(($)=>hu($?.updatedAt)).filter(($)=>$!==null),_=l[0]??y[0]??i[0]??null,n=r.at(-1)??y.at(-1)??i.at(-1)??_;return{startMs:_,endMs:n}}function ND(u,f,l,r,y=""){let i=Hu(u?.procedureRuns).filter((n)=>A8(n,f)===l);if(i.length===0)return null;if(y){let n=i.find(($)=>Tr($)===y);if(n)return n}if(r===null)return i.at(-1)||null;let _=i.find((n)=>{let $=hu(a4(n,u)),j=hu(o4(n,u))??$;return $!==null&&j!==null&&r>=$-1000&&r<=j+1000});if(_)return _;return i.slice().sort((n,$)=>{let j=hu(a4(n,u))??r,F=hu(o4(n,u))??j,J=hu(a4($,u))??r,U=hu(o4($,u))??J,q=Math.min(Math.abs(j-r),Math.abs(F-r)),W=Math.min(Math.abs(J-r),Math.abs(U-r));return q-W})[0]||null}function bz(u,f){let l=Hu(u?.attempts).filter(Yu);if(l.length===0)return null;let r=String(f?.attempt||"");if(r){let _=l.find((n)=>$8(n)===r);if(_)return _}let y=Number.isFinite(Number(f?.ms))?Number(f.ms):null;if(y===null)return l.at(-1)||null;let i=l.find((_)=>{let n=lj(_);return Number.isFinite(n.startMs)&&Number.isFinite(n.endMs)&&y>=Number(n.startMs)-1000&&y<=Number(n.endMs)+1000});if(i)return i;return l.slice().sort((_,n)=>{let $=lj(_),j=lj(n),F=Math.min(Math.abs(Number($.startMs??y)-y),Math.abs(Number($.endMs??y)-y)),J=Math.min(Math.abs(Number(j.startMs??y)-y),Math.abs(Number(j.endMs??y)-y));return F-J})[0]||l.at(-1)||null}function vz(u,f){let l=n8(u);if(l.length===0)return{step:null,stepIndex:-1,stepKey:""};if(f===null){let i=l[0];return{step:i,stepIndex:0,stepKey:W$(i,0)}}for(let i=0;i=n-1000&&f<=$+1000)return{step:_,stepIndex:i,stepKey:W$(_,i)}}let r=l.findIndex((i)=>{let _=hu(i?.createdAt)??hu(i?.completedAt);return _!==null&&_>=f});if(r>=0){let i=l[r];return{step:i,stepIndex:r,stepKey:W$(i,r)}}let y=Math.max(0,l.length-1);return{step:l[y],stepIndex:y,stepKey:W$(l[y],y)}}function zD(u,f){let l=String(f?.runId||u?.runId||"");if(String(f?.mode||"")==="interval"){let j=f?.interval||{},F=nj(u,j)||j.raw||{};return{mode:"interval",runId:l,interval:j,marker:null,nodeId:String(j?.nodeId||A8(F,l)||""),procedure:F,attempt:null,matchedStep:null,matchedStepIndex:-1,matchedStepKey:""}}let r=Yu(f?.marker)?f.marker:{},y=Number.isFinite(Number(r?.ms))?Number(r.ms):null,i=String(r?.nodeId||""),_=i?ND(u,l,i,y,String(r?.procedureRunId||"")):null,n=_?bz(_,r):null,$=n?vz(n,y):{step:null,stepIndex:-1,stepKey:""};return{mode:"event",runId:l,interval:null,marker:r,nodeId:i,procedure:_,attempt:n,matchedStep:$.step,matchedStepIndex:$.stepIndex,matchedStepKey:$.stepKey}}function GD({procedure:u,matchedStepKey:f="",matchedAttemptId:l=""}){let r=Hu(u?.attempts);if(r.length===0)return L($r,{title:"暂无 attempt 详情",text:"当前 procedure 还没有可展示的 attempt / OpenCode Trace;若刚点击甘特线,请等待 node 详情抓取完成。"});return r.map((y,i)=>{let _=y?.opencodeMessages||{},n=n8(y),$=Hu(_.sessionIds).map((U)=>String(U)).filter(Boolean),j=QD(n,$),F=$8(y)||`attempt-${i+1}`,J=n.reduce((U,q)=>U+Hu(q?.parts).filter((W)=>String(W?.type||"").toLowerCase()==="tool"&&hz(W)==="failed").length,0);return L("article",{key:F,className:`pipeline-attempt-card ${l===F?"matched":""}`},L("div",{className:"pipeline-attempt-head"},L("div",null,L("strong",null,F),L("span",null,_.source||"opencode")),L("div",{className:"pipeline-attempt-badges"},L("span",null,`${n.length} steps`),L("span",null,`${_.toolCallCount??"--"} tools`),J>0?L("span",{className:"danger"},`${J} failed`):null)),L(_j,{items:[{label:"messages",value:_.messageCount??"--"},{label:"steps",value:_.stepCount??n.length},{label:"tools",value:_.toolCallCount??"--"},{label:"updated",value:Nu(_.updatedAt)},{label:"sessions",value:$.join(", ")||"--"}]}),n.length===0?L("p",{className:"muted paragraph"},"当前 attempt 尚未返回 OpenCode Trace;请确认 D601 pipeline-control 已重建并重新抓取。"):L(qD,{steps:n,sessionIds:$,sessionFacts:j,matchedStepKey:f}))})}function rj(u,f){return`${u}::${f}`}function f8(u,f,l){if(!Yu(u))return null;return String(u.runId||"")===f&&String(u.nodeId||"")===l?u:null}function KD(u,f){let l=Yu(u)?u:{};if(!Yu(f))return l;let r=Hu(f.attempts),y=Hu(l.attempts);return{...l,...f,attempts:r.length>0?r:y}}function LD(u,f,l,r){if(!f8(f,l,r))return u;let y=Hu(f.procedureRuns),i=Yu(u)?u:{};return{...i,...f,controlCommands:Hu(f.controlCommands).length>0?f.controlCommands:i.controlCommands,controlEvents:Hu(f.controlEvents).length>0?f.controlEvents:i.controlEvents,procedureRuns:y.length>0?y:i.procedureRuns}}function wD({selection:u,runDetails:f,nodeDetails:l,nodeDetailsState:r,onRaw:y,onCollapse:i}){if(!u?.mode)return L("aside",{className:"pipeline-gantt-detail-panel empty","data-testid":"pipeline-gantt-detail-panel"},L("div",{className:"pipeline-gantt-detail-head"},L("div",null,L("span",{className:"panel-eyebrow"},"Gantt Detail"),L(Af,{title:"未选择元素",level:3})),L("button",{type:"button",className:"ghost-btn mini",onClick:i,"data-testid":"pipeline-gantt-sidebar-collapse"},"收起")),L($r,{title:"选择一条执行线或一个控制点",text:"点击甘特图中的 node 执行线、prompt 点或控制点,在这里查看结构化过程和 OpenCode step。"}));let _=String(u?.runId||""),n=String(u?.interval?.nodeId||u?.marker?.nodeId||""),$=f?.runId===_?f.details:null,j=f8(l,_,n),F=String(r?.runId||"")===_&&String(r?.nodeId||"")===n,J=LD($,j,_,n),U=(String(f?.runId||"")!==_||Boolean(f?.loading))&&!J,q=String(f?.runId||"")===_?String(f?.error||""):"",W=F?String(r?.error||""):"",G=J?zD(J,u):null,K=G?.interval||u?.interval||null,Q=G?.marker||u?.marker||null,N=String(K?.procedureRunId||Q?.procedureRunId||""),c=j?UD(j,N)||nj(j,K||{procedureRunId:N}):null,z=G?.procedure||(J?nj(J,K||{procedureRunId:N}):null)||K?.raw||{};if(c&&(fj(z)===0||Gz(c)>=Gz(z)))z=KD(z,c);let w=G?.attempt||null,H=String(G?.matchedStepKey||"");if(!w&&Q&&fj(z)>0)w=bz(z,Q),H=String(vz(w,Number.isFinite(Number(Q?.ms))?Number(Q.ms):null).stepKey||"");let B=$8(w),T=fj(z)>0,X=F&&Boolean(r?.loading)&&!T,R=Boolean(U||X),Y=[T?"":q,W].filter(Boolean).join(" / "),P=F&&r?.fetchedAt?r.fetchedAt:f?.fetchedAt,t=Rz(z?.status||K?.status||Q?.status||Q?.event),O=u?.mode==="event"?Q?.label||Lz(Q?.raw||Q)||"event":G?.nodeId||K?.nodeId||"node",M=Q?cD(Q?.raw||Q):[],S=Q?[xr(Q?.raw||Q)?`event ${xr(Q?.raw||Q)}`:"",Q?.promptEvent?`prompt ${Q.promptEvent}`:"",Q?.action?`action ${Q.action}`:"",Q?.sourceKind?`source ${Kz(Q.sourceKind)}`:"",Q?.sourceNodeId?`from ${Q.sourceNodeId}`:"",Q?.targetNodeId?`to ${Q.targetNodeId}`:"",Q?.snapReason?`draw ${Q.snapReason}`:""].filter(Boolean):[];return L("aside",{className:"pipeline-gantt-detail-panel","data-testid":"pipeline-gantt-detail-panel"},L("div",{className:"pipeline-gantt-detail-head"},L("div",null,L("span",{className:"panel-eyebrow"},u?.mode==="event"?"Gantt Event Detail":"Gantt Line Detail"),L(Af,{title:O,level:3,loading:R})),L("div",{className:"pipeline-gantt-detail-head-actions"},L(D1,{status:t},t),L("button",{type:"button",className:"ghost-btn mini",onClick:i,"data-testid":"pipeline-gantt-sidebar-collapse"},"收起"))),Q?L("article",{className:"pipeline-event-card"},L("div",{className:"pipeline-event-card-head"},L("strong",null,Q?.label||Lz(Q?.raw||Q)),L(qj,{items:S})),L(_j,{items:[{label:"event time",value:Nu(Q?.timestampIso||Q?.timestamp||"--")},Q?.snapped?{label:"drawn time",value:Nu(Q?.renderedTimestampIso||Q?.ms)}:null,{label:"node",value:Q?.nodeId||"--"},{label:"procedure",value:Q?.procedureRunId||Tr(z)||"--"},{label:"attempt",value:Q?.attempt||B||"--"},{label:"source kind",value:Q?.sourceKind?Kz(Q.sourceKind):"--"},{label:"source node",value:Q?.sourceNodeId||"--"},{label:"target node",value:Q?.targetNodeId||"--"},{label:"command",value:Q?.commandId||Q?.eventId||"--"},Q?.snapReason?{label:"placement",value:Q.snapReason}:null]}),M.length>0?L("div",{className:"pipeline-event-blocks"},M.map((b,Z)=>L("section",{key:`${b.label}-${Z}`,className:"pipeline-event-text-block"},L("b",null,b.label),L("p",null,b.value)))):null,wz(Q?.raw||Q)?L("p",{className:"pipeline-text-preview"},wz(Q?.raw||Q)):null):null,L(_j,{items:[{label:"epoch",value:_||K?.runId||"--"},{label:"node",value:G?.nodeId||K?.nodeId||Q?.nodeId||"--"},{label:"procedure",value:K?.procedureRunId||Q?.procedureRunId||Tr(z)||"--"},{label:"started",value:Nu(K?.startedAt||z?.startedAt)},{label:"finished",value:Nu(K?.finishedAt||z?.finishedAt)},{label:"duration",value:Er(K?.durationMs||z?.durationMs)},{label:"fetched",value:P?qf(P):"--"},G?.matchedStep?{label:"matched step",value:`Step ${G.matchedStep.index??G.matchedStepIndex+1}`}:null]}),L(jf,{error:Y}),L("div",{className:"pipeline-gantt-detail-actions"},L(Rr,{title:`Procedure ${K?.procedureRunId||Q?.procedureRunId||G?.nodeId||"node"}`,data:z,onOpen:y,testId:"raw-pipeline-gantt-procedure"}),Q?L(Rr,{title:`Pipeline event ${Q?.id||Q?.commandId||Q?.eventId||G?.nodeId||"event"}`,data:Q?.raw||Q,onOpen:y,testId:"raw-pipeline-gantt-event"}):null,J?L(Rr,{title:`Pipeline run ${_||"--"}`,data:J,onOpen:y,testId:"raw-pipeline-gantt-node-details"}):null),!R&&!Tr(z)&&!Q?L($r,{title:"暂无过程详情",text:"当前选择还没有可匹配的 procedure 运行记录。"}):null,!R&&Tr(z)?L(GD,{procedure:z,matchedStepKey:H,matchedAttemptId:B}):null)}function ED({value:u}){let l=String(u||"--").split(/([_-])/u);return L(Y1.default.Fragment,null,l.map((r,y)=>r==="-"||r==="_"?L(Y1.default.Fragment,{key:y},r,L("wbr",null)):L(Y1.default.Fragment,{key:y},r)))}async function B1(u,f={}){return Xu(u,{invalidJsonPrefix:"Pipeline 返回了无效 JSON",...f})}function D1({status:u,children:f}){let l=String(u||"unknown").toLowerCase();return L("span",{className:`status-badge ${l}`},f||u||"unknown")}function Hl({label:u,value:f,hint:l,tone:r}){return L("article",{className:`metric-card ${r||""}`},L("div",{className:"metric-label"},u),L("div",{className:"metric-value"},f),L("div",{className:"metric-hint"},l))}function n0({title:u,eyebrow:f,actions:l,children:r,className:y,loading:i}){return L("section",{className:`panel ${y||""}`},L("div",{className:"panel-head"},L("div",null,f?L("p",{className:"panel-eyebrow"},f):null,L(Af,{title:u,loading:i})),l?L("div",{className:"panel-actions"},l):null),L("div",{className:"panel-body"},r))}function Rr({title:u,data:f,onOpen:l,testId:r}){return L("button",{type:"button",className:"ghost-btn","data-testid":r,onClick:()=>l(u,f)},"查看原始JSON")}function wr({title:u,subtitle:f,facts:l,data:r,onRaw:y,testId:i}){let _=Hu(l).map((n)=>String(n||"")).filter(Boolean);return L("article",{className:"pipeline-evidence-row"},L("div",{className:"pipeline-evidence-main"},L("strong",null,u),f?L("span",null,f):null),L("div",{className:"pipeline-evidence-facts"},_.map((n,$)=>L("span",{key:`${$}-${n.slice(0,16)}`},n))),r!==void 0?L(Rr,{title:u,data:r,onOpen:y,testId:i}):null)}function $r({title:u,text:f}){return L("div",{className:"empty-state"},L("strong",null,u),L("span",null,f))}function TD(u){return u?.runtime&&typeof u.runtime==="object"&&!Array.isArray(u.runtime)?u.runtime:{}}function ZD(u){return u?.backend&&typeof u.backend==="object"&&!Array.isArray(u.backend)?u.backend:{}}function HD(u){return u?.repository&&typeof u.repository==="object"&&!Array.isArray(u.repository)?u.repository:{}}function OD(u){return{components:Array.isArray(u?.registry?.components)?u.registry.components:[],pipelines:Array.isArray(u?.pipelines)?u.pipelines:[],runs:Array.isArray(u?.runs)?u.runs:[]}}function Ez(u,f,l){let r=u?._unidesk?.arrayLimits?.[f],y=Number(r?.originalLength);return Number.isFinite(y)?y:l}function Iz(u){if(!u||typeof u!=="object"||Array.isArray(u))return"--";return`${u.componentClass||"--"}/${u.id||"--"}`}function l8(u){if(!u||typeof u!=="object"||Array.isArray(u))return"";let f=String(u.componentClass||"").trim(),l=String(u.id||"").trim();return f&&l?`${f}/${l}`:""}function Wj(u){return u?.config&&typeof u.config==="object"&&!Array.isArray(u.config)?u.config:{}}function kz(u){let f=Wj(u),l=Array.isArray(f.nodes)?f.nodes:Array.isArray(u?.nodes)?u.nodes:[],r=new Map;for(let _ of l){let n=String(_?.id||_?.nodeId||"");if(n)r.set(n,{..._,id:n})}let y=cj(u),i=(_)=>{if(_&&!r.has(_))r.set(_,{id:_})};for(let _ of Nj(u))K$(_).forEach(i);for(let _ of y)i(String(_?.from||_?.source||"")),i(String(_?.to||_?.target||""));return Array.from(r.values())}function cj(u){let f=Wj(u);return Array.isArray(f.edges)?f.edges:Array.isArray(u?.edges)?u.edges:[]}function Nj(u){let f=Wj(u);return Array.isArray(f.topologicalBatches)?f.topologicalBatches:Array.isArray(u?.topologicalBatches)?u.topologicalBatches:[]}function BD(u){let f=new Map;for(let l of u){let r=l8(l);if(r)f.set(r,l);let y=Array.isArray(l?.refs)?l.refs:[];for(let i of y){let _=l8(i);if(_)f.set(_,l)}}return f}function Tz(u,f){let l=f.get(l8(u?.componentRef));if(l)return l;let r=l8({componentClass:u?.kind,id:u?.id});return r?f.get(r)||null:null}function Zz(u,f){let l=gz(u,f);return String(l?.status||"pending")}function gz(u,f){return(Array.isArray(u?.nodes)?u.nodes:[]).find((r)=>r?.nodeId===f||r?.id===f)||null}function VD(u){return u.reduce((f,l)=>{let r=String(l?.status||"unknown").toLowerCase();return f[r]=(f[r]||0)+1,f},{})}function XD(u){if(Array.isArray(u?.scorers))return u.scorers.filter(Yu);if(Array.isArray(u?.summary?.scorers))return u.summary.scorers.filter(Yu);if(Array.isArray(u?.artifact?.summary?.scorers))return u.artifact.summary.scorers.filter(Yu);return[]}function YD(u){if(Yu(u?.run))return u.run;if(Yu(u?.runSummary))return u.runSummary;return null}function DD(u,f){if(!Yu(u)&&!Yu(f))return null;if(!Yu(u))return f;if(!Yu(f))return u;return{...u,...f,request:Yu(u.request)||Yu(f.request)?{...Yu(u.request)?u.request:{},...Yu(f.request)?f.request:{}}:f.request??u.request,artifact:Yu(u.artifact)||Yu(f.artifact)?{...Yu(u.artifact)?u.artifact:{},...Yu(f.artifact)?f.artifact:{}}:f.artifact??u.artifact,summary:Yu(u.summary)||Yu(f.summary)?{...Yu(u.summary)?u.summary:{},...Yu(f.summary)?f.summary:{}}:f.summary??u.summary}}function r8(u){let f=XD(u),l=f.find((F)=>Yu(F?.score))||f[0]||null,r=Yu(l?.score)?l.score:{},y=Number(r.passed),i=Number(r.total),_=Number(r.ratio),n=Number.isFinite(_)?_:Number.isFinite(y)&&Number.isFinite(i)&&i>0?y/i:null,$=n===null?null:Math.round(Math.max(0,Math.min(100,n<=1?n*100:n))),j=String(r.text||(Number.isFinite(y)&&Number.isFinite(i)?`${y}/${i}`:""));return{scorer:l,scorers:f,score:r,passed:Number.isFinite(y)?y:null,total:Number.isFinite(i)?i:null,percent:$,text:j}}function Aj(u){let f=r8(u);return f.text||(f.scorers.length>0?String(f.scorer?.status||"pending"):"--")}function zj(u){let f=r8(u);if(f.total>0&&f.passed===f.total)return"succeeded";if(f.total>0&&f.passed>0)return"running";if(f.scorers.length>0)return"failed";return"pending"}function tD(u){return Array.isArray(u?.items)?u.items.filter(Yu):[]}function SD({run:u}){let f=Aj(u);return L("span",{className:`pipeline-score-badge ${zj(u)}`},`score ${f}`)}function PD({run:u,onRaw:f}){let r=r8(u).scorers;if(!u)return L($r,{title:"暂无评分",text:"选择一个 epoch 后会显示 scorer 结果。"});if(r.length===0)return L("div",{className:"pipeline-score-empty"},L("strong",null,"评分器等待中"),L("span",null,"DAG 完成后,Pipeline control backend 会把 scorer summary 追加到 run artifact,并通过 UniDesk 显示。"));return L("div",{className:"pipeline-score-board","data-testid":"pipeline-score-board"},r.map((y,i)=>{let _=r8({scorers:[y]}),n=tD(y),$=_.percent??0;return L("article",{key:`${y.scorerId||y.component||i}`,className:`pipeline-score-card ${zj({scorers:[y]})}`},L("div",{className:"pipeline-score-head"},L("div",null,L("span",null,y.scorerId||y.component||"scorer"),L("strong",null,_.text||y.status||"--")),L(D1,{status:y.status||"unknown"},y.status||"unknown")),L("div",{className:"pipeline-score-meter","aria-label":`score ${$}%`},L("span",{style:{width:`${$}%`}})),L("div",{className:"pipeline-score-facts"},L("span",null,`${$}%`),L("span",null,y.component||"--"),L("span",null,y.applicationCheckoutRef||"--")),n.length>0?L("div",{className:"pipeline-score-items"},n.map((j)=>L("span",{key:`${j.id||j.filter}`,className:`pipeline-score-item ${String(j.status||"").toLowerCase()}`,title:`${j.filter||"--"} / ran=${j.ran??"?"}`},L("b",null,j.id||"--"),L("small",null,j.status||"--")))):L("p",{className:"muted paragraph"},"当前 scorer 尚未返回 item 级结果。"),y.error?L("p",{className:"pipeline-score-error"},xz(y.error,360)):null,L("div",{className:"panel-actions inline-actions"},L(Rr,{title:`Scorer ${y.scorerId||i}`,data:y,onOpen:f,testId:"raw-pipeline-score"})))}))}function MD(u){let f=u.reduce((l,r)=>{let y=String(r?.componentClass||"unknown");return l[y]=(l[y]||0)+1,l},{});return Object.entries(f).map(([l,r])=>({name:l,count:Number(r)})).sort((l,r)=>r.count-l.count||l.name.localeCompare(r.name))}function K$(u){if(Array.isArray(u))return u.map((f)=>typeof f==="string"?f:String(f?.id||f?.nodeId||"")).filter(Boolean);if(Array.isArray(u?.nodes))return K$(u.nodes);if(Array.isArray(u?.nodeIds))return K$(u.nodeIds);return[]}function mD(u){return Yu(u?.instanceInputs?.monitor)?u.instanceInputs.monitor:{}}function sz(u,f){if(String(u?.kind||"").toLowerCase()!=="procedure")return!1;let l=mD(u);if(u?.instanceInputs?.monitorMode===!0||l.enabled===!0)return!0;let r=Iz(u?.componentRef);return String(f?.id||f?.config?.id||r||"").toLowerCase().includes("monitor")}function pD(u){return u.filter((f)=>sz(f)).map((f)=>String(f?.id||"")).filter(Boolean)}function CD(u,f){if(f.length===0)return u;let l=new Set(f),r=f.filter((y)=>u.includes(y));if(r.length===0)return u;return[...r,...u.filter((y)=>!l.has(y))]}function xD(u,f){if(f.length===0)return u;let l=new Set(f),r=f.filter((i)=>u.some((_)=>_.includes(i)));if(r.length===0)return u;let y=u.map((i)=>i.filter((_)=>!l.has(_))).filter((i)=>i.length>0);return[r,...y]}function RD(u,f,l){let y=Nj(u).map(K$).filter((U)=>U.length>0);if(y.length>0)return y;let i=f.map((U)=>String(U?.id||"")).filter(Boolean),_=new Set(i),n=new Map(i.map((U)=>[U,0])),$=new Map(i.map((U)=>[U,[]]));for(let U of l){let q=String(U?.from||U?.source||""),W=String(U?.to||U?.target||"");if(!_.has(q)||!_.has(W))continue;$.get(q)?.push(W),n.set(W,(n.get(W)||0)+1)}let j=new Map,F=i.filter((U)=>(n.get(U)||0)===0);for(let U of F)j.set(U,0);while(F.length>0){let U=F.shift(),q=(j.get(U)||0)+1;for(let W of $.get(U)||[])if(n.set(W,Math.max(0,(n.get(W)||0)-1)),j.set(W,Math.max(j.get(W)||0,q)),(n.get(W)||0)===0)F.push(W)}i.forEach((U)=>{if(!j.has(U))j.set(U,0)});let J=Math.max(0,...Array.from(j.values()));return Array.from({length:J+1},(U,q)=>i.filter((W)=>j.get(W)===q)).filter((U)=>U.length>0)}function hD(u,f,l){let y=Nj(u).map(K$).filter((n)=>n.length>0),i=y.length>0?y.flatMap((n)=>n):(()=>{let n=f.map((G)=>String(G?.id||"")).filter(Boolean),$=new Set(n),j=l.filter((G)=>String(G?.edgeType||"").toLowerCase()!=="rework"),F=new Map(n.map((G)=>[G,0])),J=new Map(n.map((G)=>[G,[]]));for(let G of j){let K=String(G?.from||G?.source||""),Q=String(G?.to||G?.target||"");if(!$.has(K)||!$.has(Q))continue;J.get(K)?.push(Q),F.set(Q,(F.get(Q)||0)+1)}let U=new Map,q=n.filter((G)=>(F.get(G)||0)===0);for(let G of q)U.set(G,0);while(q.length>0){let G=q.shift(),K=(U.get(G)||0)+1;for(let Q of J.get(G)||[])if(F.set(Q,Math.max(0,(F.get(Q)||0)-1)),U.set(Q,Math.max(U.get(Q)||0,K)),(F.get(Q)||0)===0)q.push(Q)}n.forEach((G)=>{if(!U.has(G))U.set(G,0)});let W=Math.max(0,...Array.from(U.values()));return Array.from({length:W+1},(G,K)=>n.filter((Q)=>U.get(Q)===K)).flatMap((G)=>G)})(),_=new Set(i);for(let n of f){let $=String(n?.id||"");if(!$||_.has($))continue;i.push($),_.add($)}return CD(i,pD(f))}function U$(u){return`${u.source}->${u.target}-${u.index}`}function Hz(u,f,l){let r=kz(u),y=cj(u),i=BD(l),_=new Map(r.map((t)=>[String(t?.id||""),t])),n=r.filter((t)=>sz(t,Tz(t,i))).map((t)=>String(t?.id||"")).filter(Boolean),$=xD(RD(u,r,y),n),j=[],F=new Map,J=330,U=122;$.forEach((t,O)=>{let M=t.length*122;t.forEach((S,b)=>{let Z=_.get(S)||{id:S},D=Tz(Z,i),I=Zz(f,S).toLowerCase(),k=String(Z.kind||D?.componentClass||"node").toLowerCase(),h=Iz(Z.componentRef||D),o=String(D?.config?.version||D?.version||""),s=String(D?.config?.description||D?.description||""),x=b*122-Math.floor(M/2);F.set(S,{column:O,row:b,y:x}),j.push({id:S,type:"pipelineNode",position:{x:O*330,y:x},data:{exportLabel:{id:S,kind:k,componentRef:h,componentVersion:o,componentDescription:s,status:I},label:L("div",{className:"flow-node-label"},L("strong",null,S),L("span",null,k),L("code",{title:s||h},o?`${h}@${o}`:h),L(D1,{status:I},I))},className:`pipeline-flow-node ${k} ${I}`})})});let q=y.flatMap((t,O)=>{let M=String(t?.from||t?.source||""),S=String(t?.to||t?.target||"");if(!_.has(M)||!_.has(S))return[];return[{source:M,target:S,index:O,condition:t?.condition,edgeType:t?.edgeType}]}),W=q.reduce((t,O)=>t.set(O.source,(t.get(O.source)||0)+1),new Map),G=q.reduce((t,O)=>t.set(O.target,(t.get(O.target)||0)+1),new Map),K=q.reduce((t,O)=>{let M=`${O.source}->${O.target}`;return t.set(M,(t.get(M)||0)+1)},new Map),Q=new Map,N=new Map,c=new Map,z=new Map,w=new Map,H=new Map,B=q.reduce((t,O)=>{let M=F.get(O.source),S=F.get(O.target),b=(S?.column||0)-(M?.column||0);if(b<=0||String(O.edgeType||"").toLowerCase()==="rework"||b!==1)return t;let D=`${O.source}->column:${S?.column??""}`,I=t.get(D)||[];return I.push(O),t.set(D,I),t},new Map);for(let t of B.values()){if(t.length<2)continue;t.slice().sort((O,M)=>{let S=F.get(O.target),b=F.get(M.target);return(S?.y||0)-(b?.y||0)||O.index-M.index}).forEach((O,M,S)=>{H.set(U$(O),{slot:M-(S.length-1)/2,count:S.length})})}[...q].sort((t,O)=>{let M=F.get(t.source),S=F.get(t.target),b=F.get(O.source),Z=F.get(O.target),D=Math.abs((S?.column||0)-(M?.column||0))*330+Math.abs((S?.y||0)-(M?.y||0)),I=Math.abs((Z?.column||0)-(b?.column||0))*330+Math.abs((Z?.y||0)-(b?.y||0));return D-I||t.index-O.index}).forEach((t)=>{let O=F.get(t.source)||{column:0,row:0,y:0},M=F.get(t.target)||{column:0,row:0,y:0},S=M.column-O.column,b=Math.max(0,S),Z=S<=0||String(t.edgeType||"").toLowerCase()==="rework",D=O.y-M.y,I=G.get(t.target)||1,k=H.has(U$(t)),h=!Z&&b<=1&&(k||I===1),o=w.get(t.target)||new Map;w.set(t.target,o);let s=z$.slice().sort((x,uu)=>{let nu=(Wu)=>{let m=String(Wu.side),d=0;if(Z){if(m==="left")d+=86;if(m==="top")d+=M.y<=0?-22:12;if(m==="bottom")d+=M.y>=0?-22:12;if(Math.abs(M.y)<12&&m!=="left")d+=t.index%2===0?m==="top"?-6:6:m==="bottom"?-6:6;return d}if(h){if(m==="left")d-=k?72:44;if(m!=="left")d+=k?72:44;return d+Math.abs(D)*0.02}if(m==="left")d+=b<=1?0:24;if(m==="top")d+=D<-36?-18:42;if(m==="bottom")d+=D>36?-18:42;if(b<=1&&Math.abs(D)<=82&&m!=="left")d+=38;if(b>1&&m!=="left")d-=10;return d},$u=O.y-M.y,Fu=$u!==0?$u:t.index%2===0?-1:1,Ku=(Wu)=>{let m=o.get(Wu.id)||0;return nu(Wu)+m*64+nD(Wu,o,Fu)};return Ku(x)-Ku(uu)||String(x.id).localeCompare(String(uu.id))})[0];o.set(s.id,(o.get(s.id)||0)+1),z.set(U$(t),s)});let X=q.map((t)=>{let O=Zz(f,t.target).toLowerCase(),M=`${t.source}->${t.target}`,S=Q.get(t.source)||0,b=N.get(t.target)||0,Z=c.get(M)||0;Q.set(t.source,S+1),N.set(t.target,b+1),c.set(M,Z+1);let D=S-((W.get(t.source)||1)-1)/2,I=b-((G.get(t.target)||1)-1)/2,k=Z-((K.get(M)||1)-1)/2,h=F.get(t.source),o=F.get(t.target),s=(o?.column||0)-(h?.column||0),x=Math.max(1,Math.abs(s)),uu=s<=0||String(t.edgeType||"").toLowerCase()==="rework",nu=Math.abs((o?.y||0)-(h?.y||0)),$u=H.get(U$(t)),Fu=!uu&&s===1&&(G.get(t.target)||0)>1,Ku=$u?$u.slot:k*2+D+I*0.45,Wu=Ku===0?t.index%2===0?-1:1:Math.sign(Ku),m=z.get(U$(t))||z$[1],d=m.side==="top"?-1:m.side==="bottom"?1:Wu,e=uu||x>1||nu>96||Math.abs(Ku)>0.2||m.side!=="left",cu=uu?118+x*18:22+x*16,g=m.side==="left"?0:28,Qu=e?Math.max(-280,Math.min(280,d*Math.min(180,cu+g+nu*0.22)+Ku*28)):0,Eu=Math.max(0,Math.min(q$.length-1,Math.round(D+(q$.length-1)/2))),Tu=q$[Eu]||q$[1],Du=O==="succeeded"?"var(--accent-2)":O==="running"?"var(--accent)":O==="failed"?"var(--danger)":"rgba(129, 147, 159, 0.78)",ff=h?.column||0,rf=o?.column||0,Lf=Qu===0?0:Math.sign(Qu),gf=uu?`feedback:${ff}->${rf}:${Lf}`:$u?`fanout:${ff}->${rf}:${t.source}`:Fu?`fanin:${ff}->${rf}:${t.target}`:m.side!=="left"||x>1?`corridor:${ff}->${rf}:${m.side}:${Lf}:${Math.round(Math.abs(Qu)/56)}`:"";return{id:`${t.source}->${t.target}-${t.index}`,source:t.source,target:t.target,sourceHandle:Tu.id,targetHandle:m.id,type:"pipelineCurve",zIndex:12,animated:O==="running",data:{baseEdgeColor:Du,laneOffset:Qu,routeMode:$u&&m.side==="left"?"direct-forward-left":"",targetSide:m.side,isFeedback:uu,overlapGroup:gf},targetStatus:O}}),R=X.reduce((t,O)=>{let M=String(O.data?.overlapGroup||"");return M?t.set(M,(t.get(M)||0)+1):t},new Map),Y=new Map,P=X.map((t)=>{let O=String(t.targetStatus||"pending"),M={...t};delete M.targetStatus;let S=String(t.data?.overlapGroup||""),b=S?R.get(S)||0:0,Z=b>1?Y.get(S)||0:-1;if(b>1)Y.set(S,Z+1);let D=Z>=0?Qz[Z%Qz.length]:String(t.data.baseEdgeColor),I={stroke:D};if(t.data.isFeedback)I.strokeDasharray="9 7";return{...M,data:{...t.data,edgeColor:D,overlapSlot:Z,overlapCount:b},style:I,markerEnd:{type:T1.ArrowClosed,color:D},className:`pipeline-flow-edge ${O} ${t.data.isFeedback?"feedback":""} ${Z>=0?"overlap-colored":""}`}});return{nodes:j,edges:P}}function Rl(u){return String(u??"").replace(/&/g,"&").replace(//g,">").replace(/"/g,""")}function Oz(u){let f=String(u||"");if(f.includes("--accent-2"))return"#4eb7a8";if(f.includes("--accent"))return"#d7a13a";if(f.includes("--danger"))return"#cf6a54";return f.startsWith("#")?f:"#81939f"}function y8(u){return`arrow-${u.replace(/[^a-zA-Z0-9_-]+/g,"")}`}function az(u,f="pipeline"){return String(u||f).replace(/[^a-zA-Z0-9_-]+/g,"-").replace(/^-|-$/g,"")||f}function Bz(u,f){let l=u.position.x,r=u.position.y,y=z$.find((i)=>i.id===f);if(y?.side==="top")return{x:l+ai*cz(y.style?.left,0.5),y:r,position:zu.Top};if(y?.side==="bottom")return{x:l+ai*cz(y.style?.left,0.5),y:r+oi,position:zu.Bottom};return{x:l,y:r+oi/2,position:zu.Left}}function bD(u){return{x:u.position.x+ai,y:u.position.y+oi/2}}function vD(u,f){let l=Math.min(...u.nodes.map((G)=>G.position.x),0)-220,r=Math.min(...u.nodes.map((G)=>G.position.y),0)-220,y=Math.max(...u.nodes.map((G)=>G.position.x+ai),1)+220,i=Math.max(...u.nodes.map((G)=>G.position.y+oi),1)+220,_=Math.ceil(y-l),n=Math.ceil(i-r),$=new Map(u.nodes.map((G)=>[G.id,G])),j=u.edges.map((G)=>Oz(G.data?.edgeColor||G.style?.stroke)),J=Array.from(new Set(["#4eb7a8","#d7a13a","#cf6a54","#81939f",...j])).map((G)=>``).join(""),U=u.edges.flatMap((G)=>{let K=$.get(G.source),Q=$.get(G.target);if(!K||!Q)return[];let N=bD(K),c=Bz(Q,String(G.targetHandle||"in-left")),z=mz(N.x,N.y,c.x,c.y,c.position,Number(G.data?.laneOffset||0),String(G.data?.routeMode||"")),w=Oz(G.data?.edgeColor||G.style?.stroke),H=G.data?.isFeedback?' stroke-dasharray="9 7"':"";return``}).join(` +`),q=u.nodes.map((G)=>{let K=G.data?.exportLabel||{},Q=String(K.status||"pending").toLowerCase(),N=Q==="succeeded"?"#4eb7a8":Q==="running"?"#d7a13a":Q==="failed"?"#cf6a54":"#81939f",c=G.position.x,z=G.position.y,w=z$.map((H)=>{let B=Bz(G,H.id);if(H.side==="top"||H.side==="bottom")return``;return``}).join(` `);return` - - ${q} - - ${vu(O.id||H.id)} - ${vu(O.kind||"node")} - ${vu(O.componentRef||"--")} - ${vu(z)} + + ${w} + + ${Rl(K.id||G.id)} + ${Rl(K.kind||"node")} + ${Rl(K.componentRef||"--")} + ${Rl(Q)} `}).join(` -`);return{svg:` - ${Q} +`);return{svg:` + ${J} - ${vu(u)} - ${G}${W} - `,width:r,height:j}}function Tn(f){let u=String(f||"").toLowerCase();if(u==="succeeded"||u==="completed")return"#4eb7a8";if(u==="failed")return"#cf6a54";if(cE(u))return"#69aee8";return"#d7a13a"}function Mn(f){let u=String(f?.kind||""),l=String(f?.tone||f?.status||"").toLowerCase();if(u==="prompt"&&l==="initial")return"#d7a13a";if(u==="prompt"&&l==="monitor")return"#69aee8";if(u==="prompt")return"#4eb7a8";if(l==="modify")return"#e0b95a";if(l==="approve"||l==="guide"||l==="monitor")return"#4eb7a8";if(l==="restart"||l==="redo")return"#d7a13a";if(l==="ignored")return"#81939f";if(l==="webui")return"#69aee8";if(l==="cli")return"#d7a13a";return"#a7bac5"}function wE(f){let u=String(f?.sourceKind||"").toLowerCase(),l=String(f?.action||"").toLowerCase(),_=String(f?.status||"").toLowerCase();if(l==="observe"||_==="observation"||u==="monitor")return"#4eb7a8";if(u==="webui")return"#69aee8";if(u==="cli")return"#d7a13a";if(_.includes("ignored"))return"#81939f";return"#8aa0ad"}function Pn(f,u,l){let _=Mn(f),y=String(f?.kind||"");if(y==="control-source")return``;if(y==="control-target"){let r=String(f?.tone||"").toLowerCase()==="approve"?"rgba(78,183,168,0.22)":"#081118";return``}return``}function nn(f){let u=Xf(f.visibleNodeIds).map((X)=>String(X||"")).filter(Boolean),l=Xf(f.intervals).filter(Pf),_=Xf(f.markers).filter(Pf),y=Xf(f.arrows).filter(Pf),$=Xf(f.ticks).filter(Pf),r=Pf(f.bounds)?f.bounds:{},j=Pf(f.backendLayout)?f.backendLayout:null,A=Math.max(240,Math.round(Number(f.chartHeight||360))),J=Math.max(j1,108),U=128,Q=24,W=58,G=56,K=128+Math.max(1,u.length)*J,H=Math.max(760,K+48),O=114+A+24,z=24,Z=58,N=114,E=(X)=>152+X*J,q=(X)=>E(X)+J/2,Y=Xf(f.meta).map((X)=>String(X||"")).filter(Boolean).slice(0,4).join(" · "),w=new Map(_.map((X)=>[String(X.id||""),X])),P=Array.from(new Set(["#4eb7a8","#69aee8","#d7a13a","#cf6a54","#8aa0ad",...y.map(wE)])).map((X)=>``).join(""),h=$.map((X)=>{let D=114+lH(X,r,A,j);return` - - ${vu(Nf(X.ms))} - +${vu(ql(Number(X.offsetMs??Number(X.ms)-Number(r.startMs))))} + ${Rl(f)} + ${q}${U} + `,width:_,height:n}}function ID(u){let f=String(u||"").toLowerCase();if(f==="succeeded"||f==="completed")return"#4eb7a8";if(f==="failed")return"#cf6a54";if(pz(f))return"#69aee8";return"#d7a13a"}function kD(u){let f=String(u?.kind||""),l=String(u?.tone||u?.status||"").toLowerCase();if(f==="prompt"&&l==="initial")return"#d7a13a";if(f==="prompt"&&l==="monitor")return"#69aee8";if(f==="prompt")return"#4eb7a8";if(l==="modify")return"#e0b95a";if(l==="approve"||l==="guide"||l==="monitor")return"#4eb7a8";if(l==="restart"||l==="redo")return"#d7a13a";if(l==="ignored")return"#81939f";if(l==="webui")return"#69aee8";if(l==="cli")return"#d7a13a";return"#a7bac5"}function Vz(u){let f=String(u?.sourceKind||"").toLowerCase(),l=String(u?.action||"").toLowerCase(),r=String(u?.status||"").toLowerCase();if(l==="observe"||r==="observation"||f==="monitor")return"#4eb7a8";if(f==="webui")return"#69aee8";if(f==="cli")return"#d7a13a";if(r.includes("ignored"))return"#81939f";return"#8aa0ad"}function gD(u,f,l){let r=kD(u),y=String(u?.kind||"");if(y==="control-source")return``;if(y==="control-target"){let _=String(u?.tone||"").toLowerCase()==="approve"?"rgba(78,183,168,0.22)":"#081118";return``}return``}function sD(u){let f=Hu(u.visibleNodeIds).map((Z)=>String(Z||"")).filter(Boolean),l=Hu(u.intervals).filter(Yu),r=Hu(u.markers).filter(Yu),y=Hu(u.arrows).filter(Yu),i=Hu(u.ticks).filter(Yu),_=Yu(u.bounds)?u.bounds:{},n=Yu(u.backendLayout)?u.backendLayout:null,$=Math.max(240,Math.round(Number(u.chartHeight||360))),j=Math.max(_0,108),F=128,J=24,U=58,q=56,W=128+Math.max(1,f.length)*j,G=Math.max(760,W+48),K=114+$+24,Q=24,N=58,c=114,z=(Z)=>152+Z*j,w=(Z)=>z(Z)+j/2,H=Hu(u.meta).map((Z)=>String(Z||"")).filter(Boolean).slice(0,4).join(" · "),B=new Map(r.map((Z)=>[String(Z.id||""),Z])),X=Array.from(new Set(["#4eb7a8","#69aee8","#d7a13a","#cf6a54","#8aa0ad",...y.map(Vz)])).map((Z)=>``).join(""),R=i.map((Z)=>{let D=114+yG(Z,_,$,n);return` + + ${Rl(Nu(Z.ms))} + +${Rl(Er(Number(Z.offsetMs??Number(Z.ms)-Number(_.startMs))))} `}).join(` -`),M=['','TIME',...u.map((X,D)=>{let p=E(D),m=X.length>18?`${X.slice(0,16)}…`:X;return` - - ${vu(m)} - node ${D+1} +`),Y=['','TIME',...f.map((Z,D)=>{let I=z(D),k=Z.length>18?`${Z.slice(0,16)}…`:Z;return` + + ${Rl(k)} + node ${D+1} `})].join(` -`),n=u.map((X,D)=>{return``}).join(` -`),S=l.map((X)=>{let D=u.indexOf(String(X.nodeId||""));if(D<0)return"";let p=114+yr(X,r,A,j),m=Math.max(2,uH(X,r,A,j)),s=Tn(X.status),d=q(D)-3.5,a=X.live?``:"",I=m>=28?`${vu(String(X.status||"working"))} - ${vu(ql(X.durationMs))}`:"";return` - - ${a} - ${I} +`),P=f.map((Z,D)=>{return``}).join(` +`),t=l.map((Z)=>{let D=f.indexOf(String(Z.nodeId||""));if(D<0)return"";let I=114+_8(Z,_,$,n),k=Math.max(2,rG(Z,_,$,n)),h=ID(Z.status),o=w(D)-3.5,s=Z.live?``:"",x=k>=28?`${Rl(String(Z.status||"working"))} + ${Rl(Er(Z.durationMs))}`:"";return` + + ${s} + ${x} `}).join(` -`),T=_.map((X)=>{let D=u.indexOf(String(X.nodeId||""));if(D<0)return"";let p=114+rl(X,r,A,j);return Pn(X,q(D),p)}).join(` -`),i=y.map((X)=>{let D=w.get(String(X.targetMarkerId||""));if(!D)return"";let p=w.get(String(X.sourceMarkerId||"")),m=String(p?.nodeId||X.sourceNodeId||""),s=String(D.nodeId||X.targetNodeId||""),d=u.indexOf(m),a=u.indexOf(s);if(d<0||a<0)return"";let I=q(d)-24-128,ff=q(a)-24-128,yf=f3(j)?Y0(X.sourceY??X.y1)??(p?rl(p,r,A,j):rl(D,r,A,j)):p?rl(p,r,A,j):rl(D,r,A,j),rf=f3(j)?Y0(X.targetY??X.y2)??rl(D,r,A,j):rl(D,r,A,j),Wf=wE(X),Ef=String(X.action||"").toLowerCase()==="observe"?"3 4":"6 5",Gf=vu(_H(I,yf,ff,rf));return` - `}).join(` -`),C=u.length===0?'No visible Gantt nodes':"";return{svg:` - ${P} +`),O=r.map((Z)=>{let D=f.indexOf(String(Z.nodeId||""));if(D<0)return"";let I=114+nr(Z,_,$,n);return gD(Z,w(D),I)}).join(` +`),M=y.map((Z)=>{let D=B.get(String(Z.targetMarkerId||""));if(!D)return"";let I=B.get(String(Z.sourceMarkerId||"")),k=String(I?.nodeId||Z.sourceNodeId||""),h=String(D.nodeId||Z.targetNodeId||""),o=f.indexOf(k),s=f.indexOf(h);if(o<0||s<0)return"";let x=w(o)-24-128,uu=w(s)-24-128,nu=di(n)?Bf(Z.sourceY??Z.y1)??(I?nr(I,_,$,n):nr(D,_,$,n)):I?nr(I,_,$,n):nr(D,_,$,n),$u=di(n)?Bf(Z.targetY??Z.y2)??nr(D,_,$,n):nr(D,_,$,n),Fu=Vz(Z),Ku=String(Z.action||"").toLowerCase()==="observe"?"3 4":"6 5",Wu=Rl(iG(x,nu,uu,$u));return` + `}).join(` +`),S=f.length===0?'No visible Gantt nodes':"";return{svg:` + ${X} - - ${vu(f.title||"Pipeline Epoch Gantt")} - ${vu(Y)} - ${M} - - ${n} - ${h} + + ${Rl(u.title||"Pipeline Epoch Gantt")} + ${Rl(H)} + ${Y} + + ${P} + ${R} + ${t} + ${M} + ${O} ${S} - ${i} - ${T} - ${C} - `,width:H,height:O}}function _r(f,u){let l=URL.createObjectURL(f),_=document.createElement("a");_.href=l,_.download=u,_.click(),setTimeout(()=>URL.revokeObjectURL(l),1000)}async function sE(f,u){let l=tE(u,"pipeline"),{svg:_,width:y,height:$}=Dn(f,u),r=new Blob([_],{type:"image/svg+xml;charset=utf-8"}),j=URL.createObjectURL(r);try{let A=new Image;await new Promise((W,G)=>{A.onload=()=>W(),A.onerror=()=>G(Error("svg image load failed")),A.src=j});let J=document.createElement("canvas");J.width=y,J.height=$;let U=J.getContext("2d");if(!U)throw Error("canvas unavailable");U.drawImage(A,0,0);let Q=await new Promise((W)=>J.toBlob(W,"image/png"));if(!Q)throw Error("png export failed");_r(Q,`${l}.png`)}catch{_r(r,`${l}.svg`)}finally{URL.revokeObjectURL(j)}}async function Sn(f){let u=tE(String(f?.title||"pipeline-gantt"),"pipeline-gantt"),{svg:l,width:_,height:y}=nn(f),$=new Blob([l],{type:"image/svg+xml;charset=utf-8"}),r=URL.createObjectURL($);try{let j=new Image;await new Promise((Q,W)=>{j.onload=()=>Q(),j.onerror=()=>W(Error("gantt svg image load failed")),j.src=r});let A=document.createElement("canvas");A.width=_,A.height=y;let J=A.getContext("2d");if(!J)throw Error("canvas unavailable");J.drawImage(j,0,0);let U=await new Promise((Q)=>A.toBlob(Q,"image/png"));if(!U)throw Error("gantt png export failed");_r(U,`${u}.png`)}catch{_r($,`${u}.svg`)}finally{URL.revokeObjectURL(r)}}async function Cn(f){for(let u of f){if(u.flow.nodes.length===0)continue;await sE(u.flow,u.title),await new Promise((l)=>setTimeout(l,750))}}function DE(f,u){return f.find((l)=>String(l?.pipelineId||"")===u)||null}function TE(f){return vf(f?.startedAt)??vf(f?.artifact?.startedAt)??vf(f?.request?.createdAt)??vf(f?.updatedAt)??0}function cn(f,u){return f.filter((l)=>String(l?.pipelineId||"")===u).slice().sort((l,_)=>TE(l)-TE(_)||String(l?.runId||"").localeCompare(String(_?.runId||"")))}function JJ(f,u){let l=String(u?.runId||""),_=f.findIndex((r)=>String(r?.runId||"")===l),y=_>=0?_+1:f.length,$=String(u?.status||"--");return`Epoch ${y} / ${l||"--"} / ${$}`}function Ll(f){return String(f?.procedureRunId||f?.runId||"")}function jr(f,u){let l=String(f?.nodeId||f?.request?.nodeId||"");if(l)return l;let _=Ll(f),y=`${u}__`;if(_.startsWith(y))return _.slice(y.length).replace(/__\d+$/u,"");return""}function t5(f,u){let l=Pf(f?.artifact)?f.artifact:{},_=Pf(f?.request)?f.request:{};return V4(f?.startedAt,l.startedAt,_.createdAt,_.startedAt,f?.createdAt,f?.updatedAt,u?.startedAt,u?.request?.createdAt)}function s5(f,u){let l=String(f?.status?.status||f?.artifact?.status||f?.status||"").toLowerCase(),_=Pf(f?.artifact)?f.artifact:{},y=zJ(l);return V4(f?.finishedAt,_.finishedAt,f?.completedAt,y?f?.updatedAt:void 0,y?_.updatedAt:void 0,y?u?.updatedAt:void 0)}function oE(f,u,l=Date.now()){let _=String(f?.runId||""),y=new Set(u.map(($)=>String($?.id||"")).filter(Boolean));return Xf(f?.procedureRuns).flatMap(($)=>{let r=jr($,_);if(!r)return[];let j=String($?.status?.status||$?.artifact?.status||$?.status||"unknown").toLowerCase(),A=t5($,f),J=vf(A);if(J===null)return[];let U=s5($,f),Q=vf(U)??(zJ(j)?vf($?.updatedAt)??J+1000:l),W=Math.max(J+1000,Q);return[{nodeId:r,knownNode:y.has(r),procedureRunId:Ll($),status:j,startMs:J,endMs:W,startedAt:E4(J),finishedAt:E4(W),durationMs:W-J,runId:_,raw:$}]}).sort(($,r)=>$.startMs-r.startMs||$.endMs-r.endMs||$.nodeId.localeCompare(r.nodeId))}function Rn(f,u,l=[]){let _=u.map((U)=>Number(U.startMs)).filter(Number.isFinite),y=u.map((U)=>Number(U.endMs)).filter(Number.isFinite);for(let U of l){let Q=Y0(U?.eventMs??U?.ms);if(Q!==null)_.push(Q),y.push(Q)}let $=vf(f?.startedAt)??vf(f?.artifact?.startedAt)??vf(f?.request?.createdAt),r=vf(f?.finishedAt)??vf(f?.artifact?.finishedAt)??vf(f?.updatedAt);if($!==null)_.push($);if(r!==null)y.push(r);let j=Date.now(),A=_.length>0?Math.min(..._):j-60000,J=Math.max(A+60000,y.length>0?Math.max(...y):j);return{startMs:A,endMs:J,durationMs:J-A}}var o5=12,aE=20,UJ=100,xn=!1;function n_(f){let u=Number(f);if(!Number.isFinite(u))return 0;return Math.max(0,Math.min(100,Math.round(u*100)/100))}function bn(f){let u=Math.max(o5,Number(f||o5)),l=Math.log(u/o5)/Math.log(aE);return n_(l*100)}var O4=bn(UJ);function HJ(f){let u=n_(f)/100,l=o5*Math.pow(aE,u),_=u<0.24?"全局":u<0.64?"均衡":"细节";return{value:n_(u*100),pxPerMinute:l,label:_}}function yJ(f){let u=Math.round(Number(f));return Math.abs(u-UJ)<=1?UJ:u}function vn(f,u=O4){let l=Math.max(1,Number(f.durationMs||0)/60000),_=HJ(u);return Math.round(Math.max(360,Math.min(7200,l*Number(_.pxPerMinute||48))))}function hn(f,u=7){let l=Math.max(1,Number(f.endMs||0)-Number(f.startMs||0));return Array.from({length:u},(_,y)=>{let $=u===1?0:y/(u-1);return{ms:Number(f.startMs)+l*$,percent:$*100}})}function In(f,u){let l=Math.max(1,Number(u.endMs)-Number(u.startMs));return Math.max(0,Math.min(100,(f-Number(u.startMs))/l*100))}function Y0(f){let u=Number(f);return Number.isFinite(u)?u:null}function OJ(f){return cE(f?.status)&&!zJ(f?.status)}function dE(f,u,l,_){let y=Math.max(1,l-u),$=Math.max(0,Math.min(1,(f-u)/y));return Number(($*_).toFixed(3))}function ME(f,u){if(!u)return null;let l=Y0(u?.startMs),_=Y0(u?.endMs),y=Y0(u?.chartHeight);if(l===null||_===null||y===null)return null;return dE(f,l,_,y)}function eE(f,u){let l=Y0(f?.rawStartMs??f?.startMs)??Y0(f?.startMs)??u,_=Y0(f?.endMs)??l+1000;if(!OJ(f))return Math.max(l+1000,_);return Math.max(l+1000,_,u)}function pn(f,u,l,_){let y=Y0(f?.startMs)??_-60000,$=Y0(f?.endMs)??_,r=l.reduce((K,H)=>Math.max(K,eE(H,_)),$),j=Math.max(y+60000,$,r),A=Math.max(1,j-y),J={startMs:y,endMs:j,durationMs:A},U=vn(J,u),Q=HJ(u),W=Math.max(5,Math.min(18,Math.round(U/150))),G=hn(J,W).map((K)=>{let H=Number(K.ms),O=dE(H,y,j,U);return{...K,y:O,timestamp:E4(H),offsetMs:H-y}});return{source:"frontend-y",startMs:y,endMs:j,durationMs:A,chartHeight:U,scale:n_(u),normalizedScale:Number((n_(u)/100).toFixed(3)),pxPerMinute:Number(Number(Q.pxPerMinute||0).toFixed(3)),ticks:G}}function mn(f,u,l){if(!OJ(f))return f;let _=Y0(f?.rawStartMs??f?.startMs)??Y0(f?.startMs)??l,y=eE(f,l),$=ME(_,u),r=ME(y,u),j=Y0($??f?.y1??f?.startY)??0,A=Y0(r??f?.y2??f?.endY)??j+10,J=Math.max(24,A-j);return{...f,live:!0,startMs:_,endMs:y,durationMs:Math.max(1000,y-_),finishedAt:E4(y),y1:j,y2:A,startY:j,endY:A,height:J}}function VJ(f,u,l){return In(f,u)/100*l}function f3(f){return Boolean(f&&String(f?.source||"")!=="frontend-y")}function fH(f,u,l,_,y){if(f3(_))for(let r of y){let j=Y0(f?.[r]);if(j!==null)return j}let $=Y0(f?.ms??f?.eventMs??f?.startMs);return VJ($??Number(u.startMs),u,l)}function yr(f,u,l,_){return fH(f,u,l,_,["y1","startY"])}function QJ(f,u,l,_){if(f3(_)){let $=Y0(f?.y2??f?.endY);if($!==null)return $}let y=Y0(f?.endMs)??Number(u.endMs);return VJ(y,u,l)}function uH(f,u,l,_){if(f3(_)){let $=Y0(f?.height);if($!==null)return Math.max(1,$)}let y=f?.live?24:10;return Math.max(y,QJ(f,u,l,_)-yr(f,u,l,_))}function rl(f,u,l,_){return fH(f,u,l,_,["y","timeAxisY"])}function lH(f,u,l,_){if(f3(_)||String(_?.source||"")==="frontend-y"){let r=Y0(f?.y);if(r!==null)return r}let y=Y0(f?.percent);if(y!==null)return y/100*l;let $=Y0(f?.ms)??Number(u.startMs);return VJ($,u,l)}function gn(f){let u=String(f?.promptEvent||f?.raw?.promptEvent||f?.event||"").toLowerCase();if(!["node-long-running-observation","node-finished"].includes(u))return"";let l=String(f?.sourceNodeId||f?.raw?.sourceNodeId||f?.raw?.detail?.nodeId||""),_=String(f?.nodeId||f?.targetNodeId||"");return l&&l!==_?l:""}function kn(f,u){let l=new Set(u.map((y)=>[String(y.sourceNodeId||""),String(y.targetNodeId||""),String(y.targetMarkerId||""),String(y.action||"")].join(":"))),_=[...u];for(let y of f){let $=gn(y),r=String(y?.nodeId||""),j=String(y?.id||"");if(!$||!r||!j)continue;let A=[$,r,j,"observe"].join(":");if(l.has(A))continue;l.add(A),_.push({id:`observation-arrow:${j}:${$}:${r}`,commandId:String(y?.commandId||y?.eventId||j),sourceNodeId:$,targetNodeId:r,sourceMarkerId:"",targetMarkerId:j,sourceKind:"monitor",action:"observe",status:"observation"})}return{markers:f,arrows:_}}function PE(f,u=""){let l=hl(f)||u,_=String(f?.promptEvent||"");if(l==="initial-prompt-delivered")return"initial";if(_==="node-finished"||_==="node-long-running-observation"||_.startsWith("monitor-"))return"monitor";if(l==="monitor-prompt-delivered"||String(f?.sourceKind||"").toLowerCase()==="monitor"||u==="monitor-prompt-queued")return"monitor";return"append"}function tn(f){return Xf(f?.tags||f?.raw?.tags).map((u)=>String(u||"")).filter(Boolean)}function nE(f,u=""){let l=hl(f)||u,_=String(f?.promptEvent||"");if(l==="initial-prompt-delivered")return"初始 prompt";if(_==="node-long-running-observation")return"长任务观察";if(_==="node-finished")return tn(f).includes("monitor.audit")?"节点完成 / OA 审核":"节点完成";if(_==="monitor-interval")return"旧版轮询";if(_==="monitor-start")return"Monitor start";if(_==="monitor-stop")return"Monitor stop";if(l==="monitor-prompt-delivered"||u==="monitor-prompt-queued")return"Monitor prompt";if(l==="append-prompt-queued")return"追加 prompt 已排队";return"追加 prompt"}function SE(f){let u=hl(f);if(u==="control-command-applied")return 3;if(u==="control-command-ignored")return 2;if(u==="control-command-queued")return 1;return 0}function CE(f,u){let l=String(f?.commandId||"");if(l)return`command:${l}`;return["fallback",Ty(f)||V4(f?.createdAt,f?.timestamp)||`index-${u}`,String(f?.sourceKind||""),String(f?.sourceNodeId||""),String(f?.targetNodeId||""),My(f)].join(":")}function sn(f){return AJ([f?.targetNodeId,...Xf(f?.resetNodeIds)])}function on(f,u){let l=N4(f),_=hl(f),y=String(f?.targetNodeId||""),$=Boolean(y)&&u!==y;if(_==="control-command-applied")return $?`${l} 波及`:`${l} 生效`;if(_==="control-command-ignored")return`${l} 忽略`;if(_==="control-command-queued")return`${l} 已发起`;return $?`${l} 波及`:l}function an(f){if(hl(f)==="control-command-ignored")return"ignored";let l=My(f);if(l==="restart"||l==="redo")return"restart";if(l==="modify")return"modify";if(l==="approve")return"approve";if(l==="guide")return"guide";return"pending"}function dn(f){let u=String(f?.sourceKind||"").toLowerCase();if(u==="monitor")return"monitor";if(u==="webui")return"webui";if(u==="cli")return"cli";return"system"}function en(f,u,l,_){let y=f.filter((J)=>String(J.nodeId||"")===u).sort((J,U)=>Number(J.startMs)-Number(U.startMs)),$=y.find((J)=>l>=Number(J.startMs)-1000&&l<=Number(J.endMs)+1000);if($)return{ms:l,onInterval:!0,snapReason:"inside-interval",procedureRunId:String($.procedureRunId||"")};let r=My(_),j=y.slice().reverse().find((J)=>Number(J.endMs)<=l+1000);if(j&&r==="approve")return{ms:Number(j.endMs),onInterval:!0,snapReason:"previous-interval-end",procedureRunId:String(j.procedureRunId||"")};let A=y.find((J)=>Number(J.startMs)>=l-1000);if(A&&["guide","modify","restart","redo"].includes(r))return{ms:Number(A.startMs),onInterval:!0,snapReason:"next-interval-start",procedureRunId:String(A.procedureRunId||"")};return{ms:l,onInterval:!1,snapReason:"event-time",procedureRunId:String(_?.procedureRunId||"")}}function _H(f,u,l,_){let y=Math.hypot(l-f,_-u),$=y>zE?zE:0,r=$>0?l-(l-f)/y*$:l,j=$>0?_-(_-u)/y*$:_,A=r-f,J=Math.max(16,Math.min(42,Math.abs(A)*0.45+12)),U=A===0?1:Math.sign(A);return`M ${f},${u} C ${f+U*J},${u} ${r-U*J},${j} ${r},${j}`}function fS(f,u){let l=String(f?.runId||u?.runId||""),_=oE({...Pf(u)?u:{},...Pf(f)?f:{},runId:l,procedureRuns:Xf(f?.procedureRuns).length>0?f.procedureRuns:u?.procedureRuns},[]),y=[],$=[],r=[],j=new Set,A=new Map,J=(W,G)=>{if(!W.nodeId||!Number.isFinite(Number(W.ms)))return;if(j.has(W.id))return;j.add(W.id),G.push(W)};for(let W of Xf(f?.procedureRuns)){let G=jr(W,l),K=Ll(W);if(!G)continue;for(let H of Xf(W?.attempts)){let O=rr(H),z=new Set,Z=new Set;for(let E of K4(H?.controlEventRecords)){let q=hl(E);if(!["initial-prompt-delivered","append-prompt-delivered","monitor-prompt-delivered"].includes(q))continue;let Y=Ty(E),w=vf(Y);if(w===null)continue;let B=String(E?.eventId||"");if(B)z.add(B);Z.add(`${q}:${Y}:${String(E?.sourceKind||"")}:${String(E?.promptPreview||"")}`),J({id:`prompt:${B||`${K}:${O}:${q}:${w}`}`,runId:l,nodeId:G,procedureRunId:K,attempt:O,kind:"prompt",tone:PE(E,q),status:"delivered",label:nE(E,q),ms:w,timestampIso:Y,sourceKind:String(E?.sourceKind||""),sourceNodeId:String(E?.sourceNodeId||""),targetNodeId:G,action:"",eventId:B,commandId:String(E?.commandId||""),raw:E},y)}let N=[{records:K4(H?.controlPromptRecords),fallbackKind:"append-prompt-queued"},{records:K4(H?.monitorPromptRecords),fallbackKind:"monitor-prompt-queued"}];for(let E of N)for(let q of E.records){let Y=Ty(q),w=vf(Y);if(w===null)continue;let B=String(q?.eventId||"");if(B&&z.has(B))continue;let h=`${E.fallbackKind==="monitor-prompt-queued"?"monitor-prompt-delivered":"append-prompt-delivered"}:${Y}:${String(q?.sourceKind||"")}:${String(q?.promptPreview||"")}`;if(Z.has(h))continue;J({id:`prompt-fallback:${B||`${K}:${O}:${E.fallbackKind}:${w}`}`,runId:l,nodeId:G,procedureRunId:K,attempt:O,kind:"prompt",tone:PE(q,E.fallbackKind),status:"queued",label:nE(q,E.fallbackKind),ms:w,timestampIso:Y,sourceKind:String(q?.sourceKind||""),sourceNodeId:String(q?.sourceNodeId||""),targetNodeId:G,action:"",eventId:B,commandId:String(q?.commandId||""),raw:q},y)}}}let U=new Map;K4(f?.controlEvents).forEach((W,G)=>{let K=CE(W,G),H=U.get(K)||{key:K,events:[],commands:[]};H.events.push(W),U.set(K,H)}),Xf(f?.controlCommands).filter(Pf).forEach((W,G)=>{let K=CE(W,G),H=U.get(K)||{key:K,events:[],commands:[]};H.commands.push(W),U.set(K,H)});for(let W of U.values()){let G=Xf(W.events).slice().sort((n,S)=>SE(S)-SE(n)),K=Xf(W.commands),H=Xf(W.events).find((n)=>hl(n)==="control-command-queued")||K[0]||null,O=G[0]||K[0]||H;if(!H&&!O)continue;let z=String(H?.sourceNodeId||O?.sourceNodeId||""),Z=String(H?.sourceKind||O?.sourceKind||""),N=Ty(H)||Ty(O)||V4(H?.createdAt,O?.createdAt),E=vf(N),q=String(O?.commandId||H?.commandId||W.key),Y=(hl(O)||"control-command-queued").replace(/^control-command-/u,""),w="";if(z&&E!==null)w=`control-source:${q}:${z}`,A.set(q,w),J({id:w,runId:l,nodeId:z,procedureRunId:String(H?.procedureRunId||O?.procedureRunId||""),attempt:"",kind:"control-source",tone:dn(H||O),status:Y,label:`${N4(H||O)} 发起`,ms:E,timestampIso:N,action:My(H||O),sourceKind:Z,sourceNodeId:z,targetNodeId:String(O?.targetNodeId||H?.targetNodeId||""),commandId:q,raw:H||O},$);let B=O||H,P=Ty(B)||N,h=vf(P);if(h===null)continue;let M=sn(B);for(let n of M){let S=en(_,n,h,B),T=`control-target:${q}:${n}`;if(J({id:T,runId:l,nodeId:n,procedureRunId:S.procedureRunId,attempt:"",kind:"control-target",tone:an(B),status:Y,label:on(B,n),ms:S.ms,eventMs:h,onInterval:S.onInterval,snapReason:S.snapReason,snapped:Number(S.ms)!==h,timestampIso:P,renderedTimestampIso:E4(Number(S.ms)),action:My(B),sourceKind:Z,sourceNodeId:z,targetNodeId:n,commandId:q,raw:B},$),w&&z&&z!==n)r.push({id:`control-arrow:${q}:${z}:${n}`,commandId:q,sourceNodeId:z,targetNodeId:n,sourceMarkerId:w,targetMarkerId:T,sourceKind:Z,action:My(B),status:Y})}}let Q=[...y,...$].sort((W,G)=>Number(W.ms)-Number(G.ms)||String(W.nodeId).localeCompare(String(G.nodeId))||String(W.id).localeCompare(String(G.id)));return{...kn(Q,r),sourceMarkerByCommand:A}}function uS({details:f,selectedNodeId:u,selectedNodeRuntime:l,control:_,onRaw:y}){if(!f)return V("span",{className:"muted"},"点击“抓取过程”读取 node 运行材料;主界面只显示结构化摘要,完整内容需点开原始 JSON。");let $=Xf(f.procedureRuns),r=$.at(-1)||{},j=Xf(r.attempts),A=j.at(-1)||{},J=Xf(r.workerLogTail),U=Xf(A.controlEventsTail),Q=Xf(A.controlPromptsTail),W=Xf(A.monitorPromptsTail),G=fJ(U),K=fJ(Q),H=fJ(W),O=A.opencodeMessages||{};return V("div",{className:"pipeline-evidence-list compact"},V(Vl,{title:"Node runtime",subtitle:u||"--",facts:[`status ${l?.status||"pending"}`,`attempts ${l?.attempts??j.length}`,`procedure ${l?.currentProcedureRunId||Ll(r)||"--"}`,_.fetchedAt?`fetched ${W0(_.fetchedAt)}`:"not fetched"],data:f.node||f,onRaw:y,testId:"raw-pipeline-node-runtime"}),V(Vl,{title:"Procedure runs",subtitle:`${$.length} groups`,facts:[`latest ${r.status?.status||r.status||"--"}`,`steps ${Xf(r.recentSteps).length}`,`duration ${ql(vf(r.finishedAt)&&vf(r.startedAt)?Number(vf(r.finishedAt))-Number(vf(r.startedAt)):r.durationMs)}`],data:$,onRaw:y,testId:"raw-pipeline-node-procedures"}),V(Vl,{title:"OpenCode messages",subtitle:String(O.exists?"available":"not indexed"),facts:[`messages ${d5(O.messageCount)}`,`size ${d5(O.size)}`,`updated ${Nf(O.updatedAt)}`],data:O,onRaw:y,testId:"raw-pipeline-node-messages"}),V(Vl,{title:"Control prompts",subtitle:"manual / monitor append queues",facts:[`manual tail ${K.total}`,`monitor tail ${H.total}`,`last ${Nf(WJ(K.lastAt,H.lastAt))}`],data:{controlPromptsTail:Q,monitorPromptsTail:W},onRaw:y,testId:"raw-pipeline-node-prompts"}),V(Vl,{title:"Control events",subtitle:G.eventKinds.length>0?G.eventKinds.join(", "):"event tail",facts:[`tail ${G.total}`,`parsed ${G.parsed}`,`last ${Nf(G.lastAt)}`],data:U,onRaw:y,testId:"raw-pipeline-node-events"}),V(Vl,{title:"Worker log",subtitle:"tail is hidden on main canvas",facts:[`tail ${J.length} lines`,"raw only via button",`procedure ${Ll(r)||"--"}`],data:J,onRaw:y,testId:"raw-pipeline-node-worker-log"}))}function lS({activeRun:f,onRaw:u}){if(!f)return V(jl,{title:"暂无运行材料",text:"没有 Pipeline epoch 时不会展示运行材料索引。"});let l=Xf(f.nodes),_=Xf(f.procedureRuns),y=Xf(f.submissions),$=Xf(f.workerLogTail),r=NE(l),j=NE(_),A=_.filter((U)=>String(U?.status||"").toLowerCase()==="failed"),J=WJ(..._.flatMap((U)=>[U.updatedAt,U.finishedAt,U.startedAt]));return V("div",{className:"pipeline-evidence-list"},V(Vl,{title:"Epoch overview",subtitle:f.runId||"--",facts:[`pipeline ${f.pipelineId||"--"}`,`status ${f.status||"--"}`,`started ${Nf(f.startedAt)}`,`updated ${Nf(f.updatedAt)}`],data:f,onRaw:u,testId:"raw-pipeline-run"}),V(Vl,{title:"Node states",subtitle:`${l.length} nodes`,facts:[`running ${r.running||0}`,`succeeded ${r.succeeded||0}`,`failed ${r.failed||0}`,`pending ${r.pending||0}`],data:l,onRaw:u,testId:"raw-pipeline-run-nodes"}),V(Vl,{title:"Procedure run index",subtitle:`${_.length} procedure records`,facts:[`succeeded ${j.succeeded||0}`,`failed ${j.failed||0}`,`latest ${Nf(J)}`,`errors ${A.length}`],data:_,onRaw:u,testId:"raw-pipeline-run-procedures"}),V(Vl,{title:"OA submissions",subtitle:`${y.length} submission files`,facts:[`records ${y.length}`,`task ${d5(f.task)}`,"raw grouped by run"],data:y,onRaw:u,testId:"raw-pipeline-run-submissions"}),V(Vl,{title:"Worker log tail",subtitle:"hidden from main interface",facts:[`tail ${$.length} lines`,"display raw only after click",`updated ${Nf(f.updatedAt)}`],data:$,onRaw:u,testId:"raw-pipeline-run-worker-log"}))}function _S({diagnostics:f,onRaw:u}){let l=Xf(f?.runs).filter(Pf),_=Xf(f?.forbiddenResiduals),y=Pf(f?.guarantees)?f.guarantees:{},$=f?.hasNeutralNodeFinishedEvidence===!0&&f?.hasNoAuditPolicyEvidence===!0&&f?.hasAuditPolicyEvidence===!0,r=f?.ok===!0&&$&&_.length===0,j=l[0]||null,A=[{label:"中性完成事实",ok:y.neutralNodeFinished===!0,hint:"node-finished 不携带流程策略"},{label:"Config 策略判定",ok:y.auditPolicyFromConfig===!0,hint:"OA backend 读取当前 epoch 配置"},{label:"控制命令来自 OA",ok:y.runnerConsumesControlCommandsFromOaEvents===!0,hint:"runner 只消费 OA control.command"},{label:"无独立审核事件",ok:y.noIndependentAuditRequestEvent===!0,hint:"审核由 node-finished + policy 派生"},{label:"无批次门禁",ok:y.noBatchFinishedControlGate===!0,hint:"下游启动由每个 node 完成驱动"}];return V("div",{className:"pipeline-oa-panel","data-testid":"pipeline-oa-event-flow-panel"},V("div",{className:"metric-grid compact"},V(wu,{label:"OA Flow",value:r?"100%":"--",hint:String(f?.mode||"waiting diagnostics"),tone:r?"ok":"warn"}),V(wu,{label:"禁止残留",value:_.length,hint:_.length===0?"source scan clean":"needs cleanup",tone:_.length===0?"ok":"warn"}),V(wu,{label:"No-audit",value:f?.hasNoAuditPolicyEvidence?"OK":"--",hint:"OA 下游策略证据",tone:f?.hasNoAuditPolicyEvidence?"ok":"warn"}),V(wu,{label:"Monitor 审核",value:f?.hasAuditPolicyEvidence?"OK":"--",hint:"OA 控制事件闭环",tone:f?.hasAuditPolicyEvidence?"ok":"warn"})),V("div",{className:"pipeline-oa-guarantees"},A.map((J)=>V("article",{key:J.label,className:`pipeline-oa-guarantee ${J.ok?"ok":"warn"}`},V(P_,{status:J.ok?"online":"warn"},J.ok?"OK":"MISS"),V("div",null,V("strong",null,J.label),V("span",null,J.hint))))),V("div",{className:"pipeline-evidence-list compact"},l.slice(0,6).map((J)=>V(Vl,{key:J.runId,title:String(J.runId||"--"),subtitle:[Number(J.monitorAuditNodeFinishedCount||0)>0?"monitor audit":"",Number(J.noAuditPolicyCount||0)>0?"no-audit policy":""].filter(Boolean).join(" / ")||"event evidence",facts:[`events ${J.eventCount||0}`,`node-finished ${J.nodeFinishedCount||0}`,`policy-in-detail ${J.nodeFinishedWithPolicyCount||0}`,`queued ${J.controlQueuedCount||0}`,`applied ${J.controlAppliedCount||0}`],data:J,onRaw:u,testId:`raw-pipeline-oa-run-${String(J.runId||"run").replace(/[^a-zA-Z0-9_.-]+/g,"-")}`}))),j?V("p",{className:"muted paragraph"},`最新证据 ${j.runId}: ${j.nodeFinishedCount||0} 个 node-finished,${j.controlAppliedCount||0} 个控制结果。`):V(jl,{title:"暂无 OA 事件流证据",text:"等待 Pipeline backend 暴露 diagnostics。"}),f?V("div",{className:"panel-actions inline-actions"},V(Il,{title:"Pipeline OA Event Flow Diagnostics",data:f,onOpen:u,testId:"raw-pipeline-oa-event-flow"})):null)}function yS({quota:f,onRaw:u}){let l=Pf(f?.summary)?f.summary:{},_=Pf(f?.target)?f.target:{},y=Pf(f?.cache)?f.cache:{},$=f?.ok===!0,r=String(f?.modelId||l.modelName||_.modelName||"MiniMax-M2.7"),j=l.totalCount??_.currentIntervalTotalCount,A=l.usageCount??_.currentIntervalUsageCount,J=l.remainingCount??_.currentIntervalRemainingCount,U=l.remainingRatio??(Number.isFinite(Number(j))&&Number(j)>0&&Number.isFinite(Number(J))?Number(J)/Number(j):void 0),Q=l.usageRatio??(Number.isFinite(Number(j))&&Number(j)>0&&Number.isFinite(Number(A))?Number(A)/Number(j):void 0),W=l.resetAt||_.endAt,G=l.remainsMs??_.remainsMs,K=Number(J),H=!$||Number.isFinite(K)&&K<=0?"warn":"ok",O=[$?`endpoint ${f?.endpoint||"--"}`:"quota unavailable",`fetched ${a5(f?.fetchedAt)}`,y.hit?`cache ${ql(y.ageMs)}`:"live quota"];return V("div",{className:"pipeline-minimax-quota-panel","data-testid":"pipeline-minimax-quota-panel"},V("div",{className:"metric-grid compact"},V(wu,{label:"MiniMax",value:$?r:"--",hint:f?.modelComponent||f?.error||"model/minimax-m27",tone:H}),V(wu,{label:"当前窗口",value:`${eF(A)}/${eF(j)}`,hint:`已用 ${KE(Q)}`,tone:H}),V(wu,{label:"剩余额度",value:eF(J),hint:`剩余 ${KE(U)}`,tone:H}),V(wu,{label:"重置时间",value:a5(W),hint:G!==void 0?`约 ${ql(G)}`:Nf(W),tone:H})),V(GJ,{items:O}),$?V("p",{className:"muted paragraph"},`MiniMax 限额来自 D601 Pipeline 后端实时查询;当前模型匹配 ${l.modelName||_.modelName||r}。`):V(A0,{error:f?.error||"MiniMax 限额查询失败"}),f?V("div",{className:"panel-actions inline-actions"},V(Il,{title:"Pipeline MiniMax Quota",data:f,onOpen:u,testId:"raw-pipeline-minimax-quota"})):null)}function $S({epochs:f,activeRun:u,activePipeline:l,pipelineNodes:_,pipelineEdges:y,runDetails:$,nodeDetails:r,nodeDetailsState:j,ganttScale:A=O4,onGanttScaleChange:J,onRunChange:U,onIntervalSelect:Q,onMarkerSelect:W,selection:G,detailOpen:K,onDetailOpenChange:H,onRaw:O}){let[z,Z]=bu(xn),[N,E]=bu({startY:0,endY:0,startMs:0,endMs:0}),[q,Y]=bu(Date.now()),w=T_(null),B=String(u?.runId||""),P=Boolean(K),h=(Uf)=>{if(typeof H==="function")H(Uf)},M=n_(A??O4),n=String($?.runId||"")===B?$?.details:null,S=n?{...Pf(u)?u:{},...Pf(n)?n:{},runId:B,procedureRuns:Xf(n?.procedureRuns).length>0?n.procedureRuns:u?.procedureRuns}:u,T=oE(S,_,q),i=n?fS(n,S):{markers:[],arrows:[]},C=Xf(i.markers),v=Rn(S,T,C),X=pn(v,M,T,q),D=String(X.source||"frontend-y"),p=T.map((Uf)=>mn(Uf,X,q)),m={startMs:Number(X.startMs),endMs:Number(X.endMs),durationMs:Math.max(1,Number(X.durationMs??Number(X.endMs)-Number(X.startMs)))},s=HJ(M),d={...s,pxPerMinute:Number(X.pxPerMinute??s.pxPerMinute)},a=Math.round(Number(X.chartHeight||360)),I=T.some(OJ);F1(()=>{if(!B||!I)return;let Uf=window.setInterval(()=>Y(Date.now()),1000);return()=>window.clearInterval(Uf)},[B,I]);let ff=Yn(l,_,Array.isArray(y)?y:[]),yf=_.map((Uf)=>String(Uf?.id||"")).filter(Boolean),rf=p.map((Uf)=>String(Uf.nodeId||"")).filter(Boolean),Wf=C.map((Uf)=>String(Uf.nodeId||"")).filter(Boolean),Ef=Array.from(new Set([...ff,...yf,...rf,...Wf])),Gf={startY:0,endY:a,startMs:Number(m.startMs),endMs:Number(m.endMs)},c=Number(N?.endY||0)>0?N:Gf,o=(Uf)=>{return yr(Uf,m,a,X)<=Number(c.endY)&&QJ(Uf,m,a,X)>=Number(c.startY)},e=(Uf)=>{let nf=rl(Uf,m,a,X);return nf>=Number(c.startY)&&nf<=Number(c.endY)},Kf=new Set(Ef.filter((Uf)=>p.some((nf)=>nf.nodeId===Uf&&o(nf))||C.some((nf)=>nf.nodeId===Uf&&e(nf)))),k=z?Ef.filter((Uf)=>Kf.has(Uf)):Ef,Af=`${aF}px ${k.length>0?k.map(()=>`${j1}px`).join(" "):"minmax(160px, 1fr)"}`,Yf=Xf(X.ticks).filter(Pf),Bf=String(G?.mode==="interval"?G?.interval?.procedureRunId||"":""),df=String(G?.mode==="event"?G?.marker?.id||"":""),_0=()=>{let Uf=w.current;if(!Uf){E(Gf);return}let nf=Math.max(0,Uf.scrollTop-dF),Nu=Math.max(120,Uf.clientHeight-dF),Cf=Math.min(a,nf+Nu),d0={startY:nf,endY:Cf,startMs:Number(m.startMs),endMs:Number(m.endMs)},e0=Math.max(0,Math.min(1,nf/a)),Zu=Math.max(e0,Math.min(1,Cf/a)),i0=Math.max(1,Number(m.endMs)-Number(m.startMs));d0.startMs=Number(m.startMs)+i0*e0,d0.endMs=Number(m.startMs)+i0*Zu,E(d0)};F1(()=>{let Uf=w.current,nf=window.setTimeout(_0,0);return Uf?.addEventListener("scroll",_0),window.addEventListener("resize",_0),()=>{window.clearTimeout(nf),Uf?.removeEventListener("scroll",_0),window.removeEventListener("resize",_0)}},[B,m.startMs,m.endMs,a]);let y0=Math.max(0,Ef.length-k.length),N0=new Set(C.filter((Uf)=>k.includes(String(Uf.nodeId||""))&&e(Uf)).map((Uf)=>String(Uf.id))),a0=new Map(C.map((Uf)=>[String(Uf.id),Uf])),pu=Xf(i.arrows).filter((Uf)=>{if(!N0.has(String(Uf.targetMarkerId||"")))return!1;if(String(Uf.action||"")==="observe")return k.includes(String(Uf.sourceNodeId||""));return N0.has(String(Uf.sourceMarkerId||""))}),mu=aF+Math.max(1,k.length)*j1,C0=(Uf)=>{let nf=n_(Uf.target.value);if(typeof J==="function")J(nf);window.setTimeout(_0,0)},Q1=()=>Sn({title:`${l?.id||"pipeline"}-${B||"epoch"}-gantt`,meta:[`run ${B||"--"}`,`${Nf(m.startMs)} -> ${Nf(m.endMs)}`,`duration ${ql(m.durationMs)}`,`${d.label} / ${yJ(d.pxPerMinute)} px/min`,`${k.length}/${Ef.length} nodes`,`${C.length} markers`],visibleNodeIds:k,intervals:p,markers:C.filter((Uf)=>k.includes(String(Uf.nodeId||""))),arrows:pu,ticks:Yf,bounds:m,chartHeight:a,backendLayout:X}),ru=Pf(n?.gantt?.diagnostics)?n.gantt.diagnostics:null;return V(A1,{title:"Epoch 甘特图",eyebrow:`${l?.id||"pipeline"} / ${f.length} epochs`,className:"pipeline-wide-panel",loading:$?.loading,actions:V("div",{className:"pipeline-gantt-actions"},V("select",{value:B,disabled:f.length===0,onChange:(Uf)=>U(Uf.target.value),"data-testid":"pipeline-epoch-select"},f.map((Uf)=>V("option",{key:Uf.runId,value:Uf.runId},JJ(f,Uf)))),V("label",{className:"pipeline-gantt-toggle"},V("input",{type:"checkbox","data-testid":"pipeline-gantt-auto-hide-idle",checked:z,onChange:(Uf)=>{Z(Boolean(Uf.target.checked)),window.setTimeout(_0,0)}}),V("span",null,"自动隐藏空闲列")),V("label",{className:"pipeline-gantt-scale"},V("span",null,V("b",null,"时间尺度"),V("em",{"data-testid":"pipeline-gantt-scale-label"},`${d.label} · ${yJ(d.pxPerMinute)} px/min`)),V("input",{type:"range",min:0,max:100,step:0.01,value:M,onChange:C0,"aria-label":"调整甘特图时间尺度","data-testid":"pipeline-gantt-time-scale"}),V("small",null,V("span",null,"全局"),V("span",null,"细节"))),u?V("button",{type:"button",className:"ghost-btn",onClick:Q1,disabled:k.length===0,"data-testid":"pipeline-export-gantt"},"导出甘特图"):null,u?V(Il,{title:`Pipeline Epoch ${u.runId}`,data:u,onOpen:O,testId:"raw-pipeline-epoch-gantt"}):null)},!u?V(jl,{title:"暂无 Epoch",text:"当前 pipeline 还没有完整运行记录。"}):p.length===0?V(jl,{title:"暂无时间区间",text:"等待 D601 Pipeline backend 在 procedure summary 中返回 startedAt / finishedAt。"}):V("div",{className:"pipeline-gantt-wrap"},V("div",{className:`pipeline-gantt-detail-layout ${P?"detail-open":"detail-collapsed"}`,"data-testid":"pipeline-gantt-detail-layout","data-sidebar-open":P?"true":"false"},V("div",{className:"pipeline-gantt-main"},V("div",{className:"pipeline-gantt-main-head"},V("div",{className:"pipeline-gantt-meta"},V("span",null,`time ${Nf(m.startMs)} -> ${Nf(m.endMs)}`),V("span",null,`duration ${ql(m.durationMs)}`),V("span",null,`scale ${d.label} / ${yJ(d.pxPerMinute)} px/min`),V("span",null,`layout ${D}`),ru?V("span",null,`align ${ru.timeAxisAlignmentOk===!1?"check":"ok"}`):null,V("span",null,`visible ${k.length}/${Ef.length} nodes`),n?V("span",null,`markers ${C.length}`):null,z&&y0>0?V("span",null,`hidden idle ${y0}`):null),!P?V("button",{type:"button",className:"pipeline-sidecar-tab right",disabled:!G?.mode,onClick:()=>h(!0),"data-testid":"pipeline-gantt-sidebar-toggle"},G?.mode?"展开详情":"点击甘特图元素展开详情"):null),V("div",{className:"pipeline-gantt-viewport",ref:w,"data-testid":"pipeline-epoch-gantt","data-pipeline-id":l?.id||"","data-run-id":B,"data-layout-source":D,"data-start-ms":String(m.startMs),"data-end-ms":String(m.endMs),"data-chart-height":String(a)},V("div",{className:"pipeline-gantt-board",style:{gridTemplateColumns:Af,minWidth:`${mu}px`}},V("div",{className:"pipeline-gantt-head time"},"Time"),k.length===0?V("div",{className:"pipeline-gantt-head empty"},"当前时间窗无工作节点"):k.map((Uf)=>V("div",{key:`head-${Uf}`,className:"pipeline-gantt-head node",title:Uf,"data-testid":"pipeline-gantt-head-node","data-node-id":Uf},V(An,{value:Uf}))),V("div",{className:"pipeline-gantt-time-axis",style:{height:`${a}px`}},Yf.map((Uf)=>{let nf=lH(Uf,m,a,X);return V("div",{key:`tick-${Uf.ms}-${nf}`,className:"pipeline-gantt-tick",style:{top:`${nf}px`},"data-testid":"pipeline-gantt-tick","data-ms":String(Uf.ms),"data-y":String(nf)},V("b",null,Nf(Uf.ms)),V("span",null,`+${ql(Number(Uf.offsetMs??Number(Uf.ms)-Number(m.startMs)))}`))})),k.length>0?V("svg",{className:"pipeline-gantt-arrow-layer",width:k.length*j1,height:a,viewBox:`0 0 ${k.length*j1} ${a}`,style:{left:`${aF}px`,top:`${dF}px`,width:`${k.length*j1}px`,height:`${a}px`},"aria-hidden":"true"},V("defs",null,V("marker",{id:"pipeline-gantt-arrowhead",viewBox:"0 0 10 10",refX:9,refY:5,markerWidth:6,markerHeight:6,orient:"auto-start-reverse"},V("path",{d:"M 0 0 L 10 5 L 0 10 z",fill:"context-stroke"}))),pu.map((Uf)=>{let nf=a0.get(String(Uf.targetMarkerId||""));if(!nf)return null;let Nu=a0.get(String(Uf.sourceMarkerId||"")),Cf=String(Nu?.nodeId||Uf.sourceNodeId||""),d0=k.indexOf(Cf),e0=k.indexOf(String(nf.nodeId||""));if(d0<0||e0<0)return null;let Zu=d0*j1+j1/2,i0=e0*j1+j1/2,Du=Nu?rl(Nu,m,a,X):rl(nf,m,a,X),W1=rl(nf,m,a,X);return V("path",{key:Uf.id,className:`pipeline-gantt-arrow ${String(Uf.sourceKind||"").toLowerCase()} ${String(Uf.status||"").toLowerCase()} ${String(Uf.action||"").toLowerCase()}`,d:_H(Zu,Du,i0,W1),markerEnd:"url(#pipeline-gantt-arrowhead)","data-testid":String(Uf.action||"")==="observe"?"pipeline-gantt-observation-arrow":"pipeline-gantt-arrow","data-source-node-id":String(Uf.sourceNodeId||""),"data-target-node-id":String(Uf.targetNodeId||""),"data-target-marker-id":String(Uf.targetMarkerId||""),"data-action":String(Uf.action||""),"data-source-y":String(Du),"data-target-y":String(W1)})})):null,k.length===0?V("div",{className:"pipeline-gantt-empty-col",style:{height:`${a}px`}},"滚动到有活动的时间段后,相关 node 列会自动出现。"):k.map((Uf)=>{let nf=p.filter((Cf)=>Cf.nodeId===Uf),Nu=C.filter((Cf)=>String(Cf.nodeId||"")===Uf);return V("div",{key:`col-${Uf}`,className:"pipeline-gantt-node-col",style:{height:`${a}px`}},nf.map((Cf)=>{let d0=yr(Cf,m,a,X),e0=QJ(Cf,m,a,X),Zu=uH(Cf,m,a,X),i0=String(Cf.procedureRunId||`${Uf}-${Cf.startMs}`);return V("button",{key:i0,type:"button",className:`pipeline-gantt-bar ${Cf.status} ${Cf.live?"live":""} ${Bf===i0?"selected":""}`,style:{top:`${d0}px`,height:`${Zu}px`},title:`${Uf} ${Cf.status} ${Nf(Cf.startedAt||Cf.startMs)} -> ${Nf(Cf.finishedAt||Cf.endMs)}`,onClick:()=>Q(Cf),"data-testid":"pipeline-gantt-line","data-node-id":Uf,"data-procedure-run-id":String(Cf.procedureRunId||""),"data-status":String(Cf.status||""),"data-live":Cf.live?"true":"false","data-start-ms":String(Cf.startMs||""),"data-end-ms":String(Cf.endMs||""),"data-y1":String(d0),"data-y2":String(e0),"data-natural-height":String(Math.max(0,e0-d0))},V("strong",null,Cf.status||"working"),V("span",null,ql(Cf.durationMs)))}),Nu.map((Cf)=>V("button",{key:Cf.id,type:"button",className:`pipeline-gantt-marker ${Cf.kind} ${Cf.tone||""} ${Cf.status||""} ${df===String(Cf.id)?"selected":""}`,style:{top:`${rl(Cf,m,a,X)}px`},title:`${Cf.label||"event"} / ${Nf(Cf.timestampIso||Cf.timestamp||Cf.ms)}`,onClick:()=>W(Cf),"data-testid":Cf.kind==="prompt"?"pipeline-gantt-prompt-marker":"pipeline-gantt-control-marker","data-marker-id":String(Cf.id||""),"data-ms":String(Cf.ms??Cf.eventMs??""),"data-y":String(rl(Cf,m,a,X))})))})))),P?V(jn,{selection:G,runDetails:$,nodeDetails:r,nodeDetailsState:j,onRaw:O,onCollapse:()=>h(!1)}):null)))}function R1(){return{loading:!1,actionLoading:"",error:"",message:"",details:null,fetchedAt:null,appendPrompt:"",guidePrompt:"",modifyPrompt:"",approveReason:"",redoReason:""}}function D_(){return{mode:"",runId:"",interval:null,marker:null}}function $J(){return{runId:"",loading:!1,error:"",details:null,fetchedAt:null}}function W4(f,u){return`${f}/microservices/pipeline/proxy${u}`}function rS({activeRun:f,pipelineRuns:u,selectedRunId:l,onRunChange:_,selectedNodeId:y,selectedNodeConfig:$,selectedNodeRuntime:r,control:j,onControlChange:A,onFetch:J,onAction:U,onRaw:Q,onCollapse:W}){let G=String(f?.runId||""),K=String(r?.status||"pending"),H=!G||!y||j.loading||Boolean(j.actionLoading),O=(Z)=>(N)=>A({[Z]:N.target.value,error:"",message:""}),z=u.length>0?u:f?[f]:[];return V("aside",{className:"pipeline-node-control","data-testid":"pipeline-node-control"},V("div",{className:"pipeline-node-control-head"},V("div",null,V("p",{className:"panel-eyebrow"},"Manual Node Control"),V(j0,{title:y||"点击控制图中的 node",level:3,loading:j.loading||Boolean(j.actionLoading)})),V("div",{className:"pipeline-node-control-head-actions"},y?V(P_,{status:K},K):V(P_,{status:"pending"},"idle"),V("button",{type:"button",className:"ghost-btn mini",onClick:W,"data-testid":"pipeline-node-sidebar-collapse"},"收起"))),V("div",{className:"pipeline-control-runbar"},V("label",null,V("span",null,"目标 run"),V("select",{value:G||l,disabled:z.length===0,onChange:(Z)=>_(Z.target.value),"data-testid":"pipeline-node-run-select"},z.map((Z)=>V("option",{key:Z.runId,value:Z.runId},`${Z.runId||"--"} / ${Z.status||"--"}`)))),V("button",{type:"button",className:"ghost-btn",disabled:H,onClick:J,"data-testid":"pipeline-node-fetch"},j.loading?"抓取中":"抓取过程"),j.details?V(Il,{title:`Pipeline Node ${y}`,data:j.details,onOpen:Q,testId:"raw-pipeline-node-control"}):null),V("div",{className:"pipeline-control-meta"},V("span",null,V("b",null,"kind"),String($?.kind||"--")),V("span",null,V("b",null,"procedure"),String(r?.currentProcedureRunId||"--")),V("span",null,V("b",null,"attempts"),String(r?.attempts??"--")),V("span",null,V("b",null,"updated"),Nf(f?.updatedAt))),!y?V(jl,{title:"未选择 node",text:"点击 React Flow 控制图中的任意 node 后,可抓取执行过程、追加 prompt、下发引导、增量修改、审核通过或重做。"}):null,V(A0,{error:j.error,wide:!0}),V("div",{className:"pipeline-control-actions"},V("label",null,V("span",null,"实时追加 prompt(仅 running node)"),V("textarea",{value:j.appendPrompt,onChange:O("appendPrompt"),placeholder:"让当前执行中的 agent 继续、补充检查或调整当前步骤...",rows:4,disabled:!y,"data-testid":"pipeline-node-append-input"}),V("button",{type:"button",className:"primary-btn compact",disabled:H||!String(j.appendPrompt||"").trim(),onClick:()=>U("append"),"data-testid":"pipeline-node-append-button"},j.actionLoading==="append"?"追加中":"追加到运行中 node")),V("label",null,V("span",null,"下次尝试引导 prompt"),V("textarea",{value:j.guidePrompt,onChange:O("guidePrompt"),placeholder:"给该 node 下一次 attempt 的执行提示;不会立即打断当前 session。",rows:4,disabled:!y,"data-testid":"pipeline-node-guide-input"}),V("button",{type:"button",className:"ghost-btn compact",disabled:H||!String(j.guidePrompt||"").trim(),onClick:()=>U("guide"),"data-testid":"pipeline-node-guide-button"},j.actionLoading==="guide"?"下发中":"下发 guide")),V("label",null,V("span",null,"完成后增量修改 prompt"),V("textarea",{value:j.modifyPrompt,onChange:O("modifyPrompt"),placeholder:"在该 node 已完成结果基础上追加修改要求;runner 会重跑目标 node,并保留同 node 既有 OA 输出作为上下文。",rows:4,disabled:!y,"data-testid":"pipeline-node-modify-input"}),V("button",{type:"button",className:"ghost-btn compact",disabled:H||!String(j.modifyPrompt||"").trim(),onClick:()=>U("modify"),"data-testid":"pipeline-node-modify-button"},j.actionLoading==="modify"?"排队中":"增量修改 node")),V("label",null,V("span",null,"Monitor 审核通过原因"),V("textarea",{value:j.approveReason,onChange:O("approveReason"),placeholder:"当流程配置开启 monitor 审核时,记录审核通过原因并释放后续 node。",rows:3,disabled:!y,"data-testid":"pipeline-node-approve-input"}),V("button",{type:"button",className:"primary-btn compact",disabled:H||!String(j.approveReason||"").trim(),onClick:()=>U("approve"),"data-testid":"pipeline-node-approve-button"},j.actionLoading==="approve"?"提交中":"审核通过")),V("label",null,V("span",null,"重做 / restart 原因"),V("textarea",{value:j.redoReason,onChange:O("redoReason"),placeholder:"说明为什么需要重做;runner 会重置目标 node 以及非 rework 下游 node。",rows:4,disabled:!y,"data-testid":"pipeline-node-redo-input"}),V("button",{type:"button",className:"danger-btn compact",disabled:H||!String(j.redoReason||"").trim(),onClick:()=>U("redo"),"data-testid":"pipeline-node-redo-button"},j.actionLoading==="redo"?"排队中":"重做 node"))),V("div",{className:"pipeline-control-evidence"},V("strong",null,"Node 过程索引"),V(uS,{details:j.details,selectedNodeId:y,selectedNodeRuntime:r,control:j,onRaw:Q})))}function yH({microservices:f,onRaw:u,apiBaseUrl:l="/api"}){let _=f.find((uf)=>uf.id==="pipeline")||null,[y,$]=bu({loading:!1,error:"",health:null,snapshot:null,oaDiagnostics:null,minimaxQuota:null,refreshedAt:null}),[r,j]=bu(""),[A,J]=bu(""),[U,Q]=bu(""),[W,G]=bu(R1()),[K,H]=bu({}),[O,z]=bu(D_()),[Z,N]=bu($J()),[E,q]=bu(O4),[Y,w]=bu(!1),[B,P]=bu(!1),h=T_(0),{addNotification:M}=Lu(),n=T_(!1),S=T_(0),T=T_(""),i=T_({}),C=T_(""),v=T_("");async function X(uf={}){let wf=uf.silent===!0;if(!_)return;if(n.current)return;n.current=!0;let Hf=h.current+1;if(h.current=Hf,!wf)$((gf)=>({...gf,loading:!0,error:""}));try{let gf=`__unideskArrayLimit=registry.components:80,runs:${pP}`,[pf,Q0,u0]=await Promise.all([w_(`${l}/microservices/pipeline/proxy/api/snapshot?${gf}`,{cache:"no-store"}),w_(`${l}/microservices/pipeline/proxy/api/oa-event-flow/diagnostics`,{cache:"no-store"}).catch((Bl)=>({ok:!1,error:Df(Bl,"OA event flow diagnostics failed")})),w_(`${l}/microservices/pipeline/proxy/api/model-quota/minimax`,{cache:"no-store"}).catch((Bl)=>({ok:!1,error:Df(Bl,"MiniMax quota failed")}))]);if(Hf!==h.current)return;let fu={ok:pf?.ok!==!1,service:"pipeline-v2-control snapshot"};$({loading:!1,error:"",health:fu,snapshot:pf,oaDiagnostics:Q0,minimaxQuota:u0,refreshedAt:new Date})}catch(gf){if(Hf!==h.current)return;$((pf)=>({...pf,loading:!1,error:Df(gf,"Pipeline 加载失败")}))}finally{n.current=!1}}F1(()=>{if(X(),!_)return;let uf=()=>{if(g5())X({silent:!0})},wf=window.setInterval(()=>{uf()},WE),Hf=()=>{if(g5())uf()};return document.addEventListener("visibilitychange",Hf),()=>{window.clearInterval(wf),document.removeEventListener("visibilitychange",Hf)}},[_?.id,_?.runtime?.providerStatus,l]);let D=Fn(_),p=Un(_),m=Jn(_),s=y.snapshot||{},d=y.oaDiagnostics||null,a=y.minimaxQuota||null,{components:I,pipelines:ff,runs:yf}=Qn(s),rf=String(yf[0]?.pipelineId||""),Wf=(rf?ff.find((uf)=>String(uf.id||"")===rf):null)||ff[0]||{},Ef=ff.find((uf)=>String(uf.id||"")===r)||Wf,Gf=String(Ef.id||""),c=mE(Ef),o=NJ(Ef),e=DE(yf,Gf),Kf=cn(yf,Gf),k=Kf.find((uf)=>String(uf?.runId||"")===A)||e,Af=String(Z.runId||"")===String(k?.runId||"")?Kn(Z.details):null,Yf=Nn(k,Af),Bf=String(Yf?.runId||""),df=c.find((uf)=>String(uf?.id||"")===U)||null,_0=U?gE(Yf,U):null,y0=zn(yf),N0=On(I),a0=Number(y.health?.components)||VE(s,"registry.components",I.length),pu=VE(s,"runs",yf.length),mu=XE(Ef,Yf,I),C0={nodes:mu.nodes.map((uf)=>uf.id===U?{...uf,selected:!0,className:`${uf.className||""} selected-control-node`}:uf),edges:mu.edges},Q1=ff.map((uf)=>{let wf=String(uf.id||"pipeline"),Hf=DE(yf,wf);return{title:`${wf}-${Hf?.runId||"snapshot"}`,flow:XE(uf,Hf,I)}}),ru=String(O?.runId||Bf||""),Uf=String(O?.interval?.nodeId||O?.marker?.nodeId||""),nf=ru&&Uf?K[_J(ru,Uf)]||null:null,Nu=e5(W.details,ru,Uf),Cf=e5(nf?.details,ru,Uf)||Nu,d0=ru&&Uf?{...Pf(nf)?nf:{},runId:ru,nodeId:Uf,details:Cf,loading:Boolean(nf?.loading)||!Cf&&Boolean(W.loading)&&U===Uf,error:String(nf?.error||""),fetchedAt:nf?.fetchedAt||(Nu?W.fetchedAt:null)}:null,e0=Kf.map((uf)=>String(uf?.runId||"")).filter(Boolean).join("|"),Zu=c.map((uf)=>String(uf?.id||"")).filter(Boolean).join("|");F1(()=>{C.current=U},[U]),F1(()=>{v.current=Bf},[Bf]),F1(()=>{if(!A||e0.split("|").includes(A))return;J("")},[A,e0]),F1(()=>{if(!U||Zu.split("|").includes(U))return;Q(""),G(R1()),z(D_()),w(!1),P(!1)},[U,Zu]),F1(()=>{if(!U)w(!1)},[U]),F1(()=>{if(!O.mode)P(!1)},[O.mode]);async function i0(uf=Bf,wf={}){if(!uf){N($J());return}let Hf=n_(wf.scale??E??O4),gf=`${uf}:timeline`;if(T.current===gf)return;T.current=gf;let pf=wf.silent===!0,Q0=S.current+1;S.current=Q0,N((u0)=>({runId:uf,scale:Hf,loading:!pf||String(u0.runId||"")!==uf||!u0.details,error:"",details:pf&&u0.runId===uf?u0.details:u0.runId===uf?u0.details:null,fetchedAt:u0.runId===uf?u0.fetchedAt:null}));try{let[u0,fu]=await Promise.all([w_(W4(l,`/api/node-control/runs/${encodeURIComponent(uf)}?tail=160&view=timeline`),{cache:"no-store",strictJson:!0}),w_(W4(l,`/api/runs/${encodeURIComponent(uf)}`),{cache:"no-store"}).catch((Bl)=>({ok:!1,runSummaryError:Df(Bl,"抓取评分失败")}))]);if(Q0!==S.current)return;N({runId:uf,scale:Hf,loading:!1,error:"",details:{...u0,run:Pf(fu?.run)?fu.run:void 0,runSummaryError:fu?.runSummaryError},fetchedAt:new Date})}catch(u0){if(Q0!==S.current)return;N((fu)=>({runId:uf,scale:Hf,loading:!1,error:Df(u0,"抓取 epoch 执行过程失败"),details:fu.runId===uf?fu.details:null,fetchedAt:fu.runId===uf?fu.fetchedAt:null}))}finally{if(T.current===gf)T.current=""}}function Du(uf,wf,Hf){let gf=_J(uf,wf);H((pf)=>{let Q0={...pf,[gf]:{...Pf(pf?.[gf])?pf[gf]:{},runId:uf,nodeId:wf,...Hf}},u0=Object.keys(Q0);if(u0.length>32)for(let fu of u0.slice(0,u0.length-32))delete Q0[fu];return Q0})}async function W1(uf,wf){if(!uf||!wf)return;let Hf=_J(uf,wf),gf=Number(i.current?.[Hf]||0)+1;i.current={...i.current,[Hf]:gf},Du(uf,wf,{loading:!0,error:""});try{let pf=await w_(W4(l,`/api/node-control/runs/${encodeURIComponent(uf)}/nodes/${encodeURIComponent(wf)}?tail=160`),{cache:"no-store",strictJson:!0});if(Number(i.current?.[Hf]||0)!==gf)return;let Q0=new Date;if(Du(uf,wf,{loading:!1,details:pf,fetchedAt:Q0,error:""}),C.current===wf&&v.current===uf)G((u0)=>({...u0,loading:!1,details:pf,fetchedAt:Q0,error:""}))}catch(pf){if(Number(i.current?.[Hf]||0)!==gf)return;Du(uf,wf,{loading:!1,error:Df(pf,"抓取 Gantt node 详情失败")})}}F1(()=>{if(!Bf){N($J());return}i0(Bf);let uf=()=>{if(g5())i0(Bf,{silent:!0})},wf=window.setInterval(()=>{uf()},WE),Hf=()=>{if(g5())uf()};return document.addEventListener("visibilitychange",Hf),()=>{window.clearInterval(wf),document.removeEventListener("visibilitychange",Hf)}},[Bf,l]);async function pl(uf=Bf,wf=U){if(!uf||!wf){G((Hf)=>({...Hf,error:"请先选择 run 和 node",message:""}));return}G((Hf)=>({...Hf,loading:!0,error:"",message:""}));try{let Hf=await w_(W4(l,`/api/node-control/runs/${encodeURIComponent(uf)}/nodes/${encodeURIComponent(wf)}?tail=160`),{cache:"no-store",strictJson:!0}),gf=new Date;G((pf)=>({...pf,loading:!1,details:Hf,fetchedAt:gf,error:""})),Du(uf,wf,{loading:!1,details:Hf,fetchedAt:gf,error:""})}catch(Hf){G((gf)=>({...gf,loading:!1,error:Df(Hf,"抓取 node 执行过程失败")}))}}async function R_(uf){let wf=String(uf?.runId||Bf||""),Hf=String(uf?.nodeId||"");if(z({mode:"interval",runId:wf,interval:uf,marker:null}),P(!0),!wf||!Hf)return;if(wf!==Bf)J(wf);Q(Hf),G(R1()),i0(wf,{silent:!0}),W1(wf,Hf)}async function x_(uf){let wf=String(uf?.runId||Bf||""),Hf=String(uf?.nodeId||"");if(z({mode:"event",runId:wf,interval:null,marker:uf}),P(!0),!wf)return;if(wf!==Bf)J(wf);if(i0(wf,{silent:!0}),!Hf)return;Q(Hf),G(R1()),W1(wf,Hf)}async function v0(uf){if(!Bf||!U){G((gf)=>({...gf,error:"请先选择 run 和 node",message:""}));return}let wf=uf==="append"?"prompts":uf,Hf=uf==="append"?W.appendPrompt:uf==="guide"?W.guidePrompt:uf==="modify"?W.modifyPrompt:uf==="approve"?W.approveReason:W.redoReason;if(!String(Hf||"").trim()){G((gf)=>({...gf,error:"操作内容不能为空",message:""}));return}G((gf)=>({...gf,actionLoading:uf,error:"",message:""}));try{let gf=uf==="redo"||uf==="approve"?{reason:Hf,source:"unidesk-frontend",sourceKind:"webui"}:{prompt:Hf,source:"unidesk-frontend",sourceKind:"webui"},pf=await w_(W4(l,`/api/node-control/runs/${encodeURIComponent(Bf)}/nodes/${encodeURIComponent(U)}/${wf}`),{method:"POST",body:JSON.stringify(gf)});if(G((u0)=>({...u0,actionLoading:"",details:pf,fetchedAt:new Date,appendPrompt:uf==="append"?"":u0.appendPrompt,guidePrompt:uf==="guide"?"":u0.guidePrompt,modifyPrompt:uf==="modify"?"":u0.modifyPrompt,approveReason:uf==="approve"?"":u0.approveReason,redoReason:uf==="redo"?"":u0.redoReason,message:uf==="append"?"已追加到运行中 node":uf==="guide"?"已下发 guide,等待 runner 处理":uf==="modify"?"已排队增量修改命令":uf==="approve"?"已提交审核通过决策":"已排队重做命令"})),M("success",uf==="append"?"已追加到运行中 node":uf==="guide"?"已下发 guide,等待 runner 处理":uf==="modify"?"已排队增量修改命令":uf==="approve"?"已提交审核通过决策":"已排队重做命令"),await pl(Bf,U),await i0(Bf,{silent:!0}),uf!=="append")await X()}catch(gf){G((pf)=>({...pf,actionLoading:"",error:Df(gf,"node 控制操作失败")}))}}if(!_)return V(jl,{title:"Pipeline 未登记",text:"请在 config.json 的 microservices 中登记用户服务 id=pipeline"});return V("div",{className:"pipeline-page","data-testid":"pipeline-page"},V(A1,{title:"Pipeline v2 工作台",eyebrow:"D601 Snapshot 用户服务",loading:y.loading,actions:V("div",{className:"panel-actions"},V("button",{type:"button",className:"ghost-btn",onClick:X,disabled:y.loading,"data-testid":"pipeline-refresh-button"},y.loading?"刷新中":"刷新"),V(Il,{title:"Pipeline 用户服务",data:_,onOpen:u,testId:"raw-pipeline-service"}))},V("div",{className:"pipeline-hero"},V("div",null,V("div",{className:"node-version-line"},V(P_,{status:D.providerStatus==="online"?"online":"warn"},D.providerStatus||"unknown"),V("span",null,_.providerId),V("span",null,m.public?"公网暴露":"仅 UniDesk frontend 代理访问")),V("p",{className:"muted paragraph"},_.description)),V("div",{className:"microservice-ref-card"},V("span",null,"Repo"),V("strong",null,p.url||"--"),V("code",null,p.commitId||"--")),V("div",{className:"microservice-ref-card"},V("span",null,"D601 Docker"),V("strong",null,`${m.nodeBindHost||"--"}:${m.nodePort||"--"}`),V("code",null,`${p.composeFile||"--"} / ${p.composeService||"--"}`))),V(A0,{error:y.error,wide:!0})),V("div",{className:"pipeline-grid"},V(A1,{title:"控制图",eyebrow:`${Ef.id||"pipeline"} / run ${Yf?.status||"--"}`,className:"pipeline-wide-panel",loading:y.loading,actions:V("div",{className:"pipeline-toolbar"},V("select",{value:Gf,disabled:ff.length===0,onChange:(uf)=>{j(uf.target.value),J(""),Q(""),G(R1()),z(D_()),w(!1),P(!1)},"data-testid":"pipeline-select"},ff.map((uf)=>V("option",{key:uf.id,value:uf.id},uf.id||uf.key))),V("select",{value:Bf,disabled:Kf.length===0,onChange:(uf)=>{if(J(uf.target.value),G(R1()),z(D_()),w(!1),P(!1),U)pl(uf.target.value,U)},"data-testid":"pipeline-run-select"},Kf.map((uf)=>V("option",{key:uf.runId,value:uf.runId},JJ(Kf,uf)))),V("button",{type:"button",className:"ghost-btn",disabled:C0.nodes.length===0,onClick:()=>sE(C0,`${Ef.id||"pipeline"}-${Yf?.runId||"snapshot"}`),"data-testid":"pipeline-export-graph"},"导出渲染图"),V("button",{type:"button",className:"ghost-btn",disabled:Q1.every((uf)=>uf.flow.nodes.length===0),onClick:()=>Cn(Q1),"data-testid":"pipeline-export-all-graphs"},"批量导出"))},c.length===0?V(jl,{title:"暂无控制图",text:"等待 D601 pipeline backend 返回 config.nodes / config.edges"}):V("div",{className:`pipeline-control-shell ${Y?"detail-open":"detail-collapsed"}`,"data-testid":"pipeline-control-shell","data-sidebar-open":Y?"true":"false"},V("div",{className:"pipeline-flow-frame","data-testid":"pipeline-react-flow"},V(rE,{nodes:C0.nodes,edges:C0.edges,nodeTypes:sP,edgeTypes:tP,fitView:!0,fitViewOptions:{padding:0.18},nodesDraggable:!1,nodesConnectable:!1,elementsSelectable:!0,minZoom:0.25,maxZoom:1.4,proOptions:{hideAttribution:!0},onNodeClick:(uf,wf)=>{let Hf=String(wf.id);if(Q(Hf),G(R1()),w(!0),Bf)pl(Bf,Hf)}},V(AE,{gap:22,size:1,color:"rgba(215, 161, 58, 0.24)"}),V(JE,{showInteractive:!1})),!Y?V("button",{type:"button",className:"pipeline-sidecar-tab right",disabled:!U,onClick:()=>w(!0),"data-testid":"pipeline-node-sidebar-toggle"},U?"展开 node 控制":"点击 node 展开控制"):null),Y?V(rS,{activeRun:Yf,pipelineRuns:Kf,selectedRunId:A,onRunChange:(uf)=>{if(J(uf),G(R1()),z(D_()),U)pl(uf,U)},selectedNodeId:U,selectedNodeConfig:df,selectedNodeRuntime:_0,control:W,onControlChange:(uf)=>G((wf)=>({...wf,...uf})),onFetch:()=>pl(),onAction:v0,onRaw:u,onCollapse:()=>w(!1)}):null),V("div",{className:"pipeline-flow-summary"},V("span",null,`${C0.nodes.length} nodes`),V("span",null,`${C0.edges.length} edges`),V("span",null,`${ff.length} pipelines`),V("span",null,`source config+components(${I.length})`),V("span",null,`run ${Yf?.runId||"--"}`),V("span",null,`score ${FJ(Yf)}`),V("span",null,U?`selected ${U}`:"click node to control"))),V($S,{epochs:Kf,activeRun:Yf,activePipeline:Ef,pipelineNodes:c,pipelineEdges:o,selection:O,detailOpen:B,onDetailOpenChange:P,runDetails:Z,nodeDetails:Cf,nodeDetailsState:d0,ganttScale:E,onGanttScaleChange:q,onIntervalSelect:R_,onMarkerSelect:x_,onRunChange:(uf)=>{if(J(uf),G(R1()),z(D_()),P(!1),U)pl(uf,U)},onRaw:u}),V(A1,{title:"观测指标",eyebrow:y.refreshedAt?`Updated ${W0(y.refreshedAt)}`:"Snapshot",loading:y.loading},V("div",{className:"metric-grid"},V(wu,{label:"Health",value:y.health?.ok?"OK":"--",hint:y.health?.service||"D601 /health",tone:y.health?.ok?"ok":"warn"}),V(wu,{label:"组件",value:a0,hint:"components registry",tone:s?.registry?.ok===!1?"warn":"ok"}),V(wu,{label:"Pipeline",value:ff.length,hint:`${c.length} nodes / ${o.length} edges`}),V(wu,{label:"运行记录",value:pu,hint:`${y0.succeeded||0} succeeded / ${y0.running||0} running`}),V(wu,{label:"OA 记录",value:Array.isArray(e?.submissions)?e.submissions.length:0,hint:e?.runId||"latest run"}),V(wu,{label:"Procedure",value:Array.isArray(e?.procedureRuns)?e.procedureRuns.length:0,hint:e?.status||"no run"}),V(wu,{label:"Score",value:FJ(Yf),hint:Yf?.runId||"selected epoch",tone:EJ(Yf)})),V("div",{className:"panel-actions inline-actions"},V(Il,{title:"Pipeline Snapshot",data:s,onOpen:u,testId:"raw-pipeline-snapshot"}))),V(A1,{title:"评分器",eyebrow:Yf?.runId||"selected epoch",loading:y.loading},V(Hn,{run:Yf,onRaw:u})),V(A1,{title:"MiniMax 限额",eyebrow:"model/minimax-m27 quota",loading:y.loading},V(yS,{quota:a,onRaw:u})),V(A1,{title:"OA 事件流",eyebrow:"100% event-driven diagnostics",className:"pipeline-wide-panel",loading:y.loading},V(_S,{diagnostics:d,onRaw:u})),V(A1,{title:"组件矩阵",eyebrow:`${N0.length} classes`,loading:y.loading},N0.length===0?V(jl,{title:"暂无组件",text:"等待 D601 pipeline backend 返回 registry.components"}):V("div",{className:"component-strata"},N0.map((uf)=>V("article",{key:uf.name,className:"component-stratum"},V("span",null,uf.name),V("strong",null,uf.count)))),V("div",{className:"pipeline-component-list"},I.slice(0,12).map((uf)=>V("span",{key:uf.key,className:"data-chip"},V("b",null,uf.componentClass||"--"),V("span",null,uf.id||uf.key||"--"))))),V(A1,{title:"Epoch 列表",eyebrow:`${Kf.length}/${pu} preview`,loading:y.loading},Kf.length===0?V(jl,{title:"暂无运行记录",text:"当前 pipeline 在 .state/pipeline-runs 中还没有 epoch。"}):V("div",{className:"pipeline-run-list"},Kf.map((uf)=>{let wf=String(uf?.runId||"")===Bf?Yf:uf;return V("article",{key:uf.runId,className:`pipeline-run-card ${String(uf.runId||"")===Bf?"active":""}`,role:"button",tabIndex:0,onClick:()=>{J(String(uf.runId||"")),z(D_())},onKeyDown:(Hf)=>{if(Hf.key==="Enter"||Hf.key===" ")J(String(uf.runId||"")),z(D_())}},V("div",{className:"node-card-head"},V("strong",null,JJ(Kf,uf)),V(P_,{status:uf.status},uf.status||"--")),V("div",{className:"docker-meta compact"},V("span",null,wf?.pipelineId||"--"),V("span",null,`nodes ${Array.isArray(wf?.nodes)?wf.nodes.length:0}`),V("span",null,`oa ${Array.isArray(wf?.submissions)?wf.submissions.length:0}`),V("span",null,`procedures ${Array.isArray(wf?.procedureRuns)?wf.procedureRuns.length:0}`),V(En,{run:wf})),V("p",{className:"muted paragraph"},d5(wf?.task)),V("span",{className:"pipeline-run-time"},Nf(wf?.updatedAt)))}))),V(A1,{title:"运行材料索引",eyebrow:Yf?.runId||"selected epoch",className:"pipeline-wide-panel",loading:y.loading},V(lS,{activeRun:Yf,onRaw:u}))))}var Jr=cf(O0(),1);var $f=Jr.default.createElement,{useEffect:jS}=Jr.default,Ar=Jr.default.useState,qJ={id:"",sequenceNo:"",contractNo:"",name:"",currentStatus:"",pending:"",paymentStatus:"",notes:""};function AS({status:f,children:u}){let l=String(f||"unknown").toLowerCase();return $f("span",{className:`status-badge ${l}`},u||f||"unknown")}function Fr({label:f,value:u,hint:l,tone:_}){return $f("article",{className:`metric-card ${_||""}`},$f("div",{className:"metric-label"},f),$f("div",{className:"metric-value"},u),$f("div",{className:"metric-hint"},l))}function LJ({title:f,eyebrow:u,actions:l,children:_,className:y,loading:$}){return $f("section",{className:`panel ${y||""}`},$f("div",{className:"panel-head"},$f("div",null,u?$f("p",{className:"panel-eyebrow"},u):null,$f(j0,{title:f,loading:$})),l?$f("div",{className:"panel-actions"},l):null),$f("div",{className:"panel-body"},_))}function $H({title:f,data:u,onOpen:l,testId:_}){return $f("button",{type:"button",className:"ghost-btn","data-testid":_,onClick:()=>l(f,u)},"查看原始JSON")}function rH({title:f,text:u}){return $f("div",{className:"empty-state"},$f("strong",null,f),$f("span",null,u))}function FS(f){return f?.runtime&&typeof f.runtime==="object"&&!Array.isArray(f.runtime)?f.runtime:{}}function JS(f){return f?.backend&&typeof f.backend==="object"&&!Array.isArray(f.backend)?f.backend:{}}function US(f){return f?.repository&&typeof f.repository==="object"&&!Array.isArray(f.repository)?f.repository:{}}function u3(f,u){return`${f}/microservices/project-manager/proxy${u}`}function QS(f){return{id:String(f.id||""),sequenceNo:f.sequenceNo===null||f.sequenceNo===void 0?"":String(f.sequenceNo),contractNo:String(f.contractNo||""),name:String(f.name||""),currentStatus:String(f.currentStatus||""),pending:String(f.pending||""),paymentStatus:String(f.paymentStatus||""),notes:String(f.notes||"")}}function WS(f){return{sequenceNo:f.sequenceNo===""?null:Number(f.sequenceNo),contractNo:String(f.contractNo||"").trim(),name:String(f.name||"").trim(),currentStatus:String(f.currentStatus||"").trim(),pending:String(f.pending||"").trim(),paymentStatus:String(f.paymentStatus||"").trim(),paymentRatio:String(f.paymentStatus||"").trim(),notes:String(f.notes||"").trim()}}function XJ(f){return String(f||"item").replace(/[^A-Za-z0-9_-]+/g,"-")}function zS(f){let u=new Uint8Array(f),l="",_=32768;for(let y=0;y$f("tr",{key:y.id,className:u===y.id?"active-row":"","data-testid":`project-manager-row-${XJ(y.id)}`},$f("td",null,y.sequenceNo??"--"),$f("td",null,$f("strong",null,y.contractNo||"--"),$f("code",null,y.id||"--")),$f("td",null,$f("strong",null,y.name||"--"),$f("span",{className:"muted block"},y.sourceFile||"--")),$f("td",null,y.currentStatus||"--"),$f("td",null,$f("span",{className:"preline"},y.pending||"--")),$f("td",null,$f(AS,{status:Number(y.paymentRatio||0)>=1?"online":"warn"},y.paymentStatus||"--")),$f("td",null,y.notes||"--"),$f("td",null,$f("div",{className:"inline-actions"},$f("button",{type:"button",className:"ghost-btn",onClick:()=>l(y),"data-testid":`project-manager-edit-${XJ(y.id)}`},"编辑"),$f($H,{title:`Project ${y.contractNo||y.id}`,data:y,onOpen:_,testId:`raw-project-${XJ(y.id)}`}))))))))}function jH({microservices:f,onRaw:u,apiBaseUrl:l="/api"}){let _=f.find((B)=>B.id==="project-manager")||null,[y,$]=Ar({loading:!1,saving:!1,importing:!1,exporting:!1,error:"",notice:"",health:null,list:null,refreshedAt:null}),[r,j]=Ar({...qJ}),[A,J]=Ar(""),[U,Q]=Ar("all"),{addNotification:W}=Lu();async function G(B=A,P=U){if(!_)return;$((h)=>({...h,loading:!0,error:""}));try{let h=new URLSearchParams({pageSize:"200",status:P});if(B.trim())h.set("q",B.trim());let[M,n]=await Promise.all([Mf(`${l}/microservices/project-manager/health`),Mf(u3(l,`/api/projects?${h.toString()}`))]);$((S)=>({...S,loading:!1,health:M,list:n,refreshedAt:new Date,error:""}))}catch(h){$((M)=>({...M,loading:!1,error:Df(h,"Project Manager 加载失败")}))}}jS(()=>{G()},[_?.id,_?.runtime?.providerStatus]);async function K(B){B.preventDefault(),$((P)=>({...P,saving:!0,error:"",notice:""}));try{let P=WS(r);if(r.id)await Mf(u3(l,`/api/projects/${encodeURIComponent(r.id)}`),{method:"PUT",body:JSON.stringify(P)});else await Mf(u3(l,"/api/projects"),{method:"POST",body:JSON.stringify(P)});let h=r.id?"项目已更新":"项目已创建";$((M)=>({...M,saving:!1,notice:h})),W("success",h),await G()}catch(P){$((h)=>({...h,saving:!1,error:Df(P,"保存项目失败")}))}}async function H(){if(!r.id)return;if(!window.confirm(`删除项目 ${r.contractNo||r.name||r.id} ?`))return;$((B)=>({...B,saving:!0,error:"",notice:""}));try{await Mf(u3(l,`/api/projects/${encodeURIComponent(r.id)}`),{method:"DELETE"}),j({...qJ});let B="项目已删除";$((P)=>({...P,saving:!1,notice:B})),W("success",B),await G()}catch(B){$((P)=>({...P,saving:!1,error:Df(B,"删除项目失败")}))}}async function O(B){let P=B.target.files?.[0];if(!P)return;$((h)=>({...h,importing:!0,error:"",notice:""}));try{let h=zS(await P.arrayBuffer()),n=`Excel 已导入 ${(await Mf(u3(l,"/api/import/excel"),{method:"POST",body:JSON.stringify({fileName:P.name,contentBase64:h,replace:!1})})).imported||0} 条项目`;$((S)=>({...S,importing:!1,notice:n})),W("success",n),B.target.value="",await G()}catch(h){$((M)=>({...M,importing:!1,error:Df(h,"Excel 导入失败")}))}}async function z(){$((B)=>({...B,exporting:!0,error:""}));try{let B=await nz(u3(l,"/api/projects/export.xlsx")),P=URL.createObjectURL(B),h=document.createElement("a");h.href=P,h.download=`project-manager-${UU()}.xlsx`,document.body.appendChild(h),h.click(),h.remove(),URL.revokeObjectURL(P),$((M)=>({...M,exporting:!1,notice:"Excel 已导出"}))}catch(B){$((P)=>({...P,exporting:!1,error:Df(B,"Excel 导出失败")}))}}if(!_)return $f(rH,{title:"Project Manager 未登记",text:"请在 config.json 的 microservices 中登记用户服务 id=project-manager"});let Z=FS(_),N=US(_),E=JS(_),q=Array.isArray(y.list?.projects)?y.list.projects:[],Y=y.list?.summary||{},w=y.health||{};return $f("div",{className:"project-manager-page","data-testid":"project-manager-page"},$f(LJ,{title:"项目管理工作台",eyebrow:"Main Server PostgreSQL 用户服务",loading:y.loading||y.exporting,actions:$f("div",{className:"panel-actions"},$f("button",{type:"button",className:"ghost-btn",disabled:y.loading,onClick:()=>G(),"data-testid":"project-manager-refresh-button"},y.loading?"刷新中":"刷新"),$f("button",{type:"button",className:"ghost-btn",disabled:y.exporting,onClick:z,"data-testid":"project-manager-export-button"},y.exporting?"导出中":"导出 Excel"),$f($H,{title:"Project Manager 用户服务",data:_,onOpen:u,testId:"raw-project-manager-service"}))},$f("div",{className:"project-manager-hero"},$f(Fr,{label:"项目总数",value:Y.total??q.length,hint:`PG 表 ${w.storage?.table||"project_manager_projects"}`,tone:"ok"}),$f(Fr,{label:"进行中",value:Y.active??"--",hint:"当前状态未完全完成"}),$f(Fr,{label:"已完成",value:Y.completed??"--",hint:"按 完成 关键字统计",tone:"ok"}),$f(Fr,{label:"未全款",value:Y.unpaid??"--",hint:"付款比例 < 1",tone:Number(Y.unpaid||0)>0?"warn":"ok"})),$f(A0,{error:y.error}),y.notice?$f("div",{className:"form-success"},y.notice):null),$f("div",{className:"project-manager-hero"},$f("div",{className:"microservice-ref-card"},$f("span",null,"Repo"),$f("strong",null,N.url||"--"),$f("code",null,N.commitId||"--")),$f("div",{className:"microservice-ref-card"},$f("span",null,"Main Server Docker"),$f("strong",null,`${E.nodeBindHost||"--"}:${E.nodePort||"--"}`),$f("code",null,`${N.composeService||"--"} / ${N.containerName||"--"}`)),$f("div",{className:"microservice-ref-card"},$f("span",null,"Runtime"),$f("strong",null,Z.providerName||_.providerId),$f("code",null,`Health ${w.ok?"OK":"--"} / ${y.refreshedAt?W0(y.refreshedAt):"--"}`)),$f("div",{className:"microservice-ref-card"},$f("span",null,"Import Source"),$f("strong",null,"D601 WeChat Excel"),$f("code",null,"合作项目列表_I_20260309.xlsx"))),$f("div",{className:"project-manager-layout"},$f(LJ,{title:"项目清单",eyebrow:"CRUD + Excel Export",loading:y.loading||y.importing||y.exporting,actions:$f("div",{className:"inline-actions project-manager-filters"},$f("input",{value:A,onChange:(B)=>J(B.target.value),placeholder:"搜索合同号 / 项目名称 / 状态","data-testid":"project-manager-search"}),$f("select",{value:U,onChange:(B)=>{Q(B.target.value),G(A,B.target.value)},"data-testid":"project-manager-status-filter"},$f("option",{value:"all"},"全部"),$f("option",{value:"active"},"进行中"),$f("option",{value:"completed"},"已完成"),$f("option",{value:"unpaid"},"未全款")),$f("button",{type:"button",className:"ghost-btn",onClick:()=>G(A,U)},"筛选"))},$f(GS,{projects:q,activeId:r.id,onSelect:(B)=>j(QS(B)),onRaw:u})),$f(LJ,{title:r.id?"编辑项目":"新建项目",eyebrow:"PostgreSQL Write Path",loading:y.saving||y.importing},$f("form",{className:"stack-form project-manager-form",onSubmit:K,"data-testid":"project-manager-form"},r.id?$f("label",null,"项目 ID",$f("input",{value:r.id,disabled:!0})):null,$f("label",null,"序号",$f("input",{type:"number",value:r.sequenceNo,onChange:(B)=>j((P)=>({...P,sequenceNo:B.target.value}))})),$f("label",null,"合同号",$f("input",{value:r.contractNo,onChange:(B)=>j((P)=>({...P,contractNo:B.target.value})),required:!0})),$f("label",null,"项目名称",$f("input",{value:r.name,onChange:(B)=>j((P)=>({...P,name:B.target.value})),required:!0})),$f("label",null,"当前状况",$f("textarea",{value:r.currentStatus,onChange:(B)=>j((P)=>({...P,currentStatus:B.target.value}))})),$f("label",null,"待完成",$f("textarea",{value:r.pending,onChange:(B)=>j((P)=>({...P,pending:B.target.value}))})),$f("label",null,"付款情况",$f("input",{value:r.paymentStatus,onChange:(B)=>j((P)=>({...P,paymentStatus:B.target.value})),placeholder:"例如 1 / 0.5 / 50%"})),$f("label",null,"其它",$f("input",{value:r.notes,onChange:(B)=>j((P)=>({...P,notes:B.target.value}))})),$f("div",{className:"inline-actions"},$f("button",{type:"submit",className:"primary-btn",disabled:y.saving,"data-testid":"project-manager-save-button"},y.saving?"保存中":r.id?"保存修改":"创建项目"),$f("button",{type:"button",className:"ghost-btn",onClick:()=>j({...qJ})},"清空"),r.id?$f("button",{type:"button",className:"danger-btn",disabled:y.saving,onClick:H,"data-testid":"project-manager-delete-button"},"删除"):null)),$f("div",{className:"project-manager-import"},$f("p",{className:"muted paragraph"},"浏览器只访问 UniDesk frontend;后端通过同源用户服务代理写入主 PostgreSQL,不暴露 4233 公网端口。"),$f("label",{className:"file-import"},y.importing?"导入中...":"导入 Excel",$f("input",{type:"file",accept:".xlsx",onChange:O,disabled:y.importing,"data-testid":"project-manager-import-input"}))))))}var Wr=cf(O0(),1);var Jf=Wr.default.createElement,{useEffect:KS}=Wr.default,hu=Wr.default.useState;function NS({status:f,children:u}){let l=String(f||"unknown").toLowerCase();return Jf("span",{className:`status-badge ${l}`},u||f||"unknown")}function Ur({label:f,value:u,hint:l,tone:_}){return Jf("article",{className:`metric-card ${_||""}`},Jf("div",{className:"metric-label"},f),Jf("div",{className:"metric-value"},u),Jf("div",{className:"metric-hint"},l))}function BJ({title:f,eyebrow:u,actions:l,children:_,className:y,loading:$}){return Jf("section",{className:`panel ${y||""}`},Jf("div",{className:"panel-head"},Jf("div",null,u?Jf("p",{className:"panel-eyebrow"},u):null,Jf(j0,{title:f,loading:$})),l?Jf("div",{className:"panel-actions"},l):null),Jf("div",{className:"panel-body"},_))}function AH({title:f,data:u,onOpen:l,testId:_}){return Jf("button",{type:"button",className:"ghost-btn","data-testid":_,onClick:()=>l(f,u)},"查看原始JSON")}function Qr({title:f,text:u}){return Jf("div",{className:"empty-state"},Jf("strong",null,f),Jf("span",null,u))}function ZS(f){return f?.runtime&&typeof f.runtime==="object"&&!Array.isArray(f.runtime)?f.runtime:{}}function ES(f){return f?.backend&&typeof f.backend==="object"&&!Array.isArray(f.backend)?f.backend:{}}function HS(f){return f?.repository&&typeof f.repository==="object"&&!Array.isArray(f.repository)?f.repository:{}}function JH(f){return String(f).replace(/[^a-zA-Z0-9_-]/g,"_")}function OS(f){if(!Number.isFinite(f))return"--";return`${f.toFixed(1)}%`}function l3(f,u){return`${f}/microservices/todo-note/proxy${u}`}function UH(f){return f.reduce((u,l)=>{let _=UH(Array.isArray(l.children)?l.children:[]),y=Boolean(l.completed);return{total:u.total+1+_.total,completed:u.completed+(y?1:0)+_.completed,active:u.active+(y?0:1)+_.active}},{total:0,completed:0,active:0})}function wJ(f,u){let l=u==="all"||(u==="completed"?Boolean(f.completed):!f.completed),_=Array.isArray(f.children)?f.children:[];return l||_.some((y)=>wJ(y,u))}function FH(f){return Array.isArray(f?.instances)?f.instances:[]}function YJ(f,u){for(let l of f){if(l?.id===u)return Array.isArray(l.children)?l.children:[];let _=YJ(Array.isArray(l?.children)?l.children:[],u);if(_.length>0)return _}return[]}function QH({microservices:f,onRaw:u,apiBaseUrl:l="/api"}){let _=f.find((k)=>k.id==="todo-note")||null,[y,$]=hu(null),[r,j]=hu(null),[A,J]=hu(""),[U,Q]=hu(null),[W,G]=hu("all"),[K,H]=hu(13),[O,z]=hu(""),[Z,N]=hu(""),[E,q]=hu(""),[Y,w]=hu(""),[B,P]=hu(""),[h,M]=hu(!1),[n,S]=hu(""),[T,i]=hu(null),C=FH(r),v=UH(Array.isArray(U?.todos)?U.todos:[]),X=_?ZS(_):{},D=_?HS(_):{},p=_?ES(_):{};async function m(k=A){let[Af,Yf]=await Promise.all([Mf(`${l}/microservices/todo-note/health`),Mf(l3(l,"/api/instances"))]);$(Af),j(Yf);let Bf=FH(Yf),df=Bf.some((_0)=>_0.id===k)?k:Bf[0]?.id||"";return J(df),df}async function s(k=A){if(!k){Q(null);return}let Af=await Mf(l3(l,`/api/instances/${encodeURIComponent(k)}`));Q(Af)}async function d(k=A){if(!_)return;M(!0),S("");try{let Af=await m(k);await s(Af),i(new Date)}catch(Af){S(Df(Af,"Todo Note 加载失败"))}finally{M(!1)}}async function a(k){if(!A)return null;S("");try{let Af=await Mf(l3(l,`/api/instances/${encodeURIComponent(A)}/actions`),{method:"POST",body:JSON.stringify({action:k})});return Q(Af),await m(A),Af}catch(Af){return S(Df(Af,"Todo 操作失败")),null}}async function I(k){k.preventDefault();let Af=O.trim();if(!Af)return;M(!0),S("");try{let Yf=await Mf(l3(l,"/api/instances"),{method:"POST",body:JSON.stringify({name:Af})});z(""),await d(Yf.id)}catch(Yf){S(Df(Yf,"创建清单失败"))}finally{M(!1)}}async function ff(k){if(!window.confirm("确认删除这个 Todo Note 清单?"))return;M(!0),S("");try{await Mf(l3(l,`/api/instances/${encodeURIComponent(k)}`),{method:"DELETE"}),await d(A===k?"":A)}catch(Af){S(Df(Af,"删除清单失败"))}finally{M(!1)}}async function yf(k){k.preventDefault();let Af=Z.trim();if(!Af)return;N(""),await a({type:"addTodo",title:Af})}async function rf(k){if(!A)return;S("");try{let Af=await Mf(l3(l,`/api/instances/${encodeURIComponent(A)}/${k}`),{method:"POST",body:JSON.stringify({})});Q(Af),await m(A)}catch(Af){S(Df(Af,`${k} 失败`))}}function Wf(k){q(k.id),w(String(k.title||""))}async function Ef(k){let Af=Y.trim();if(q(""),w(""),Af)await a({type:"updateTodoTitle",todoId:k,title:Af})}async function Gf(k){let Yf=window.prompt("新增子任务标题")?.trim();if(!Yf)return;let Bf=YJ(Array.isArray(U?.todos)?U.todos:[],k),df=new Set(Bf.map((a0)=>a0.id)),_0=await a({type:"addTodo",title:Yf,parentId:k,targetIndex:0});if(!_0)return;let y0=YJ(Array.isArray(_0?.todos)?_0.todos:[],k),N0=y0.find((a0)=>!df.has(a0.id));if(N0&&y0[0]?.id!==N0.id)await a({type:"moveTodo",todoId:N0.id,targetParentId:k,targetIndex:0})}async function c(k,Af){if(!B)return;let Yf={type:"moveTodo",todoId:B,targetIndex:Af};if(k)Yf.targetParentId=k;P(""),await a(Yf)}if(KS(()=>{d()},[_?.id,_?.runtime?.providerStatus]),!_)return Jf(Qr,{title:"Todo Note 未登记",text:"请在 config.json 的 microservices 中登记用户服务 id=todo-note"});let o=C.find((k)=>k.id===A)||null,e=Array.isArray(U?.todos)?U.todos:[],Kf=e.map((k,Af)=>({todo:k,index:Af})).filter((k)=>wJ(k.todo,W));return Jf("div",{className:"todo-note-page","data-testid":"todo-note-page"},Jf(BJ,{title:"Todo Note 工作台",eyebrow:"Main Server 用户服务",loading:h,actions:Jf("div",{className:"panel-actions"},Jf("button",{type:"button",className:"ghost-btn",disabled:h,onClick:()=>d(A),"data-testid":"todo-note-refresh-button"},h?"刷新中":"刷新"),Jf(AH,{title:"Todo Note 用户服务",data:_,onOpen:u,testId:"raw-todo-note-service"}))},Jf("div",{className:"todo-note-hero"},Jf("div",null,Jf("div",{className:"node-version-line"},Jf(NS,{status:X.providerStatus==="online"?"online":"warn"},X.providerStatus||"unknown"),Jf("span",null,_.providerId),Jf("span",null,p.public?"公网暴露":"仅 UniDesk frontend 代理访问"),Jf("span",null,y?.ok?"Health OK":"Health --")),Jf("p",{className:"muted paragraph"},_.description)),Jf("div",{className:"microservice-ref-card"},Jf("span",null,"Repo"),Jf("strong",null,D.url||"--"),Jf("code",null,D.commitId||"--")),Jf("div",{className:"microservice-ref-card"},Jf("span",null,"Main Server Docker"),Jf("strong",null,`${p.nodeBindHost||"--"}:${p.nodePort||"--"}`),Jf("code",null,`${D.composeService||"--"} / ${D.containerName||"--"}`))),Jf(A0,{error:n,wide:!0})),Jf("div",{className:"todo-note-layout"},Jf(BJ,{title:"清单",eyebrow:`${C.length} Instances`,className:"todo-list-panel",loading:h},Jf("form",{className:"todo-create-list",onSubmit:I},Jf("input",{placeholder:"新清单名称",value:O,onChange:(k)=>z(k.target.value),"aria-label":"新清单名称"}),Jf("button",{type:"submit",className:"ghost-btn",disabled:h||!O.trim()},"创建")),C.length===0?Jf(Qr,{title:"暂无清单",text:"迁移或创建清单后会出现在这里"}):Jf("div",{className:"todo-instance-list"},C.map((k)=>Jf("button",{key:k.id,type:"button",className:`todo-instance-row ${A===k.id?"active":""}`,onClick:()=>{J(k.id),s(k.id)},"data-testid":`todo-instance-${JH(k.id)}`},Jf("strong",null,k.name),Jf("span",null,`${k.completedCount??0}/${k.todoCount??0} 完成`),Jf("code",null,k.id))))),Jf("div",{className:"todo-main-stack"},Jf(BJ,{title:o?.name||"待选择清单",eyebrow:T?`Updated ${W0(T)}`:"Todo Tree",loading:h,actions:U?Jf("div",{className:"panel-actions"},Jf("button",{type:"button",className:"ghost-btn",onClick:()=>a({type:"renameInstance",name:window.prompt("清单新名称",U.name)||U.name})},"重命名"),Jf("button",{type:"button",className:"ghost-btn danger",onClick:()=>ff(A)},"删除清单"),Jf(AH,{title:`Todo Instance ${A}`,data:U,onOpen:u,testId:"raw-todo-instance"})):null},!U?Jf(Qr,{title:"未选择清单",text:"左侧选择一个 Todo Note 清单"}):Jf("div",{className:"todo-workbench",style:{"--todo-font-size":`${K}px`}},Jf("div",{className:"todo-toolbar"},Jf("form",{className:"todo-add-form",onSubmit:yf},Jf("input",{placeholder:"新增根任务",value:Z,onChange:(k)=>N(k.target.value),"aria-label":"新增根任务"}),Jf("button",{type:"submit",className:"ghost-btn",disabled:!Z.trim()},"新增")),Jf("div",{className:"todo-filter-strip"},["all","active","completed"].map((k)=>Jf("button",{key:k,type:"button",className:`todo-filter ${W===k?"active":""}`,onClick:()=>G(k)},k==="all"?"全部":k==="active"?"未完成":"已完成"))),Jf("div",{className:"todo-toolbar-actions"},Jf("button",{type:"button",className:"ghost-btn",onClick:()=>a({type:"setAllTodosExpanded",expanded:!0})},"全部展开"),Jf("button",{type:"button",className:"ghost-btn",onClick:()=>a({type:"setAllTodosExpanded",expanded:!1})},"全部收起"),Jf("button",{type:"button",className:"ghost-btn",onClick:()=>rf("undo")},"撤销"),Jf("button",{type:"button",className:"ghost-btn",onClick:()=>rf("redo")},"重做"),Jf("label",{className:"todo-font-control"},"字号",Jf("input",{type:"range",min:11,max:18,value:K,onChange:(k)=>H(Number(k.target.value))})))),Jf("div",{className:"todo-stats-grid"},Jf(Ur,{label:"总任务",value:v.total,hint:`${C.length} lists`}),Jf(Ur,{label:"已完成",value:v.completed,hint:`${OS(v.total?v.completed/v.total*100:0)}`,tone:"ok"}),Jf(Ur,{label:"未完成",value:v.active,hint:W==="active"?"当前筛选":"active tasks",tone:v.active>0?"warn":"ok"}),Jf(Ur,{label:"历史指针",value:U.historyPointer??0,hint:"undo / redo"})),Jf("div",{className:"todo-root-drop",onDragOver:(k)=>k.preventDefault(),onDrop:(k)=>{k.preventDefault(),c(null,e.length)}},"拖到这里可移为根任务末尾"),Jf("div",{className:"todo-tree","data-testid":"todo-note-tree"},Kf.length===0?Jf(Qr,{title:"没有匹配任务",text:"调整筛选或新增任务"}):Kf.map(({todo:k,index:Af})=>Jf(WH,{key:k.id,todo:k,depth:0,parentId:null,index:Af,siblingCount:e.length,filter:W,editingId:E,editingTitle:Y,setEditingTitle:w,beginEdit:Wf,saveEdit:Ef,applyTodoAction:a,addChild:Gf,dragTodoId:B,setDragTodoId:P,dropTodo:c}))))))))}function WH(f){let{todo:u,depth:l,parentId:_,index:y,siblingCount:$,filter:r,editingId:j,editingTitle:A,setEditingTitle:J,beginEdit:U,saveEdit:Q,applyTodoAction:W,addChild:G,dragTodoId:K,setDragTodoId:H,dropTodo:O}=f,z=Array.isArray(u.children)?u.children:[],Z=z.map((q,Y)=>({child:q,childIndex:Y})).filter((q)=>wJ(q.child,r)),N=j===u.id,E=_||null;return Jf("div",{className:"todo-row-wrap"},Jf("article",{className:`todo-row ${u.completed?"completed":""} ${K===u.id?"dragging":""}`,style:{"--todo-depth":l},draggable:!0,onDragStart:(q)=>{H(u.id),q.dataTransfer.effectAllowed="move"},onDragOver:(q)=>q.preventDefault(),onDrop:(q)=>{q.preventDefault(),O(u.id,z.length)},"data-testid":`todo-row-${JH(u.id)}`},Jf("button",{type:"button",className:"todo-expand",disabled:z.length===0,onClick:()=>W({type:"toggleTodoExpanded",todoId:u.id})},z.length===0?"·":u.expanded?"▾":"▸"),Jf("input",{type:"checkbox",checked:Boolean(u.completed),onChange:()=>W({type:"toggleTodoCompleted",todoId:u.id}),"aria-label":`完成 ${u.title}`}),Jf("div",{className:"todo-title-cell",onDoubleClick:()=>U(u)},N?Jf("div",{className:"todo-edit-inline"},Jf("input",{value:A,autoFocus:!0,onChange:(q)=>J(q.target.value),onKeyDown:(q)=>{if(q.key==="Enter")Q(u.id);if(q.key==="Escape")U({id:"",title:""})}}),Jf("button",{type:"button",className:"ghost-btn",onClick:()=>Q(u.id)},"保存")):Jf("strong",null,u.title||"Untitled"),Jf("div",{className:"todo-meta-line"},Jf("span",null,`子项 ${z.length}`),Jf("span",null,`更新 ${Nf(u.updatedAt)}`),u.reminderAt?Jf("span",{className:"todo-reminder"},`提醒 ${Nf(u.reminderAt)}`):Jf("span",null,"无提醒"))),Jf("input",{className:"todo-reminder-input",type:"datetime-local",value:ir(u.reminderAt),onChange:(q)=>W({type:"setTodoReminder",todoId:u.id,reminderAt:QU(q.target.value)})}),Jf("div",{className:"todo-row-actions"},Jf("button",{type:"button",className:"ghost-btn",onClick:()=>U(u)},"编辑"),Jf("button",{type:"button",className:"ghost-btn",onClick:()=>G(u.id)},"子项"),Jf("button",{type:"button",className:"ghost-btn",disabled:y<=0,onClick:()=>W({type:"moveTodo",todoId:u.id,...E?{targetParentId:E}:{},targetIndex:y-1})},"上移"),Jf("button",{type:"button",className:"ghost-btn",disabled:y<=0,onClick:()=>W({type:"moveTodo",todoId:u.id,...E?{targetParentId:E}:{},targetIndex:0})},"置顶"),Jf("button",{type:"button",className:"ghost-btn",disabled:y>=$-1,onClick:()=>W({type:"moveTodo",todoId:u.id,...E?{targetParentId:E}:{},targetIndex:y+1})},"下移"),Jf("button",{type:"button",className:"ghost-btn",disabled:!_,onClick:()=>W({type:"moveTodo",todoId:u.id,targetIndex:9999})},"提升"),Jf("button",{type:"button",className:"ghost-btn danger",onClick:()=>W({type:"deleteTodo",todoId:u.id})},"删除"))),u.expanded&&Z.length>0?Jf("div",{className:"todo-children"},Z.map(({child:q,childIndex:Y})=>Jf(WH,{key:q.id,todo:q,depth:l+1,parentId:u.id,index:Y,siblingCount:z.length,filter:r,editingId:j,editingTitle:A,setEditingTitle:J,beginEdit:U,saveEdit:Q,applyTodoAction:W,addChild:G,dragTodoId:K,setDragTodoId:H,dropTodo:O}))):null)}var zH=cf(O0(),1),S_=zH.default.createElement;function GH({title:f,items:u,actions:l,className:_,testId:y}){let $=Array.isArray(u)?u:[];return S_("section",{className:`top-status-bar ${_||""}`,"data-testid":y},S_("div",{className:"top-status-main"},f?S_("strong",{className:"top-status-title"},f):null,S_("div",{className:"top-status-chips"},$.map((r,j)=>S_("span",{key:r?.key||`${r?.label||"status"}-${j}`,className:`top-status-chip ${r?.tone||""}`,"data-testid":r?.testId},r?.label?S_("b",null,r.label):null,S_("span",null,r?.value??"--"))))),l?S_("div",{className:"top-status-actions"},l):null)}var q4=cf(O0(),1);var x0=q4.default.createElement;function KH({onClose:f}){let{notifications:u,removeNotification:l,clearNotifications:_}=Lu(),y=q4.default.useRef(null);if(q4.default.useEffect(()=>{let $=(r)=>{if(y.current&&!y.current.contains(r.target))f()};return document.addEventListener("mousedown",$),()=>document.removeEventListener("mousedown",$)},[f]),u.length===0)return x0("div",{className:"notification-popup",ref:y},x0("div",{className:"notification-popup-header"},x0("span",null,"通知"),x0("button",{className:"notification-popup-close",onClick:f},"×")),x0("div",{className:"notification-popup-empty"},"暂无通知"));return x0("div",{className:"notification-popup",ref:y},x0("div",{className:"notification-popup-header"},x0("span",null,`通知 (${u.length})`),x0("div",{className:"notification-popup-actions"},x0("button",{className:"notification-popup-clear",onClick:_},"清空"),x0("button",{className:"notification-popup-close",onClick:f},"×"))),x0("div",{className:"notification-popup-list"},u.slice().reverse().map(($)=>x0("div",{key:$.id,className:`notification-item ${$.type}`},x0("span",{className:"notification-item-icon"},$.type==="success"?"✓":"×"),x0("span",{className:"notification-item-message"},$.message),x0("button",{className:"notification-item-dismiss",onClick:()=>l($.id)},"×")))))}function NH({notification:f}){let{removeNotification:u}=Lu();return q4.default.useEffect(()=>{let l=setTimeout(()=>{u(f.id)},3000);return()=>clearTimeout(l)},[f.id,u]),x0("div",{className:`notification-banner ${f.type}`,role:"alert"},x0("span",{className:"notification-banner-icon"},f.type==="success"?"✓":"×"),x0("span",{className:"notification-banner-message"},f.message),x0("button",{className:"notification-banner-dismiss",onClick:()=>u(f.id)},"×"))}function DH(f,u){let l=document.getElementById("root")?.getAttribute(f);if(!l)return u;try{let _=JSON.parse(l);return typeof _==="object"&&_!==null&&!Array.isArray(_)?_:u}catch{return u}}var mf=DH("data-config",{apiBaseUrl:"/api",authUsername:"admin"}),VS=DH("data-codex-overview",null),F=i_.default.createElement,{useEffect:J1,useMemo:B4}=i_.default,bf=i_.default.useState,PJ=i_.default.createContext(!1),Xl=WK(p2),qS={id:"code-queue",name:"Code Queue",providerId:"main-server",description:"Code Queue",repository:{containerName:"code-queue-backend"},backend:{nodeBaseUrl:"http://code-queue:4222",nodeBindHost:"code-queue",nodePort:4222,public:!1},runtime:{providerStatus:"loading",providerName:"main-server"}};function ZH(){return typeof document>"u"||document.visibilityState!=="hidden"}function LS(f,u){if(f==="ops"&&u==="status")return 5000;if(f==="nodes"&&u==="monitor")return 5000;if(f==="tasks"&&(u==="dispatch"||u==="scheduled"||u==="pending"))return 5000;if(f==="nodes"||f==="ops")return 1e4;if(f==="apps")return 15000;if(f==="tasks")return 15000;return 30000}async function XS(f){if(!f?._summaryOnly||!f?.id)return f;return(await Mf(`${mf.apiBaseUrl}/tasks/${encodeURIComponent(String(f.id))}`))?.task||f}function Y4(f){return f?._summaryOnly?{...f,_loadRaw:()=>XS(f)}:f}function x1(f){if(!Number.isFinite(f))return"--";let u=Math.max(0,f);if(u===0)return"0s";if(u<0.01)return"<0.01s";if(u<0.1)return`${u.toFixed(2)}s`;if(u<1)return`${u.toFixed(1)}s`;if(u<10&&!Number.isInteger(u))return`${u.toFixed(1)}s`;if(u<60)return`${Math.round(u)}s`;let l=Math.floor(u);if(l<3600)return`${Math.floor(l/60)}m ${l%60}s`;return`${Math.floor(l/3600)}h ${Math.floor(l%3600/60)}m`}function Al(f){let u=Number(f);if(!Number.isFinite(u))return"--";if(u<1)return`${Math.max(0,u).toFixed(1)}ms`;if(u<10)return`${u.toFixed(1)}ms`;if(u<1000)return`${Math.round(u)}ms`;return x1(u/1000)}function Ku(f){let u=Number(f);if(!Number.isFinite(u)||u<=0)return"--";let l=["B","KB","MB","GB","TB"],_=u,y=0;while(_>=1024&&y0)return l[_]}return"任务失败但 provider 未返回明确原因"}function Py(f){if(f===null||f===void 0)return"--";if(typeof f==="boolean")return f?"是":"否";if(typeof f==="number")return String(f);if(typeof f==="string")return f.length>80?`${f.slice(0,77)}...`:f;if(Array.isArray(f))return`${f.length} 项`;if(typeof f==="object")return`${Object.keys(f).length} 字段`;return String(f)}function YS(f,u){let l=f.replace(/[-_\s]/g,"").toLowerCase(),_=l==="ts"||l.endsWith("at")||l.endsWith("timestamp")||l.endsWith("heartbeat");if((typeof u==="string"||typeof u==="number")&&_){let y=Nf(u);if(y!=="--")return y}if(f==="bodyText"&&typeof u==="string")return`${/^\s*[{[]/.test(u)?"JSON":"HTTP"} body ${u.length} chars`;return Py(u)}function PH(f){if(!f||typeof f!=="object"||Array.isArray(f))return[];return Object.entries(f)}function Iu(f){return String(f).replace(/[^a-zA-Z0-9_-]/g,"_")}function SJ(f,u){return f&&typeof f==="object"&&!Array.isArray(f)?f[u]:void 0}function Gr(f,u,l="未知"){let _=SJ(f?.labels,u);return typeof _==="string"&&_.length>0?_:l}function nH(f){return Gr(f,"providerGatewayVersion")}function X4(f){return Gr(f,"providerGatewayUpgradePolicy")}function EH(f){return Gr(f,"providerGatewayStartedAt","")}function SH(f){let u=SJ(f?.labels,"unideskCapabilities");if(typeof u==="string")return u.split(",").map((l)=>l.trim()).filter(Boolean);return Array.isArray(u)?u.filter((l)=>typeof l==="string"):[]}function CH(f,u){return SH(f).includes(u)}function HH(f,u){let l=SJ(f?.labels,u);return l===!0||l==="true"||l==="1"}function wS(f){if(!CH(f,"host.ssh"))return{tone:"fail",label:"不可用",detail:"未声明 host.ssh"};if(!HH(f,"hostSshConfigured"))return{tone:"warn",label:"未配置",detail:"缺少 SSH 环境变量"};if(!HH(f,"hostSshKeyPresent"))return{tone:"warn",label:"缺 key",detail:"私钥未挂载"};return{tone:"ok",label:"可用",detail:Gr(f,"hostSshTarget","host.ssh ready")}}function DS(f){if(!CH(f,"provider.upgrade"))return{tone:"fail",label:"不可用",detail:"未声明 provider.upgrade"};let u=X4(f);if(u!=="always-enabled")return{tone:"warn",label:"待确认",detail:`策略 ${u}`};return{tone:"ok",label:"可用",detail:"always-enabled"}}function CJ(f){let u=typeof f==="string"&&f.length>0?f:"未知";if(u==="未知")return"版本未知";return u.startsWith("v")?u:`v${u}`}function iH(f){return f?.payload&&typeof f.payload==="object"&&!Array.isArray(f.payload)?f.payload:{}}function Kr(f){return f?.result&&typeof f.result==="object"&&!Array.isArray(f.result)?f.result:{}}function zr(f){let u=iH(f),l=Kr(f);return(u.mode??l.mode)==="schedule"?"schedule":"plan"}function TS(f){let u=iH(f).source;return typeof u==="string"&&u.length>0?u:"unknown"}function MS(f){let u=Kr(f),l=u.plan&&typeof u.plan==="object"&&!Array.isArray(u.plan)?u.plan:{},_=u.policy??l.policy;return typeof _==="string"&&_.length>0?_:"--"}function cH(f){let u=Kr(f),l=u.plan&&typeof u.plan==="object"&&!Array.isArray(u.plan)?u.plan:{},_=u.targetProviderGatewayVersion??u.providerGatewayVersion??l.targetProviderGatewayVersion??l.providerGatewayVersion;return typeof _==="string"&&_.length>0?CJ(_):"版本未知"}function RH(f){if(String(f?.status||"").toLowerCase()==="failed")return MH(f);if(y3(f))return"等待 provider 回传升级终态";let l=Kr(f);if(typeof l.updaterContainerId==="string"&&l.updaterContainerId.length>0)return`updater ${l.updaterContainerId.slice(0,18)}`;if(typeof l.message==="string"&&l.message.length>0)return l.message;if(l.plan)return"升级计划已生成";return"无升级结果摘要"}function xH(f,u){return f.filter((l)=>l?.providerId===u&&l?.command==="provider.upgrade").sort((l,_)=>(U1(_.updatedAt)??0)-(U1(l.updatedAt)??0))}function PS(f){return f.find((u)=>zr(u)==="schedule")||f[0]||null}function bH(f){return f?.runtime&&typeof f.runtime==="object"&&!Array.isArray(f.runtime)?f.runtime:{}}function OH(f){return f?.backend&&typeof f.backend==="object"&&!Array.isArray(f.backend)?f.backend:{}}function nS(f){return f?.repository&&typeof f.repository==="object"&&!Array.isArray(f.repository)?f.repository:{}}function K0({status:f,children:u}){let l=String(f||"unknown").toLowerCase();return F("span",{className:`status-badge ${l}`},u||f||"unknown")}function F0({label:f,value:u,hint:l,tone:_,onClick:y,testId:$}){let r=typeof y==="function";return F("article",{className:`metric-card ${_||""} ${r?"clickable":""}`,role:r?"button":void 0,tabIndex:r?0:void 0,"data-testid":$,onClick:y,onKeyDown:r?(j)=>{if(j.key==="Enter"||j.key===" ")j.preventDefault(),y()}:void 0},F("div",{className:"metric-label"},f),F("div",{className:"metric-value"},u),F("div",{className:"metric-hint"},l))}function sf({title:f,eyebrow:u,actions:l,children:_,className:y,loading:$}){let r=i_.default.useContext(PJ),j=Boolean($)||r;return F("section",{className:`panel ${y||""}`},F("div",{className:"panel-head"},F("div",null,u?F("p",{className:"panel-eyebrow"},u):null,F(j0,{title:f,loading:j})),l?F("div",{className:"panel-actions"},l):null),F("div",{className:"panel-body"},_))}function b0({title:f,data:u,onOpen:l,testId:_}){let[y,$]=bf(!1),r=u&&typeof u==="object"&&typeof u._loadRaw==="function"?u._loadRaw:null;async function j(){if(!r){l(f,u);return}$(!0);try{l(f,await r())}catch(A){l(f,{ok:!1,error:Df(A,"读取原始 JSON 失败"),fallback:u})}finally{$(!1)}}return F("button",{type:"button",className:"ghost-btn","data-testid":_,disabled:y,onClick:()=>void j()},y?"读取中":"查看原始JSON")}function SS({raw:f,onClose:u}){if(!f)return null;return F("div",{className:"modal-backdrop",role:"presentation"},F("section",{className:"raw-dialog",role:"dialog","aria-modal":"true","aria-label":f.title},F("div",{className:"raw-dialog-head"},F("h2",null,f.title),F("button",{type:"button",className:"ghost-btn",onClick:u},"关闭")),F("pre",{className:"raw-json","data-testid":"raw-json"},JSON.stringify(f.data,null,2))))}function vH({labels:f,limit:u=8}){let l=PH(f).slice(0,u);if(l.length===0)return F("span",{className:"muted"},"无标签");return F("div",{className:"chip-row"},l.map(([_,y])=>F("span",{key:_,className:"data-chip"},F("b",null,_),F("span",null,Py(y)))))}function _3({node:f}){let u=nH(f);return F("span",{className:`version-chip ${u==="未知"?"unknown":""}`,"data-testid":`gateway-version-${Iu(f?.providerId||"unknown")}`},CJ(u))}function VH({title:f,state:u,testId:l}){return F("span",{className:`capability-badge ${u.tone}`,title:u.detail,"data-testid":l},F("b",null,f),F("strong",null,u.label),F("small",null,u.detail))}function iJ({node:f}){let u=Iu(f?.providerId||"unknown");return F("div",{className:"node-availability-strip"},F(VH,{title:"SSH 透传",state:wS(f),testId:`ssh-availability-${u}`}),F(VH,{title:"远程更新",state:DS(f),testId:`upgrade-availability-${u}`}))}function c_({data:f,empty:u="无数据"}){if(f===null||f===void 0)return F("span",{className:"muted"},u);if(typeof f!=="object")return F("span",{className:"summary-value"},Py(f));if(Array.isArray(f))return F("span",{className:"summary-value"},`${f.length} 项列表`);let l=Object.entries(f).slice(0,5);if(l.length===0)return F("span",{className:"muted"},u);return F("div",{className:"summary-grid"},l.map(([_,y])=>F("span",{key:_,className:"summary-item"},F("b",null,_),F("span",null,YS(_,y)))))}function J0({title:f,text:u}){return F("div",{className:"empty-state"},F("strong",null,f),F("span",null,u))}function CS({onLogin:f}){let[u,l]=bf(mf.authUsername||"admin"),[_,y]=bf(""),[$,r]=bf(""),[j,A]=bf(!1);async function J(U){U.preventDefault(),A(!0),r("");try{let Q=await Mf("/login",{method:"POST",body:JSON.stringify({username:u,password:_})});f(Q)}catch(Q){r(Df(Q,"登录失败"))}finally{A(!1)}}return F("main",{className:"login-screen","data-testid":"login-screen"},F("section",{className:"login-card"},F("div",{className:"login-brand"},F("span",{className:"brand-mark"},"UD"),F("div",null,F("h1",null,"UniDesk"),F("p",null,"Control Plane Login"))),F("form",{className:"login-form",onSubmit:J},F("label",null,"账号",F("input",{name:"username",autoComplete:"username",value:u,onChange:(U)=>l(U.target.value)})),F("label",null,"密码",F("input",{name:"password",type:"password",autoComplete:"current-password",value:_,onChange:(U)=>y(U.target.value)})),F(A0,{error:$}),F("button",{type:"submit",disabled:j},j?"登录中":"登录")),F("div",{className:"login-note"},"默认账号由 config.json 注入;公网入口只暴露前端登录面。")))}function iS({connection:f,lastRefresh:u,onRefresh:l,onLogout:_,session:y,clock:$,activeStatusItems:r=[],onNotificationToggle:j,unreadCount:A=0}){let J=[{key:"core",label:"核心",value:f.text,tone:f.ok?"ok":"fail",testId:"conn-text"},...Array.isArray(r)?r:[],{key:"refresh",label:"刷新",value:u?W0(u):"未刷新"},{key:"clock",label:g4,value:W0($)},{key:"user",label:"用户",value:y?.user?.username||"--",tone:"user"}];return F("header",{className:"topbar"},F("div",null,F("p",{className:"eyebrow"},"Distributed Work Platform"),F("h1",null,"UniDesk 控制平面")),F(GH,{className:"global-top-status",title:"状态",items:J,actions:[F("button",{key:"notification",type:"button",className:`notification-icon-btn ${A>0?"has-unread":""}`,onClick:j,"aria-label":"通知"},"\uD83D\uDD14",A>0?F("span",{key:"badge",className:"notification-badge"},A>99?"99+":A):null),F("button",{key:"refresh",type:"button",className:"ghost-btn",onClick:l},"刷新"),F("button",{key:"logout",type:"button",className:"ghost-btn danger",onClick:_},"退出")]}))}function cS(f){return!f.defaultPrevented&&f.button===0&&!f.metaKey&&!f.altKey&&!f.ctrlKey&&!f.shiftKey&&f.currentTarget.target!=="_blank"}function hH({moduleId:f,tabId:u,className:l,active:_=!1,title:y,testId:$,onNavigate:r,children:j}){let A=m2(Xl,f,u);return F("a",{href:A,role:"button",className:l,title:y,"aria-current":_?"page":void 0,"data-testid":$,"data-route":A,onClick:(J)=>{if(!cS(J))return;J.preventDefault(),r(f,u)}},j)}function RS({activeModule:f,activeTabs:u,onNavigate:l,collapsed:_,onToggle:y}){return F("aside",{className:`rail ${_?"collapsed":""}`,"aria-label":"主模块"},F("div",{className:"brand"},F("span",{className:"brand-mark"},"UD"),F("span",{className:"brand-text"},"UniDesk"),F("button",{type:"button",className:"rail-toggle",onClick:y,"aria-label":_?"展开左侧边栏":"收起左侧边栏","data-testid":"rail-toggle"},_?"»":"«")),p2.map(($)=>{let r=u[$.id]||n6[$.id]||$.tabs[0]?.id||"";return F(hH,{key:$.id,moduleId:$.id,tabId:r,className:`module ${f===$.id?"active":""}`,active:f===$.id,title:$.label,onNavigate:l},F("span",{className:"module-code"},$.code),F("span",null,$.label))}))}function xS({module:f,activeTab:u,onNavigate:l}){return F("nav",{className:"tabs","aria-label":`${f.label} 子功能`},f.tabs.map((_)=>F(hH,{key:_.id,moduleId:f.id,tabId:_.id,className:`tab ${u===_.id?"active":""}`,active:u===_.id,onNavigate:l},_.label)))}function bS({data:f,onRaw:u,onNavigate:l}){let _=f.overview||{},y=f.nodes.filter((J)=>J.status==="online"),$=f.pendingTasks||f.tasks.filter(y3),r=_.pendingTaskCount??$.length,j=f.tasks.slice(0,5),A=_.pgdata||{};return F("div",{className:"page-grid overview-grid","data-testid":"overview-page"},F(sf,{title:"核心指标",eyebrow:"Control"},F("div",{className:"metric-grid"},F(F0,{label:"数据库",value:_.dbReady?"READY":"WAIT",hint:"PostgreSQL internal network",tone:_.dbReady?"ok":"warn"}),F(F0,{label:"PGDATA",value:Ku(A.databaseBytes),hint:`${A.volumeName||"unidesk_pgdata_10gb"} / ${A.databasePretty||"--"}`,tone:"ok",testId:"pgdata-usage-card"}),F(F0,{label:"在线节点",value:_.onlineNodeCount??0,hint:`${_.nodeCount??0} registered`,tone:"ok"}),F(F0,{label:"WebSocket",value:_.activeSocketCount??0,hint:"Provider ingress sockets"}),F(F0,{label:"待处理任务",value:r,hint:r>0?"点击查看具体任务":`timeout ${x1(Math.floor((_.taskPendingTimeoutMs??0)/1000))}`,tone:r>0?"warn":"ok",onClick:()=>l("tasks","pending"),testId:"pending-task-card"}))),F(sf,{title:"本机 Provider",eyebrow:"Self Connected"},y.length===0?F(J0,{title:"暂无在线节点",text:"provider-gateway 未完成自接入"}):F("div",{className:"node-card-list"},y.slice(0,4).map((J)=>F(vS,{key:J.providerId,node:J,onRaw:u})))),F(sf,{title:"待处理任务明细",eyebrow:`${r} Pending`,actions:F("button",{type:"button",className:"ghost-btn",onClick:()=>l("tasks","pending"),"data-testid":"pending-task-detail-link"},"进入任务调度")},$.length===0?F(J0,{title:"当前无待处理",text:"queued / dispatched / running 超时后会自动转为 failed,避免总览长期卡住"}):F("div",{className:"compact-list"},$.slice(0,5).map((J)=>F(BH,{key:J.id,task:J,onRaw:u})))),F(sf,{title:"最近任务",eyebrow:"Dispatch"},j.length===0?F(J0,{title:"暂无任务",text:"可以在任务调度模块发起 docker.ps 或 echo"}):F("div",{className:"compact-list"},j.map((J)=>F(BH,{key:J.id,task:J,onRaw:u})))))}function vS({node:f,onRaw:u}){return F("article",{className:"node-card"},F("div",{className:"node-card-head"},F("div",null,F("strong",null,f.name),F("code",null,f.providerId)),F(K0,{status:f.status})),F("div",{className:"node-version-line"},F(_3,{node:f}),F("span",null,`升级策略 ${X4(f)}`)),F(iJ,{node:f}),F(vH,{labels:f.labels,limit:6}),F("div",{className:"node-card-foot"},F("span",null,`心跳 ${Nf(f.lastHeartbeat)}`),F(b0,{title:`Provider ${f.providerId}`,data:f,onOpen:u,testId:`raw-node-${Iu(f.providerId)}`})))}function hS({events:f,onRaw:u}){return F(sf,{title:"事件摘要",eyebrow:"Latest 100"},f.length===0?F(J0,{title:"暂无事件",text:"Provider 注册、心跳超时和任务状态会写入事件流"}):F("div",{className:"table-wrap"},F("table",null,F("thead",null,F("tr",null,F("th",null,"ID"),F("th",null,"类型"),F("th",null,"来源"),F("th",null,"摘要"),F("th",null,"时间"),F("th",null,"操作"))),F("tbody",null,f.map((l)=>F("tr",{key:l.id},F("td",null,F("code",null,l.id)),F("td",null,F(K0,{status:l.type},l.type)),F("td",null,F("code",null,l.source)),F("td",null,F(c_,{data:l.payload})),F("td",null,Nf(l.createdAt)),F("td",null,F(b0,{title:`Event ${l.id}`,data:l,onOpen:u}))))))))}function IS({logs:f,onRaw:u}){return F(sf,{title:"服务日志",eyebrow:"Core Recent"},f.length===0?F(J0,{title:"暂无日志",text:"backend-core 内存日志会在请求和 provider 事件后出现"}):F("div",{className:"log-list"},f.slice(-80).reverse().map((l,_)=>F("article",{key:_,className:`log-row ${l.level||"info"}`},F("span",null,Nf(l.ts)),F("b",null,l.level||"info"),F("strong",null,l.message||"log"),F(c_,{data:l.data,empty:"无附加字段"}),F(b0,{title:`Log ${l.message||_}`,data:l,onOpen:u})))))}function pS({nodes:f,onRaw:u}){return F(sf,{title:"节点清单",eyebrow:`${f.length} Providers`},f.length===0?F(J0,{title:"暂无 Provider 节点",text:"确认 provider-gateway 已连接 provider ingress"}):F("div",{className:"table-wrap"},F("table",{className:"node-list-table"},F("thead",null,F("tr",null,F("th",null,"状态"),F("th",null,"Provider"),F("th",null,"网关版本"),F("th",null,"运维可用性"),F("th",null,"资源标签"),F("th",null,"连接时间"),F("th",null,"最后心跳"),F("th",null,"操作"))),F("tbody",null,f.map((l)=>F("tr",{key:l.providerId},F("td",null,F(K0,{status:l.status})),F("td",null,F("strong",null,l.name),F("code",null,l.providerId)),F("td",null,F("div",{className:"gateway-cell"},F(_3,{node:l}),F("span",null,X4(l)))),F("td",null,F(iJ,{node:l})),F("td",null,F(vH,{labels:l.labels,limit:5})),F("td",null,Nf(l.connectedAt)),F("td",null,Nf(l.lastHeartbeat)),F("td",null,F(b0,{title:`Provider ${l.providerId}`,data:l,onOpen:u,testId:`raw-node-table-${Iu(l.providerId)}`}))))))))}function mS({nodes:f}){let u=B4(()=>{let l=[];for(let _ of f)for(let[y,$]of PH(_.labels))l.push({providerId:_.providerId,name:_.name,key:y,value:$});return l},[f]);return F(sf,{title:"资源标签",eyebrow:"Structured Labels"},u.length===0?F(J0,{title:"暂无标签",text:"provider-gateway 注册消息会同步资源标签"}):F("div",{className:"label-matrix"},u.map((l)=>F("article",{key:`${l.providerId}-${l.key}`,className:"label-card"},F("span",null,l.key),F("strong",null,Py(l.value)),F("code",null,l.providerId)))))}function gS({nodes:f}){return F(sf,{title:"心跳状态",eyebrow:"Provider Liveness"},f.length===0?F(J0,{title:"无心跳",text:"等待 provider 注册和 heartbeat"}):F("div",{className:"heartbeat-list"},f.map((u)=>F("article",{key:u.providerId,className:"heartbeat-row"},F("span",{className:`pulse ${u.status}`}),F("div",null,F("strong",null,u.name),F("code",null,u.providerId)),F("div",null,F("span",null,"connected"),F("b",null,Nf(u.connectedAt))),F("div",null,F("span",null,"last heartbeat"),F("b",null,Nf(u.lastHeartbeat)))))))}function kS({nodes:f,systemStatuses:u,tasks:l,onRaw:_,refresh:y}){let[$,r]=bf(""),j=B4(()=>f.map((H)=>{let O=u.find((z)=>z.providerId===H.providerId);return{...H,systemCurrent:O?.current||null,systemHistory:O?.history||[],systemUpdatedAt:O?.updatedAt||null}}),[f,u]),A=j.find((H)=>H.providerId===$)||j[0]||null;if(J1(()=>{if(!$&&j[0])r(j[0].providerId)},[j.length,$]),!A)return F(J0,{title:"暂无资源监控",text:"等待 provider 上报 CPU、内存和硬盘指标"});let J=A.systemCurrent,U=A.systemHistory||[],Q=J?.cpu||{},W=J?.memory||{},G=J?.disk||{},K=U.length>0?U:J?[{at:J.collectedAt,cpuPercent:Rf(Q.percent),memoryPercent:Rf(W.percent),diskPercent:Rf(G.percent)}]:[];return F("div",{className:"monitor-page","data-testid":"node-monitor-page"},F("div",{className:"docker-node-strip"},j.map((H)=>F("button",{key:H.providerId,type:"button",className:`docker-node-tile ${A.providerId===H.providerId?"active":""}`,onClick:()=>r(H.providerId)},F("span",{className:`pulse ${H.status}`}),F("strong",null,H.name),F("code",null,H.providerId),F("span",null,H.systemCurrent?`CPU ${C_(H.systemCurrent.cpu?.percent)} / MEM ${C_(H.systemCurrent.memory?.percent)}`:"等待指标")))),F("div",{className:"monitor-layout"},F(sf,{title:"任务管理器视图",eyebrow:A.name,className:"monitor-main-panel",actions:J?F(b0,{title:`System ${A.providerId}`,data:{current:J,history:U},onOpen:_}):null},!J?F(J0,{title:"系统指标未上报",text:"provider-gateway 会周期性采集 /proc 与 df,并保存历史曲线"}):F("div",null,F("div",{className:"monitor-hero"},F("div",null,F("p",{className:"panel-eyebrow"},"Node Performance"),F("h3",null,A.name),F("div",{className:"docker-meta"},F("span",null,`${Q.cores||0} CPU cores`),F("span",null,`load ${Rf(Q.load1).toFixed(2)} / ${Rf(Q.load5).toFixed(2)} / ${Rf(Q.load15).toFixed(2)}`),F("span",null,`memory actual ${Ku(W.usedBytes)} / ${Ku(W.totalBytes)}`),F("span",null,`disk ${Ku(G.usedBytes)} / ${Ku(G.totalBytes)}`))),F(K0,{status:J.ok?"online":"warn"},J.ok?"METRICS READY":"METRICS DEGRADED")),F("div",{className:"monitor-chart-grid"},F(TJ,{title:"CPU",metricKey:"cpuPercent",current:Q.percent,points:K,detail:`${Q.cores||0} cores / load ${Rf(Q.load1).toFixed(2)}`,tone:"cpu",testId:"metric-chart-cpu"}),F(TJ,{title:"Memory",metricKey:"memoryPercent",current:W.percent,points:K,detail:`${Ku(W.usedBytes)} actual / ${Ku(W.cacheBytes)} cache excluded`,tone:"memory",testId:"metric-chart-memory"}),F(TJ,{title:"Disk",metricKey:"diskPercent",current:G.percent,points:K,detail:`${G.path||"/"} mounted ${G.mount||"--"}`,tone:"disk",testId:"metric-chart-disk"})),F("div",{className:"monitor-summary-grid"},F(F0,{label:"CPU 当前",value:C_(Q.percent),hint:`history ${K.length} samples`,tone:"ok"}),F(F0,{label:"实际内存",value:Ku(W.usedBytes),hint:`${C_(W.percent)} 不含缓存`}),F(F0,{label:"硬盘已用",value:Ku(G.usedBytes),hint:C_(G.percent)}),F(F0,{label:"更新时间",value:Nf(A.systemUpdatedAt||J.collectedAt),hint:A.providerId})),F(tS,{current:J,onRaw:_}))),F("div",{className:"monitor-side-stack"},F(lC,{provider:A,refresh:y,onRaw:_}),F(_C,{provider:A,tasks:l,onRaw:_,limit:5}),F(sf,{title:"采样说明",eyebrow:"Retention"},F("div",{className:"monitor-note-list"},F("article",null,F("b",null,"CPU"),F("span",null,"从 /proc/stat 计算相邻采样差值,首个采样用 load/cores 近似")),F("article",null,F("b",null,"Memory"),F("span",null,"实际内存 = MemTotal - MemFree - Buffers - Cached - SReclaimable + Shmem,不把 page cache / buffer 计入占用")),F("article",null,F("b",null,"Disk"),F("span",null,"使用 df -PB1 对配置路径采样,默认监控根文件系统")),F("article",null,F("b",null,"Process"),F("span",null,"从 /proc/[pid] 采集进程 CPU、实际内存 RSS、线程数和磁盘 I/O 速率;表格默认按内存占用降序")))))))}function qH(f,u){if(u==="memory")return Rf(f.rssBytes);if(u==="cpu")return Rf(f.cpuPercent);if(u==="disk")return Rf(f.readBytesPerSecond)+Rf(f.writeBytesPerSecond);if(u==="pid")return Rf(f.pid);if(u==="threads")return Rf(f.threads);if(u==="runtime")return Rf(f.elapsedSeconds);if(u==="user")return String(f.user||"");return String(f.name||f.command||"")}function LH({value:f,label:u,tone:l}){let _=Math.max(1,Math.min(100,Rf(f)));return F("div",{className:`process-meter ${l||""}`},F("span",{style:{width:`${_}%`}}),F("b",null,u))}function tS({current:f,onRaw:u}){let[l,_]=bf({key:"memory",direction:"desc"}),y=i_.default.useContext(PJ),$=f?.processSummary&&typeof f.processSummary==="object"?f.processSummary:{},r=Array.isArray(f?.processes)?f.processes:[],j=B4(()=>{let J=l.direction==="asc"?1:-1;return[...r].sort((U,Q)=>{let W=qH(U,l.key),G=qH(Q,l.key);if(typeof W==="string"||typeof G==="string")return String(W).localeCompare(String(G),"zh-CN")*J;return(W-G)*J||Rf(U.pid)-Rf(Q.pid)})},[r,l.key,l.direction]),A=(J,U)=>{let Q=l.key===U,W=Q?l.direction==="asc"?"ascending":"descending":"none";return F("th",{"aria-sort":W},F("button",{type:"button",className:`process-sort-button ${Q?"active":""}`,"data-testid":`process-sort-${U}`,onClick:()=>_((G)=>({key:U,direction:G.key===U&&G.direction==="desc"?"asc":"desc"}))},J,F("span",null,Q?l.direction==="desc"?"↓":"↑":"↕")))};return F("section",{className:"process-resource-panel","data-testid":"process-resource-panel"},F("div",{className:"process-resource-head"},F("div",null,F("p",{className:"panel-eyebrow"},"Windows Resource Monitor Style"),F(j0,{title:"进程资源占用",level:3,loading:y})),F("div",{className:"process-resource-actions"},F("span",{className:"data-chip"},"默认按内存排序"),F("span",{className:"data-chip"},`${Rf($.visible,j.length)} / ${Rf($.total,j.length)} 进程`),F(b0,{title:"Process Resource Snapshot",data:{processSummary:$,processes:r},onOpen:u,testId:"raw-process-resources"}))),j.length===0?F(J0,{title:"暂无进程资源数据",text:"等待 provider-gateway 上报 /proc/[pid] 采样;旧版 provider 需要先升级到支持进程资源表的版本"}):F("div",{className:"process-table-wrap"},F("table",{className:"process-resource-table","data-testid":"process-resource-table"},F("thead",null,F("tr",null,A("进程","name"),A("PID","pid"),A("用户","user"),F("th",null,"状态"),A("CPU","cpu"),A("内存","memory"),F("th",null,"RSS"),A("磁盘 I/O","disk"),A("线程","threads"),A("运行时长","runtime"))),F("tbody",null,j.map((J)=>{let U=Rf(J.readBytesPerSecond)+Rf(J.writeBytesPerSecond);return F("tr",{key:`${J.pid}-${J.startedAt}`,"data-testid":`process-row-${Iu(J.pid)}`,"data-memory-bytes":String(Rf(J.rssBytes)),"data-cpu-percent":String(Rf(J.cpuPercent)),"data-disk-bps":String(U),"data-pid":String(Rf(J.pid))},F("td",null,F("div",{className:"process-name-cell"},F("strong",null,J.name||"--"),F("span",{className:"process-command"},J.command||"--"))),F("td",null,F("code",null,J.pid||"--")),F("td",null,J.user||`uid:${J.uid??"--"}`),F("td",null,F("span",{className:`process-state state-${Iu(J.state||"unknown")}`},J.state||"?")),F("td",null,F(LH,{value:J.cpuPercent,label:BS(J.cpuPercent),tone:"cpu"})),F("td",null,F(LH,{value:J.memoryPercent,label:C_(J.memoryPercent),tone:"memory"})),F("td",null,Ku(J.rssBytes)),F("td",null,F("div",{className:"process-io-cell"},F("strong",null,DJ(U)),F("span",null,`R ${DJ(J.readBytesPerSecond)} / W ${DJ(J.writeBytesPerSecond)}`))),F("td",null,J.threads||0),F("td",null,x1(Rf(J.elapsedSeconds))))})))))}function TJ({title:f,metricKey:u,current:l,points:_,detail:y,tone:$,testId:r}){let j=_.map((W)=>Math.max(0,Math.min(100,Rf(W[u])))),A=j.length>1?j:[j[0]||0,j[0]||0],J=A.length<=1?100:100/(A.length-1),U=A.map((W,G)=>`${(G*J).toFixed(2)},${(46-W*0.42).toFixed(2)}`).join(" "),Q=`0,48 ${U} 100,48`;return F("article",{className:`metric-chart ${$}`,"data-testid":r},F("div",{className:"metric-chart-head"},F("div",null,F("span",null,f),F("strong",null,C_(l))),F("code",null,`${_.length} pts`)),F("svg",{viewBox:"0 0 100 48",preserveAspectRatio:"none",role:"img","aria-label":`${f} usage curve`},F("polygon",{points:Q}),F("polyline",{points:U}),F("line",{x1:"0",x2:"100",y1:"24",y2:"24"})),F("div",{className:"metric-chart-foot"},F("span",null,"0%"),F("span",null,y),F("span",null,"100%")))}function b1(f){return Array.isArray(f)?f:[]}function sS(f){let u=b1(f?.core?.requests?.componentSummary);return[...b1(f?.frontend?.requests?.componentSummary),...u].sort((_,y)=>Rf(y.requestCount)-Rf(_.requestCount))}function oS(f){let u=b1(f?.core?.operations?.summary);return[...b1(f?.frontend?.operations?.summary),...u].sort((_,y)=>Rf(y.count)-Rf(_.count))}function aS(f){let u=b1(f?.core?.requests?.recentFailures).map((_)=>({source:"backend",..._}));return[...b1(f?.frontend?.requests?.recentFailures).map((_)=>({source:"frontend",..._})),...u].sort((_,y)=>(U1(y.at)??0)-(U1(_.at)??0)).slice(0,20)}function dS(f){let u=b1(f?.core?.operations?.recentSlowOperations);return[...b1(f?.frontend?.operations?.recentSlowOperations),...u].sort((_,y)=>Rf(y.durationMs)-Rf(_.durationMs)).slice(0,20)}function eS(f){let u=performance.memory,l=Number(u?.usedJSHeapSize);if(Number.isFinite(l)&&l>0)return l;let _=Number(f?.appBundleBytes);if(Number.isFinite(_)&&_>0)return _;return Rf(f?.process?.heapUsedBytes)}function fC({points:f}){let u=b1(f),l=u.map((W)=>Rf(W.mb)),_=Math.max(1,...l),y=Math.max(0,Math.min(...l,0)),$=Math.max(1,_-y),r=u.length>1?u:[...u,...u],j=r.length<=1?100:100/(r.length-1),A=r.map((W,G)=>{let K=Rf(W.mb);return`${(G*j).toFixed(2)},${(48-(K-y)/$*42).toFixed(2)}`}).join(" "),J=`0,50 ${A} 100,50`,U=u.at(-1),Q=u[0];return F("article",{className:"performance-memory-card","data-testid":"performance-memory-chart"},F("div",{className:"performance-memory-head"},F("strong",null,`Bwebui: ${U?`${Rf(U.mb).toFixed(1)}MB`:"--"}`),F("span",null,u.length>0?`${u.length} samples`:"等待采样")),F("svg",{viewBox:"0 0 100 50",preserveAspectRatio:"none",role:"img","aria-label":"Bwebui memory trend"},F("polygon",{points:J}),F("polyline",{points:A}),F("line",{x1:"0",x2:"100",y1:"25",y2:"25"})),F("div",{className:"performance-axis-row"},F("span",null,Q?W0(new Date(Q.at)):"--"),F("span",null,"时间"),F("span",null,U?W0(new Date(U.at)):"--")),F("div",{className:"performance-axis-row"},F("span",null,`${y.toFixed(1)}`),F("span",null,"(MB)"),F("span",null,`${_.toFixed(1)}`)))}function uC({onRaw:f}){let[u,l]=bf({core:null,frontend:null}),[_,y]=bf([]),[$,r]=bf(""),[j,A]=bf(!1),[J,U]=bf(null),[Q,W]=bf(!1);async function G(){A(!0),r("");try{let[n,S]=await Promise.all([Mf(`${mf.apiBaseUrl}/performance`,{cache:"no-store"}),Mf(`${mf.apiBaseUrl}/frontend-performance`,{cache:"no-store"})]);l({core:n,frontend:S});let T=eS(S);y((i)=>[...i,{at:new Date().toISOString(),mb:T/1048576}].slice(-80))}catch(n){r(Df(n,"性能指标加载失败"))}finally{A(!1)}}J1(()=>{G();let n=setInterval(()=>void G(),5000);return()=>clearInterval(n)},[]);async function K(){W(!0),r(""),U(null);try{let n=await Mf(`${mf.apiBaseUrl}/code-queue-load-test`,{method:"POST",body:JSON.stringify({targetMs:1000,timeoutMs:90000,url:mf.frontendPublicUrl||window.location.origin})});U(n),G()}catch(n){r(Df(n,"Code Queue Playwright 测量失败"))}finally{W(!1)}}let H=sS(u),O=aS(u),z=oS(u),Z=dS(u),N=u.core?.process||{},E=u.frontend?.process||{},q=u.core?.database?.codeQueueStorage||{},Y=Rf(q.total),w=J?.result||{},B=Rf(w.wallMs,NaN),P=Rf(w.networkIdleMs,NaN),h=w.withinTarget===!0,M=Q?"running":J===null?"idle":J.measurementOk===!0?h?"passed":"slow":"failed";return F("div",{className:"performance-page","data-testid":"performance-page"},F("div",{className:"performance-hero"},F("div",null,F("p",{className:"panel-eyebrow"},"Unified Performance"),F(j0,{title:"性能面板",loading:j||Q}),F("p",null,"按组件统计 HTTP 请求、失败率、P95 延迟,并汇总 backend/frontend 内部操作耗时。")),F("div",{className:"inline-actions"},F("button",{type:"button",className:"ghost-btn",onClick:()=>void K(),disabled:Q,"data-testid":"code-queue-load-test-button"},Q?"测试中...":"测试 Code Queue 加载"),F("button",{type:"button",className:"ghost-btn",onClick:()=>void G(),disabled:j,"data-testid":"performance-refresh-button"},j?"刷新中":"刷新"),F(b0,{title:"Performance Snapshot",data:u,onOpen:f,testId:"raw-performance"}))),F(A0,{error:$}),F("div",{className:"performance-top-grid"},F(fC,{points:_}),F("div",{className:"performance-metric-stack"},F(F0,{label:"backend RSS",value:Ku(N.rssBytes),hint:`heap ${Ku(N.heapUsedBytes)}`}),F(F0,{label:"frontend RSS",value:Ku(E.rssBytes),hint:`bundle ${Ku(u.frontend?.appBundleBytes)}`}),F(F0,{label:"Codex PG 任务",value:Y||"--",hint:q.ok?"unidesk_code_queue_tasks":"等待表初始化",tone:q.ok?"ok":"warn"}),F(F0,{label:"请求样本",value:Rf(u.core?.requests?.sampleCount)+Rf(u.frontend?.requests?.sampleCount),hint:"rolling window 3000"}))),F(sf,{title:"Code Queue 加载基准",eyebrow:"Playwright / target <1s",className:"codex-load-test-panel",loading:Q,actions:F("div",{className:"panel-actions"},F("button",{type:"button",className:"primary-btn",onClick:()=>void K(),disabled:Q,"data-testid":"code-queue-load-test-panel-button"},Q?"正在运行 Playwright...":"手动触发测试"),J?F(b0,{title:"Code Queue Load Test",data:J,onOpen:f,testId:"raw-code-queue-load-test"}):null)},F("div",{className:"codex-load-test-grid","data-testid":"code-queue-load-test-result"},F(F0,{label:"总耗时",value:Q?"运行中":Number.isFinite(B)?Al(B):"--",hint:J===null?"点击按钮启动远端 Playwright":`目标 ${Al(w.targetMs||1000)} / ${w.url||"Code Queue"}`,tone:M==="passed"?"ok":M==="failed"||M==="slow"?"warn":""}),F(F0,{label:"判定",value:Q?"RUNNING":M==="passed"?"PASS <1s":M==="slow"?"SLOW":M==="failed"?"FAILED":"--",hint:J?.measurementOk===!1?String(J.error||w.error||"measurement failed").slice(0,120):"导航开始 -> DOMContentLoaded -> data-load-state=complete",tone:M==="passed"?"ok":M==="idle"||M==="running"?"":"fail"}),F(F0,{label:"Network idle",value:Number.isFinite(P)?Al(P):"--",hint:`DOMContentLoaded ${Al(w.domContentLoadedMs)} / ${w.networkIdleReached===!1?"未在 5s 内空闲":"已空闲"}`,tone:Number.isFinite(P)&&P<=1000?"ok":"warn"}),F(F0,{label:"组件耗时",value:Number.isFinite(Rf(w.componentLoadMs,NaN))?Al(w.componentLoadMs):"--",hint:`queue ${Al(w.queueMs)} / detail ${Al(w.detailMs)}`,tone:Rf(w.componentLoadMs)>1000?"warn":"ok"}),F(F0,{label:"Trace 规模",value:Number.isFinite(Rf(w.transcriptRows,NaN))?String(w.transcriptRows):"--",hint:`${w.visibleTaskCount??0} visible tasks / ${w.partial?"preview":"complete"}`})),Q?F("div",{className:"performance-empty-line"},"正在通过 main-server Host SSH 启动 Playwright,完成后会显示 wall time、组件耗时和最慢 API。"):null,J&&Array.isArray(w.slowestApi)&&w.slowestApi.length>0?F("div",{className:"table-wrap performance-table-wrap compact codex-load-api-table"},F("table",{className:"performance-table"},F("thead",null,F("tr",null,["API","状态","耗时"].map((n)=>F("th",{key:n},n)))),F("tbody",null,w.slowestApi.slice(0,5).map((n,S)=>F("tr",{key:`${n.url}-${S}`},F("td",null,F("code",null,n.url)),F("td",null,n.status),F("td",null,Al(n.durationMs))))))):null),F("div",{className:"performance-grid"},F(sf,{title:"组件汇总",eyebrow:"Requests",loading:j},H.length===0?F(J0,{title:"暂无请求样本",text:"刷新几次或打开页面后会自动形成组件统计"}):F("div",{className:"table-wrap performance-table-wrap"},F("table",{className:"performance-table"},F("thead",null,F("tr",null,["组件","请求数","失败数","失败率","平均延迟","P95"].map((n)=>F("th",{key:n},n)))),F("tbody",null,H.map((n)=>F("tr",{key:n.component},F("td",null,F("code",null,n.component)),F("td",null,n.requestCount),F("td",null,n.failureCount),F("td",null,C_(Rf(n.failureRate)*100)),F("td",null,Al(n.averageLatencyMs)),F("td",null,Al(n.p95LatencyMs)))))))),F(sf,{title:"最近失败请求",eyebrow:"Failures",loading:j},O.length===0?F("div",{className:"performance-empty-line"},"最近没有失败请求"):F("div",{className:"table-wrap performance-table-wrap compact"},F("table",{className:"performance-table"},F("thead",null,F("tr",null,["时间","来源","组件","状态","路径"].map((n)=>F("th",{key:n},n)))),F("tbody",null,O.map((n,S)=>F("tr",{key:`${n.at}-${S}`},F("td",null,Nf(n.at)),F("td",null,n.source),F("td",null,F("code",null,n.component)),F("td",null,F(K0,{status:"failed"},n.status)),F("td",null,F("code",null,n.path)))))))),F(sf,{title:"内部操作汇总",eyebrow:"Operations",loading:j},z.length===0?F(J0,{title:"暂无内部操作样本",text:"API 查询和代理请求会自动记录内部操作耗时"}):F("div",{className:"table-wrap performance-table-wrap"},F("table",{className:"performance-table"},F("thead",null,F("tr",null,["服务","操作","次数","平均延迟","P95"].map((n)=>F("th",{key:n},n)))),F("tbody",null,z.map((n)=>F("tr",{key:`${n.service}-${n.operation}`},F("td",null,n.service),F("td",null,F("code",null,n.operation)),F("td",null,n.count),F("td",null,Al(n.averageLatencyMs)),F("td",null,Al(n.p95LatencyMs)))))))),F(sf,{title:"最近慢操作",eyebrow:"Slowest",loading:j},Z.length===0?F(J0,{title:"暂无慢操作",text:"后端会记录最近窗口内耗时最高的内部操作"}):F("div",{className:"table-wrap performance-table-wrap"},F("table",{className:"performance-table"},F("thead",null,F("tr",null,["时间","操作","耗时","结果","细节"].map((n)=>F("th",{key:n},n)))),F("tbody",null,Z.map((n,S)=>F("tr",{key:`${n.at}-${n.operation}-${S}`},F("td",null,Nf(n.at)),F("td",null,F("code",null,n.operation)),F("td",null,Al(n.durationMs)),F("td",null,n.ok?"成功":"失败"),F("td",null,n.detail||"-")))))))))}function lC({provider:f,refresh:u,onRaw:l}){let[_,y]=bf(""),[$,r]=bf(null),[j,A]=bf("");async function J(U){y(U),A("");try{let Q=await Mf(`${mf.apiBaseUrl}/dispatch`,{method:"POST",body:JSON.stringify({providerId:f.providerId,command:"provider.upgrade",payload:{mode:U,source:"frontend-resource-monitor",requestedAt:new Date().toISOString()}})});r({mode:U,...Q}),await u()}catch(Q){A(Df(Q,"升级命令下发失败"))}finally{y("")}}return F(sf,{title:"Provider Gateway 升级",eyebrow:"Remote Control",loading:Boolean(_)},F("div",{className:"upgrade-control","data-testid":"provider-upgrade-control"},F("p",null,"通过 UniDesk WebSocket 向当前计算节点下发 provider.upgrade;预检只生成升级计划,执行升级会调度节点本地 updater 容器。"),F("div",{className:"upgrade-target-line"},F("span",null,"指定 Provider"),F("code",null,f.providerId),F(_3,{node:f})),F("div",{className:"upgrade-actions"},F("button",{type:"button",className:"ghost-btn",disabled:Boolean(_),onClick:()=>J("plan"),"data-testid":"upgrade-plan-button"},_==="plan"?"预检中":"预检升级"),F("button",{type:"button",className:"ghost-btn danger",disabled:Boolean(_),onClick:()=>J("schedule"),"data-testid":"upgrade-schedule-button"},_==="schedule"?"调度中":"执行升级")),F(A0,{error:j}),$?F("div",{className:"upgrade-result"},F(K0,{status:$.status||"queued"},$.status||"queued"),F("span",null,`${$.mode==="schedule"?"执行升级":"预检升级"} 已下发`),F("span",null,`指定版本 ${CJ(nH(f))}`),F("code",null,$.taskId||"--"),F(b0,{title:"Provider Upgrade Dispatch",data:$,onOpen:l})):F("span",{className:"muted"},"升级任务结果会进入任务历史;执行升级可能导致 provider 短暂重连。")))}function IH({records:f,onRaw:u,compact:l=!1}){if(f.length===0)return F(J0,{title:"暂无远程更新记录",text:"该节点还没有 provider.upgrade 任务;执行预检或升级后会在这里形成结构化记录"});return F("div",{className:`upgrade-record-table-wrap table-wrap ${l?"compact":""}`},F("table",{className:"upgrade-record-table"},F("thead",null,F("tr",null,F("th",null,"状态"),F("th",null,"模式"),F("th",null,"任务"),F("th",null,"来源"),F("th",null,"耗时"),F("th",null,"策略"),F("th",null,"Gateway 版本"),F("th",null,"结果记录"),F("th",null,"更新时间"),F("th",null,"操作"))),F("tbody",null,f.map((_)=>F("tr",{key:_.id,"data-testid":`gateway-upgrade-record-${Iu(_.id)}`},F("td",null,F(K0,{status:_.status})),F("td",null,F("span",{className:`mode-chip ${zr(_)}`},zr(_)==="schedule"?"执行升级":"预检")),F("td",null,F("strong",null,"provider.upgrade"),F("code",null,_.id)),F("td",null,TS(_)),F("td",null,F(mH,{task:_})),F("td",null,MS(_)),F("td",null,F("span",{className:"version-chip"},cH(_))),F("td",null,F("span",{className:`upgrade-outcome ${String(_.status||"").toLowerCase()}`},RH(_))),F("td",null,Nf(_.updatedAt)),F("td",null,F(b0,{title:`Provider Upgrade Task ${_.id}`,data:Y4(_),onOpen:u})))))))}function _C({provider:f,tasks:u,onRaw:l,limit:_=5}){let y=xH(u,f.providerId).slice(0,_);return F(sf,{title:"远程更新记录",eyebrow:f.providerId,actions:F(_3,{node:f}),className:"provider-upgrade-records-panel"},F("div",{"data-testid":`provider-upgrade-records-${Iu(f.providerId)}`},F(IH,{records:y,onRaw:l,compact:!0})))}function yC({nodes:f,tasks:u,onRaw:l}){let _=B4(()=>f.map(($)=>{let r=xH(u,$.providerId);return{node:$,records:r,latest:PS(r),capabilities:SH($)}}),[f,u]),y=_.reduce(($,r)=>$+r.records.length,0);return F("div",{className:"gateway-page","data-testid":"gateway-version-page"},F(sf,{title:"Provider Gateway 版本",eyebrow:`${f.length} Providers / ${y} 更新记录`},f.length===0?F(J0,{title:"暂无 Provider 节点",text:"等待 provider-gateway 注册后显示版本号和升级记录"}):F("div",{className:"table-wrap gateway-version-table-wrap"},F("table",{className:"gateway-version-table"},F("thead",null,F("tr",null,F("th",null,"状态"),F("th",null,"Provider"),F("th",null,"Gateway 版本"),F("th",null,"升级策略"),F("th",null,"运维可用性"),F("th",null,"运行时间"),F("th",null,"能力"),F("th",null,"最近远程更新"),F("th",null,"操作"))),F("tbody",null,_.map(($)=>F("tr",{key:$.node.providerId},F("td",null,F(K0,{status:$.node.status})),F("td",null,F("strong",null,$.node.name),F("code",null,$.node.providerId)),F("td",null,F(_3,{node:$.node})),F("td",null,X4($.node)),F("td",null,F(iJ,{node:$.node})),F("td",null,EH($.node)?Nf(EH($.node)):"待新版上报"),F("td",null,F("div",{className:"capability-row"},$.capabilities.length===0?F("span",{className:"muted"},"未声明"):$.capabilities.slice(0,5).map((r)=>F("span",{key:r,className:"data-chip"},r)))),F("td",null,$.latest?F("div",{className:"latest-upgrade-cell"},F(K0,{status:$.latest.status}),F("span",null,`${zr($.latest)==="schedule"?"执行升级":"预检"} / ${Nf($.latest.updatedAt)}`),F("small",null,`Gateway ${cH($.latest)}`),F("small",null,RH($.latest))):F("span",{className:"muted"},"暂无记录")),F("td",null,F(b0,{title:`Provider ${$.node.providerId}`,data:$.node,onOpen:l})))))))),F(sf,{title:"远程更新记录",eyebrow:"Structured provider.upgrade records"},f.length===0?F(J0,{title:"暂无记录",text:"没有 provider 节点时不会生成远程更新记录"}):F("div",{className:"gateway-record-grid"},_.map(($)=>F("article",{key:$.node.providerId,className:"gateway-record-card","data-testid":`gateway-records-${Iu($.node.providerId)}`},F("div",{className:"gateway-record-head"},F("div",null,F("strong",null,$.node.name),F("code",null,$.node.providerId)),F(_3,{node:$.node})),F("div",{className:"gateway-record-meta"},F("span",null,`心跳 ${Nf($.node.lastHeartbeat)}`),F("span",null,`策略 ${X4($.node)}`),F("span",null,`${$.records.length} 条记录`)),F(IH,{records:$.records.slice(0,8),onRaw:l,compact:!0}))))))}function $C(f){if(f==="running")return"online";if(f==="paused"||f==="restarting")return"warn";if(f==="exited"||f==="dead")return"offline";return"internal"}function pH(f){return/^[a-f0-9]{48,64}$/i.test(f)}function L4(f){let u=String(f?.name||""),l=String(f?.labels||"");return u==="unidesk_pgdata_10gb"||l.includes("com.docker.compose.volume=unidesk_pgdata_10gb")||u.toLowerCase().includes("pgdata")}function XH(f){let u=String(f?.name||""),l=String(f?.labels||"");if(L4(f))return 0;if(l.includes("com.docker.compose.project=unidesk"))return 1;if(!pH(u))return 2;return 3}function rC(f){return[...f].sort((u,l)=>{let _=XH(u)-XH(l);if(_!==0)return _;return String(u.name||"").localeCompare(String(l.name||""))})}function jC({nodes:f,dockerStatuses:u,onRaw:l}){let[_,y]=bf(""),$=B4(()=>f.map((Z)=>{let N=u.find((E)=>E.providerId===Z.providerId);return{...Z,dockerStatus:N?.dockerStatus||null,dockerUpdatedAt:N?.updatedAt||null}}),[f,u]),r=$.find((Z)=>Z.providerId===_)||$[0]||null;if(J1(()=>{if(!_&&$[0])y($[0].providerId)},[$.length,_]),!r)return F(J0,{title:"暂无 Docker 节点",text:"等待 provider 上报 Docker daemon 状态"});let j=r.dockerStatus,A=r.providerId==="main-server",J=j?.counts||{},U=j?.daemon||{},Q=j?.containers||[],W=j?.images||[],G=rC(j?.volumes||[]),K=A?G.find(L4):null,H=j?.networks||[],O=Q.filter((Z)=>Z.state==="running"),z=Q.filter((Z)=>Z.state!=="running");return F("div",{className:"docker-page","data-testid":"docker-status-page"},F("div",{className:"docker-node-strip"},$.map((Z)=>F("button",{key:Z.providerId,type:"button",className:`docker-node-tile ${r.providerId===Z.providerId?"active":""}`,onClick:()=>y(Z.providerId)},F("span",{className:`pulse ${Z.status}`}),F("strong",null,Z.name),F("code",null,Z.providerId),F("span",null,Z.dockerStatus?`Docker ${Z.dockerStatus.ok?"ready":"degraded"}`:"等待上报")))),F("div",{className:"docker-layout"},F(sf,{title:"Docker Desktop 视图",eyebrow:r.name,className:"docker-main-panel",actions:j?F(b0,{title:`Docker ${r.providerId}`,data:j,onOpen:l}):null},!j?F(J0,{title:"Docker 状态未上报",text:"provider-gateway 会在连接后周期性采集 docker info / ps / images / volume / network"}):F("div",null,F("div",{className:"docker-hero"},F("div",null,F("p",{className:"panel-eyebrow"},"Daemon"),F("h3",null,U.name||r.providerId),F("div",{className:"docker-meta"},F("span",null,U.serverVersion?`Engine ${U.serverVersion}`:"Engine --"),F("span",null,U.operatingSystem||"OS --"),F("span",null,U.architecture||"arch --"),F("span",null,`${U.cpus||0} CPU / ${Ku(U.memoryBytes)}`))),F(K0,{status:j.ok?"online":"warn"},j.ok?"Docker Ready":"Docker Degraded")),F("div",{className:"docker-metrics"},F(F0,{label:"Containers",value:J.containers??Q.length,hint:`${J.running??O.length} running / ${J.stopped??z.length} stopped`,tone:"ok"}),F(F0,{label:"Images",value:J.images??W.length,hint:`${J.daemonImages??J.images??W.length} daemon images`}),F(F0,{label:"Volumes",value:J.volumes??G.length,hint:A?K?"database volume visible":"database volume missing":"node local volumes",tone:K?"ok":""}),F(F0,{label:"Networks",value:J.networks??H.length,hint:U.driver?`driver ${U.driver}`:"docker networks"})),A?F(AC,{volume:K,volumeCount:G.length}):null,F("div",{className:"docker-section-head"},F("h3",null,"Containers"),F("span",null,`updated ${Nf(r.dockerUpdatedAt||j.collectedAt)}`)),F("div",{className:"docker-container-table table-wrap","data-testid":"docker-container-table"},F("table",null,F("thead",null,F("tr",null,F("th",null,"状态"),F("th",null,"容器"),F("th",null,"镜像"),F("th",null,"端口"),F("th",null,"运行时间"),F("th",null,"重启策略"),F("th",null,"PID"),F("th",null,"大小"))),F("tbody",null,Q.length===0?F("tr",null,F("td",{colSpan:8},"暂无容器")):Q.map((Z)=>F("tr",{key:`${Z.id}-${Z.name}`},F("td",null,F(K0,{status:$C(Z.state)},Z.state||"unknown")),F("td",null,F("strong",null,Z.name||"--"),F("code",null,Z.id||"--")),F("td",null,Z.image||"--"),F("td",null,Z.ports||F("span",{className:"muted"},"未发布")),F("td",null,Z.runningFor||Z.status||"--"),F("td",null,Z.restartPolicy?F(K0,{status:Z.restartPolicy==="always"?"online":"warn"},Z.restartPolicy):"--"),F("td",null,Z.pidMode?F("code",null,Z.pidMode):"--"),F("td",null,Z.size||"--")))))))),F("div",{className:"docker-side-stack"},F(MJ,{title:"Images",items:W,render:(Z)=>F("article",{key:`${Z.id}-${Z.repository}`,className:"docker-side-row"},F("strong",null,`${Z.repository}:${Z.tag}`),F("span",null,Z.size||"--"),F("code",null,Z.id||"--"))}),F(MJ,{title:"Volumes",items:G,limit:G.length,render:(Z)=>F("article",{key:Z.name,className:`docker-side-row volume-row ${A&&L4(Z)?"database-volume":""}`,"data-testid":A&&L4(Z)?"database-volume-row":void 0},F("strong",null,Z.name),F("span",null,A&&L4(Z)?"PostgreSQL":pH(String(Z.name||""))?"anonymous":"named"),F("code",null,Z.mountpoint||Z.driver||Z.scope||"--"))}),F(MJ,{title:"Networks",items:H,render:(Z)=>F("article",{key:Z.id||Z.name,className:"docker-side-row"},F("strong",null,Z.name),F("span",null,Z.driver||"--"),F("code",null,Z.id||"--"))}))))}function AC({volume:f,volumeCount:u}){return F("section",{className:`docker-volume-focus ${f?"ready":"missing"}`,"data-testid":"database-volume-card"},F("div",{className:"volume-focus-head"},F("span",{className:"panel-eyebrow"},"Database Named Volume"),F(K0,{status:f?"online":"warn"},f?"FOUND":"MISSING")),f?F("div",{className:"volume-focus-body"},F("strong",null,f.name),F("span",null,"PostgreSQL data volume for unidesk-database"),F("div",{className:"volume-route"},F("code",null,f.mountpoint||"/var/lib/docker/volumes/unidesk_pgdata_10gb/_data"),F("span",null,"->"),F("code",null,"unidesk-database:/var/lib/postgresql/data")),F("div",{className:"docker-meta compact"},F("span",null,`driver ${f.driver||"--"}`),F("span",null,`scope ${f.scope||"--"}`),F("span",null,`${u} volumes reported`))):F("div",{className:"volume-focus-body"},F("strong",null,"unidesk_pgdata_10gb"),F("span",null,"当前 Docker 快照没有发现数据库命名卷;请检查 provider-gateway 的 Docker volume 上报。")))}function MJ({title:f,items:u,render:l,limit:_}){let y=u.slice(0,_??12),$=Math.max(0,u.length-y.length);return F(sf,{title:f,eyebrow:`${u.length} items`,className:"docker-side-panel"},u.length===0?F(J0,{title:`暂无 ${f}`,text:"等待 Docker 状态采集"}):F("div",{className:"docker-side-list"},y.map(l),$>0?F("div",{className:"docker-side-more"},`+ ${$} more`):null))}function FC({microservices:f,onRaw:u,onNavigate:l}){let _=f.filter((y)=>OH(y).public===!1);return F("div",{className:"microservice-page","data-testid":"microservice-catalog-page"},F(sf,{title:"用户服务目录",eyebrow:"Provider Mounted User Services"},F("div",{className:"metric-grid"},F(F0,{label:"服务总数",value:f.length,hint:"config.json 用户服务登记"}),F(F0,{label:"私有后端",value:_.length,hint:"不直接暴露公网",tone:"ok"}),F(F0,{label:"D601 服务",value:f.filter((y)=>y.providerId==="D601").length,hint:"compute-node docker"}),F(F0,{label:"集成前端",value:f.filter((y)=>y.frontend?.integrated).length,hint:"UniDesk React 页面"}))),F(sf,{title:"服务映射",eyebrow:"Repo Reference + Runtime"},f.length===0?F(J0,{title:"暂无用户服务",text:"在 config.json 的 microservices 中登记用户服务的 provider、仓库引用和后端映射"}):F("div",{className:"table-wrap"},F("table",{className:"microservice-table"},F("thead",null,F("tr",null,F("th",null,"服务"),F("th",null,"Provider"),F("th",null,"代码引用"),F("th",null,"Docker 引用"),F("th",null,"后端映射"),F("th",null,"开发入口"),F("th",null,"运行态"),F("th",null,"操作"))),F("tbody",null,f.map((y)=>{let $=bH(y),r=nS(y),j=OH(y);return F("tr",{key:y.id,"data-testid":`microservice-row-${Iu(y.id)}`},F("td",null,F("strong",null,y.name),F("code",null,y.id)),F("td",null,F("strong",null,$.providerName||y.providerId),F("code",null,y.providerId)),F("td",null,F("span",null,r.url||"--"),F("code",null,r.commitId||"--")),F("td",null,F("span",null,r.composeFile||"--"),F("code",null,`${r.composeService||"--"} / ${r.containerName||"--"}`)),F("td",null,F(K0,{status:j.public?"warn":"online"},j.public?"public":"private"),F("code",null,`${j.nodeBindHost||"--"}:${j.nodePort||"--"} -> ${j.proxyMode||"--"}`)),F("td",null,F("span",null,y.development?.sshPassthrough?"SSH 透传":"未配置"),F("code",null,y.development?.worktreePath||"--")),F("td",null,F(K0,{status:$.providerStatus==="online"?"online":"warn"},$.providerStatus||"unknown"),F(c_,{data:$.container,empty:"容器快照未上报"})),F("td",null,F("div",{className:"microservice-actions"},y.id==="findjob"?F("button",{type:"button",className:"ghost-btn",onClick:()=>l("apps","findjob"),"data-testid":"open-findjob-button"},"打开"):null,y.id==="pipeline"?F("button",{type:"button",className:"ghost-btn",onClick:()=>l("apps","pipeline"),"data-testid":"open-pipeline-button"},"打开"):null,y.id==="todo-note"?F("button",{type:"button",className:"ghost-btn",onClick:()=>l("apps","todo-note"),"data-testid":"open-todo-note-button"},"打开"):null,y.id==="met-nonlinear"?F("button",{type:"button",className:"ghost-btn",onClick:()=>l("apps","met-nonlinear"),"data-testid":"open-met-nonlinear-button"},"打开"):null,y.id==="claudeqq"?F("button",{type:"button",className:"ghost-btn",onClick:()=>l("apps","claudeqq"),"data-testid":"open-claudeqq-button"},"打开"):null,y.id==="baidu-netdisk"?F("button",{type:"button",className:"ghost-btn",onClick:()=>l("apps","baidu-netdisk"),"data-testid":"open-baidu-netdisk-button"},"打开"):null,y.id==="code-queue"?F("button",{type:"button",className:"ghost-btn",onClick:()=>l("apps","code-queue"),"data-testid":"open-code-queue-button"},"打开"):null,y.id==="project-manager"?F("button",{type:"button",className:"ghost-btn",onClick:()=>l("apps","project-manager"),"data-testid":"open-project-manager-button"},"打开"):null,F(b0,{title:`用户服务 ${y.id}`,data:y,onOpen:u}))))}))))))}function JC({nodes:f,onDispatched:u,onRaw:l}){let _=f.filter((M)=>M.status==="online"),[y,$]=bf(_[0]?.providerId||f[0]?.providerId||""),[r,j]=bf("docker.ps"),[A,J]=bf("frontend"),[U,Q]=bf("operator-check"),[W,G]=bf("normal"),[K,H]=bf(!1),[O,z]=bf(""),[Z,N]=bf(!1),[E,q]=bf(null),[Y,w]=bf("");J1(()=>{if(!y&&(_[0]?.providerId||f[0]?.providerId))$(_[0]?.providerId||f[0].providerId)},[f.length,_.length,y]);function B(){return{source:A,note:U,priority:W}}function P(){z(JSON.stringify(B(),null,2)),H(!0)}async function h(M){M.preventDefault(),N(!0),w("");try{let n=K?JSON.parse(O||"{}"):B(),S=await Mf(`${mf.apiBaseUrl}/dispatch`,{method:"POST",body:JSON.stringify({providerId:y,command:r,payload:n})});q(S),await u()}catch(n){w(Df(n,"下发失败"))}finally{N(!1)}}return F("div",{className:"page-grid dispatch-grid"},F(sf,{title:"下发任务",eyebrow:"Real WebSocket Dispatch"},F("form",{className:"dispatch-form",onSubmit:h},F("label",null,"Provider",F("select",{value:y,onChange:(M)=>$(M.target.value)},f.map((M)=>F("option",{key:M.providerId,value:M.providerId},`${M.name} / ${M.providerId}`)))),F("label",null,"Command",F("select",{value:r,onChange:(M)=>j(M.target.value)},F("option",{value:"docker.ps"},"docker.ps"),F("option",{value:"host.ssh"},"host.ssh"),F("option",{value:"microservice.http"},"microservice.http"),F("option",{value:"echo"},"echo"))),F("label",null,"来源",F("input",{value:A,onChange:(M)=>J(M.target.value)})),F("label",null,"备注",F("input",{value:U,onChange:(M)=>Q(M.target.value)})),F("label",null,"优先级",F("select",{value:W,onChange:(M)=>G(M.target.value)},F("option",{value:"normal"},"normal"),F("option",{value:"low"},"low"),F("option",{value:"urgent"},"urgent"))),F("div",{className:"dispatch-actions"},F("button",{type:"button",className:"ghost-btn",onClick:P},"查看原始JSON"),F("button",{type:"submit",disabled:Z||!y},Z?"下发中":"下发任务")),K?F("label",{className:"raw-editor-label"},"高级 Payload",F("textarea",{className:"raw-editor",value:O,onChange:(M)=>z(M.target.value)})):null,F(A0,{error:Y,wide:!0}))),F(sf,{title:"下发结果",eyebrow:"Response"},E?F("div",{className:"result-card"},F(K0,{status:E.status||"queued"},E.status||"queued"),F("dl",null,F("dt",null,"Task ID"),F("dd",null,F("code",null,E.taskId||"--")),F("dt",null,"Provider 在线"),F("dd",null,Py(E.providerOnline))),F(b0,{title:"Dispatch Response",data:E,onOpen:l})):F(J0,{title:"等待操作",text:"任务响应会以结构化结果卡展示"})))}function BH({task:f,onRaw:u}){return F("article",{className:"compact-row"},F(K0,{status:f.status}),F("div",null,F("strong",null,f.command),F("code",null,f.id)),F("span",null,y3(f)?`已等待 ${nJ(f.updatedAt)}`:`耗时 ${x1(TH(f)??0)}`),F(b0,{title:`Task ${f.id}`,data:Y4(f),onOpen:u}))}function mH({task:f}){let u=TH(f),l=y3(f);return F("div",{className:"task-duration"},F("strong",null,u===null?"--":x1(u)),F("span",null,l?`已运行 / 创建 ${Nf(f.createdAt)}`:`创建 ${Nf(f.createdAt)}`))}function UC({task:f}){let u=String(f?.status||"").toLowerCase(),l=f?.result,_=l&&typeof l==="object"&&!Array.isArray(l)?l:{},$=["exitCode","code","signal","timeoutMs","previousStatus","mode"].filter((r)=>_[r]!==void 0&&_[r]!==null);if(u==="failed"){let r=MH(f);return F("div",{className:"task-diagnostic failed"},F("b",null,"失败原因"),F("span",{className:"diagnostic-reason"},Py(r)),$.length>0?F("div",{className:"diagnostic-meta"},$.map((j)=>F("span",{key:j,className:"data-chip"},F("b",null,j),F("span",null,Py(_[j]))))):null)}if(y3(f))return F("div",{className:"task-diagnostic warn"},F("b",null,"等待终态"),F("span",null,`最后更新 ${nJ(f.updatedAt)} 前`));return F("div",{className:"task-diagnostic ok"},F("b",null,"完成摘要"),F(c_,{data:l,empty:"无执行输出"}))}function QC({tasks:f,onRaw:u}){let l=f.filter(y3);return F("div",{"data-testid":"pending-task-page"},F(sf,{title:"待处理任务",eyebrow:`${l.length} Pending`},l.length===0?F(J0,{title:"当前无待处理任务",text:"queued / dispatched / running 会在超时后自动转为 failed;历史记录仍可在任务历史中查看"}):F("div",{className:"table-wrap","data-testid":"pending-task-table"},F("table",null,F("thead",null,F("tr",null,F("th",null,"状态"),F("th",null,"任务"),F("th",null,"Provider"),F("th",null,"已等待"),F("th",null,"载荷摘要"),F("th",null,"操作"))),F("tbody",null,l.map((_)=>F("tr",{key:_.id},F("td",null,F(K0,{status:_.status})),F("td",null,F("strong",null,_.command),F("code",null,_.id)),F("td",null,F("code",null,_.providerId)),F("td",null,nJ(_.updatedAt)),F("td",null,F(c_,{data:_.payload})),F("td",null,F(b0,{title:`Pending Task ${_.id}`,data:Y4(_),onOpen:u})))))))))}function WC({tasks:f,onRaw:u}){return F("div",{"data-testid":"task-history-page"},F(sf,{title:"任务历史",eyebrow:`${f.length} Tasks`},f.length===0?F(J0,{title:"暂无任务",text:"下发任务后会在这里看到生命周期"}):F("div",{className:"table-wrap"},F("table",{className:"task-history-table"},F("thead",null,F("tr",null,F("th",null,"状态"),F("th",null,"任务"),F("th",null,"Provider"),F("th",null,"任务耗时"),F("th",null,"载荷摘要"),F("th",null,"诊断信息"),F("th",null,"更新时间"),F("th",null,"操作"))),F("tbody",null,f.map((l)=>F("tr",{key:l.id,"data-testid":`task-row-${Iu(l.id)}`},F("td",null,F(K0,{status:l.status})),F("td",null,F("strong",null,l.command),F("code",null,l.id)),F("td",null,F("code",null,l.providerId)),F("td",null,F(mH,{task:l})),F("td",null,F(c_,{data:l.payload})),F("td",null,F(UC,{task:l})),F("td",null,Nf(l.updatedAt)),F("td",null,F(b0,{title:`Task ${l.id}`,data:Y4(l),onOpen:u})))))))))}function zC({tasks:f,onRaw:u}){let l=f.filter((_)=>["succeeded","failed"].includes(_.status));return F(sf,{title:"执行结果",eyebrow:"Finished Tasks"},l.length===0?F(J0,{title:"暂无结果",text:"任务完成后展示 provider 返回的结构化摘要"}):F("div",{className:"result-grid"},l.map((_)=>F("article",{key:_.id,className:"result-card"},F("div",{className:"node-card-head"},F("strong",null,_.command),F(K0,{status:_.status})),F("code",null,_.id),F(c_,{data:_.result,empty:"无执行输出"}),F(b0,{title:`Task Result ${_.id}`,data:Y4(_),onOpen:u})))))}function GC(f){if(!f||typeof f!=="object")return"--";if(f.type==="interval")return`每 ${x1(Number(f.everySeconds||0))}`;return`每天 ${f.timeOfDay||"03:00"} UTC`}function KC(f){if(!f||typeof f!=="object")return"--";if(f.type==="pgdata_backup")return`PGDATA -> ${f.remoteBaseDir||"/SERVER_DATA/UNIDESK_PG_DATA"}`;if(f.type==="dispatch")return`${f.providerId||"--"} / ${f.command||"--"}`;return String(f.type||"--")}function NC(f){let u=String(f||"").toLowerCase();if(u==="succeeded")return"online";if(u==="failed")return"failed";if(u==="running"||u==="queued")return"warn";return u}function ZC(f){let u=Number(f?.durationMs);if(Number.isFinite(u)&&u>=0)return x1(u/1000);let l=U1(f?.startedAt||f?.createdAt);if(l===null)return"--";let y=U1(f?.finishedAt)??Date.now();return x1(Math.max(0,(y-l)/1000))}function YH(f){return{id:"unidesk-pgdata-baidu-daily",name:"PGDATA daily Baidu Netdisk backup",description:"Daily PostgreSQL physical base backup uploaded to Baidu Netdisk /SERVER_DATA with monthly rotation.",enabled:!0,timeOfDay:"03:30",actionType:"pgdata_backup",providerId:f[0]?.providerId||"main-server",command:"echo",payloadJson:JSON.stringify({source:"scheduled-task",message:"hello from scheduler"},null,2),remoteBaseDir:"/SERVER_DATA/UNIDESK_PG_DATA",stagingSubdir:"server-data/unidesk-pg-data",timeoutMs:"3600000"}}function EC({schedules:f,scheduleRuns:u,nodes:l,refresh:_,onRaw:y}){let[$,r]=bf(YH(l||[])),[j,A]=bf(!1),[J,U]=bf(""),[Q,W]=bf(""),G=[...u||[]].sort((E,q)=>(U1(q.updatedAt)??0)-(U1(E.updatedAt)??0));function K(E,q){r((Y)=>({...Y,[E]:q}))}function H(E){let q=E?.action||{};r({id:E?.id||"",name:E?.name||"",description:E?.description||"",enabled:E?.enabled!==!1,timeOfDay:E?.schedule?.timeOfDay||"03:30",actionType:q.type||"dispatch",providerId:q.providerId||l[0]?.providerId||"main-server",command:q.command||"echo",payloadJson:JSON.stringify(q.payload||{source:"scheduled-task"},null,2),remoteBaseDir:q.remoteBaseDir||"/SERVER_DATA/UNIDESK_PG_DATA",stagingSubdir:q.stagingSubdir||"server-data/unidesk-pg-data",timeoutMs:String(q.timeoutMs||3600000)}),W(`正在编辑 ${E?.id||""}`)}function O(){let E={id:$.id,name:$.name,description:$.description,enabled:$.enabled,concurrencyPolicy:"skip",schedule:{type:"daily",timeOfDay:$.timeOfDay,timezone:"Etc/UTC"}};if($.actionType==="pgdata_backup")return{...E,action:{type:"pgdata_backup",volumeName:"unidesk_pgdata_10gb",remoteBaseDir:$.remoteBaseDir,stagingSubdir:$.stagingSubdir,timeoutMs:Number($.timeoutMs)||3600000,cleanupLocal:!0}};return{...E,action:{type:"dispatch",providerId:$.providerId,command:$.command,payload:JSON.parse($.payloadJson||"{}"),timeoutMs:Number($.timeoutMs)||600000}}}async function z(E){E.preventDefault(),A(!0),U(""),W("");try{let q=O(),Y=encodeURIComponent(String(q.id));await Mf(`${mf.apiBaseUrl}/schedules/${Y}`,{method:"PUT",body:JSON.stringify(q)}),W("定时任务已保存"),await _()}catch(q){U(Df(q,"保存定时任务失败"))}finally{A(!1)}}async function Z(E){if(!E?.id)return;A(!0),U(""),W("");try{await Mf(`${mf.apiBaseUrl}/schedules/${encodeURIComponent(E.id)}`,{method:"DELETE"}),W(`已删除 ${E.id}`),await _()}catch(q){U(Df(q,"删除定时任务失败"))}finally{A(!1)}}async function N(E){if(!E?.id)return;A(!0),U(""),W("");try{let q=await Mf(`${mf.apiBaseUrl}/schedules/${encodeURIComponent(E.id)}/run`,{method:"POST",body:"{}"});W(`已触发 ${E.id} / ${q?.run?.id||"run"}`),await _()}catch(q){U(Df(q,"触发定时任务失败"))}finally{A(!1)}}return F("div",{className:"page-grid scheduled-task-page","data-testid":"scheduled-task-page"},F(sf,{title:"定时任务",eyebrow:`${(f||[]).length} Schedules`},(f||[]).length===0?F(J0,{title:"暂无定时任务",text:"创建 daily / dispatch / PGDATA backup 任务后会在这里展示下一次执行时间和最近结果"}):F("div",{className:"schedule-card-grid"},(f||[]).map((E)=>F("article",{key:E.id,className:"schedule-card","data-testid":`schedule-row-${Iu(E.id)}`},F("div",{className:"node-card-head"},F("strong",null,E.name||E.id),F(K0,{status:E.enabled?"online":"warn"},E.enabled?"enabled":"disabled")),F("code",null,E.id),F("dl",null,F("dt",null,"计划"),F("dd",null,GC(E.schedule)),F("dt",null,"动作"),F("dd",null,KC(E.action)),F("dt",null,"下次执行"),F("dd",null,Nf(E.nextRunAt)),F("dt",null,"最近执行"),F("dd",null,E.lastRunAt?`${Nf(E.lastRunAt)} / ${E.lastRunId||"--"}`:"--")),F("div",{className:"dispatch-actions"},F("button",{type:"button",className:"ghost-btn",disabled:j,onClick:()=>H(E)},"编辑"),F("button",{type:"button",className:"ghost-btn",disabled:j,onClick:()=>N(E),"data-testid":`schedule-run-${Iu(E.id)}`},"手动触发"),F("button",{type:"button",className:"ghost-btn danger",disabled:j,onClick:()=>Z(E)},"删除"),F(b0,{title:`Schedule ${E.id}`,data:E,onOpen:y})))))),F(sf,{title:$.id?"配置定时任务":"新建定时任务",eyebrow:"CRUD"},F("form",{className:"dispatch-form schedule-form",onSubmit:z},F("label",null,"ID",F("input",{value:$.id,onChange:(E)=>K("id",E.target.value)})),F("label",null,"名称",F("input",{value:$.name,onChange:(E)=>K("name",E.target.value)})),F("label",null,"每日执行时间 UTC",F("input",{value:$.timeOfDay,placeholder:"03:30",onChange:(E)=>K("timeOfDay",E.target.value)})),F("label",null,"启用",F("select",{value:$.enabled?"true":"false",onChange:(E)=>K("enabled",E.target.value==="true")},F("option",{value:"true"},"enabled"),F("option",{value:"false"},"disabled"))),F("label",null,"动作类型",F("select",{value:$.actionType,onChange:(E)=>K("actionType",E.target.value)},F("option",{value:"pgdata_backup"},"PGDATA 备份到百度网盘"),F("option",{value:"dispatch"},"Provider Dispatch"))),$.actionType==="pgdata_backup"?[F("label",{key:"remote"},"网盘根目录",F("input",{value:$.remoteBaseDir,onChange:(E)=>K("remoteBaseDir",E.target.value)})),F("label",{key:"staging"},"本地 staging 子目录",F("input",{value:$.stagingSubdir,onChange:(E)=>K("stagingSubdir",E.target.value)}))]:[F("label",{key:"provider"},"Provider",F("select",{value:$.providerId,onChange:(E)=>K("providerId",E.target.value)},(l||[]).map((E)=>F("option",{key:E.providerId,value:E.providerId},`${E.name} / ${E.providerId}`)))),F("label",{key:"command"},"Command",F("select",{value:$.command,onChange:(E)=>K("command",E.target.value)},F("option",{value:"echo"},"echo"),F("option",{value:"docker.ps"},"docker.ps"),F("option",{value:"host.ssh"},"host.ssh"),F("option",{value:"microservice.http"},"microservice.http"))),F("label",{key:"payload",className:"raw-editor-label"},"Payload JSON",F("textarea",{className:"raw-editor",value:$.payloadJson,onChange:(E)=>K("payloadJson",E.target.value)}))],F("label",null,"超时 ms",F("input",{value:$.timeoutMs,onChange:(E)=>K("timeoutMs",E.target.value)})),F("label",{className:"raw-editor-label"},"描述",F("textarea",{className:"raw-editor compact",value:$.description,onChange:(E)=>K("description",E.target.value)})),F("div",{className:"dispatch-actions"},F("button",{type:"button",className:"ghost-btn",disabled:j,onClick:()=>r(YH(l||[]))},"重置"),F("button",{type:"submit",disabled:j||!$.id},j?"保存中":"保存任务")),Q?F("p",{className:"muted paragraph"},Q):null,F(A0,{error:J,wide:!0}))),F(sf,{title:"历史执行记录",eyebrow:`${G.length} Runs`},G.length===0?F(J0,{title:"暂无执行记录",text:"定时触发或手动触发后会生成 run history"}):F("div",{className:"table-wrap"},F("table",{className:"task-history-table schedule-run-table"},F("thead",null,F("tr",null,F("th",null,"状态"),F("th",null,"任务"),F("th",null,"触发"),F("th",null,"耗时"),F("th",null,"结果摘要"),F("th",null,"更新时间"),F("th",null,"操作"))),F("tbody",null,G.map((E)=>F("tr",{key:E.id,"data-testid":`schedule-run-row-${Iu(E.id)}`},F("td",null,F(K0,{status:NC(E.status)},E.status)),F("td",null,F("strong",null,E.scheduleId),F("code",null,E.id),E.taskId?F("code",null,E.taskId):null),F("td",null,E.trigger||"--"),F("td",null,ZC(E)),F("td",null,F(c_,{data:E.result||E.error,empty:"无结果"})),F("td",null,Nf(E.updatedAt)),F("td",null,F(b0,{title:`Schedule Run ${E.id}`,data:E,onOpen:y})))))))))}function HC({data:f}){let u=f.overview||{};return F("div",{className:"page-grid topology-grid"},F(sf,{title:"公开入口",eyebrow:"Public"},F("div",{className:"endpoint-list"},F("article",null,F("b",null,"Frontend"),F("span",null,mf.frontendPublicUrl||window.location.origin),F(K0,{status:"online"},"public")),F("article",null,F("b",null,"Provider Ingress"),F("span",null,mf.providerIngressPublicUrl||"ws://public/ws/provider"),F(K0,{status:"online"},"public")))),F(sf,{title:"内部服务",eyebrow:"Docker Network Only"},F("div",{className:"endpoint-list"},F("article",null,F("b",null,"backend-core API"),F("span",null,"http://backend-core:8080"),F(K0,{status:"internal"},"internal")),F("article",null,F("b",null,"database"),F("span",null,"postgres://database:5432/unidesk"),F(K0,{status:"internal"},"internal")))),F(sf,{title:"运行态",eyebrow:"Runtime"},F("div",{className:"metric-grid"},F(F0,{label:"DB Ready",value:u.dbReady?"YES":"NO",hint:"internal health"}),F(F0,{label:"Online Nodes",value:u.onlineNodeCount??0,hint:"provider-gateway self-link"}))))}function OC({session:f}){return F(sf,{title:"认证策略",eyebrow:"Frontend Login"},F("div",{className:"policy-grid"},F("article",null,F("span",null,"默认账号"),F("strong",null,mf.authUsername||"admin")),F("article",null,F("span",null,"当前会话"),F("strong",null,f?.user?.username||"--")),F("article",null,F("span",null,"Session TTL"),F("strong",null,`${mf.sessionTtlSeconds||0}s`)),F("article",null,F("span",null,"API 访问"),F("strong",null,"同源 Cookie 保护"))),F("p",{className:"muted paragraph"},"浏览器只访问 frontend 同源接口;frontend 容器使用 Docker 内网代理 backend-core API。"))}function VC(){return F(sf,{title:"安全边界",eyebrow:"Exposure Rule"},F("div",{className:"security-board"},F("article",{className:"allow"},F("b",null,"允许公网"),F("span",null,"frontend 登录入口"),F("span",null,"provider ingress WebSocket/health")),F("article",{className:"deny"},F("b",null,"禁止公网"),F("span",null,"backend-core REST API"),F("span",null,"PostgreSQL database")),F("article",null,F("b",null,"数据库卷"),F("span",null,"named volume unidesk_pgdata_10gb"),F("span",null,"CLI stop/start 不删除数据卷"))))}function qC({activeModule:f,activeTab:u,data:l,session:_,refresh:y,onRaw:$,onNavigate:r}){if(f==="ops"&&u==="status")return F(bS,{data:l,onRaw:$,onNavigate:r});if(f==="ops"&&u==="performance")return F(uC,{onRaw:$});if(f==="ops"&&u==="events")return F(hS,{events:l.events,onRaw:$});if(f==="ops"&&u==="logs")return F(IS,{logs:l.logs,onRaw:$});if(f==="nodes"&&u==="list")return F(pS,{nodes:l.nodes,onRaw:$});if(f==="nodes"&&u==="monitor")return F(kS,{nodes:l.nodes,systemStatuses:l.systemStatuses,tasks:l.tasks,onRaw:$,refresh:y});if(f==="nodes"&&u==="docker")return F(jC,{nodes:l.nodes,dockerStatuses:l.dockerStatuses,onRaw:$});if(f==="nodes"&&u==="gateway")return F(yC,{nodes:l.nodes,tasks:l.tasks,onRaw:$});if(f==="nodes"&&u==="labels")return F(mS,{nodes:l.nodes});if(f==="nodes"&&u==="heartbeats")return F(gS,{nodes:l.nodes});if(f==="tasks"&&u==="dispatch")return F(JC,{nodes:l.nodes,onDispatched:y,onRaw:$});if(f==="tasks"&&u==="scheduled")return F(EC,{schedules:l.schedules,scheduleRuns:l.scheduleRuns,nodes:l.nodes,refresh:y,onRaw:$});if(f==="tasks"&&u==="pending")return F(QC,{tasks:l.pendingTasks,onRaw:$});if(f==="tasks"&&u==="history")return F(WC,{tasks:l.tasks,onRaw:$});if(f==="tasks"&&u==="results")return F(zC,{tasks:l.tasks,onRaw:$});if(f==="apps"&&u==="catalog")return F(FC,{microservices:l.microservices,onRaw:$,onNavigate:r});if(f==="apps"&&u==="todo-note")return F(QH,{microservices:l.microservices,onRaw:$,apiBaseUrl:mf.apiBaseUrl});if(f==="apps"&&u==="findjob")return F($K,{microservices:l.microservices,onRaw:$,apiBaseUrl:mf.apiBaseUrl});if(f==="apps"&&u==="pipeline")return F(yH,{microservices:l.microservices,onRaw:$,apiBaseUrl:mf.apiBaseUrl});if(f==="apps"&&u==="met-nonlinear")return F(JK,{microservices:l.microservices,onRaw:$,apiBaseUrl:mf.apiBaseUrl});if(f==="apps"&&u==="claudeqq")return F(vz,{microservices:l.microservices,onRaw:$,apiBaseUrl:mf.apiBaseUrl});if(f==="apps"&&u==="baidu-netdisk")return F(Rz,{microservices:l.microservices,onRaw:$,apiBaseUrl:mf.apiBaseUrl});if(f==="apps"&&u==="filebrowser")return F(yK,{microservices:l.microservices,onRaw:$,apiBaseUrl:mf.apiBaseUrl});if(f==="apps"&&u==="code-queue")return F(dG,{microservices:l.microservices,onRaw:$,apiBaseUrl:mf.apiBaseUrl,initialTasksData:VS});if(f==="apps"&&u==="project-manager")return F(jH,{microservices:l.microservices,onRaw:$,apiBaseUrl:mf.apiBaseUrl});if(f==="config"&&u==="topology")return F(HC,{data:l});if(f==="config"&&u==="auth")return F(OC,{session:_});if(f==="config"&&u==="security")return F(VC);return F(J0,{title:"未找到页面",text:"请选择左侧主模块和顶部子功能标签"})}function LC({session:f,onLogout:u}){let l=gj(Xl,window.location.pathname),[_,y]=bf(l.moduleId),[$,r]=bf({...n6,[l.moduleId]:l.tabId}),[j,A]=bf({overview:null,nodes:[],systemStatuses:[],dockerStatuses:[],microservices:[],events:[],tasks:[],pendingTasks:[],schedules:[],scheduleRuns:[],logs:[]}),[J,U]=bf({ok:!1,text:"连接中"}),[Q,W]=bf(null),[G,K]=bf(new Date),[H,O]=bf(null),[z,Z]=bf(!1),[N,E]=bf(!1),q=i_.default.useRef(!1),Y=Xl.moduleById[_]||Xl.modules[0],w=$[_]||n6[_]||Y.tabs[0].id,B=Array.isArray(j.microservices)?j.microservices:[],P=B.length===0&&_==="apps"&&w==="code-queue"?[qS]:B,h=P===B?j:{...j,microservices:P},M=_==="apps"?P.find((d)=>String(d?.id||"")===w):null,n=M?bH(M):{},S=Y.tabs.find((d)=>d.id===w)?.label||w,T=M?[{key:"microservice",label:"用户服务",value:`${S} ${n.providerStatus==="online"?"在线":n.providerStatus||"未知"}`,tone:n.providerStatus==="online"?"ok":"warn",testId:"active-microservice-status"}]:[];async function i(){if(q.current)return;q.current=!0,E(!0);try{let d=[],a=(Wf,Ef)=>{d.push([Wf,Mf(Ef)])},I=_==="ops"&&w==="status",ff=I||_==="config"&&w==="topology",yf=I||_==="nodes"||_==="tasks"&&(w==="dispatch"||w==="scheduled"),rf=_==="apps"&&w!=="code-queue";if(ff)a("overview",`${mf.apiBaseUrl}/overview`);if(yf)a("nodes",`${mf.apiBaseUrl}/nodes`);if(_==="nodes"&&w==="monitor")a("systemStatuses",`${mf.apiBaseUrl}/nodes/system-status?limit=60`),a("tasks",`${mf.apiBaseUrl}/tasks?limit=120&summary=1`);else if(_==="nodes"&&w==="docker")a("dockerStatuses",`${mf.apiBaseUrl}/nodes/docker-status`);else if(_==="nodes"&&w==="gateway")a("tasks",`${mf.apiBaseUrl}/tasks?limit=300&summary=1`);else if(_==="tasks"&&w==="scheduled")a("schedules",`${mf.apiBaseUrl}/schedules?limit=100`),a("scheduleRuns",`${mf.apiBaseUrl}/schedules/runs?limit=100`);else if(_==="tasks"&&w==="pending")a("pendingTasks",`${mf.apiBaseUrl}/tasks?status=pending&limit=100&summary=1`);else if(_==="tasks"&&(w==="history"||w==="results"))a("tasks",`${mf.apiBaseUrl}/tasks?limit=300&summary=1`);else if(I)a("tasks",`${mf.apiBaseUrl}/tasks?limit=8&lite=1`),a("pendingTasks",`${mf.apiBaseUrl}/tasks?status=pending&limit=20&lite=1`);if(rf)a("microservices",`${mf.apiBaseUrl}/microservices`);if(_==="ops"&&w==="events")a("events",`${mf.apiBaseUrl}/events?limit=100`);if(_==="ops"&&w==="logs")a("logs","/logs?limit=100");await Promise.all(d.map(async([Wf,Ef])=>{let Gf=await Ef,c={};if(Wf==="overview")c.overview=Gf;if(Wf==="nodes")c.nodes=Gf.nodes||[];if(Wf==="systemStatuses")c.systemStatuses=Gf.systemStatuses||[];if(Wf==="dockerStatuses")c.dockerStatuses=Gf.dockerStatuses||[];if(Wf==="microservices")c.microservices=Gf.microservices||[];if(Wf==="events")c.events=Gf.events||[];if(Wf==="tasks")c.tasks=Gf.tasks||[];if(Wf==="pendingTasks")c.pendingTasks=Gf.tasks||[];if(Wf==="schedules")c.schedules=Gf.schedules||[];if(Wf==="scheduleRuns")c.scheduleRuns=Gf.runs||[];if(Wf==="logs")c.logs=Gf.logs||[];A((o)=>({...o,...c}))})),U({ok:!0,text:"核心在线"}),W(new Date)}catch(d){if(U({ok:!1,text:Df(d,"连接失败")}),d.status===401)u(!1)}finally{q.current=!1,E(!1)}}J1(()=>{let d=()=>{if(!ZH())return;i()};d();let a=setInterval(d,LS(_,w)),I=()=>{if(ZH())d()};return document.addEventListener("visibilitychange",I),()=>{clearInterval(a),document.removeEventListener("visibilitychange",I)}},[_,w]),J1(()=>{let d=setInterval(()=>K(new Date),1000);return()=>clearInterval(d)},[]),J1(()=>{let d=zK(Xl,window.location.pathname);if(d&&window.location.pathname!==d)window.history.replaceState(null,"",d)},[]),J1(()=>{let d=()=>{let a=gj(Xl,window.location.pathname);y(a.moduleId),r((I)=>({...I,[a.moduleId]:a.tabId})),O(null)};return window.addEventListener("popstate",d),()=>window.removeEventListener("popstate",d)},[]),J1(()=>{window.scrollTo({top:0,left:0,behavior:"auto"})},[_,w]);function C(d,a,I="push"){let ff=Xl.moduleById[d]?d:Xl.fallbackTarget.moduleId,yf=Xl.moduleById[ff]?.tabs.some((Wf)=>Wf.id===a)?a:n6[ff]||Xl.moduleById[ff]?.tabs[0]?.id||Xl.fallbackTarget.tabId;y(ff),r((Wf)=>({...Wf,[ff]:yf}));let rf=m2(Xl,ff,yf);if(window.location.pathname!==rf){let Wf=I==="replace"?"replaceState":"pushState";window.history[Wf](null,"",rf)}}function v(d,a){O({title:d,data:a})}let[X,D]=bf(!1),{unreadCount:p,notifications:m}=Lu(),s=m.length>0?m[m.length-1]:null;return F("div",{className:`shell ${z?"rail-collapsed":""}`,"data-testid":"app-shell"},F(RS,{activeModule:_,activeTabs:$,onNavigate:C,collapsed:z,onToggle:()=>Z((d)=>!d)}),F("main",{className:"workspace"},F(iS,{connection:J,lastRefresh:Q,onRefresh:i,onLogout:()=>u(!0),session:f,clock:G,activeStatusItems:T,onNotificationToggle:()=>D((d)=>!d),unreadCount:p}),F(xS,{module:Y,activeTab:w,onNavigate:C}),F(PJ.Provider,{value:N},F(qC,{activeModule:_,activeTab:w,data:h,session:f,refresh:i,onRaw:v,onNavigate:C}))),F(SS,{raw:H,onClose:()=>O(null)}),s&&F(NH,{key:s.id,notification:s}),X&&F(KH,{onClose:()=>D(!1)}))}function XC(){let[f,u]=bf(!0),[l,_]=bf(null);async function y(){u(!0);try{let r=await Mf("/api/session");_(r.authenticated?r:null)}catch{_(null)}finally{u(!1)}}async function $(r){if(r)try{await Mf("/logout",{method:"POST"})}catch{}_(null)}if(J1(()=>{y()},[]),f)return F("main",{className:"loading-screen"},F("div",{className:"brand-mark"},"UD"),F("span",null,"加载会话"));if(!l)return F(CS,{onLogin:_});return F(cz,null,F(LC,{session:l,onLogout:$}))}var gH=document.getElementById("root");if(gH===null)throw Error("root element not found");wH.createRoot(gH).render(F(XC));})(); + `,width:G,height:K}}function i8(u,f){let l=URL.createObjectURL(u),r=document.createElement("a");r.href=l,r.download=f,r.click(),setTimeout(()=>URL.revokeObjectURL(l),1000)}async function oz(u,f){let l=az(f,"pipeline"),{svg:r,width:y,height:i}=vD(u,f),_=new Blob([r],{type:"image/svg+xml;charset=utf-8"}),n=URL.createObjectURL(_);try{let $=new Image;await new Promise((U,q)=>{$.onload=()=>U(),$.onerror=()=>q(Error("svg image load failed")),$.src=n});let j=document.createElement("canvas");j.width=y,j.height=i;let F=j.getContext("2d");if(!F)throw Error("canvas unavailable");F.drawImage($,0,0);let J=await new Promise((U)=>j.toBlob(U,"image/png"));if(!J)throw Error("png export failed");i8(J,`${l}.png`)}catch{i8(_,`${l}.svg`)}finally{URL.revokeObjectURL(n)}}async function aD(u){let f=az(String(u?.title||"pipeline-gantt"),"pipeline-gantt"),{svg:l,width:r,height:y}=sD(u),i=new Blob([l],{type:"image/svg+xml;charset=utf-8"}),_=URL.createObjectURL(i);try{let n=new Image;await new Promise((J,U)=>{n.onload=()=>J(),n.onerror=()=>U(Error("gantt svg image load failed")),n.src=_});let $=document.createElement("canvas");$.width=r,$.height=y;let j=$.getContext("2d");if(!j)throw Error("canvas unavailable");j.drawImage(n,0,0);let F=await new Promise((J)=>$.toBlob(J,"image/png"));if(!F)throw Error("gantt png export failed");i8(F,`${f}.png`)}catch{i8(i,`${f}.svg`)}finally{URL.revokeObjectURL(_)}}async function oD(u){for(let f of u){if(f.flow.nodes.length===0)continue;await oz(f.flow,f.title),await new Promise((l)=>setTimeout(l,750))}}function Xz(u,f){return u.find((l)=>String(l?.pipelineId||"")===f)||null}function Yz(u){return hu(u?.startedAt)??hu(u?.artifact?.startedAt)??hu(u?.request?.createdAt)??hu(u?.updatedAt)??0}function dD(u,f){return u.filter((l)=>String(l?.pipelineId||"")===f).slice().sort((l,r)=>Yz(l)-Yz(r)||String(l?.runId||"").localeCompare(String(r?.runId||"")))}function jj(u,f){let l=String(f?.runId||""),r=u.findIndex((_)=>String(_?.runId||"")===l),y=r>=0?r+1:u.length,i=String(f?.status||"--");return`Epoch ${y} / ${l||"--"} / ${i}`}function Tr(u){return String(u?.procedureRunId||u?.runId||"")}function A8(u,f){let l=String(u?.nodeId||u?.request?.nodeId||"");if(l)return l;let r=Tr(u),y=`${f}__`;if(r.startsWith(y))return r.slice(y.length).replace(/__\d+$/u,"");return""}function a4(u,f){let l=Yu(u?.artifact)?u.artifact:{},r=Yu(u?.request)?u.request:{};return w$(u?.startedAt,l.startedAt,r.createdAt,r.startedAt,u?.createdAt,u?.updatedAt,f?.startedAt,f?.request?.createdAt)}function o4(u,f){let l=String(u?.status?.status||u?.artifact?.status||u?.status||"").toLowerCase(),r=Yu(u?.artifact)?u.artifact:{},y=Qj(l);return w$(u?.finishedAt,r.finishedAt,u?.completedAt,y?u?.updatedAt:void 0,y?r.updatedAt:void 0,y?f?.updatedAt:void 0)}function dz(u,f,l=Date.now()){let r=String(u?.runId||""),y=new Set(f.map((i)=>String(i?.id||"")).filter(Boolean));return Hu(u?.procedureRuns).flatMap((i)=>{let _=A8(i,r);if(!_)return[];let n=String(i?.status?.status||i?.artifact?.status||i?.status||"unknown").toLowerCase(),$=a4(i,u),j=hu($);if(j===null)return[];let F=o4(i,u),J=hu(F)??(Qj(n)?hu(i?.updatedAt)??j+1000:l),U=Math.max(j+1000,J);return[{nodeId:_,knownNode:y.has(_),procedureRunId:Tr(i),status:n,startMs:j,endMs:U,startedAt:G$(j),finishedAt:G$(U),durationMs:U-j,runId:r,raw:i}]}).sort((i,_)=>i.startMs-_.startMs||i.endMs-_.endMs||i.nodeId.localeCompare(_.nodeId))}function eD(u,f,l=[]){let r=f.map((F)=>Number(F.startMs)).filter(Number.isFinite),y=f.map((F)=>Number(F.endMs)).filter(Number.isFinite);for(let F of l){let J=Bf(F?.eventMs??F?.ms);if(J!==null)r.push(J),y.push(J)}let i=hu(u?.startedAt)??hu(u?.artifact?.startedAt)??hu(u?.request?.createdAt),_=hu(u?.finishedAt)??hu(u?.artifact?.finishedAt)??hu(u?.updatedAt);if(i!==null)r.push(i);if(_!==null)y.push(_);let n=Date.now(),$=r.length>0?Math.min(...r):n-60000,j=Math.max($+60000,y.length>0?Math.max(...y):n);return{startMs:$,endMs:j,durationMs:j-$}}var d4=12,ez=20,Fj=100,ut=!1;function t1(u){let f=Number(u);if(!Number.isFinite(f))return 0;return Math.max(0,Math.min(100,Math.round(f*100)/100))}function ft(u){let f=Math.max(d4,Number(u||d4)),l=Math.log(f/d4)/Math.log(ez);return t1(l*100)}var L$=ft(Fj);function Gj(u){let f=t1(u)/100,l=d4*Math.pow(ez,f),r=f<0.24?"全局":f<0.64?"均衡":"细节";return{value:t1(f*100),pxPerMinute:l,label:r}}function yj(u){let f=Math.round(Number(u));return Math.abs(f-Fj)<=1?Fj:f}function lt(u,f=L$){let l=Math.max(1,Number(u.durationMs||0)/60000),r=Gj(f);return Math.round(Math.max(360,Math.min(7200,l*Number(r.pxPerMinute||48))))}function rt(u,f=7){let l=Math.max(1,Number(u.endMs||0)-Number(u.startMs||0));return Array.from({length:f},(r,y)=>{let i=f===1?0:y/(f-1);return{ms:Number(u.startMs)+l*i,percent:i*100}})}function yt(u,f){let l=Math.max(1,Number(f.endMs)-Number(f.startMs));return Math.max(0,Math.min(100,(u-Number(f.startMs))/l*100))}function Bf(u){let f=Number(u);return Number.isFinite(f)?f:null}function Kj(u){return pz(u?.status)&&!Qj(u?.status)}function uG(u,f,l,r){let y=Math.max(1,l-f),i=Math.max(0,Math.min(1,(u-f)/y));return Number((i*r).toFixed(3))}function Dz(u,f){if(!f)return null;let l=Bf(f?.startMs),r=Bf(f?.endMs),y=Bf(f?.chartHeight);if(l===null||r===null||y===null)return null;return uG(u,l,r,y)}function fG(u,f){let l=Bf(u?.rawStartMs??u?.startMs)??Bf(u?.startMs)??f,r=Bf(u?.endMs)??l+1000;if(!Kj(u))return Math.max(l+1000,r);return Math.max(l+1000,r,f)}function it(u,f,l,r){let y=Bf(u?.startMs)??r-60000,i=Bf(u?.endMs)??r,_=l.reduce((W,G)=>Math.max(W,fG(G,r)),i),n=Math.max(y+60000,i,_),$=Math.max(1,n-y),j={startMs:y,endMs:n,durationMs:$},F=lt(j,f),J=Gj(f),U=Math.max(5,Math.min(18,Math.round(F/150))),q=rt(j,U).map((W)=>{let G=Number(W.ms),K=uG(G,y,n,F);return{...W,y:K,timestamp:G$(G),offsetMs:G-y}});return{source:"frontend-y",startMs:y,endMs:n,durationMs:$,chartHeight:F,scale:t1(f),normalizedScale:Number((t1(f)/100).toFixed(3)),pxPerMinute:Number(Number(J.pxPerMinute||0).toFixed(3)),ticks:q}}function _t(u,f,l){if(!Kj(u))return u;let r=Bf(u?.rawStartMs??u?.startMs)??Bf(u?.startMs)??l,y=fG(u,l),i=Dz(r,f),_=Dz(y,f),n=Bf(i??u?.y1??u?.startY)??0,$=Bf(_??u?.y2??u?.endY)??n+10,j=Math.max(24,$-n);return{...u,live:!0,startMs:r,endMs:y,durationMs:Math.max(1000,y-r),finishedAt:G$(y),y1:n,y2:$,startY:n,endY:$,height:j}}function Lj(u,f,l){return yt(u,f)/100*l}function di(u){return Boolean(u&&String(u?.source||"")!=="frontend-y")}function lG(u,f,l,r,y){if(di(r))for(let _ of y){let n=Bf(u?.[_]);if(n!==null)return n}let i=Bf(u?.ms??u?.eventMs??u?.startMs);return Lj(i??Number(f.startMs),f,l)}function _8(u,f,l,r){return lG(u,f,l,r,["y1","startY"])}function Jj(u,f,l,r){if(di(r)){let i=Bf(u?.y2??u?.endY);if(i!==null)return i}let y=Bf(u?.endMs)??Number(f.endMs);return Lj(y,f,l)}function rG(u,f,l,r){if(di(r)){let i=Bf(u?.height);if(i!==null)return Math.max(1,i)}let y=u?.live?24:10;return Math.max(y,Jj(u,f,l,r)-_8(u,f,l,r))}function nr(u,f,l,r){return lG(u,f,l,r,["y","timeAxisY"])}function yG(u,f,l,r){if(di(r)||String(r?.source||"")==="frontend-y"){let _=Bf(u?.y);if(_!==null)return _}let y=Bf(u?.percent);if(y!==null)return y/100*l;let i=Bf(u?.ms)??Number(f.startMs);return Lj(i,f,l)}function nt(u){let f=String(u?.promptEvent||u?.raw?.promptEvent||u?.event||"").toLowerCase();if(!["node-long-running-observation","node-finished"].includes(f))return"";let l=String(u?.sourceNodeId||u?.raw?.sourceNodeId||u?.raw?.detail?.nodeId||""),r=String(u?.nodeId||u?.targetNodeId||"");return l&&l!==r?l:""}function $t(u,f){let l=new Set(f.map((y)=>[String(y.sourceNodeId||""),String(y.targetNodeId||""),String(y.targetMarkerId||""),String(y.action||"")].join(":"))),r=[...f];for(let y of u){let i=nt(y),_=String(y?.nodeId||""),n=String(y?.id||"");if(!i||!_||!n)continue;let $=[i,_,n,"observe"].join(":");if(l.has($))continue;l.add($),r.push({id:`observation-arrow:${n}:${i}:${_}`,commandId:String(y?.commandId||y?.eventId||n),sourceNodeId:i,targetNodeId:_,sourceMarkerId:"",targetMarkerId:n,sourceKind:"monitor",action:"observe",status:"observation"})}return{markers:u,arrows:r}}function tz(u,f=""){let l=xr(u)||f,r=String(u?.promptEvent||"");if(l==="initial-prompt-delivered")return"initial";if(r==="node-finished"||r==="node-long-running-observation"||r.startsWith("monitor-"))return"monitor";if(l==="monitor-prompt-delivered"||String(u?.sourceKind||"").toLowerCase()==="monitor"||f==="monitor-prompt-queued")return"monitor";return"append"}function At(u){return Hu(u?.tags||u?.raw?.tags).map((f)=>String(f||"")).filter(Boolean)}function Sz(u,f=""){let l=xr(u)||f,r=String(u?.promptEvent||"");if(l==="initial-prompt-delivered")return"初始 prompt";if(r==="node-long-running-observation")return"长任务观察";if(r==="node-finished")return At(u).includes("monitor.audit")?"节点完成 / OA 审核":"节点完成";if(r==="monitor-interval")return"旧版轮询";if(r==="monitor-start")return"Monitor start";if(r==="monitor-stop")return"Monitor stop";if(l==="monitor-prompt-delivered"||f==="monitor-prompt-queued")return"Monitor prompt";if(l==="append-prompt-queued")return"追加 prompt 已排队";return"追加 prompt"}function Pz(u){let f=xr(u);if(f==="control-command-applied")return 3;if(f==="control-command-ignored")return 2;if(f==="control-command-queued")return 1;return 0}function Mz(u,f){let l=String(u?.commandId||"");if(l)return`command:${l}`;return["fallback",Hy(u)||w$(u?.createdAt,u?.timestamp)||`index-${f}`,String(u?.sourceKind||""),String(u?.sourceNodeId||""),String(u?.targetNodeId||""),Oy(u)].join(":")}function jt(u){return $j([u?.targetNodeId,...Hu(u?.resetNodeIds)])}function Ft(u,f){let l=N$(u),r=xr(u),y=String(u?.targetNodeId||""),i=Boolean(y)&&f!==y;if(r==="control-command-applied")return i?`${l} 波及`:`${l} 生效`;if(r==="control-command-ignored")return`${l} 忽略`;if(r==="control-command-queued")return`${l} 已发起`;return i?`${l} 波及`:l}function Jt(u){if(xr(u)==="control-command-ignored")return"ignored";let l=Oy(u);if(l==="restart"||l==="redo")return"restart";if(l==="modify")return"modify";if(l==="approve")return"approve";if(l==="guide")return"guide";return"pending"}function Ut(u){let f=String(u?.sourceKind||"").toLowerCase();if(f==="monitor")return"monitor";if(f==="webui")return"webui";if(f==="cli")return"cli";return"system"}function Qt(u,f,l,r){let y=u.filter((j)=>String(j.nodeId||"")===f).sort((j,F)=>Number(j.startMs)-Number(F.startMs)),i=y.find((j)=>l>=Number(j.startMs)-1000&&l<=Number(j.endMs)+1000);if(i)return{ms:l,onInterval:!0,snapReason:"inside-interval",procedureRunId:String(i.procedureRunId||"")};let _=Oy(r),n=y.slice().reverse().find((j)=>Number(j.endMs)<=l+1000);if(n&&_==="approve")return{ms:Number(n.endMs),onInterval:!0,snapReason:"previous-interval-end",procedureRunId:String(n.procedureRunId||"")};let $=y.find((j)=>Number(j.startMs)>=l-1000);if($&&["guide","modify","restart","redo"].includes(_))return{ms:Number($.startMs),onInterval:!0,snapReason:"next-interval-start",procedureRunId:String($.procedureRunId||"")};return{ms:l,onInterval:!1,snapReason:"event-time",procedureRunId:String(r?.procedureRunId||"")}}function iG(u,f,l,r){let y=Math.hypot(l-u,r-f),i=y>Wz?Wz:0,_=i>0?l-(l-u)/y*i:l,n=i>0?r-(r-f)/y*i:r,$=_-u,j=Math.max(16,Math.min(42,Math.abs($)*0.45+12)),F=$===0?1:Math.sign($);return`M ${u},${f} C ${u+F*j},${f} ${_-F*j},${n} ${_},${n}`}function qt(u,f){let l=String(u?.runId||f?.runId||""),r=dz({...Yu(f)?f:{},...Yu(u)?u:{},runId:l,procedureRuns:Hu(u?.procedureRuns).length>0?u.procedureRuns:f?.procedureRuns},[]),y=[],i=[],_=[],n=new Set,$=new Map,j=(U,q)=>{if(!U.nodeId||!Number.isFinite(Number(U.ms)))return;if(n.has(U.id))return;n.add(U.id),q.push(U)};for(let U of Hu(u?.procedureRuns)){let q=A8(U,l),W=Tr(U);if(!q)continue;for(let G of Hu(U?.attempts)){let K=$8(G),Q=new Set,N=new Set;for(let z of c$(G?.controlEventRecords)){let w=xr(z);if(!["initial-prompt-delivered","append-prompt-delivered","monitor-prompt-delivered"].includes(w))continue;let H=Hy(z),B=hu(H);if(B===null)continue;let T=String(z?.eventId||"");if(T)Q.add(T);N.add(`${w}:${H}:${String(z?.sourceKind||"")}:${String(z?.promptPreview||"")}`),j({id:`prompt:${T||`${W}:${K}:${w}:${B}`}`,runId:l,nodeId:q,procedureRunId:W,attempt:K,kind:"prompt",tone:tz(z,w),status:"delivered",label:Sz(z,w),ms:B,timestampIso:H,sourceKind:String(z?.sourceKind||""),sourceNodeId:String(z?.sourceNodeId||""),targetNodeId:q,action:"",eventId:T,commandId:String(z?.commandId||""),raw:z},y)}let c=[{records:c$(G?.controlPromptRecords),fallbackKind:"append-prompt-queued"},{records:c$(G?.monitorPromptRecords),fallbackKind:"monitor-prompt-queued"}];for(let z of c)for(let w of z.records){let H=Hy(w),B=hu(H);if(B===null)continue;let T=String(w?.eventId||"");if(T&&Q.has(T))continue;let R=`${z.fallbackKind==="monitor-prompt-queued"?"monitor-prompt-delivered":"append-prompt-delivered"}:${H}:${String(w?.sourceKind||"")}:${String(w?.promptPreview||"")}`;if(N.has(R))continue;j({id:`prompt-fallback:${T||`${W}:${K}:${z.fallbackKind}:${B}`}`,runId:l,nodeId:q,procedureRunId:W,attempt:K,kind:"prompt",tone:tz(w,z.fallbackKind),status:"queued",label:Sz(w,z.fallbackKind),ms:B,timestampIso:H,sourceKind:String(w?.sourceKind||""),sourceNodeId:String(w?.sourceNodeId||""),targetNodeId:q,action:"",eventId:T,commandId:String(w?.commandId||""),raw:w},y)}}}let F=new Map;c$(u?.controlEvents).forEach((U,q)=>{let W=Mz(U,q),G=F.get(W)||{key:W,events:[],commands:[]};G.events.push(U),F.set(W,G)}),Hu(u?.controlCommands).filter(Yu).forEach((U,q)=>{let W=Mz(U,q),G=F.get(W)||{key:W,events:[],commands:[]};G.commands.push(U),F.set(W,G)});for(let U of F.values()){let q=Hu(U.events).slice().sort((P,t)=>Pz(t)-Pz(P)),W=Hu(U.commands),G=Hu(U.events).find((P)=>xr(P)==="control-command-queued")||W[0]||null,K=q[0]||W[0]||G;if(!G&&!K)continue;let Q=String(G?.sourceNodeId||K?.sourceNodeId||""),N=String(G?.sourceKind||K?.sourceKind||""),c=Hy(G)||Hy(K)||w$(G?.createdAt,K?.createdAt),z=hu(c),w=String(K?.commandId||G?.commandId||U.key),H=(xr(K)||"control-command-queued").replace(/^control-command-/u,""),B="";if(Q&&z!==null)B=`control-source:${w}:${Q}`,$.set(w,B),j({id:B,runId:l,nodeId:Q,procedureRunId:String(G?.procedureRunId||K?.procedureRunId||""),attempt:"",kind:"control-source",tone:Ut(G||K),status:H,label:`${N$(G||K)} 发起`,ms:z,timestampIso:c,action:Oy(G||K),sourceKind:N,sourceNodeId:Q,targetNodeId:String(K?.targetNodeId||G?.targetNodeId||""),commandId:w,raw:G||K},i);let T=K||G,X=Hy(T)||c,R=hu(X);if(R===null)continue;let Y=jt(T);for(let P of Y){let t=Qt(r,P,R,T),O=`control-target:${w}:${P}`;if(j({id:O,runId:l,nodeId:P,procedureRunId:t.procedureRunId,attempt:"",kind:"control-target",tone:Jt(T),status:H,label:Ft(T,P),ms:t.ms,eventMs:R,onInterval:t.onInterval,snapReason:t.snapReason,snapped:Number(t.ms)!==R,timestampIso:X,renderedTimestampIso:G$(Number(t.ms)),action:Oy(T),sourceKind:N,sourceNodeId:Q,targetNodeId:P,commandId:w,raw:T},i),B&&Q&&Q!==P)_.push({id:`control-arrow:${w}:${Q}:${P}`,commandId:w,sourceNodeId:Q,targetNodeId:P,sourceMarkerId:B,targetMarkerId:O,sourceKind:N,action:Oy(T),status:H})}}let J=[...y,...i].sort((U,q)=>Number(U.ms)-Number(q.ms)||String(U.nodeId).localeCompare(String(q.nodeId))||String(U.id).localeCompare(String(q.id)));return{...$t(J,_),sourceMarkerByCommand:$}}function Wt({details:u,selectedNodeId:f,selectedNodeRuntime:l,control:r,onRaw:y}){if(!u)return L("span",{className:"muted"},"点击“抓取过程”读取 node 运行材料;主界面只显示结构化摘要,完整内容需点开原始 JSON。");let i=Hu(u.procedureRuns),_=i.at(-1)||{},n=Hu(_.attempts),$=n.at(-1)||{},j=Hu(_.workerLogTail),F=Hu($.controlEventsTail),J=Hu($.controlPromptsTail),U=Hu($.monitorPromptsTail),q=uj(F),W=uj(J),G=uj(U),K=$.opencodeMessages||{};return L("div",{className:"pipeline-evidence-list compact"},L(wr,{title:"Node runtime",subtitle:f||"--",facts:[`status ${l?.status||"pending"}`,`attempts ${l?.attempts??n.length}`,`procedure ${l?.currentProcedureRunId||Tr(_)||"--"}`,r.fetchedAt?`fetched ${qf(r.fetchedAt)}`:"not fetched"],data:u.node||u,onRaw:y,testId:"raw-pipeline-node-runtime"}),L(wr,{title:"Procedure runs",subtitle:`${i.length} groups`,facts:[`latest ${_.status?.status||_.status||"--"}`,`steps ${Hu(_.recentSteps).length}`,`duration ${Er(hu(_.finishedAt)&&hu(_.startedAt)?Number(hu(_.finishedAt))-Number(hu(_.startedAt)):_.durationMs)}`],data:i,onRaw:y,testId:"raw-pipeline-node-procedures"}),L(wr,{title:"OpenCode messages",subtitle:String(K.exists?"available":"not indexed"),facts:[`messages ${u8(K.messageCount)}`,`size ${u8(K.size)}`,`updated ${Nu(K.updatedAt)}`],data:K,onRaw:y,testId:"raw-pipeline-node-messages"}),L(wr,{title:"Control prompts",subtitle:"manual / monitor append queues",facts:[`manual tail ${W.total}`,`monitor tail ${G.total}`,`last ${Nu(Uj(W.lastAt,G.lastAt))}`],data:{controlPromptsTail:J,monitorPromptsTail:U},onRaw:y,testId:"raw-pipeline-node-prompts"}),L(wr,{title:"Control events",subtitle:q.eventKinds.length>0?q.eventKinds.join(", "):"event tail",facts:[`tail ${q.total}`,`parsed ${q.parsed}`,`last ${Nu(q.lastAt)}`],data:F,onRaw:y,testId:"raw-pipeline-node-events"}),L(wr,{title:"Worker log",subtitle:"tail is hidden on main canvas",facts:[`tail ${j.length} lines`,"raw only via button",`procedure ${Tr(_)||"--"}`],data:j,onRaw:y,testId:"raw-pipeline-node-worker-log"}))}function ct({activeRun:u,onRaw:f}){if(!u)return L($r,{title:"暂无运行材料",text:"没有 Pipeline epoch 时不会展示运行材料索引。"});let l=Hu(u.nodes),r=Hu(u.procedureRuns),y=Hu(u.submissions),i=Hu(u.workerLogTail),_=zz(l),n=zz(r),$=r.filter((F)=>String(F?.status||"").toLowerCase()==="failed"),j=Uj(...r.flatMap((F)=>[F.updatedAt,F.finishedAt,F.startedAt]));return L("div",{className:"pipeline-evidence-list"},L(wr,{title:"Epoch overview",subtitle:u.runId||"--",facts:[`pipeline ${u.pipelineId||"--"}`,`status ${u.status||"--"}`,`started ${Nu(u.startedAt)}`,`updated ${Nu(u.updatedAt)}`],data:u,onRaw:f,testId:"raw-pipeline-run"}),L(wr,{title:"Node states",subtitle:`${l.length} nodes`,facts:[`running ${_.running||0}`,`succeeded ${_.succeeded||0}`,`failed ${_.failed||0}`,`pending ${_.pending||0}`],data:l,onRaw:f,testId:"raw-pipeline-run-nodes"}),L(wr,{title:"Procedure run index",subtitle:`${r.length} procedure records`,facts:[`succeeded ${n.succeeded||0}`,`failed ${n.failed||0}`,`latest ${Nu(j)}`,`errors ${$.length}`],data:r,onRaw:f,testId:"raw-pipeline-run-procedures"}),L(wr,{title:"OA submissions",subtitle:`${y.length} submission files`,facts:[`records ${y.length}`,`task ${u8(u.task)}`,"raw grouped by run"],data:y,onRaw:f,testId:"raw-pipeline-run-submissions"}),L(wr,{title:"Worker log tail",subtitle:"hidden from main interface",facts:[`tail ${i.length} lines`,"display raw only after click",`updated ${Nu(u.updatedAt)}`],data:i,onRaw:f,testId:"raw-pipeline-run-worker-log"}))}function Nt({diagnostics:u,onRaw:f}){let l=Hu(u?.runs).filter(Yu),r=Hu(u?.forbiddenResiduals),y=Yu(u?.guarantees)?u.guarantees:{},i=u?.hasNeutralNodeFinishedEvidence===!0&&u?.hasNoAuditPolicyEvidence===!0&&u?.hasAuditPolicyEvidence===!0,_=u?.ok===!0&&i&&r.length===0,n=l[0]||null,$=[{label:"中性完成事实",ok:y.neutralNodeFinished===!0,hint:"node-finished 不携带流程策略"},{label:"Config 策略判定",ok:y.auditPolicyFromConfig===!0,hint:"OA backend 读取当前 epoch 配置"},{label:"控制命令来自 OA",ok:y.runnerConsumesControlCommandsFromOaEvents===!0,hint:"runner 只消费 OA control.command"},{label:"无独立审核事件",ok:y.noIndependentAuditRequestEvent===!0,hint:"审核由 node-finished + policy 派生"},{label:"无批次门禁",ok:y.noBatchFinishedControlGate===!0,hint:"下游启动由每个 node 完成驱动"}];return L("div",{className:"pipeline-oa-panel","data-testid":"pipeline-oa-event-flow-panel"},L("div",{className:"metric-grid compact"},L(Hl,{label:"OA Flow",value:_?"100%":"--",hint:String(u?.mode||"waiting diagnostics"),tone:_?"ok":"warn"}),L(Hl,{label:"禁止残留",value:r.length,hint:r.length===0?"source scan clean":"needs cleanup",tone:r.length===0?"ok":"warn"}),L(Hl,{label:"No-audit",value:u?.hasNoAuditPolicyEvidence?"OK":"--",hint:"OA 下游策略证据",tone:u?.hasNoAuditPolicyEvidence?"ok":"warn"}),L(Hl,{label:"Monitor 审核",value:u?.hasAuditPolicyEvidence?"OK":"--",hint:"OA 控制事件闭环",tone:u?.hasAuditPolicyEvidence?"ok":"warn"})),L("div",{className:"pipeline-oa-guarantees"},$.map((j)=>L("article",{key:j.label,className:`pipeline-oa-guarantee ${j.ok?"ok":"warn"}`},L(D1,{status:j.ok?"online":"warn"},j.ok?"OK":"MISS"),L("div",null,L("strong",null,j.label),L("span",null,j.hint))))),L("div",{className:"pipeline-evidence-list compact"},l.slice(0,6).map((j)=>L(wr,{key:j.runId,title:String(j.runId||"--"),subtitle:[Number(j.monitorAuditNodeFinishedCount||0)>0?"monitor audit":"",Number(j.noAuditPolicyCount||0)>0?"no-audit policy":""].filter(Boolean).join(" / ")||"event evidence",facts:[`events ${j.eventCount||0}`,`node-finished ${j.nodeFinishedCount||0}`,`policy-in-detail ${j.nodeFinishedWithPolicyCount||0}`,`queued ${j.controlQueuedCount||0}`,`applied ${j.controlAppliedCount||0}`],data:j,onRaw:f,testId:`raw-pipeline-oa-run-${String(j.runId||"run").replace(/[^a-zA-Z0-9_.-]+/g,"-")}`}))),n?L("p",{className:"muted paragraph"},`最新证据 ${n.runId}: ${n.nodeFinishedCount||0} 个 node-finished,${n.controlAppliedCount||0} 个控制结果。`):L($r,{title:"暂无 OA 事件流证据",text:"等待 Pipeline backend 暴露 diagnostics。"}),u?L("div",{className:"panel-actions inline-actions"},L(Rr,{title:"Pipeline OA Event Flow Diagnostics",data:u,onOpen:f,testId:"raw-pipeline-oa-event-flow"})):null)}function zt({quota:u,onRaw:f}){let l=Yu(u?.summary)?u.summary:{},r=Yu(u?.target)?u.target:{},y=Yu(u?.cache)?u.cache:{},i=u?.ok===!0,_=String(u?.modelId||l.modelName||r.modelName||"MiniMax-M2.7"),n=l.totalCount??r.currentIntervalTotalCount,$=l.usageCount??r.currentIntervalUsageCount,j=l.remainingCount??r.currentIntervalRemainingCount,F=l.remainingRatio??(Number.isFinite(Number(n))&&Number(n)>0&&Number.isFinite(Number(j))?Number(j)/Number(n):void 0),J=l.usageRatio??(Number.isFinite(Number(n))&&Number(n)>0&&Number.isFinite(Number($))?Number($)/Number(n):void 0),U=l.resetAt||r.endAt,q=l.remainsMs??r.remainsMs,W=Number(j),G=!i||Number.isFinite(W)&&W<=0?"warn":"ok",K=[i?`endpoint ${u?.endpoint||"--"}`:"quota unavailable",`fetched ${e4(u?.fetchedAt)}`,y.hit?`cache ${Er(y.ageMs)}`:"live quota"];return L("div",{className:"pipeline-minimax-quota-panel","data-testid":"pipeline-minimax-quota-panel"},L("div",{className:"metric-grid compact"},L(Hl,{label:"MiniMax",value:i?_:"--",hint:u?.modelComponent||u?.error||"model/minimax-m27",tone:G}),L(Hl,{label:"当前窗口",value:`${e7($)}/${e7(n)}`,hint:`已用 ${Nz(J)}`,tone:G}),L(Hl,{label:"剩余额度",value:e7(j),hint:`剩余 ${Nz(F)}`,tone:G}),L(Hl,{label:"重置时间",value:e4(U),hint:q!==void 0?`约 ${Er(q)}`:Nu(U),tone:G})),L(qj,{items:K}),i?L("p",{className:"muted paragraph"},`MiniMax 限额来自 D601 Pipeline 后端实时查询;当前模型匹配 ${l.modelName||r.modelName||_}。`):L(jf,{error:u?.error||"MiniMax 限额查询失败"}),u?L("div",{className:"panel-actions inline-actions"},L(Rr,{title:"Pipeline MiniMax Quota",data:u,onOpen:f,testId:"raw-pipeline-minimax-quota"})):null)}function Gt({epochs:u,activeRun:f,activePipeline:l,pipelineNodes:r,pipelineEdges:y,runDetails:i,nodeDetails:_,nodeDetailsState:n,ganttScale:$=L$,onGanttScaleChange:j,onRunChange:F,onIntervalSelect:J,onMarkerSelect:U,selection:q,detailOpen:W,onDetailOpenChange:G,onRaw:K}){let[Q,N]=xl(ut),[c,z]=xl({startY:0,endY:0,startMs:0,endMs:0}),[w,H]=xl(Date.now()),B=X1(null),T=String(f?.runId||""),X=Boolean(W),R=(ju)=>{if(typeof G==="function")G(ju)},Y=t1($??L$),P=String(i?.runId||"")===T?i?.details:null,t=P?{...Yu(f)?f:{},...Yu(P)?P:{},runId:T,procedureRuns:Hu(P?.procedureRuns).length>0?P.procedureRuns:f?.procedureRuns}:f,O=dz(t,r,w),M=P?qt(P,t):{markers:[],arrows:[]},S=Hu(M.markers),b=eD(t,O,S),Z=it(b,Y,O,w),D=String(Z.source||"frontend-y"),I=O.map((ju)=>_t(ju,Z,w)),k={startMs:Number(Z.startMs),endMs:Number(Z.endMs),durationMs:Math.max(1,Number(Z.durationMs??Number(Z.endMs)-Number(Z.startMs)))},h=Gj(Y),o={...h,pxPerMinute:Number(Z.pxPerMinute??h.pxPerMinute)},s=Math.round(Number(Z.chartHeight||360)),x=O.some(Kj);$0(()=>{if(!T||!x)return;let ju=window.setInterval(()=>H(Date.now()),1000);return()=>window.clearInterval(ju)},[T,x]);let uu=hD(l,r,Array.isArray(y)?y:[]),nu=r.map((ju)=>String(ju?.id||"")).filter(Boolean),$u=I.map((ju)=>String(ju.nodeId||"")).filter(Boolean),Fu=S.map((ju)=>String(ju.nodeId||"")).filter(Boolean),Ku=Array.from(new Set([...uu,...nu,...$u,...Fu])),Wu={startY:0,endY:s,startMs:Number(k.startMs),endMs:Number(k.endMs)},m=Number(c?.endY||0)>0?c:Wu,d=(ju)=>{return _8(ju,k,s,Z)<=Number(m.endY)&&Jj(ju,k,s,Z)>=Number(m.startY)},e=(ju)=>{let bu=nr(ju,k,s,Z);return bu>=Number(m.startY)&&bu<=Number(m.endY)},cu=new Set(Ku.filter((ju)=>I.some((bu)=>bu.nodeId===ju&&d(bu))||S.some((bu)=>bu.nodeId===ju&&e(bu)))),g=Q?Ku.filter((ju)=>cu.has(ju)):Ku,Qu=`${o7}px ${g.length>0?g.map(()=>`${_0}px`).join(" "):"minmax(160px, 1fr)"}`,Eu=Hu(Z.ticks).filter(Yu),Tu=String(q?.mode==="interval"?q?.interval?.procedureRunId||"":""),Du=String(q?.mode==="event"?q?.marker?.id||"":""),ff=()=>{let ju=B.current;if(!ju){z(Wu);return}let bu=Math.max(0,ju.scrollTop-d7),ul=Math.max(120,ju.clientHeight-d7),tu=Math.min(s,bu+ul),ou={startY:bu,endY:tu,startMs:Number(k.startMs),endMs:Number(k.endMs)},Al=Math.max(0,Math.min(1,bu/s)),Bl=Math.max(Al,Math.min(1,tu/s)),sf=Math.max(1,Number(k.endMs)-Number(k.startMs));ou.startMs=Number(k.startMs)+sf*Al,ou.endMs=Number(k.startMs)+sf*Bl,z(ou)};$0(()=>{let ju=B.current,bu=window.setTimeout(ff,0);return ju?.addEventListener("scroll",ff),window.addEventListener("resize",ff),()=>{window.clearTimeout(bu),ju?.removeEventListener("scroll",ff),window.removeEventListener("resize",ff)}},[T,k.startMs,k.endMs,s]);let rf=Math.max(0,Ku.length-g.length),Lf=new Set(S.filter((ju)=>g.includes(String(ju.nodeId||""))&&e(ju)).map((ju)=>String(ju.id))),gf=new Map(S.map((ju)=>[String(ju.id),ju])),jr=Hu(M.arrows).filter((ju)=>{if(!Lf.has(String(ju.targetMarkerId||"")))return!1;if(String(ju.action||"")==="observe")return g.includes(String(ju.sourceNodeId||""));return Lf.has(String(ju.sourceMarkerId||""))}),Ol=o7+Math.max(1,g.length)*_0,ef=(ju)=>{let bu=t1(ju.target.value);if(typeof j==="function")j(bu);window.setTimeout(ff,0)},hr=()=>aD({title:`${l?.id||"pipeline"}-${T||"epoch"}-gantt`,meta:[`run ${T||"--"}`,`${Nu(k.startMs)} -> ${Nu(k.endMs)}`,`duration ${Er(k.durationMs)}`,`${o.label} / ${yj(o.pxPerMinute)} px/min`,`${g.length}/${Ku.length} nodes`,`${S.length} markers`],visibleNodeIds:g,intervals:I,markers:S.filter((ju)=>g.includes(String(ju.nodeId||""))),arrows:jr,ticks:Eu,bounds:k,chartHeight:s,backendLayout:Z}),vl=Yu(P?.gantt?.diagnostics)?P.gantt.diagnostics:null;return L(n0,{title:"Epoch 甘特图",eyebrow:`${l?.id||"pipeline"} / ${u.length} epochs`,className:"pipeline-wide-panel",loading:i?.loading,actions:L("div",{className:"pipeline-gantt-actions"},L("select",{value:T,disabled:u.length===0,onChange:(ju)=>F(ju.target.value),"data-testid":"pipeline-epoch-select"},u.map((ju)=>L("option",{key:ju.runId,value:ju.runId},jj(u,ju)))),L("label",{className:"pipeline-gantt-toggle"},L("input",{type:"checkbox","data-testid":"pipeline-gantt-auto-hide-idle",checked:Q,onChange:(ju)=>{N(Boolean(ju.target.checked)),window.setTimeout(ff,0)}}),L("span",null,"自动隐藏空闲列")),L("label",{className:"pipeline-gantt-scale"},L("span",null,L("b",null,"时间尺度"),L("em",{"data-testid":"pipeline-gantt-scale-label"},`${o.label} · ${yj(o.pxPerMinute)} px/min`)),L("input",{type:"range",min:0,max:100,step:0.01,value:Y,onChange:ef,"aria-label":"调整甘特图时间尺度","data-testid":"pipeline-gantt-time-scale"}),L("small",null,L("span",null,"全局"),L("span",null,"细节"))),f?L("button",{type:"button",className:"ghost-btn",onClick:hr,disabled:g.length===0,"data-testid":"pipeline-export-gantt"},"导出甘特图"):null,f?L(Rr,{title:`Pipeline Epoch ${f.runId}`,data:f,onOpen:K,testId:"raw-pipeline-epoch-gantt"}):null)},!f?L($r,{title:"暂无 Epoch",text:"当前 pipeline 还没有完整运行记录。"}):I.length===0?L($r,{title:"暂无时间区间",text:"等待 D601 Pipeline backend 在 procedure summary 中返回 startedAt / finishedAt。"}):L("div",{className:"pipeline-gantt-wrap"},L("div",{className:`pipeline-gantt-detail-layout ${X?"detail-open":"detail-collapsed"}`,"data-testid":"pipeline-gantt-detail-layout","data-sidebar-open":X?"true":"false"},L("div",{className:"pipeline-gantt-main"},L("div",{className:"pipeline-gantt-main-head"},L("div",{className:"pipeline-gantt-meta"},L("span",null,`time ${Nu(k.startMs)} -> ${Nu(k.endMs)}`),L("span",null,`duration ${Er(k.durationMs)}`),L("span",null,`scale ${o.label} / ${yj(o.pxPerMinute)} px/min`),L("span",null,`layout ${D}`),vl?L("span",null,`align ${vl.timeAxisAlignmentOk===!1?"check":"ok"}`):null,L("span",null,`visible ${g.length}/${Ku.length} nodes`),P?L("span",null,`markers ${S.length}`):null,Q&&rf>0?L("span",null,`hidden idle ${rf}`):null),!X?L("button",{type:"button",className:"pipeline-sidecar-tab right",disabled:!q?.mode,onClick:()=>R(!0),"data-testid":"pipeline-gantt-sidebar-toggle"},q?.mode?"展开详情":"点击甘特图元素展开详情"):null),L("div",{className:"pipeline-gantt-viewport",ref:B,"data-testid":"pipeline-epoch-gantt","data-pipeline-id":l?.id||"","data-run-id":T,"data-layout-source":D,"data-start-ms":String(k.startMs),"data-end-ms":String(k.endMs),"data-chart-height":String(s)},L("div",{className:"pipeline-gantt-board",style:{gridTemplateColumns:Qu,minWidth:`${Ol}px`}},L("div",{className:"pipeline-gantt-head time"},"Time"),g.length===0?L("div",{className:"pipeline-gantt-head empty"},"当前时间窗无工作节点"):g.map((ju)=>L("div",{key:`head-${ju}`,className:"pipeline-gantt-head node",title:ju,"data-testid":"pipeline-gantt-head-node","data-node-id":ju},L(ED,{value:ju}))),L("div",{className:"pipeline-gantt-time-axis",style:{height:`${s}px`}},Eu.map((ju)=>{let bu=yG(ju,k,s,Z);return L("div",{key:`tick-${ju.ms}-${bu}`,className:"pipeline-gantt-tick",style:{top:`${bu}px`},"data-testid":"pipeline-gantt-tick","data-ms":String(ju.ms),"data-y":String(bu)},L("b",null,Nu(ju.ms)),L("span",null,`+${Er(Number(ju.offsetMs??Number(ju.ms)-Number(k.startMs)))}`))})),g.length>0?L("svg",{className:"pipeline-gantt-arrow-layer",width:g.length*_0,height:s,viewBox:`0 0 ${g.length*_0} ${s}`,style:{left:`${o7}px`,top:`${d7}px`,width:`${g.length*_0}px`,height:`${s}px`},"aria-hidden":"true"},L("defs",null,L("marker",{id:"pipeline-gantt-arrowhead",viewBox:"0 0 10 10",refX:9,refY:5,markerWidth:6,markerHeight:6,orient:"auto-start-reverse"},L("path",{d:"M 0 0 L 10 5 L 0 10 z",fill:"context-stroke"}))),jr.map((ju)=>{let bu=gf.get(String(ju.targetMarkerId||""));if(!bu)return null;let ul=gf.get(String(ju.sourceMarkerId||"")),tu=String(ul?.nodeId||ju.sourceNodeId||""),ou=g.indexOf(tu),Al=g.indexOf(String(bu.nodeId||""));if(ou<0||Al<0)return null;let Bl=ou*_0+_0/2,sf=Al*_0+_0/2,Il=ul?nr(ul,k,s,Z):nr(bu,k,s,Z),Fr=nr(bu,k,s,Z);return L("path",{key:ju.id,className:`pipeline-gantt-arrow ${String(ju.sourceKind||"").toLowerCase()} ${String(ju.status||"").toLowerCase()} ${String(ju.action||"").toLowerCase()}`,d:iG(Bl,Il,sf,Fr),markerEnd:"url(#pipeline-gantt-arrowhead)","data-testid":String(ju.action||"")==="observe"?"pipeline-gantt-observation-arrow":"pipeline-gantt-arrow","data-source-node-id":String(ju.sourceNodeId||""),"data-target-node-id":String(ju.targetNodeId||""),"data-target-marker-id":String(ju.targetMarkerId||""),"data-action":String(ju.action||""),"data-source-y":String(Il),"data-target-y":String(Fr)})})):null,g.length===0?L("div",{className:"pipeline-gantt-empty-col",style:{height:`${s}px`}},"滚动到有活动的时间段后,相关 node 列会自动出现。"):g.map((ju)=>{let bu=I.filter((tu)=>tu.nodeId===ju),ul=S.filter((tu)=>String(tu.nodeId||"")===ju);return L("div",{key:`col-${ju}`,className:"pipeline-gantt-node-col",style:{height:`${s}px`}},bu.map((tu)=>{let ou=_8(tu,k,s,Z),Al=Jj(tu,k,s,Z),Bl=rG(tu,k,s,Z),sf=String(tu.procedureRunId||`${ju}-${tu.startMs}`);return L("button",{key:sf,type:"button",className:`pipeline-gantt-bar ${tu.status} ${tu.live?"live":""} ${Tu===sf?"selected":""}`,style:{top:`${ou}px`,height:`${Bl}px`},title:`${ju} ${tu.status} ${Nu(tu.startedAt||tu.startMs)} -> ${Nu(tu.finishedAt||tu.endMs)}`,onClick:()=>J(tu),"data-testid":"pipeline-gantt-line","data-node-id":ju,"data-procedure-run-id":String(tu.procedureRunId||""),"data-status":String(tu.status||""),"data-live":tu.live?"true":"false","data-start-ms":String(tu.startMs||""),"data-end-ms":String(tu.endMs||""),"data-y1":String(ou),"data-y2":String(Al),"data-natural-height":String(Math.max(0,Al-ou))},L("strong",null,tu.status||"working"),L("span",null,Er(tu.durationMs)))}),ul.map((tu)=>L("button",{key:tu.id,type:"button",className:`pipeline-gantt-marker ${tu.kind} ${tu.tone||""} ${tu.status||""} ${Du===String(tu.id)?"selected":""}`,style:{top:`${nr(tu,k,s,Z)}px`},title:`${tu.label||"event"} / ${Nu(tu.timestampIso||tu.timestamp||tu.ms)}`,onClick:()=>U(tu),"data-testid":tu.kind==="prompt"?"pipeline-gantt-prompt-marker":"pipeline-gantt-control-marker","data-marker-id":String(tu.id||""),"data-ms":String(tu.ms??tu.eventMs??""),"data-y":String(nr(tu,k,s,Z))})))})))),X?L(wD,{selection:q,runDetails:i,nodeDetails:_,nodeDetailsState:n,onRaw:K,onCollapse:()=>R(!1)}):null)))}function t0(){return{loading:!1,actionLoading:"",error:"",message:"",details:null,fetchedAt:null,appendPrompt:"",guidePrompt:"",modifyPrompt:"",approveReason:"",redoReason:""}}function V1(){return{mode:"",runId:"",interval:null,marker:null}}function ij(){return{runId:"",loading:!1,error:"",details:null,fetchedAt:null}}function Q$(u,f){return`${u}/microservices/pipeline/proxy${f}`}function Kt({activeRun:u,pipelineRuns:f,selectedRunId:l,onRunChange:r,selectedNodeId:y,selectedNodeConfig:i,selectedNodeRuntime:_,control:n,onControlChange:$,onFetch:j,onAction:F,onRaw:J,onCollapse:U}){let q=String(u?.runId||""),W=String(_?.status||"pending"),G=!q||!y||n.loading||Boolean(n.actionLoading),K=(N)=>(c)=>$({[N]:c.target.value,error:"",message:""}),Q=f.length>0?f:u?[u]:[];return L("aside",{className:"pipeline-node-control","data-testid":"pipeline-node-control"},L("div",{className:"pipeline-node-control-head"},L("div",null,L("p",{className:"panel-eyebrow"},"Manual Node Control"),L(Af,{title:y||"点击控制图中的 node",level:3,loading:n.loading||Boolean(n.actionLoading)})),L("div",{className:"pipeline-node-control-head-actions"},y?L(D1,{status:W},W):L(D1,{status:"pending"},"idle"),L("button",{type:"button",className:"ghost-btn mini",onClick:U,"data-testid":"pipeline-node-sidebar-collapse"},"收起"))),L("div",{className:"pipeline-control-runbar"},L("label",null,L("span",null,"目标 run"),L("select",{value:q||l,disabled:Q.length===0,onChange:(N)=>r(N.target.value),"data-testid":"pipeline-node-run-select"},Q.map((N)=>L("option",{key:N.runId,value:N.runId},`${N.runId||"--"} / ${N.status||"--"}`)))),L("button",{type:"button",className:"ghost-btn",disabled:G,onClick:j,"data-testid":"pipeline-node-fetch"},n.loading?"抓取中":"抓取过程"),n.details?L(Rr,{title:`Pipeline Node ${y}`,data:n.details,onOpen:J,testId:"raw-pipeline-node-control"}):null),L("div",{className:"pipeline-control-meta"},L("span",null,L("b",null,"kind"),String(i?.kind||"--")),L("span",null,L("b",null,"procedure"),String(_?.currentProcedureRunId||"--")),L("span",null,L("b",null,"attempts"),String(_?.attempts??"--")),L("span",null,L("b",null,"updated"),Nu(u?.updatedAt))),!y?L($r,{title:"未选择 node",text:"点击 React Flow 控制图中的任意 node 后,可抓取执行过程、追加 prompt、下发引导、增量修改、审核通过或重做。"}):null,L(jf,{error:n.error,wide:!0}),L("div",{className:"pipeline-control-actions"},L("label",null,L("span",null,"实时追加 prompt(仅 running node)"),L("textarea",{value:n.appendPrompt,onChange:K("appendPrompt"),placeholder:"让当前执行中的 agent 继续、补充检查或调整当前步骤...",rows:4,disabled:!y,"data-testid":"pipeline-node-append-input"}),L("button",{type:"button",className:"primary-btn compact",disabled:G||!String(n.appendPrompt||"").trim(),onClick:()=>F("append"),"data-testid":"pipeline-node-append-button"},n.actionLoading==="append"?"追加中":"追加到运行中 node")),L("label",null,L("span",null,"下次尝试引导 prompt"),L("textarea",{value:n.guidePrompt,onChange:K("guidePrompt"),placeholder:"给该 node 下一次 attempt 的执行提示;不会立即打断当前 session。",rows:4,disabled:!y,"data-testid":"pipeline-node-guide-input"}),L("button",{type:"button",className:"ghost-btn compact",disabled:G||!String(n.guidePrompt||"").trim(),onClick:()=>F("guide"),"data-testid":"pipeline-node-guide-button"},n.actionLoading==="guide"?"下发中":"下发 guide")),L("label",null,L("span",null,"完成后增量修改 prompt"),L("textarea",{value:n.modifyPrompt,onChange:K("modifyPrompt"),placeholder:"在该 node 已完成结果基础上追加修改要求;runner 会重跑目标 node,并保留同 node 既有 OA 输出作为上下文。",rows:4,disabled:!y,"data-testid":"pipeline-node-modify-input"}),L("button",{type:"button",className:"ghost-btn compact",disabled:G||!String(n.modifyPrompt||"").trim(),onClick:()=>F("modify"),"data-testid":"pipeline-node-modify-button"},n.actionLoading==="modify"?"排队中":"增量修改 node")),L("label",null,L("span",null,"Monitor 审核通过原因"),L("textarea",{value:n.approveReason,onChange:K("approveReason"),placeholder:"当流程配置开启 monitor 审核时,记录审核通过原因并释放后续 node。",rows:3,disabled:!y,"data-testid":"pipeline-node-approve-input"}),L("button",{type:"button",className:"primary-btn compact",disabled:G||!String(n.approveReason||"").trim(),onClick:()=>F("approve"),"data-testid":"pipeline-node-approve-button"},n.actionLoading==="approve"?"提交中":"审核通过")),L("label",null,L("span",null,"重做 / restart 原因"),L("textarea",{value:n.redoReason,onChange:K("redoReason"),placeholder:"说明为什么需要重做;runner 会重置目标 node 以及非 rework 下游 node。",rows:4,disabled:!y,"data-testid":"pipeline-node-redo-input"}),L("button",{type:"button",className:"danger-btn compact",disabled:G||!String(n.redoReason||"").trim(),onClick:()=>F("redo"),"data-testid":"pipeline-node-redo-button"},n.actionLoading==="redo"?"排队中":"重做 node"))),L("div",{className:"pipeline-control-evidence"},L("strong",null,"Node 过程索引"),L(Wt,{details:n.details,selectedNodeId:y,selectedNodeRuntime:_,control:n,onRaw:J})))}function _G({microservices:u,onRaw:f,apiBaseUrl:l="/api"}){let r=u.find((fu)=>fu.id==="pipeline")||null,[y,i]=xl({loading:!1,error:"",health:null,snapshot:null,oaDiagnostics:null,minimaxQuota:null,refreshedAt:null}),[_,n]=xl(""),[$,j]=xl(""),[F,J]=xl(""),[U,q]=xl(t0()),[W,G]=xl({}),[K,Q]=xl(V1()),[N,c]=xl(ij()),[z,w]=xl(L$),[H,B]=xl(!1),[T,X]=xl(!1),R=X1(0),{addNotification:Y}=wl(),P=X1(!1),t=X1(0),O=X1(""),M=X1({}),S=X1(""),b=X1("");async function Z(fu={}){let Zu=fu.silent===!0;if(!r)return;if(P.current)return;P.current=!0;let Lu=R.current+1;if(R.current=Lu,!Zu)i((ku)=>({...ku,loading:!0,error:""}));try{let ku=`__unideskArrayLimit=registry.components:80,runs:${_D}`,[Uf,vu,yf]=await Promise.all([B1(`${l}/microservices/pipeline/proxy/api/snapshot?${ku}`,{cache:"no-store"}),B1(`${l}/microservices/pipeline/proxy/api/oa-event-flow/diagnostics`,{cache:"no-store"}).catch((xf)=>({ok:!1,error:Bu(xf,"OA event flow diagnostics failed")})),B1(`${l}/microservices/pipeline/proxy/api/model-quota/minimax`,{cache:"no-store"}).catch((xf)=>({ok:!1,error:Bu(xf,"MiniMax quota failed")}))]);if(Lu!==R.current)return;let _f={ok:Uf?.ok!==!1,service:"pipeline-v2-control snapshot"};i({loading:!1,error:"",health:_f,snapshot:Uf,oaDiagnostics:vu,minimaxQuota:yf,refreshedAt:new Date})}catch(ku){if(Lu!==R.current)return;i((Uf)=>({...Uf,loading:!1,error:Bu(ku,"Pipeline 加载失败")}))}finally{P.current=!1}}$0(()=>{if(Z(),!r)return;let fu=()=>{if(g4())Z({silent:!0})},Zu=window.setInterval(()=>{fu()},qz),Lu=()=>{if(g4())fu()};return document.addEventListener("visibilitychange",Lu),()=>{window.clearInterval(Zu),document.removeEventListener("visibilitychange",Lu)}},[r?.id,r?.runtime?.providerStatus,l]);let D=TD(r),I=HD(r),k=ZD(r),h=y.snapshot||{},o=y.oaDiagnostics||null,s=y.minimaxQuota||null,{components:x,pipelines:uu,runs:nu}=OD(h),$u=String(nu[0]?.pipelineId||""),Fu=($u?uu.find((fu)=>String(fu.id||"")===$u):null)||uu[0]||{},Ku=uu.find((fu)=>String(fu.id||"")===_)||Fu,Wu=String(Ku.id||""),m=kz(Ku),d=cj(Ku),e=Xz(nu,Wu),cu=dD(nu,Wu),g=cu.find((fu)=>String(fu?.runId||"")===$)||e,Qu=String(N.runId||"")===String(g?.runId||"")?YD(N.details):null,Eu=DD(g,Qu),Tu=String(Eu?.runId||""),Du=m.find((fu)=>String(fu?.id||"")===F)||null,ff=F?gz(Eu,F):null,rf=VD(nu),Lf=MD(x),gf=Number(y.health?.components)||Ez(h,"registry.components",x.length),jr=Ez(h,"runs",nu.length),Ol=Hz(Ku,Eu,x),ef={nodes:Ol.nodes.map((fu)=>fu.id===F?{...fu,selected:!0,className:`${fu.className||""} selected-control-node`}:fu),edges:Ol.edges},hr=uu.map((fu)=>{let Zu=String(fu.id||"pipeline"),Lu=Xz(nu,Zu);return{title:`${Zu}-${Lu?.runId||"snapshot"}`,flow:Hz(fu,Lu,x)}}),vl=String(K?.runId||Tu||""),ju=String(K?.interval?.nodeId||K?.marker?.nodeId||""),bu=vl&&ju?W[rj(vl,ju)]||null:null,ul=f8(U.details,vl,ju),tu=f8(bu?.details,vl,ju)||ul,ou=vl&&ju?{...Yu(bu)?bu:{},runId:vl,nodeId:ju,details:tu,loading:Boolean(bu?.loading)||!tu&&Boolean(U.loading)&&F===ju,error:String(bu?.error||""),fetchedAt:bu?.fetchedAt||(ul?U.fetchedAt:null)}:null,Al=cu.map((fu)=>String(fu?.runId||"")).filter(Boolean).join("|"),Bl=m.map((fu)=>String(fu?.id||"")).filter(Boolean).join("|");$0(()=>{S.current=F},[F]),$0(()=>{b.current=Tu},[Tu]),$0(()=>{if(!$||Al.split("|").includes($))return;j("")},[$,Al]),$0(()=>{if(!F||Bl.split("|").includes(F))return;J(""),q(t0()),Q(V1()),B(!1),X(!1)},[F,Bl]),$0(()=>{if(!F)B(!1)},[F]),$0(()=>{if(!K.mode)X(!1)},[K.mode]);async function sf(fu=Tu,Zu={}){if(!fu){c(ij());return}let Lu=t1(Zu.scale??z??L$),ku=`${fu}:timeline`;if(O.current===ku)return;O.current=ku;let Uf=Zu.silent===!0,vu=t.current+1;t.current=vu,c((yf)=>({runId:fu,scale:Lu,loading:!Uf||String(yf.runId||"")!==fu||!yf.details,error:"",details:Uf&&yf.runId===fu?yf.details:yf.runId===fu?yf.details:null,fetchedAt:yf.runId===fu?yf.fetchedAt:null}));try{let[yf,_f]=await Promise.all([B1(Q$(l,`/api/node-control/runs/${encodeURIComponent(fu)}?tail=160&view=timeline`),{cache:"no-store",strictJson:!0}),B1(Q$(l,`/api/runs/${encodeURIComponent(fu)}`),{cache:"no-store"}).catch((xf)=>({ok:!1,runSummaryError:Bu(xf,"抓取评分失败")}))]);if(vu!==t.current)return;c({runId:fu,scale:Lu,loading:!1,error:"",details:{...yf,run:Yu(_f?.run)?_f.run:void 0,runSummaryError:_f?.runSummaryError},fetchedAt:new Date})}catch(yf){if(vu!==t.current)return;c((_f)=>({runId:fu,scale:Lu,loading:!1,error:Bu(yf,"抓取 epoch 执行过程失败"),details:_f.runId===fu?_f.details:null,fetchedAt:_f.runId===fu?_f.fetchedAt:null}))}finally{if(O.current===ku)O.current=""}}function Il(fu,Zu,Lu){let ku=rj(fu,Zu);G((Uf)=>{let vu={...Uf,[ku]:{...Yu(Uf?.[ku])?Uf[ku]:{},runId:fu,nodeId:Zu,...Lu}},yf=Object.keys(vu);if(yf.length>32)for(let _f of yf.slice(0,yf.length-32))delete vu[_f];return vu})}async function Fr(fu,Zu){if(!fu||!Zu)return;let Lu=rj(fu,Zu),ku=Number(M.current?.[Lu]||0)+1;M.current={...M.current,[Lu]:ku},Il(fu,Zu,{loading:!0,error:""});try{let Uf=await B1(Q$(l,`/api/node-control/runs/${encodeURIComponent(fu)}/nodes/${encodeURIComponent(Zu)}?tail=160`),{cache:"no-store",strictJson:!0});if(Number(M.current?.[Lu]||0)!==ku)return;let vu=new Date;if(Il(fu,Zu,{loading:!1,details:Uf,fetchedAt:vu,error:""}),S.current===Zu&&b.current===fu)q((yf)=>({...yf,loading:!1,details:Uf,fetchedAt:vu,error:""}))}catch(Uf){if(Number(M.current?.[Lu]||0)!==ku)return;Il(fu,Zu,{loading:!1,error:Bu(Uf,"抓取 Gantt node 详情失败")})}}$0(()=>{if(!Tu){c(ij());return}sf(Tu);let fu=()=>{if(g4())sf(Tu,{silent:!0})},Zu=window.setInterval(()=>{fu()},qz),Lu=()=>{if(g4())fu()};return document.addEventListener("visibilitychange",Lu),()=>{window.clearInterval(Zu),document.removeEventListener("visibilitychange",Lu)}},[Tu,l]);async function kl(fu=Tu,Zu=F){if(!fu||!Zu){q((Lu)=>({...Lu,error:"请先选择 run 和 node",message:""}));return}q((Lu)=>({...Lu,loading:!0,error:"",message:""}));try{let Lu=await B1(Q$(l,`/api/node-control/runs/${encodeURIComponent(fu)}/nodes/${encodeURIComponent(Zu)}?tail=160`),{cache:"no-store",strictJson:!0}),ku=new Date;q((Uf)=>({...Uf,loading:!1,details:Lu,fetchedAt:ku,error:""})),Il(fu,Zu,{loading:!1,details:Lu,fetchedAt:ku,error:""})}catch(Lu){q((ku)=>({...ku,loading:!1,error:Bu(Lu,"抓取 node 执行过程失败")}))}}async function M0(fu){let Zu=String(fu?.runId||Tu||""),Lu=String(fu?.nodeId||"");if(Q({mode:"interval",runId:Zu,interval:fu,marker:null}),X(!0),!Zu||!Lu)return;if(Zu!==Tu)j(Zu);J(Lu),q(t0()),sf(Zu,{silent:!0}),Fr(Zu,Lu)}async function r_(fu){let Zu=String(fu?.runId||Tu||""),Lu=String(fu?.nodeId||"");if(Q({mode:"event",runId:Zu,interval:null,marker:fu}),X(!0),!Zu)return;if(Zu!==Tu)j(Zu);if(sf(Zu,{silent:!0}),!Lu)return;J(Lu),q(t0()),Fr(Zu,Lu)}async function y_(fu){if(!Tu||!F){q((ku)=>({...ku,error:"请先选择 run 和 node",message:""}));return}let Zu=fu==="append"?"prompts":fu,Lu=fu==="append"?U.appendPrompt:fu==="guide"?U.guidePrompt:fu==="modify"?U.modifyPrompt:fu==="approve"?U.approveReason:U.redoReason;if(!String(Lu||"").trim()){q((ku)=>({...ku,error:"操作内容不能为空",message:""}));return}q((ku)=>({...ku,actionLoading:fu,error:"",message:""}));try{let ku=fu==="redo"||fu==="approve"?{reason:Lu,source:"unidesk-frontend",sourceKind:"webui"}:{prompt:Lu,source:"unidesk-frontend",sourceKind:"webui"},Uf=await B1(Q$(l,`/api/node-control/runs/${encodeURIComponent(Tu)}/nodes/${encodeURIComponent(F)}/${Zu}`),{method:"POST",body:JSON.stringify(ku)});if(q((yf)=>({...yf,actionLoading:"",details:Uf,fetchedAt:new Date,appendPrompt:fu==="append"?"":yf.appendPrompt,guidePrompt:fu==="guide"?"":yf.guidePrompt,modifyPrompt:fu==="modify"?"":yf.modifyPrompt,approveReason:fu==="approve"?"":yf.approveReason,redoReason:fu==="redo"?"":yf.redoReason,message:fu==="append"?"已追加到运行中 node":fu==="guide"?"已下发 guide,等待 runner 处理":fu==="modify"?"已排队增量修改命令":fu==="approve"?"已提交审核通过决策":"已排队重做命令"})),Y("success",fu==="append"?"已追加到运行中 node":fu==="guide"?"已下发 guide,等待 runner 处理":fu==="modify"?"已排队增量修改命令":fu==="approve"?"已提交审核通过决策":"已排队重做命令"),await kl(Tu,F),await sf(Tu,{silent:!0}),fu!=="append")await Z()}catch(ku){q((Uf)=>({...Uf,actionLoading:"",error:Bu(ku,"node 控制操作失败")}))}}if(!r)return L($r,{title:"Pipeline 未登记",text:"请在 config.json 的 microservices 中登记用户服务 id=pipeline"});return L("div",{className:"pipeline-page","data-testid":"pipeline-page"},L(n0,{title:"Pipeline v2 工作台",eyebrow:"D601 Snapshot 用户服务",loading:y.loading,actions:L("div",{className:"panel-actions"},L("button",{type:"button",className:"ghost-btn",onClick:Z,disabled:y.loading,"data-testid":"pipeline-refresh-button"},y.loading?"刷新中":"刷新"),L(Rr,{title:"Pipeline 用户服务",data:r,onOpen:f,testId:"raw-pipeline-service"}))},L("div",{className:"pipeline-hero"},L("div",null,L("div",{className:"node-version-line"},L(D1,{status:D.providerStatus==="online"?"online":"warn"},D.providerStatus||"unknown"),L("span",null,r.providerId),L("span",null,k.public?"公网暴露":"仅 UniDesk frontend 代理访问")),L("p",{className:"muted paragraph"},r.description)),L("div",{className:"microservice-ref-card"},L("span",null,"Repo"),L("strong",null,I.url||"--"),L("code",null,I.commitId||"--")),L("div",{className:"microservice-ref-card"},L("span",null,"D601 Docker"),L("strong",null,`${k.nodeBindHost||"--"}:${k.nodePort||"--"}`),L("code",null,`${I.composeFile||"--"} / ${I.composeService||"--"}`))),L(jf,{error:y.error,wide:!0})),L("div",{className:"pipeline-grid"},L(n0,{title:"控制图",eyebrow:`${Ku.id||"pipeline"} / run ${Eu?.status||"--"}`,className:"pipeline-wide-panel",loading:y.loading,actions:L("div",{className:"pipeline-toolbar"},L("select",{value:Wu,disabled:uu.length===0,onChange:(fu)=>{n(fu.target.value),j(""),J(""),q(t0()),Q(V1()),B(!1),X(!1)},"data-testid":"pipeline-select"},uu.map((fu)=>L("option",{key:fu.id,value:fu.id},fu.id||fu.key))),L("select",{value:Tu,disabled:cu.length===0,onChange:(fu)=>{if(j(fu.target.value),q(t0()),Q(V1()),B(!1),X(!1),F)kl(fu.target.value,F)},"data-testid":"pipeline-run-select"},cu.map((fu)=>L("option",{key:fu.runId,value:fu.runId},jj(cu,fu)))),L("button",{type:"button",className:"ghost-btn",disabled:ef.nodes.length===0,onClick:()=>oz(ef,`${Ku.id||"pipeline"}-${Eu?.runId||"snapshot"}`),"data-testid":"pipeline-export-graph"},"导出渲染图"),L("button",{type:"button",className:"ghost-btn",disabled:hr.every((fu)=>fu.flow.nodes.length===0),onClick:()=>oD(hr),"data-testid":"pipeline-export-all-graphs"},"批量导出"))},m.length===0?L($r,{title:"暂无控制图",text:"等待 D601 pipeline backend 返回 config.nodes / config.edges"}):L("div",{className:`pipeline-control-shell ${H?"detail-open":"detail-collapsed"}`,"data-testid":"pipeline-control-shell","data-sidebar-open":H?"true":"false"},L("div",{className:"pipeline-flow-frame","data-testid":"pipeline-react-flow"},L($z,{nodes:ef.nodes,edges:ef.edges,nodeTypes:FD,edgeTypes:jD,fitView:!0,fitViewOptions:{padding:0.18},nodesDraggable:!1,nodesConnectable:!1,elementsSelectable:!0,minZoom:0.25,maxZoom:1.4,proOptions:{hideAttribution:!0},onNodeClick:(fu,Zu)=>{let Lu=String(Zu.id);if(J(Lu),q(t0()),B(!0),Tu)kl(Tu,Lu)}},L(jz,{gap:22,size:1,color:"rgba(215, 161, 58, 0.24)"}),L(Jz,{showInteractive:!1})),!H?L("button",{type:"button",className:"pipeline-sidecar-tab right",disabled:!F,onClick:()=>B(!0),"data-testid":"pipeline-node-sidebar-toggle"},F?"展开 node 控制":"点击 node 展开控制"):null),H?L(Kt,{activeRun:Eu,pipelineRuns:cu,selectedRunId:$,onRunChange:(fu)=>{if(j(fu),q(t0()),Q(V1()),F)kl(fu,F)},selectedNodeId:F,selectedNodeConfig:Du,selectedNodeRuntime:ff,control:U,onControlChange:(fu)=>q((Zu)=>({...Zu,...fu})),onFetch:()=>kl(),onAction:y_,onRaw:f,onCollapse:()=>B(!1)}):null),L("div",{className:"pipeline-flow-summary"},L("span",null,`${ef.nodes.length} nodes`),L("span",null,`${ef.edges.length} edges`),L("span",null,`${uu.length} pipelines`),L("span",null,`source config+components(${x.length})`),L("span",null,`run ${Eu?.runId||"--"}`),L("span",null,`score ${Aj(Eu)}`),L("span",null,F?`selected ${F}`:"click node to control"))),L(Gt,{epochs:cu,activeRun:Eu,activePipeline:Ku,pipelineNodes:m,pipelineEdges:d,selection:K,detailOpen:T,onDetailOpenChange:X,runDetails:N,nodeDetails:tu,nodeDetailsState:ou,ganttScale:z,onGanttScaleChange:w,onIntervalSelect:M0,onMarkerSelect:r_,onRunChange:(fu)=>{if(j(fu),q(t0()),Q(V1()),X(!1),F)kl(fu,F)},onRaw:f}),L(n0,{title:"观测指标",eyebrow:y.refreshedAt?`Updated ${qf(y.refreshedAt)}`:"Snapshot",loading:y.loading},L("div",{className:"metric-grid"},L(Hl,{label:"Health",value:y.health?.ok?"OK":"--",hint:y.health?.service||"D601 /health",tone:y.health?.ok?"ok":"warn"}),L(Hl,{label:"组件",value:gf,hint:"components registry",tone:h?.registry?.ok===!1?"warn":"ok"}),L(Hl,{label:"Pipeline",value:uu.length,hint:`${m.length} nodes / ${d.length} edges`}),L(Hl,{label:"运行记录",value:jr,hint:`${rf.succeeded||0} succeeded / ${rf.running||0} running`}),L(Hl,{label:"OA 记录",value:Array.isArray(e?.submissions)?e.submissions.length:0,hint:e?.runId||"latest run"}),L(Hl,{label:"Procedure",value:Array.isArray(e?.procedureRuns)?e.procedureRuns.length:0,hint:e?.status||"no run"}),L(Hl,{label:"Score",value:Aj(Eu),hint:Eu?.runId||"selected epoch",tone:zj(Eu)})),L("div",{className:"panel-actions inline-actions"},L(Rr,{title:"Pipeline Snapshot",data:h,onOpen:f,testId:"raw-pipeline-snapshot"}))),L(n0,{title:"评分器",eyebrow:Eu?.runId||"selected epoch",loading:y.loading},L(PD,{run:Eu,onRaw:f})),L(n0,{title:"MiniMax 限额",eyebrow:"model/minimax-m27 quota",loading:y.loading},L(zt,{quota:s,onRaw:f})),L(n0,{title:"OA 事件流",eyebrow:"100% event-driven diagnostics",className:"pipeline-wide-panel",loading:y.loading},L(Nt,{diagnostics:o,onRaw:f})),L(n0,{title:"组件矩阵",eyebrow:`${Lf.length} classes`,loading:y.loading},Lf.length===0?L($r,{title:"暂无组件",text:"等待 D601 pipeline backend 返回 registry.components"}):L("div",{className:"component-strata"},Lf.map((fu)=>L("article",{key:fu.name,className:"component-stratum"},L("span",null,fu.name),L("strong",null,fu.count)))),L("div",{className:"pipeline-component-list"},x.slice(0,12).map((fu)=>L("span",{key:fu.key,className:"data-chip"},L("b",null,fu.componentClass||"--"),L("span",null,fu.id||fu.key||"--"))))),L(n0,{title:"Epoch 列表",eyebrow:`${cu.length}/${jr} preview`,loading:y.loading},cu.length===0?L($r,{title:"暂无运行记录",text:"当前 pipeline 在 .state/pipeline-runs 中还没有 epoch。"}):L("div",{className:"pipeline-run-list"},cu.map((fu)=>{let Zu=String(fu?.runId||"")===Tu?Eu:fu;return L("article",{key:fu.runId,className:`pipeline-run-card ${String(fu.runId||"")===Tu?"active":""}`,role:"button",tabIndex:0,onClick:()=>{j(String(fu.runId||"")),Q(V1())},onKeyDown:(Lu)=>{if(Lu.key==="Enter"||Lu.key===" ")j(String(fu.runId||"")),Q(V1())}},L("div",{className:"node-card-head"},L("strong",null,jj(cu,fu)),L(D1,{status:fu.status},fu.status||"--")),L("div",{className:"docker-meta compact"},L("span",null,Zu?.pipelineId||"--"),L("span",null,`nodes ${Array.isArray(Zu?.nodes)?Zu.nodes.length:0}`),L("span",null,`oa ${Array.isArray(Zu?.submissions)?Zu.submissions.length:0}`),L("span",null,`procedures ${Array.isArray(Zu?.procedureRuns)?Zu.procedureRuns.length:0}`),L(SD,{run:Zu})),L("p",{className:"muted paragraph"},u8(Zu?.task)),L("span",{className:"pipeline-run-time"},Nu(Zu?.updatedAt)))}))),L(n0,{title:"运行材料索引",eyebrow:Eu?.runId||"selected epoch",className:"pipeline-wide-panel",loading:y.loading},L(ct,{activeRun:Eu,onRaw:f}))))}var J8=Pu(wf(),1);var _u=J8.default.createElement,{useEffect:Lt}=J8.default,j8=J8.default.useState,wj={id:"",sequenceNo:"",contractNo:"",name:"",currentStatus:"",pending:"",paymentStatus:"",notes:""};function wt({status:u,children:f}){let l=String(u||"unknown").toLowerCase();return _u("span",{className:`status-badge ${l}`},f||u||"unknown")}function F8({label:u,value:f,hint:l,tone:r}){return _u("article",{className:`metric-card ${r||""}`},_u("div",{className:"metric-label"},u),_u("div",{className:"metric-value"},f),_u("div",{className:"metric-hint"},l))}function Ej({title:u,eyebrow:f,actions:l,children:r,className:y,loading:i}){return _u("section",{className:`panel ${y||""}`},_u("div",{className:"panel-head"},_u("div",null,f?_u("p",{className:"panel-eyebrow"},f):null,_u(Af,{title:u,loading:i})),l?_u("div",{className:"panel-actions"},l):null),_u("div",{className:"panel-body"},r))}function nG({title:u,data:f,onOpen:l,testId:r}){return _u("button",{type:"button",className:"ghost-btn","data-testid":r,onClick:()=>l(u,f)},"查看原始JSON")}function $G({title:u,text:f}){return _u("div",{className:"empty-state"},_u("strong",null,u),_u("span",null,f))}function Et(u){return u?.runtime&&typeof u.runtime==="object"&&!Array.isArray(u.runtime)?u.runtime:{}}function Tt(u){return u?.backend&&typeof u.backend==="object"&&!Array.isArray(u.backend)?u.backend:{}}function Zt(u){return u?.repository&&typeof u.repository==="object"&&!Array.isArray(u.repository)?u.repository:{}}function ei(u,f){return`${u}/microservices/project-manager/proxy${f}`}function Ht(u){return{id:String(u.id||""),sequenceNo:u.sequenceNo===null||u.sequenceNo===void 0?"":String(u.sequenceNo),contractNo:String(u.contractNo||""),name:String(u.name||""),currentStatus:String(u.currentStatus||""),pending:String(u.pending||""),paymentStatus:String(u.paymentStatus||""),notes:String(u.notes||"")}}function Ot(u){return{sequenceNo:u.sequenceNo===""?null:Number(u.sequenceNo),contractNo:String(u.contractNo||"").trim(),name:String(u.name||"").trim(),currentStatus:String(u.currentStatus||"").trim(),pending:String(u.pending||"").trim(),paymentStatus:String(u.paymentStatus||"").trim(),paymentRatio:String(u.paymentStatus||"").trim(),notes:String(u.notes||"").trim()}}function Tj(u){return String(u||"item").replace(/[^A-Za-z0-9_-]+/g,"-")}function Bt(u){let f=new Uint8Array(u),l="",r=32768;for(let y=0;y_u("tr",{key:y.id,className:f===y.id?"active-row":"","data-testid":`project-manager-row-${Tj(y.id)}`},_u("td",null,y.sequenceNo??"--"),_u("td",null,_u("strong",null,y.contractNo||"--"),_u("code",null,y.id||"--")),_u("td",null,_u("strong",null,y.name||"--"),_u("span",{className:"muted block"},y.sourceFile||"--")),_u("td",null,y.currentStatus||"--"),_u("td",null,_u("span",{className:"preline"},y.pending||"--")),_u("td",null,_u(wt,{status:Number(y.paymentRatio||0)>=1?"online":"warn"},y.paymentStatus||"--")),_u("td",null,y.notes||"--"),_u("td",null,_u("div",{className:"inline-actions"},_u("button",{type:"button",className:"ghost-btn",onClick:()=>l(y),"data-testid":`project-manager-edit-${Tj(y.id)}`},"编辑"),_u(nG,{title:`Project ${y.contractNo||y.id}`,data:y,onOpen:r,testId:`raw-project-${Tj(y.id)}`}))))))))}function AG({microservices:u,onRaw:f,apiBaseUrl:l="/api"}){let r=u.find((T)=>T.id==="project-manager")||null,[y,i]=j8({loading:!1,saving:!1,importing:!1,exporting:!1,error:"",notice:"",health:null,list:null,refreshedAt:null}),[_,n]=j8({...wj}),[$,j]=j8(""),[F,J]=j8("all"),{addNotification:U}=wl();async function q(T=$,X=F){if(!r)return;i((R)=>({...R,loading:!0,error:""}));try{let R=new URLSearchParams({pageSize:"200",status:X});if(T.trim())R.set("q",T.trim());let[Y,P]=await Promise.all([Xu(`${l}/microservices/project-manager/health`),Xu(ei(l,`/api/projects?${R.toString()}`))]);i((t)=>({...t,loading:!1,health:Y,list:P,refreshedAt:new Date,error:""}))}catch(R){i((Y)=>({...Y,loading:!1,error:Bu(R,"Project Manager 加载失败")}))}}Lt(()=>{q()},[r?.id,r?.runtime?.providerStatus]);async function W(T){T.preventDefault(),i((X)=>({...X,saving:!0,error:"",notice:""}));try{let X=Ot(_);if(_.id)await Xu(ei(l,`/api/projects/${encodeURIComponent(_.id)}`),{method:"PUT",body:JSON.stringify(X)});else await Xu(ei(l,"/api/projects"),{method:"POST",body:JSON.stringify(X)});let R=_.id?"项目已更新":"项目已创建";i((Y)=>({...Y,saving:!1,notice:R})),U("success",R),await q()}catch(X){i((R)=>({...R,saving:!1,error:Bu(X,"保存项目失败")}))}}async function G(){if(!_.id)return;if(!window.confirm(`删除项目 ${_.contractNo||_.name||_.id} ?`))return;i((T)=>({...T,saving:!0,error:"",notice:""}));try{await Xu(ei(l,`/api/projects/${encodeURIComponent(_.id)}`),{method:"DELETE"}),n({...wj});let T="项目已删除";i((X)=>({...X,saving:!1,notice:T})),U("success",T),await q()}catch(T){i((X)=>({...X,saving:!1,error:Bu(T,"删除项目失败")}))}}async function K(T){let X=T.target.files?.[0];if(!X)return;i((R)=>({...R,importing:!0,error:"",notice:""}));try{let R=Bt(await X.arrayBuffer()),P=`Excel 已导入 ${(await Xu(ei(l,"/api/import/excel"),{method:"POST",body:JSON.stringify({fileName:X.name,contentBase64:R,replace:!1})})).imported||0} 条项目`;i((t)=>({...t,importing:!1,notice:P})),U("success",P),T.target.value="",await q()}catch(R){i((Y)=>({...Y,importing:!1,error:Bu(R,"Excel 导入失败")}))}}async function Q(){i((T)=>({...T,exporting:!0,error:""}));try{let T=await tQ(ei(l,"/api/projects/export.xlsx")),X=URL.createObjectURL(T),R=document.createElement("a");R.href=X,R.download=`project-manager-${JF()}.xlsx`,document.body.appendChild(R),R.click(),R.remove(),URL.revokeObjectURL(X),i((Y)=>({...Y,exporting:!1,notice:"Excel 已导出"}))}catch(T){i((X)=>({...X,exporting:!1,error:Bu(T,"Excel 导出失败")}))}}if(!r)return _u($G,{title:"Project Manager 未登记",text:"请在 config.json 的 microservices 中登记用户服务 id=project-manager"});let N=Et(r),c=Zt(r),z=Tt(r),w=Array.isArray(y.list?.projects)?y.list.projects:[],H=y.list?.summary||{},B=y.health||{};return _u("div",{className:"project-manager-page","data-testid":"project-manager-page"},_u(Ej,{title:"项目管理工作台",eyebrow:"Main Server PostgreSQL 用户服务",loading:y.loading||y.exporting,actions:_u("div",{className:"panel-actions"},_u("button",{type:"button",className:"ghost-btn",disabled:y.loading,onClick:()=>q(),"data-testid":"project-manager-refresh-button"},y.loading?"刷新中":"刷新"),_u("button",{type:"button",className:"ghost-btn",disabled:y.exporting,onClick:Q,"data-testid":"project-manager-export-button"},y.exporting?"导出中":"导出 Excel"),_u(nG,{title:"Project Manager 用户服务",data:r,onOpen:f,testId:"raw-project-manager-service"}))},_u("div",{className:"project-manager-hero"},_u(F8,{label:"项目总数",value:H.total??w.length,hint:`PG 表 ${B.storage?.table||"project_manager_projects"}`,tone:"ok"}),_u(F8,{label:"进行中",value:H.active??"--",hint:"当前状态未完全完成"}),_u(F8,{label:"已完成",value:H.completed??"--",hint:"按 完成 关键字统计",tone:"ok"}),_u(F8,{label:"未全款",value:H.unpaid??"--",hint:"付款比例 < 1",tone:Number(H.unpaid||0)>0?"warn":"ok"})),_u(jf,{error:y.error}),y.notice?_u("div",{className:"form-success"},y.notice):null),_u("div",{className:"project-manager-hero"},_u("div",{className:"microservice-ref-card"},_u("span",null,"Repo"),_u("strong",null,c.url||"--"),_u("code",null,c.commitId||"--")),_u("div",{className:"microservice-ref-card"},_u("span",null,"Main Server Docker"),_u("strong",null,`${z.nodeBindHost||"--"}:${z.nodePort||"--"}`),_u("code",null,`${c.composeService||"--"} / ${c.containerName||"--"}`)),_u("div",{className:"microservice-ref-card"},_u("span",null,"Runtime"),_u("strong",null,N.providerName||r.providerId),_u("code",null,`Health ${B.ok?"OK":"--"} / ${y.refreshedAt?qf(y.refreshedAt):"--"}`)),_u("div",{className:"microservice-ref-card"},_u("span",null,"Import Source"),_u("strong",null,"D601 WeChat Excel"),_u("code",null,"合作项目列表_I_20260309.xlsx"))),_u("div",{className:"project-manager-layout"},_u(Ej,{title:"项目清单",eyebrow:"CRUD + Excel Export",loading:y.loading||y.importing||y.exporting,actions:_u("div",{className:"inline-actions project-manager-filters"},_u("input",{value:$,onChange:(T)=>j(T.target.value),placeholder:"搜索合同号 / 项目名称 / 状态","data-testid":"project-manager-search"}),_u("select",{value:F,onChange:(T)=>{J(T.target.value),q($,T.target.value)},"data-testid":"project-manager-status-filter"},_u("option",{value:"all"},"全部"),_u("option",{value:"active"},"进行中"),_u("option",{value:"completed"},"已完成"),_u("option",{value:"unpaid"},"未全款")),_u("button",{type:"button",className:"ghost-btn",onClick:()=>q($,F)},"筛选"))},_u(Vt,{projects:w,activeId:_.id,onSelect:(T)=>n(Ht(T)),onRaw:f})),_u(Ej,{title:_.id?"编辑项目":"新建项目",eyebrow:"PostgreSQL Write Path",loading:y.saving||y.importing},_u("form",{className:"stack-form project-manager-form",onSubmit:W,"data-testid":"project-manager-form"},_.id?_u("label",null,"项目 ID",_u("input",{value:_.id,disabled:!0})):null,_u("label",null,"序号",_u("input",{type:"number",value:_.sequenceNo,onChange:(T)=>n((X)=>({...X,sequenceNo:T.target.value}))})),_u("label",null,"合同号",_u("input",{value:_.contractNo,onChange:(T)=>n((X)=>({...X,contractNo:T.target.value})),required:!0})),_u("label",null,"项目名称",_u("input",{value:_.name,onChange:(T)=>n((X)=>({...X,name:T.target.value})),required:!0})),_u("label",null,"当前状况",_u("textarea",{value:_.currentStatus,onChange:(T)=>n((X)=>({...X,currentStatus:T.target.value}))})),_u("label",null,"待完成",_u("textarea",{value:_.pending,onChange:(T)=>n((X)=>({...X,pending:T.target.value}))})),_u("label",null,"付款情况",_u("input",{value:_.paymentStatus,onChange:(T)=>n((X)=>({...X,paymentStatus:T.target.value})),placeholder:"例如 1 / 0.5 / 50%"})),_u("label",null,"其它",_u("input",{value:_.notes,onChange:(T)=>n((X)=>({...X,notes:T.target.value}))})),_u("div",{className:"inline-actions"},_u("button",{type:"submit",className:"primary-btn",disabled:y.saving,"data-testid":"project-manager-save-button"},y.saving?"保存中":_.id?"保存修改":"创建项目"),_u("button",{type:"button",className:"ghost-btn",onClick:()=>n({...wj})},"清空"),_.id?_u("button",{type:"button",className:"danger-btn",disabled:y.saving,onClick:G,"data-testid":"project-manager-delete-button"},"删除"):null)),_u("div",{className:"project-manager-import"},_u("p",{className:"muted paragraph"},"浏览器只访问 UniDesk frontend;后端通过同源用户服务代理写入主 PostgreSQL,不暴露 4233 公网端口。"),_u("label",{className:"file-import"},y.importing?"导入中...":"导入 Excel",_u("input",{type:"file",accept:".xlsx",onChange:K,disabled:y.importing,"data-testid":"project-manager-import-input"}))))))}var q8=Pu(wf(),1);var Au=q8.default.createElement,{useEffect:Xt}=q8.default,hl=q8.default.useState;function Yt({status:u,children:f}){let l=String(u||"unknown").toLowerCase();return Au("span",{className:`status-badge ${l}`},f||u||"unknown")}function U8({label:u,value:f,hint:l,tone:r}){return Au("article",{className:`metric-card ${r||""}`},Au("div",{className:"metric-label"},u),Au("div",{className:"metric-value"},f),Au("div",{className:"metric-hint"},l))}function Zj({title:u,eyebrow:f,actions:l,children:r,className:y,loading:i}){return Au("section",{className:`panel ${y||""}`},Au("div",{className:"panel-head"},Au("div",null,f?Au("p",{className:"panel-eyebrow"},f):null,Au(Af,{title:u,loading:i})),l?Au("div",{className:"panel-actions"},l):null),Au("div",{className:"panel-body"},r))}function jG({title:u,data:f,onOpen:l,testId:r}){return Au("button",{type:"button",className:"ghost-btn","data-testid":r,onClick:()=>l(u,f)},"查看原始JSON")}function Q8({title:u,text:f}){return Au("div",{className:"empty-state"},Au("strong",null,u),Au("span",null,f))}function Dt(u){return u?.runtime&&typeof u.runtime==="object"&&!Array.isArray(u.runtime)?u.runtime:{}}function tt(u){return u?.backend&&typeof u.backend==="object"&&!Array.isArray(u.backend)?u.backend:{}}function St(u){return u?.repository&&typeof u.repository==="object"&&!Array.isArray(u.repository)?u.repository:{}}function JG(u){return String(u).replace(/[^a-zA-Z0-9_-]/g,"_")}function Pt(u){if(!Number.isFinite(u))return"--";return`${u.toFixed(1)}%`}function u_(u,f){return`${u}/microservices/todo-note/proxy${f}`}function UG(u){return u.reduce((f,l)=>{let r=UG(Array.isArray(l.children)?l.children:[]),y=Boolean(l.completed);return{total:f.total+1+r.total,completed:f.completed+(y?1:0)+r.completed,active:f.active+(y?0:1)+r.active}},{total:0,completed:0,active:0})}function Oj(u,f){let l=f==="all"||(f==="completed"?Boolean(u.completed):!u.completed),r=Array.isArray(u.children)?u.children:[];return l||r.some((y)=>Oj(y,f))}function FG(u){return Array.isArray(u?.instances)?u.instances:[]}function Hj(u,f){for(let l of u){if(l?.id===f)return Array.isArray(l.children)?l.children:[];let r=Hj(Array.isArray(l?.children)?l.children:[],f);if(r.length>0)return r}return[]}function QG({microservices:u,onRaw:f,apiBaseUrl:l="/api"}){let r=u.find((g)=>g.id==="todo-note")||null,[y,i]=hl(null),[_,n]=hl(null),[$,j]=hl(""),[F,J]=hl(null),[U,q]=hl("all"),[W,G]=hl(13),[K,Q]=hl(""),[N,c]=hl(""),[z,w]=hl(""),[H,B]=hl(""),[T,X]=hl(""),[R,Y]=hl(!1),[P,t]=hl(""),[O,M]=hl(null),S=FG(_),b=UG(Array.isArray(F?.todos)?F.todos:[]),Z=r?Dt(r):{},D=r?St(r):{},I=r?tt(r):{};async function k(g=$){let[Qu,Eu]=await Promise.all([Xu(`${l}/microservices/todo-note/health`),Xu(u_(l,"/api/instances"))]);i(Qu),n(Eu);let Tu=FG(Eu),Du=Tu.some((ff)=>ff.id===g)?g:Tu[0]?.id||"";return j(Du),Du}async function h(g=$){if(!g){J(null);return}let Qu=await Xu(u_(l,`/api/instances/${encodeURIComponent(g)}`));J(Qu)}async function o(g=$){if(!r)return;Y(!0),t("");try{let Qu=await k(g);await h(Qu),M(new Date)}catch(Qu){t(Bu(Qu,"Todo Note 加载失败"))}finally{Y(!1)}}async function s(g){if(!$)return null;t("");try{let Qu=await Xu(u_(l,`/api/instances/${encodeURIComponent($)}/actions`),{method:"POST",body:JSON.stringify({action:g})});return J(Qu),await k($),Qu}catch(Qu){return t(Bu(Qu,"Todo 操作失败")),null}}async function x(g){g.preventDefault();let Qu=K.trim();if(!Qu)return;Y(!0),t("");try{let Eu=await Xu(u_(l,"/api/instances"),{method:"POST",body:JSON.stringify({name:Qu})});Q(""),await o(Eu.id)}catch(Eu){t(Bu(Eu,"创建清单失败"))}finally{Y(!1)}}async function uu(g){if(!window.confirm("确认删除这个 Todo Note 清单?"))return;Y(!0),t("");try{await Xu(u_(l,`/api/instances/${encodeURIComponent(g)}`),{method:"DELETE"}),await o($===g?"":$)}catch(Qu){t(Bu(Qu,"删除清单失败"))}finally{Y(!1)}}async function nu(g){g.preventDefault();let Qu=N.trim();if(!Qu)return;c(""),await s({type:"addTodo",title:Qu})}async function $u(g){if(!$)return;t("");try{let Qu=await Xu(u_(l,`/api/instances/${encodeURIComponent($)}/${g}`),{method:"POST",body:JSON.stringify({})});J(Qu),await k($)}catch(Qu){t(Bu(Qu,`${g} 失败`))}}function Fu(g){w(g.id),B(String(g.title||""))}async function Ku(g){let Qu=H.trim();if(w(""),B(""),Qu)await s({type:"updateTodoTitle",todoId:g,title:Qu})}async function Wu(g){let Eu=window.prompt("新增子任务标题")?.trim();if(!Eu)return;let Tu=Hj(Array.isArray(F?.todos)?F.todos:[],g),Du=new Set(Tu.map((gf)=>gf.id)),ff=await s({type:"addTodo",title:Eu,parentId:g,targetIndex:0});if(!ff)return;let rf=Hj(Array.isArray(ff?.todos)?ff.todos:[],g),Lf=rf.find((gf)=>!Du.has(gf.id));if(Lf&&rf[0]?.id!==Lf.id)await s({type:"moveTodo",todoId:Lf.id,targetParentId:g,targetIndex:0})}async function m(g,Qu){if(!T)return;let Eu={type:"moveTodo",todoId:T,targetIndex:Qu};if(g)Eu.targetParentId=g;X(""),await s(Eu)}if(Xt(()=>{o()},[r?.id,r?.runtime?.providerStatus]),!r)return Au(Q8,{title:"Todo Note 未登记",text:"请在 config.json 的 microservices 中登记用户服务 id=todo-note"});let d=S.find((g)=>g.id===$)||null,e=Array.isArray(F?.todos)?F.todos:[],cu=e.map((g,Qu)=>({todo:g,index:Qu})).filter((g)=>Oj(g.todo,U));return Au("div",{className:"todo-note-page","data-testid":"todo-note-page"},Au(Zj,{title:"Todo Note 工作台",eyebrow:"Main Server 用户服务",loading:R,actions:Au("div",{className:"panel-actions"},Au("button",{type:"button",className:"ghost-btn",disabled:R,onClick:()=>o($),"data-testid":"todo-note-refresh-button"},R?"刷新中":"刷新"),Au(jG,{title:"Todo Note 用户服务",data:r,onOpen:f,testId:"raw-todo-note-service"}))},Au("div",{className:"todo-note-hero"},Au("div",null,Au("div",{className:"node-version-line"},Au(Yt,{status:Z.providerStatus==="online"?"online":"warn"},Z.providerStatus||"unknown"),Au("span",null,r.providerId),Au("span",null,I.public?"公网暴露":"仅 UniDesk frontend 代理访问"),Au("span",null,y?.ok?"Health OK":"Health --")),Au("p",{className:"muted paragraph"},r.description)),Au("div",{className:"microservice-ref-card"},Au("span",null,"Repo"),Au("strong",null,D.url||"--"),Au("code",null,D.commitId||"--")),Au("div",{className:"microservice-ref-card"},Au("span",null,"Main Server Docker"),Au("strong",null,`${I.nodeBindHost||"--"}:${I.nodePort||"--"}`),Au("code",null,`${D.composeService||"--"} / ${D.containerName||"--"}`))),Au(jf,{error:P,wide:!0})),Au("div",{className:"todo-note-layout"},Au(Zj,{title:"清单",eyebrow:`${S.length} Instances`,className:"todo-list-panel",loading:R},Au("form",{className:"todo-create-list",onSubmit:x},Au("input",{placeholder:"新清单名称",value:K,onChange:(g)=>Q(g.target.value),"aria-label":"新清单名称"}),Au("button",{type:"submit",className:"ghost-btn",disabled:R||!K.trim()},"创建")),S.length===0?Au(Q8,{title:"暂无清单",text:"迁移或创建清单后会出现在这里"}):Au("div",{className:"todo-instance-list"},S.map((g)=>Au("button",{key:g.id,type:"button",className:`todo-instance-row ${$===g.id?"active":""}`,onClick:()=>{j(g.id),h(g.id)},"data-testid":`todo-instance-${JG(g.id)}`},Au("strong",null,g.name),Au("span",null,`${g.completedCount??0}/${g.todoCount??0} 完成`),Au("code",null,g.id))))),Au("div",{className:"todo-main-stack"},Au(Zj,{title:d?.name||"待选择清单",eyebrow:O?`Updated ${qf(O)}`:"Todo Tree",loading:R,actions:F?Au("div",{className:"panel-actions"},Au("button",{type:"button",className:"ghost-btn",onClick:()=>s({type:"renameInstance",name:window.prompt("清单新名称",F.name)||F.name})},"重命名"),Au("button",{type:"button",className:"ghost-btn danger",onClick:()=>uu($)},"删除清单"),Au(jG,{title:`Todo Instance ${$}`,data:F,onOpen:f,testId:"raw-todo-instance"})):null},!F?Au(Q8,{title:"未选择清单",text:"左侧选择一个 Todo Note 清单"}):Au("div",{className:"todo-workbench",style:{"--todo-font-size":`${W}px`}},Au("div",{className:"todo-toolbar"},Au("form",{className:"todo-add-form",onSubmit:nu},Au("input",{placeholder:"新增根任务",value:N,onChange:(g)=>c(g.target.value),"aria-label":"新增根任务"}),Au("button",{type:"submit",className:"ghost-btn",disabled:!N.trim()},"新增")),Au("div",{className:"todo-filter-strip"},["all","active","completed"].map((g)=>Au("button",{key:g,type:"button",className:`todo-filter ${U===g?"active":""}`,onClick:()=>q(g)},g==="all"?"全部":g==="active"?"未完成":"已完成"))),Au("div",{className:"todo-toolbar-actions"},Au("button",{type:"button",className:"ghost-btn",onClick:()=>s({type:"setAllTodosExpanded",expanded:!0})},"全部展开"),Au("button",{type:"button",className:"ghost-btn",onClick:()=>s({type:"setAllTodosExpanded",expanded:!1})},"全部收起"),Au("button",{type:"button",className:"ghost-btn",onClick:()=>$u("undo")},"撤销"),Au("button",{type:"button",className:"ghost-btn",onClick:()=>$u("redo")},"重做"),Au("label",{className:"todo-font-control"},"字号",Au("input",{type:"range",min:11,max:18,value:W,onChange:(g)=>G(Number(g.target.value))})))),Au("div",{className:"todo-stats-grid"},Au(U8,{label:"总任务",value:b.total,hint:`${S.length} lists`}),Au(U8,{label:"已完成",value:b.completed,hint:`${Pt(b.total?b.completed/b.total*100:0)}`,tone:"ok"}),Au(U8,{label:"未完成",value:b.active,hint:U==="active"?"当前筛选":"active tasks",tone:b.active>0?"warn":"ok"}),Au(U8,{label:"历史指针",value:F.historyPointer??0,hint:"undo / redo"})),Au("div",{className:"todo-root-drop",onDragOver:(g)=>g.preventDefault(),onDrop:(g)=>{g.preventDefault(),m(null,e.length)}},"拖到这里可移为根任务末尾"),Au("div",{className:"todo-tree","data-testid":"todo-note-tree"},cu.length===0?Au(Q8,{title:"没有匹配任务",text:"调整筛选或新增任务"}):cu.map(({todo:g,index:Qu})=>Au(qG,{key:g.id,todo:g,depth:0,parentId:null,index:Qu,siblingCount:e.length,filter:U,editingId:z,editingTitle:H,setEditingTitle:B,beginEdit:Fu,saveEdit:Ku,applyTodoAction:s,addChild:Wu,dragTodoId:T,setDragTodoId:X,dropTodo:m}))))))))}function qG(u){let{todo:f,depth:l,parentId:r,index:y,siblingCount:i,filter:_,editingId:n,editingTitle:$,setEditingTitle:j,beginEdit:F,saveEdit:J,applyTodoAction:U,addChild:q,dragTodoId:W,setDragTodoId:G,dropTodo:K}=u,Q=Array.isArray(f.children)?f.children:[],N=Q.map((w,H)=>({child:w,childIndex:H})).filter((w)=>Oj(w.child,_)),c=n===f.id,z=r||null;return Au("div",{className:"todo-row-wrap"},Au("article",{className:`todo-row ${f.completed?"completed":""} ${W===f.id?"dragging":""}`,style:{"--todo-depth":l},draggable:!0,onDragStart:(w)=>{G(f.id),w.dataTransfer.effectAllowed="move"},onDragOver:(w)=>w.preventDefault(),onDrop:(w)=>{w.preventDefault(),K(f.id,Q.length)},"data-testid":`todo-row-${JG(f.id)}`},Au("button",{type:"button",className:"todo-expand",disabled:Q.length===0,onClick:()=>U({type:"toggleTodoExpanded",todoId:f.id})},Q.length===0?"·":f.expanded?"▾":"▸"),Au("input",{type:"checkbox",checked:Boolean(f.completed),onChange:()=>U({type:"toggleTodoCompleted",todoId:f.id}),"aria-label":`完成 ${f.title}`}),Au("div",{className:"todo-title-cell",onDoubleClick:()=>F(f)},c?Au("div",{className:"todo-edit-inline"},Au("input",{value:$,autoFocus:!0,onChange:(w)=>j(w.target.value),onKeyDown:(w)=>{if(w.key==="Enter")J(f.id);if(w.key==="Escape")F({id:"",title:""})}}),Au("button",{type:"button",className:"ghost-btn",onClick:()=>J(f.id)},"保存")):Au("strong",null,f.title||"Untitled"),Au("div",{className:"todo-meta-line"},Au("span",null,`子项 ${Q.length}`),Au("span",null,`更新 ${Nu(f.updatedAt)}`),f.reminderAt?Au("span",{className:"todo-reminder"},`提醒 ${Nu(f.reminderAt)}`):Au("span",null,"无提醒"))),Au("input",{className:"todo-reminder-input",type:"datetime-local",value:M8(f.reminderAt),onChange:(w)=>U({type:"setTodoReminder",todoId:f.id,reminderAt:UF(w.target.value)})}),Au("div",{className:"todo-row-actions"},Au("button",{type:"button",className:"ghost-btn",onClick:()=>F(f)},"编辑"),Au("button",{type:"button",className:"ghost-btn",onClick:()=>q(f.id)},"子项"),Au("button",{type:"button",className:"ghost-btn",disabled:y<=0,onClick:()=>U({type:"moveTodo",todoId:f.id,...z?{targetParentId:z}:{},targetIndex:y-1})},"上移"),Au("button",{type:"button",className:"ghost-btn",disabled:y<=0,onClick:()=>U({type:"moveTodo",todoId:f.id,...z?{targetParentId:z}:{},targetIndex:0})},"置顶"),Au("button",{type:"button",className:"ghost-btn",disabled:y>=i-1,onClick:()=>U({type:"moveTodo",todoId:f.id,...z?{targetParentId:z}:{},targetIndex:y+1})},"下移"),Au("button",{type:"button",className:"ghost-btn",disabled:!r,onClick:()=>U({type:"moveTodo",todoId:f.id,targetIndex:9999})},"提升"),Au("button",{type:"button",className:"ghost-btn danger",onClick:()=>U({type:"deleteTodo",todoId:f.id})},"删除"))),f.expanded&&N.length>0?Au("div",{className:"todo-children"},N.map(({child:w,childIndex:H})=>Au(qG,{key:w.id,todo:w,depth:l+1,parentId:f.id,index:H,siblingCount:Q.length,filter:_,editingId:n,editingTitle:$,setEditingTitle:j,beginEdit:F,saveEdit:J,applyTodoAction:U,addChild:q,dragTodoId:W,setDragTodoId:G,dropTodo:K}))):null)}var WG=Pu(wf(),1),S1=WG.default.createElement;function cG({title:u,items:f,actions:l,className:r,testId:y}){let i=Array.isArray(f)?f:[];return S1("section",{className:`top-status-bar ${r||""}`,"data-testid":y},S1("div",{className:"top-status-main"},u?S1("strong",{className:"top-status-title"},u):null,S1("div",{className:"top-status-chips"},i.map((_,n)=>S1("span",{key:_?.key||`${_?.label||"status"}-${n}`,className:`top-status-chip ${_?.tone||""}`,"data-testid":_?.testId},_?.label?S1("b",null,_.label):null,S1("span",null,_?.value??"--"))))),l?S1("div",{className:"top-status-actions"},l):null)}var E$=Pu(wf(),1);var pf=E$.default.createElement;function NG({onClose:u}){let{notifications:f,removeNotification:l,clearNotifications:r}=wl(),y=E$.default.useRef(null);if(E$.default.useEffect(()=>{let i=(_)=>{if(y.current&&!y.current.contains(_.target))u()};return document.addEventListener("mousedown",i),()=>document.removeEventListener("mousedown",i)},[u]),f.length===0)return pf("div",{className:"notification-popup",ref:y},pf("div",{className:"notification-popup-header"},pf("span",null,"通知"),pf("button",{className:"notification-popup-close",onClick:u},"×")),pf("div",{className:"notification-popup-empty"},"暂无通知"));return pf("div",{className:"notification-popup",ref:y},pf("div",{className:"notification-popup-header"},pf("span",null,`通知 (${f.length})`),pf("div",{className:"notification-popup-actions"},pf("button",{className:"notification-popup-clear",onClick:r},"清空"),pf("button",{className:"notification-popup-close",onClick:u},"×"))),pf("div",{className:"notification-popup-list"},f.slice().reverse().map((i)=>pf("div",{key:i.id,className:`notification-item ${i.type}`},pf("span",{className:"notification-item-icon"},i.type==="success"?"✓":"×"),pf("span",{className:"notification-item-message"},i.message),pf("button",{className:"notification-item-dismiss",onClick:()=>l(i.id)},"×")))))}function zG({notification:u}){let{removeNotification:f}=wl();return E$.default.useEffect(()=>{let l=setTimeout(()=>{f(u.id)},3000);return()=>clearTimeout(l)},[u.id,f]),pf("div",{className:`notification-banner ${u.type}`,role:"alert"},pf("span",{className:"notification-banner-icon"},u.type==="success"?"✓":"×"),pf("span",{className:"notification-banner-message"},u.message),pf("button",{className:"notification-banner-dismiss",onClick:()=>f(u.id)},"×"))}function XG(u,f){let l=document.getElementById("root")?.getAttribute(u);if(!l)return f;try{let r=JSON.parse(l);return typeof r==="object"&&r!==null&&!Array.isArray(r)?r:f}catch{return f}}var Iu=XG("data-config",{apiBaseUrl:"/api",authUsername:"admin"}),Mt=XG("data-codex-overview",null),A=M1.default.createElement,{useEffect:A0,useMemo:H$}=M1.default,pu=M1.default.useState,Yj=M1.default.createContext(!1),Zr=qW(I6),mt={id:"code-queue",name:"Code Queue",providerId:"main-server",description:"Code Queue",repository:{containerName:"code-queue-backend"},backend:{nodeBaseUrl:"http://code-queue:4222",nodeBindHost:"code-queue",nodePort:4222,public:!1},runtime:{providerStatus:"loading",providerName:"main-server"}};function GG(){return typeof document>"u"||document.visibilityState!=="hidden"}function pt(u,f){if(u==="ops"&&f==="status")return 5000;if(u==="nodes"&&f==="monitor")return 5000;if(u==="tasks"&&(f==="dispatch"||f==="scheduled"||f==="pending"))return 5000;if(u==="nodes"||u==="ops")return 1e4;if(u==="apps")return 15000;if(u==="tasks")return 15000;return 30000}async function Ct(u){if(!u?._summaryOnly||!u?.id)return u;return(await Xu(`${Iu.apiBaseUrl}/tasks/${encodeURIComponent(String(u.id))}`))?.task||u}function O$(u){return u?._summaryOnly?{...u,_loadRaw:()=>Ct(u)}:u}function S0(u){if(!Number.isFinite(u))return"--";let f=Math.max(0,u);if(f===0)return"0s";if(f<0.01)return"<0.01s";if(f<0.1)return`${f.toFixed(2)}s`;if(f<1)return`${f.toFixed(1)}s`;if(f<10&&!Number.isInteger(f))return`${f.toFixed(1)}s`;if(f<60)return`${Math.round(f)}s`;let l=Math.floor(f);if(l<3600)return`${Math.floor(l/60)}m ${l%60}s`;return`${Math.floor(l/3600)}h ${Math.floor(l%3600/60)}m`}function Ar(u){let f=Number(u);if(!Number.isFinite(f))return"--";if(f<1)return`${Math.max(0,f).toFixed(1)}ms`;if(f<10)return`${f.toFixed(1)}ms`;if(f<1000)return`${Math.round(f)}ms`;return S0(f/1000)}function Nl(u){let f=Number(u);if(!Number.isFinite(f)||f<=0)return"--";let l=["B","KB","MB","GB","TB"],r=f,y=0;while(r>=1024&&y0)return l[r]}return"任务失败但 provider 未返回明确原因"}function By(u){if(u===null||u===void 0)return"--";if(typeof u==="boolean")return u?"是":"否";if(typeof u==="number")return String(u);if(typeof u==="string")return u.length>80?`${u.slice(0,77)}...`:u;if(Array.isArray(u))return`${u.length} 项`;if(typeof u==="object")return`${Object.keys(u).length} 字段`;return String(u)}function Rt(u,f){let l=u.replace(/[-_\s]/g,"").toLowerCase(),r=l==="ts"||l.endsWith("at")||l.endsWith("timestamp")||l.endsWith("heartbeat");if((typeof f==="string"||typeof f==="number")&&r){let y=Nu(f);if(y!=="--")return y}if(u==="bodyText"&&typeof f==="string")return`${/^\s*[{[]/.test(f)?"JSON":"HTTP"} body ${f.length} chars`;return By(f)}function tG(u){if(!u||typeof u!=="object"||Array.isArray(u))return[];return Object.entries(u)}function bl(u){return String(u).replace(/[^a-zA-Z0-9_-]/g,"_")}function tj(u,f){return u&&typeof u==="object"&&!Array.isArray(u)?u[f]:void 0}function c8(u,f,l="未知"){let r=tj(u?.labels,f);return typeof r==="string"&&r.length>0?r:l}function SG(u){return c8(u,"providerGatewayVersion")}function Z$(u){return c8(u,"providerGatewayUpgradePolicy")}function KG(u){return c8(u,"providerGatewayStartedAt","")}function PG(u){let f=tj(u?.labels,"unideskCapabilities");if(typeof f==="string")return f.split(",").map((l)=>l.trim()).filter(Boolean);return Array.isArray(f)?f.filter((l)=>typeof l==="string"):[]}function MG(u,f){return PG(u).includes(f)}function LG(u,f){let l=tj(u?.labels,f);return l===!0||l==="true"||l==="1"}function ht(u){if(!MG(u,"host.ssh"))return{tone:"fail",label:"不可用",detail:"未声明 host.ssh"};if(!LG(u,"hostSshConfigured"))return{tone:"warn",label:"未配置",detail:"缺少 SSH 环境变量"};if(!LG(u,"hostSshKeyPresent"))return{tone:"warn",label:"缺 key",detail:"私钥未挂载"};return{tone:"ok",label:"可用",detail:c8(u,"hostSshTarget","host.ssh ready")}}function bt(u){if(!MG(u,"provider.upgrade"))return{tone:"fail",label:"不可用",detail:"未声明 provider.upgrade"};let f=Z$(u);if(f!=="always-enabled")return{tone:"warn",label:"待确认",detail:`策略 ${f}`};return{tone:"ok",label:"可用",detail:"always-enabled"}}function Sj(u){let f=typeof u==="string"&&u.length>0?u:"未知";if(f==="未知")return"版本未知";return f.startsWith("v")?f:`v${f}`}function mG(u){return u?.payload&&typeof u.payload==="object"&&!Array.isArray(u.payload)?u.payload:{}}function N8(u){return u?.result&&typeof u.result==="object"&&!Array.isArray(u.result)?u.result:{}}function W8(u){let f=mG(u),l=N8(u);return(f.mode??l.mode)==="schedule"?"schedule":"plan"}function vt(u){let f=mG(u).source;return typeof f==="string"&&f.length>0?f:"unknown"}function It(u){let f=N8(u),l=f.plan&&typeof f.plan==="object"&&!Array.isArray(f.plan)?f.plan:{},r=f.policy??l.policy;return typeof r==="string"&&r.length>0?r:"--"}function pG(u){let f=N8(u),l=f.plan&&typeof f.plan==="object"&&!Array.isArray(f.plan)?f.plan:{},r=f.targetProviderGatewayVersion??f.providerGatewayVersion??l.targetProviderGatewayVersion??l.providerGatewayVersion;return typeof r==="string"&&r.length>0?Sj(r):"版本未知"}function CG(u){if(String(u?.status||"").toLowerCase()==="failed")return DG(u);if(l_(u))return"等待 provider 回传升级终态";let l=N8(u);if(typeof l.updaterContainerId==="string"&&l.updaterContainerId.length>0)return`updater ${l.updaterContainerId.slice(0,18)}`;if(typeof l.message==="string"&&l.message.length>0)return l.message;if(l.plan)return"升级计划已生成";return"无升级结果摘要"}function xG(u,f){return u.filter((l)=>l?.providerId===f&&l?.command==="provider.upgrade").sort((l,r)=>(j0(r.updatedAt)??0)-(j0(l.updatedAt)??0))}function kt(u){return u.find((f)=>W8(f)==="schedule")||u[0]||null}function RG(u){return u?.runtime&&typeof u.runtime==="object"&&!Array.isArray(u.runtime)?u.runtime:{}}function wG(u){return u?.backend&&typeof u.backend==="object"&&!Array.isArray(u.backend)?u.backend:{}}function gt(u){return u?.repository&&typeof u.repository==="object"&&!Array.isArray(u.repository)?u.repository:{}}function Nf({status:u,children:f}){let l=String(u||"unknown").toLowerCase();return A("span",{className:`status-badge ${l}`},f||u||"unknown")}function $f({label:u,value:f,hint:l,tone:r,onClick:y,testId:i}){let _=typeof y==="function";return A("article",{className:`metric-card ${r||""} ${_?"clickable":""}`,role:_?"button":void 0,tabIndex:_?0:void 0,"data-testid":i,onClick:y,onKeyDown:_?(n)=>{if(n.key==="Enter"||n.key===" ")n.preventDefault(),y()}:void 0},A("div",{className:"metric-label"},u),A("div",{className:"metric-value"},f),A("div",{className:"metric-hint"},l))}function au({title:u,eyebrow:f,actions:l,children:r,className:y,loading:i}){let _=M1.default.useContext(Yj),n=Boolean(i)||_;return A("section",{className:`panel ${y||""}`},A("div",{className:"panel-head"},A("div",null,f?A("p",{className:"panel-eyebrow"},f):null,A(Af,{title:u,loading:n})),l?A("div",{className:"panel-actions"},l):null),A("div",{className:"panel-body"},r))}function Cf({title:u,data:f,onOpen:l,testId:r}){let[y,i]=pu(!1),_=f&&typeof f==="object"&&typeof f._loadRaw==="function"?f._loadRaw:null;async function n(){if(!_){l(u,f);return}i(!0);try{l(u,await _())}catch($){l(u,{ok:!1,error:Bu($,"读取原始 JSON 失败"),fallback:f})}finally{i(!1)}}return A("button",{type:"button",className:"ghost-btn","data-testid":r,disabled:y,onClick:()=>void n()},y?"读取中":"查看原始JSON")}function st({raw:u,onClose:f}){if(!u)return null;return A("div",{className:"modal-backdrop",role:"presentation"},A("section",{className:"raw-dialog",role:"dialog","aria-modal":"true","aria-label":u.title},A("div",{className:"raw-dialog-head"},A("h2",null,u.title),A("button",{type:"button",className:"ghost-btn",onClick:f},"关闭")),A("pre",{className:"raw-json","data-testid":"raw-json"},JSON.stringify(u.data,null,2))))}function hG({labels:u,limit:f=8}){let l=tG(u).slice(0,f);if(l.length===0)return A("span",{className:"muted"},"无标签");return A("div",{className:"chip-row"},l.map(([r,y])=>A("span",{key:r,className:"data-chip"},A("b",null,r),A("span",null,By(y)))))}function f_({node:u}){let f=SG(u);return A("span",{className:`version-chip ${f==="未知"?"unknown":""}`,"data-testid":`gateway-version-${bl(u?.providerId||"unknown")}`},Sj(f))}function EG({title:u,state:f,testId:l}){return A("span",{className:`capability-badge ${f.tone}`,title:f.detail,"data-testid":l},A("b",null,u),A("strong",null,f.label),A("small",null,f.detail))}function Pj({node:u}){let f=bl(u?.providerId||"unknown");return A("div",{className:"node-availability-strip"},A(EG,{title:"SSH 透传",state:ht(u),testId:`ssh-availability-${f}`}),A(EG,{title:"远程更新",state:bt(u),testId:`upgrade-availability-${f}`}))}function m1({data:u,empty:f="无数据"}){if(u===null||u===void 0)return A("span",{className:"muted"},f);if(typeof u!=="object")return A("span",{className:"summary-value"},By(u));if(Array.isArray(u))return A("span",{className:"summary-value"},`${u.length} 项列表`);let l=Object.entries(u).slice(0,5);if(l.length===0)return A("span",{className:"muted"},f);return A("div",{className:"summary-grid"},l.map(([r,y])=>A("span",{key:r,className:"summary-item"},A("b",null,r),A("span",null,Rt(r,y)))))}function Ff({title:u,text:f}){return A("div",{className:"empty-state"},A("strong",null,u),A("span",null,f))}function at({onLogin:u}){let[f,l]=pu(Iu.authUsername||"admin"),[r,y]=pu(""),[i,_]=pu(""),[n,$]=pu(!1);async function j(F){F.preventDefault(),$(!0),_("");try{let J=await Xu("/login",{method:"POST",body:JSON.stringify({username:f,password:r})});u(J)}catch(J){_(Bu(J,"登录失败"))}finally{$(!1)}}return A("main",{className:"login-screen","data-testid":"login-screen"},A("section",{className:"login-card"},A("div",{className:"login-brand"},A("span",{className:"brand-mark"},"UD"),A("div",null,A("h1",null,"UniDesk"),A("p",null,"Control Plane Login"))),A("form",{className:"login-form",onSubmit:j},A("label",null,"账号",A("input",{name:"username",autoComplete:"username",value:f,onChange:(F)=>l(F.target.value)})),A("label",null,"密码",A("input",{name:"password",type:"password",autoComplete:"current-password",value:r,onChange:(F)=>y(F.target.value)})),A(jf,{error:i}),A("button",{type:"submit",disabled:n},n?"登录中":"登录")),A("div",{className:"login-note"},"默认账号由 config.json 注入;公网入口只暴露前端登录面。")))}function ot({connection:u,lastRefresh:f,onRefresh:l,onLogout:r,session:y,clock:i,activeStatusItems:_=[],onNotificationToggle:n,unreadCount:$=0}){let j=[{key:"core",label:"核心",value:u.text,tone:u.ok?"ok":"fail",testId:"conn-text"},...Array.isArray(_)?_:[],{key:"refresh",label:"刷新",value:f?qf(f):"未刷新"},{key:"clock",label:d$,value:qf(i)},{key:"user",label:"用户",value:y?.user?.username||"--",tone:"user"}];return A("header",{className:"topbar"},A("div",null,A("p",{className:"eyebrow"},"Distributed Work Platform"),A("h1",null,"UniDesk 控制平面")),A(cG,{className:"global-top-status",title:"状态",items:j,actions:[A("button",{key:"notification",type:"button",className:`notification-icon-btn ${$>0?"has-unread":""}`,onClick:n,"aria-label":"通知"},"\uD83D\uDD14",$>0?A("span",{key:"badge",className:"notification-badge"},$>99?"99+":$):null),A("button",{key:"refresh",type:"button",className:"ghost-btn",onClick:l},"刷新"),A("button",{key:"logout",type:"button",className:"ghost-btn danger",onClick:r},"退出")]}))}function dt(u){return!u.defaultPrevented&&u.button===0&&!u.metaKey&&!u.altKey&&!u.ctrlKey&&!u.shiftKey&&u.currentTarget.target!=="_blank"}function bG({moduleId:u,tabId:f,className:l,active:r=!1,title:y,testId:i,onNavigate:_,children:n}){let $=k6(Zr,u,f);return A("a",{href:$,role:"button",className:l,title:y,"aria-current":r?"page":void 0,"data-testid":i,"data-route":$,onClick:(j)=>{if(!dt(j))return;j.preventDefault(),_(u,f)}},n)}function et({activeModule:u,activeTabs:f,onNavigate:l,collapsed:r,onToggle:y}){return A("aside",{className:`rail ${r?"collapsed":""}`,"aria-label":"主模块"},A("div",{className:"brand"},A("span",{className:"brand-mark"},"UD"),A("span",{className:"brand-text"},"UniDesk"),A("button",{type:"button",className:"rail-toggle",onClick:y,"aria-label":r?"展开左侧边栏":"收起左侧边栏","data-testid":"rail-toggle"},r?"»":"«")),I6.map((i)=>{let _=f[i.id]||tn[i.id]||i.tabs[0]?.id||"";return A(bG,{key:i.id,moduleId:i.id,tabId:_,className:`module ${u===i.id?"active":""}`,active:u===i.id,title:i.label,onNavigate:l},A("span",{className:"module-code"},i.code),A("span",null,i.label))}))}function uS({module:u,activeTab:f,onNavigate:l}){return A("nav",{className:"tabs","aria-label":`${u.label} 子功能`},u.tabs.map((r)=>A(bG,{key:r.id,moduleId:u.id,tabId:r.id,className:`tab ${f===r.id?"active":""}`,active:f===r.id,onNavigate:l},r.label)))}function fS({data:u,onRaw:f,onNavigate:l}){let r=u.overview||{},y=u.nodes.filter((q)=>q.status==="online"),i=u.pendingTasks||u.tasks.filter(l_),_=r.pendingTaskCount??i.length,n=u.tasks.slice(0,5),$=r.pgdata||{},j=r.microserviceAvailability||{},F=Mu(j.totalCount),J=Mu(j.healthyCount),U=Mu(j.unhealthyCount);return A("div",{className:"page-grid overview-grid","data-testid":"overview-page"},A(au,{title:"核心指标",eyebrow:"Control"},A("div",{className:"metric-grid"},A($f,{label:"数据库",value:r.dbReady?"READY":"WAIT",hint:"PostgreSQL internal network",tone:r.dbReady?"ok":"warn"}),A($f,{label:"PGDATA",value:Nl($.databaseBytes),hint:`${$.volumeName||"unidesk_pgdata_10gb"} / ${$.databasePretty||"--"}`,tone:"ok",testId:"pgdata-usage-card"}),A($f,{label:"在线节点",value:r.onlineNodeCount??0,hint:`${r.nodeCount??0} registered`,tone:"ok"}),A($f,{label:"WebSocket",value:r.activeSocketCount??0,hint:"Provider ingress sockets"}),A($f,{label:"用户服务可用",value:F>0?`${J}/${F}`:"--",hint:F>0?`healthyCount ${J} · unhealthyCount ${U}`:"strict /health probes",tone:F>0&&U===0?"ok":"warn",testId:"microservice-availability-card"}),A($f,{label:"待处理任务",value:_,hint:_>0?"点击查看具体任务":`timeout ${S0(Math.floor((r.taskPendingTimeoutMs??0)/1000))}`,tone:_>0?"warn":"ok",onClick:()=>l("tasks","pending"),testId:"pending-task-card"}))),A(au,{title:"本机 Provider",eyebrow:"Self Connected"},y.length===0?A(Ff,{title:"暂无在线节点",text:"provider-gateway 未完成自接入"}):A("div",{className:"node-card-list"},y.slice(0,4).map((q)=>A(lS,{key:q.providerId,node:q,onRaw:f})))),A(au,{title:"待处理任务明细",eyebrow:`${_} Pending`,actions:A("button",{type:"button",className:"ghost-btn",onClick:()=>l("tasks","pending"),"data-testid":"pending-task-detail-link"},"进入任务调度")},i.length===0?A(Ff,{title:"当前无待处理",text:"queued / dispatched / running 超时后会自动转为 failed,避免总览长期卡住"}):A("div",{className:"compact-list"},i.slice(0,5).map((q)=>A(OG,{key:q.id,task:q,onRaw:f})))),A(au,{title:"最近任务",eyebrow:"Dispatch"},n.length===0?A(Ff,{title:"暂无任务",text:"可以在任务调度模块发起 docker.ps 或 echo"}):A("div",{className:"compact-list"},n.map((q)=>A(OG,{key:q.id,task:q,onRaw:f})))))}function lS({node:u,onRaw:f}){return A("article",{className:"node-card"},A("div",{className:"node-card-head"},A("div",null,A("strong",null,u.name),A("code",null,u.providerId)),A(Nf,{status:u.status})),A("div",{className:"node-version-line"},A(f_,{node:u}),A("span",null,`升级策略 ${Z$(u)}`)),A(Pj,{node:u}),A(hG,{labels:u.labels,limit:6}),A("div",{className:"node-card-foot"},A("span",null,`心跳 ${Nu(u.lastHeartbeat)}`),A(Cf,{title:`Provider ${u.providerId}`,data:u,onOpen:f,testId:`raw-node-${bl(u.providerId)}`})))}function rS({events:u,onRaw:f}){return A(au,{title:"事件摘要",eyebrow:"Latest 100"},u.length===0?A(Ff,{title:"暂无事件",text:"Provider 注册、心跳超时和任务状态会写入事件流"}):A("div",{className:"table-wrap"},A("table",null,A("thead",null,A("tr",null,A("th",null,"ID"),A("th",null,"类型"),A("th",null,"来源"),A("th",null,"摘要"),A("th",null,"时间"),A("th",null,"操作"))),A("tbody",null,u.map((l)=>A("tr",{key:l.id},A("td",null,A("code",null,l.id)),A("td",null,A(Nf,{status:l.type},l.type)),A("td",null,A("code",null,l.source)),A("td",null,A(m1,{data:l.payload})),A("td",null,Nu(l.createdAt)),A("td",null,A(Cf,{title:`Event ${l.id}`,data:l,onOpen:f}))))))))}function yS({logs:u,onRaw:f}){return A(au,{title:"服务日志",eyebrow:"Core Recent"},u.length===0?A(Ff,{title:"暂无日志",text:"backend-core 内存日志会在请求和 provider 事件后出现"}):A("div",{className:"log-list"},u.slice(-80).reverse().map((l,r)=>A("article",{key:r,className:`log-row ${l.level||"info"}`},A("span",null,Nu(l.ts)),A("b",null,l.level||"info"),A("strong",null,l.message||"log"),A(m1,{data:l.data,empty:"无附加字段"}),A(Cf,{title:`Log ${l.message||r}`,data:l,onOpen:f})))))}function iS({nodes:u,onRaw:f}){return A(au,{title:"节点清单",eyebrow:`${u.length} Providers`},u.length===0?A(Ff,{title:"暂无 Provider 节点",text:"确认 provider-gateway 已连接 provider ingress"}):A("div",{className:"table-wrap"},A("table",{className:"node-list-table"},A("thead",null,A("tr",null,A("th",null,"状态"),A("th",null,"Provider"),A("th",null,"网关版本"),A("th",null,"运维可用性"),A("th",null,"资源标签"),A("th",null,"连接时间"),A("th",null,"最后心跳"),A("th",null,"操作"))),A("tbody",null,u.map((l)=>A("tr",{key:l.providerId},A("td",null,A(Nf,{status:l.status})),A("td",null,A("strong",null,l.name),A("code",null,l.providerId)),A("td",null,A("div",{className:"gateway-cell"},A(f_,{node:l}),A("span",null,Z$(l)))),A("td",null,A(Pj,{node:l})),A("td",null,A(hG,{labels:l.labels,limit:5})),A("td",null,Nu(l.connectedAt)),A("td",null,Nu(l.lastHeartbeat)),A("td",null,A(Cf,{title:`Provider ${l.providerId}`,data:l,onOpen:f,testId:`raw-node-table-${bl(l.providerId)}`}))))))))}function _S({nodes:u}){let f=H$(()=>{let l=[];for(let r of u)for(let[y,i]of tG(r.labels))l.push({providerId:r.providerId,name:r.name,key:y,value:i});return l},[u]);return A(au,{title:"资源标签",eyebrow:"Structured Labels"},f.length===0?A(Ff,{title:"暂无标签",text:"provider-gateway 注册消息会同步资源标签"}):A("div",{className:"label-matrix"},f.map((l)=>A("article",{key:`${l.providerId}-${l.key}`,className:"label-card"},A("span",null,l.key),A("strong",null,By(l.value)),A("code",null,l.providerId)))))}function nS({nodes:u}){return A(au,{title:"心跳状态",eyebrow:"Provider Liveness"},u.length===0?A(Ff,{title:"无心跳",text:"等待 provider 注册和 heartbeat"}):A("div",{className:"heartbeat-list"},u.map((f)=>A("article",{key:f.providerId,className:"heartbeat-row"},A("span",{className:`pulse ${f.status}`}),A("div",null,A("strong",null,f.name),A("code",null,f.providerId)),A("div",null,A("span",null,"connected"),A("b",null,Nu(f.connectedAt))),A("div",null,A("span",null,"last heartbeat"),A("b",null,Nu(f.lastHeartbeat)))))))}function $S({nodes:u,systemStatuses:f,tasks:l,onRaw:r,refresh:y}){let[i,_]=pu(""),n=H$(()=>u.map((G)=>{let K=f.find((Q)=>Q.providerId===G.providerId);return{...G,systemCurrent:K?.current||null,systemHistory:K?.history||[],systemUpdatedAt:K?.updatedAt||null}}),[u,f]),$=n.find((G)=>G.providerId===i)||n[0]||null;if(A0(()=>{if(!i&&n[0])_(n[0].providerId)},[n.length,i]),!$)return A(Ff,{title:"暂无资源监控",text:"等待 provider 上报 CPU、内存和硬盘指标"});let j=$.systemCurrent,F=$.systemHistory||[],J=j?.cpu||{},U=j?.memory||{},q=j?.disk||{},W=F.length>0?F:j?[{at:j.collectedAt,cpuPercent:Mu(J.percent),memoryPercent:Mu(U.percent),diskPercent:Mu(q.percent)}]:[];return A("div",{className:"monitor-page","data-testid":"node-monitor-page"},A("div",{className:"docker-node-strip"},n.map((G)=>A("button",{key:G.providerId,type:"button",className:`docker-node-tile ${$.providerId===G.providerId?"active":""}`,onClick:()=>_(G.providerId)},A("span",{className:`pulse ${G.status}`}),A("strong",null,G.name),A("code",null,G.providerId),A("span",null,G.systemCurrent?`CPU ${P1(G.systemCurrent.cpu?.percent)} / MEM ${P1(G.systemCurrent.memory?.percent)}`:"等待指标")))),A("div",{className:"monitor-layout"},A(au,{title:"任务管理器视图",eyebrow:$.name,className:"monitor-main-panel",actions:j?A(Cf,{title:`System ${$.providerId}`,data:{current:j,history:F},onOpen:r}):null},!j?A(Ff,{title:"系统指标未上报",text:"provider-gateway 会周期性采集 /proc 与 df,并保存历史曲线"}):A("div",null,A("div",{className:"monitor-hero"},A("div",null,A("p",{className:"panel-eyebrow"},"Node Performance"),A("h3",null,$.name),A("div",{className:"docker-meta"},A("span",null,`${J.cores||0} CPU cores`),A("span",null,`load ${Mu(J.load1).toFixed(2)} / ${Mu(J.load5).toFixed(2)} / ${Mu(J.load15).toFixed(2)}`),A("span",null,`memory actual ${Nl(U.usedBytes)} / ${Nl(U.totalBytes)}`),A("span",null,`disk ${Nl(q.usedBytes)} / ${Nl(q.totalBytes)}`))),A(Nf,{status:j.ok?"online":"warn"},j.ok?"METRICS READY":"METRICS DEGRADED")),A("div",{className:"monitor-chart-grid"},A(Vj,{title:"CPU",metricKey:"cpuPercent",current:J.percent,points:W,detail:`${J.cores||0} cores / load ${Mu(J.load1).toFixed(2)}`,tone:"cpu",testId:"metric-chart-cpu"}),A(Vj,{title:"Memory",metricKey:"memoryPercent",current:U.percent,points:W,detail:`${Nl(U.usedBytes)} actual / ${Nl(U.cacheBytes)} cache excluded`,tone:"memory",testId:"metric-chart-memory"}),A(Vj,{title:"Disk",metricKey:"diskPercent",current:q.percent,points:W,detail:`${q.path||"/"} mounted ${q.mount||"--"}`,tone:"disk",testId:"metric-chart-disk"})),A("div",{className:"monitor-summary-grid"},A($f,{label:"CPU 当前",value:P1(J.percent),hint:`history ${W.length} samples`,tone:"ok"}),A($f,{label:"实际内存",value:Nl(U.usedBytes),hint:`${P1(U.percent)} 不含缓存`}),A($f,{label:"硬盘已用",value:Nl(q.usedBytes),hint:P1(q.percent)}),A($f,{label:"更新时间",value:Nu($.systemUpdatedAt||j.collectedAt),hint:$.providerId})),A(AS,{current:j,onRaw:r}))),A("div",{className:"monitor-side-stack"},A(cS,{provider:$,refresh:y,onRaw:r}),A(NS,{provider:$,tasks:l,onRaw:r,limit:5}),A(au,{title:"采样说明",eyebrow:"Retention"},A("div",{className:"monitor-note-list"},A("article",null,A("b",null,"CPU"),A("span",null,"从 /proc/stat 计算相邻采样差值,首个采样用 load/cores 近似")),A("article",null,A("b",null,"Memory"),A("span",null,"实际内存 = MemTotal - MemFree - Buffers - Cached - SReclaimable + Shmem,不把 page cache / buffer 计入占用")),A("article",null,A("b",null,"Disk"),A("span",null,"使用 df -PB1 对配置路径采样,默认监控根文件系统")),A("article",null,A("b",null,"Process"),A("span",null,"从 /proc/[pid] 采集进程 CPU、实际内存 RSS、线程数和磁盘 I/O 速率;表格默认按内存占用降序")))))))}function TG(u,f){if(f==="memory")return Mu(u.rssBytes);if(f==="cpu")return Mu(u.cpuPercent);if(f==="disk")return Mu(u.readBytesPerSecond)+Mu(u.writeBytesPerSecond);if(f==="pid")return Mu(u.pid);if(f==="threads")return Mu(u.threads);if(f==="runtime")return Mu(u.elapsedSeconds);if(f==="user")return String(u.user||"");return String(u.name||u.command||"")}function ZG({value:u,label:f,tone:l}){let r=Math.max(1,Math.min(100,Mu(u)));return A("div",{className:`process-meter ${l||""}`},A("span",{style:{width:`${r}%`}}),A("b",null,f))}function AS({current:u,onRaw:f}){let[l,r]=pu({key:"memory",direction:"desc"}),y=M1.default.useContext(Yj),i=u?.processSummary&&typeof u.processSummary==="object"?u.processSummary:{},_=Array.isArray(u?.processes)?u.processes:[],n=H$(()=>{let j=l.direction==="asc"?1:-1;return[..._].sort((F,J)=>{let U=TG(F,l.key),q=TG(J,l.key);if(typeof U==="string"||typeof q==="string")return String(U).localeCompare(String(q),"zh-CN")*j;return(U-q)*j||Mu(F.pid)-Mu(J.pid)})},[_,l.key,l.direction]),$=(j,F)=>{let J=l.key===F,U=J?l.direction==="asc"?"ascending":"descending":"none";return A("th",{"aria-sort":U},A("button",{type:"button",className:`process-sort-button ${J?"active":""}`,"data-testid":`process-sort-${F}`,onClick:()=>r((q)=>({key:F,direction:q.key===F&&q.direction==="desc"?"asc":"desc"}))},j,A("span",null,J?l.direction==="desc"?"↓":"↑":"↕")))};return A("section",{className:"process-resource-panel","data-testid":"process-resource-panel"},A("div",{className:"process-resource-head"},A("div",null,A("p",{className:"panel-eyebrow"},"Windows Resource Monitor Style"),A(Af,{title:"进程资源占用",level:3,loading:y})),A("div",{className:"process-resource-actions"},A("span",{className:"data-chip"},"默认按内存排序"),A("span",{className:"data-chip"},`${Mu(i.visible,n.length)} / ${Mu(i.total,n.length)} 进程`),A(Cf,{title:"Process Resource Snapshot",data:{processSummary:i,processes:_},onOpen:f,testId:"raw-process-resources"}))),n.length===0?A(Ff,{title:"暂无进程资源数据",text:"等待 provider-gateway 上报 /proc/[pid] 采样;旧版 provider 需要先升级到支持进程资源表的版本"}):A("div",{className:"process-table-wrap"},A("table",{className:"process-resource-table","data-testid":"process-resource-table"},A("thead",null,A("tr",null,$("进程","name"),$("PID","pid"),$("用户","user"),A("th",null,"状态"),$("CPU","cpu"),$("内存","memory"),A("th",null,"RSS"),$("磁盘 I/O","disk"),$("线程","threads"),$("运行时长","runtime"))),A("tbody",null,n.map((j)=>{let F=Mu(j.readBytesPerSecond)+Mu(j.writeBytesPerSecond);return A("tr",{key:`${j.pid}-${j.startedAt}`,"data-testid":`process-row-${bl(j.pid)}`,"data-memory-bytes":String(Mu(j.rssBytes)),"data-cpu-percent":String(Mu(j.cpuPercent)),"data-disk-bps":String(F),"data-pid":String(Mu(j.pid))},A("td",null,A("div",{className:"process-name-cell"},A("strong",null,j.name||"--"),A("span",{className:"process-command"},j.command||"--"))),A("td",null,A("code",null,j.pid||"--")),A("td",null,j.user||`uid:${j.uid??"--"}`),A("td",null,A("span",{className:`process-state state-${bl(j.state||"unknown")}`},j.state||"?")),A("td",null,A(ZG,{value:j.cpuPercent,label:xt(j.cpuPercent),tone:"cpu"})),A("td",null,A(ZG,{value:j.memoryPercent,label:P1(j.memoryPercent),tone:"memory"})),A("td",null,Nl(j.rssBytes)),A("td",null,A("div",{className:"process-io-cell"},A("strong",null,Bj(F)),A("span",null,`R ${Bj(j.readBytesPerSecond)} / W ${Bj(j.writeBytesPerSecond)}`))),A("td",null,j.threads||0),A("td",null,S0(Mu(j.elapsedSeconds))))})))))}function Vj({title:u,metricKey:f,current:l,points:r,detail:y,tone:i,testId:_}){let n=r.map((U)=>Math.max(0,Math.min(100,Mu(U[f])))),$=n.length>1?n:[n[0]||0,n[0]||0],j=$.length<=1?100:100/($.length-1),F=$.map((U,q)=>`${(q*j).toFixed(2)},${(46-U*0.42).toFixed(2)}`).join(" "),J=`0,48 ${F} 100,48`;return A("article",{className:`metric-chart ${i}`,"data-testid":_},A("div",{className:"metric-chart-head"},A("div",null,A("span",null,u),A("strong",null,P1(l))),A("code",null,`${r.length} pts`)),A("svg",{viewBox:"0 0 100 48",preserveAspectRatio:"none",role:"img","aria-label":`${u} usage curve`},A("polygon",{points:J}),A("polyline",{points:F}),A("line",{x1:"0",x2:"100",y1:"24",y2:"24"})),A("div",{className:"metric-chart-foot"},A("span",null,"0%"),A("span",null,y),A("span",null,"100%")))}function P0(u){return Array.isArray(u)?u:[]}function jS(u){let f=P0(u?.core?.requests?.componentSummary);return[...P0(u?.frontend?.requests?.componentSummary),...f].sort((r,y)=>Mu(y.requestCount)-Mu(r.requestCount))}function FS(u){let f=P0(u?.core?.operations?.summary);return[...P0(u?.frontend?.operations?.summary),...f].sort((r,y)=>Mu(y.count)-Mu(r.count))}function JS(u){let f=P0(u?.core?.requests?.recentFailures).map((r)=>({source:"backend",...r}));return[...P0(u?.frontend?.requests?.recentFailures).map((r)=>({source:"frontend",...r})),...f].sort((r,y)=>(j0(y.at)??0)-(j0(r.at)??0)).slice(0,20)}function US(u){let f=P0(u?.core?.operations?.recentSlowOperations);return[...P0(u?.frontend?.operations?.recentSlowOperations),...f].sort((r,y)=>Mu(y.durationMs)-Mu(r.durationMs)).slice(0,20)}function QS(u){let f=performance.memory,l=Number(f?.usedJSHeapSize);if(Number.isFinite(l)&&l>0)return l;let r=Number(u?.appBundleBytes);if(Number.isFinite(r)&&r>0)return r;return Mu(u?.process?.heapUsedBytes)}function qS({points:u}){let f=P0(u),l=f.map((U)=>Mu(U.mb)),r=Math.max(1,...l),y=Math.max(0,Math.min(...l,0)),i=Math.max(1,r-y),_=f.length>1?f:[...f,...f],n=_.length<=1?100:100/(_.length-1),$=_.map((U,q)=>{let W=Mu(U.mb);return`${(q*n).toFixed(2)},${(48-(W-y)/i*42).toFixed(2)}`}).join(" "),j=`0,50 ${$} 100,50`,F=f.at(-1),J=f[0];return A("article",{className:"performance-memory-card","data-testid":"performance-memory-chart"},A("div",{className:"performance-memory-head"},A("strong",null,`Bwebui: ${F?`${Mu(F.mb).toFixed(1)}MB`:"--"}`),A("span",null,f.length>0?`${f.length} samples`:"等待采样")),A("svg",{viewBox:"0 0 100 50",preserveAspectRatio:"none",role:"img","aria-label":"Bwebui memory trend"},A("polygon",{points:j}),A("polyline",{points:$}),A("line",{x1:"0",x2:"100",y1:"25",y2:"25"})),A("div",{className:"performance-axis-row"},A("span",null,J?qf(new Date(J.at)):"--"),A("span",null,"时间"),A("span",null,F?qf(new Date(F.at)):"--")),A("div",{className:"performance-axis-row"},A("span",null,`${y.toFixed(1)}`),A("span",null,"(MB)"),A("span",null,`${r.toFixed(1)}`)))}function WS({onRaw:u}){let[f,l]=pu({core:null,frontend:null}),[r,y]=pu([]),[i,_]=pu(""),[n,$]=pu(!1),[j,F]=pu(null),[J,U]=pu(!1);async function q(){$(!0),_("");try{let[P,t]=await Promise.all([Xu(`${Iu.apiBaseUrl}/performance`,{cache:"no-store"}),Xu(`${Iu.apiBaseUrl}/frontend-performance`,{cache:"no-store"})]);l({core:P,frontend:t});let O=QS(t);y((M)=>[...M,{at:new Date().toISOString(),mb:O/1048576}].slice(-80))}catch(P){_(Bu(P,"性能指标加载失败"))}finally{$(!1)}}A0(()=>{q();let P=setInterval(()=>void q(),5000);return()=>clearInterval(P)},[]);async function W(){U(!0),_(""),F(null);try{let P=await Xu(`${Iu.apiBaseUrl}/code-queue-load-test`,{method:"POST",body:JSON.stringify({targetMs:1000,timeoutMs:90000,url:Iu.frontendPublicUrl||window.location.origin})});F(P),q()}catch(P){_(Bu(P,"Code Queue Playwright 测量失败"))}finally{U(!1)}}let G=jS(f),K=JS(f),Q=FS(f),N=US(f),c=f.core?.process||{},z=f.frontend?.process||{},w=f.core?.database?.codeQueueStorage||{},H=Mu(w.total),B=j?.result||{},T=Mu(B.wallMs,NaN),X=Mu(B.networkIdleMs,NaN),R=B.withinTarget===!0,Y=J?"running":j===null?"idle":j.measurementOk===!0?R?"passed":"slow":"failed";return A("div",{className:"performance-page","data-testid":"performance-page"},A("div",{className:"performance-hero"},A("div",null,A("p",{className:"panel-eyebrow"},"Unified Performance"),A(Af,{title:"性能面板",loading:n||J}),A("p",null,"按组件统计 HTTP 请求、失败率、P95 延迟,并汇总 backend/frontend 内部操作耗时。")),A("div",{className:"inline-actions"},A("button",{type:"button",className:"ghost-btn",onClick:()=>void W(),disabled:J,"data-testid":"code-queue-load-test-button"},J?"测试中...":"测试 Code Queue 加载"),A("button",{type:"button",className:"ghost-btn",onClick:()=>void q(),disabled:n,"data-testid":"performance-refresh-button"},n?"刷新中":"刷新"),A(Cf,{title:"Performance Snapshot",data:f,onOpen:u,testId:"raw-performance"}))),A(jf,{error:i}),A("div",{className:"performance-top-grid"},A(qS,{points:r}),A("div",{className:"performance-metric-stack"},A($f,{label:"backend RSS",value:Nl(c.rssBytes),hint:`heap ${Nl(c.heapUsedBytes)}`}),A($f,{label:"frontend RSS",value:Nl(z.rssBytes),hint:`bundle ${Nl(f.frontend?.appBundleBytes)}`}),A($f,{label:"Codex PG 任务",value:H||"--",hint:w.ok?"unidesk_code_queue_tasks":"等待表初始化",tone:w.ok?"ok":"warn"}),A($f,{label:"请求样本",value:Mu(f.core?.requests?.sampleCount)+Mu(f.frontend?.requests?.sampleCount),hint:"rolling window 3000"}))),A(au,{title:"Code Queue 加载基准",eyebrow:"Playwright / target <1s",className:"codex-load-test-panel",loading:J,actions:A("div",{className:"panel-actions"},A("button",{type:"button",className:"primary-btn",onClick:()=>void W(),disabled:J,"data-testid":"code-queue-load-test-panel-button"},J?"正在运行 Playwright...":"手动触发测试"),j?A(Cf,{title:"Code Queue Load Test",data:j,onOpen:u,testId:"raw-code-queue-load-test"}):null)},A("div",{className:"codex-load-test-grid","data-testid":"code-queue-load-test-result"},A($f,{label:"总耗时",value:J?"运行中":Number.isFinite(T)?Ar(T):"--",hint:j===null?"点击按钮启动远端 Playwright":`目标 ${Ar(B.targetMs||1000)} / ${B.url||"Code Queue"}`,tone:Y==="passed"?"ok":Y==="failed"||Y==="slow"?"warn":""}),A($f,{label:"判定",value:J?"RUNNING":Y==="passed"?"PASS <1s":Y==="slow"?"SLOW":Y==="failed"?"FAILED":"--",hint:j?.measurementOk===!1?String(j.error||B.error||"measurement failed").slice(0,120):"导航开始 -> DOMContentLoaded -> data-load-state=complete",tone:Y==="passed"?"ok":Y==="idle"||Y==="running"?"":"fail"}),A($f,{label:"Network idle",value:Number.isFinite(X)?Ar(X):"--",hint:`DOMContentLoaded ${Ar(B.domContentLoadedMs)} / ${B.networkIdleReached===!1?"未在 5s 内空闲":"已空闲"}`,tone:Number.isFinite(X)&&X<=1000?"ok":"warn"}),A($f,{label:"组件耗时",value:Number.isFinite(Mu(B.componentLoadMs,NaN))?Ar(B.componentLoadMs):"--",hint:`queue ${Ar(B.queueMs)} / detail ${Ar(B.detailMs)}`,tone:Mu(B.componentLoadMs)>1000?"warn":"ok"}),A($f,{label:"Trace 规模",value:Number.isFinite(Mu(B.transcriptRows,NaN))?String(B.transcriptRows):"--",hint:`${B.visibleTaskCount??0} visible tasks / ${B.partial?"preview":"complete"}`})),J?A("div",{className:"performance-empty-line"},"正在通过 main-server Host SSH 启动 Playwright,完成后会显示 wall time、组件耗时和最慢 API。"):null,j&&Array.isArray(B.slowestApi)&&B.slowestApi.length>0?A("div",{className:"table-wrap performance-table-wrap compact codex-load-api-table"},A("table",{className:"performance-table"},A("thead",null,A("tr",null,["API","状态","耗时"].map((P)=>A("th",{key:P},P)))),A("tbody",null,B.slowestApi.slice(0,5).map((P,t)=>A("tr",{key:`${P.url}-${t}`},A("td",null,A("code",null,P.url)),A("td",null,P.status),A("td",null,Ar(P.durationMs))))))):null),A("div",{className:"performance-grid"},A(au,{title:"组件汇总",eyebrow:"Requests",loading:n},G.length===0?A(Ff,{title:"暂无请求样本",text:"刷新几次或打开页面后会自动形成组件统计"}):A("div",{className:"table-wrap performance-table-wrap"},A("table",{className:"performance-table"},A("thead",null,A("tr",null,["组件","请求数","失败数","失败率","平均延迟","P95"].map((P)=>A("th",{key:P},P)))),A("tbody",null,G.map((P)=>A("tr",{key:P.component},A("td",null,A("code",null,P.component)),A("td",null,P.requestCount),A("td",null,P.failureCount),A("td",null,P1(Mu(P.failureRate)*100)),A("td",null,Ar(P.averageLatencyMs)),A("td",null,Ar(P.p95LatencyMs)))))))),A(au,{title:"最近失败请求",eyebrow:"Failures",loading:n},K.length===0?A("div",{className:"performance-empty-line"},"最近没有失败请求"):A("div",{className:"table-wrap performance-table-wrap compact"},A("table",{className:"performance-table"},A("thead",null,A("tr",null,["时间","来源","组件","状态","路径"].map((P)=>A("th",{key:P},P)))),A("tbody",null,K.map((P,t)=>A("tr",{key:`${P.at}-${t}`},A("td",null,Nu(P.at)),A("td",null,P.source),A("td",null,A("code",null,P.component)),A("td",null,A(Nf,{status:"failed"},P.status)),A("td",null,A("code",null,P.path)))))))),A(au,{title:"内部操作汇总",eyebrow:"Operations",loading:n},Q.length===0?A(Ff,{title:"暂无内部操作样本",text:"API 查询和代理请求会自动记录内部操作耗时"}):A("div",{className:"table-wrap performance-table-wrap"},A("table",{className:"performance-table"},A("thead",null,A("tr",null,["服务","操作","次数","平均延迟","P95"].map((P)=>A("th",{key:P},P)))),A("tbody",null,Q.map((P)=>A("tr",{key:`${P.service}-${P.operation}`},A("td",null,P.service),A("td",null,A("code",null,P.operation)),A("td",null,P.count),A("td",null,Ar(P.averageLatencyMs)),A("td",null,Ar(P.p95LatencyMs)))))))),A(au,{title:"最近慢操作",eyebrow:"Slowest",loading:n},N.length===0?A(Ff,{title:"暂无慢操作",text:"后端会记录最近窗口内耗时最高的内部操作"}):A("div",{className:"table-wrap performance-table-wrap"},A("table",{className:"performance-table"},A("thead",null,A("tr",null,["时间","操作","耗时","结果","细节"].map((P)=>A("th",{key:P},P)))),A("tbody",null,N.map((P,t)=>A("tr",{key:`${P.at}-${P.operation}-${t}`},A("td",null,Nu(P.at)),A("td",null,A("code",null,P.operation)),A("td",null,Ar(P.durationMs)),A("td",null,P.ok?"成功":"失败"),A("td",null,P.detail||"-")))))))))}function cS({provider:u,refresh:f,onRaw:l}){let[r,y]=pu(""),[i,_]=pu(null),[n,$]=pu("");async function j(F){y(F),$("");try{let J=await Xu(`${Iu.apiBaseUrl}/dispatch`,{method:"POST",body:JSON.stringify({providerId:u.providerId,command:"provider.upgrade",payload:{mode:F,source:"frontend-resource-monitor",requestedAt:new Date().toISOString()}})});_({mode:F,...J}),await f()}catch(J){$(Bu(J,"升级命令下发失败"))}finally{y("")}}return A(au,{title:"Provider Gateway 升级",eyebrow:"Remote Control",loading:Boolean(r)},A("div",{className:"upgrade-control","data-testid":"provider-upgrade-control"},A("p",null,"通过 UniDesk WebSocket 向当前计算节点下发 provider.upgrade;预检只生成升级计划,执行升级会调度节点本地 updater 容器。"),A("div",{className:"upgrade-target-line"},A("span",null,"指定 Provider"),A("code",null,u.providerId),A(f_,{node:u})),A("div",{className:"upgrade-actions"},A("button",{type:"button",className:"ghost-btn",disabled:Boolean(r),onClick:()=>j("plan"),"data-testid":"upgrade-plan-button"},r==="plan"?"预检中":"预检升级"),A("button",{type:"button",className:"ghost-btn danger",disabled:Boolean(r),onClick:()=>j("schedule"),"data-testid":"upgrade-schedule-button"},r==="schedule"?"调度中":"执行升级")),A(jf,{error:n}),i?A("div",{className:"upgrade-result"},A(Nf,{status:i.status||"queued"},i.status||"queued"),A("span",null,`${i.mode==="schedule"?"执行升级":"预检升级"} 已下发`),A("span",null,`指定版本 ${Sj(SG(u))}`),A("code",null,i.taskId||"--"),A(Cf,{title:"Provider Upgrade Dispatch",data:i,onOpen:l})):A("span",{className:"muted"},"升级任务结果会进入任务历史;执行升级可能导致 provider 短暂重连。")))}function vG({records:u,onRaw:f,compact:l=!1}){if(u.length===0)return A(Ff,{title:"暂无远程更新记录",text:"该节点还没有 provider.upgrade 任务;执行预检或升级后会在这里形成结构化记录"});return A("div",{className:`upgrade-record-table-wrap table-wrap ${l?"compact":""}`},A("table",{className:"upgrade-record-table"},A("thead",null,A("tr",null,A("th",null,"状态"),A("th",null,"模式"),A("th",null,"任务"),A("th",null,"来源"),A("th",null,"耗时"),A("th",null,"策略"),A("th",null,"Gateway 版本"),A("th",null,"结果记录"),A("th",null,"更新时间"),A("th",null,"操作"))),A("tbody",null,u.map((r)=>A("tr",{key:r.id,"data-testid":`gateway-upgrade-record-${bl(r.id)}`},A("td",null,A(Nf,{status:r.status})),A("td",null,A("span",{className:`mode-chip ${W8(r)}`},W8(r)==="schedule"?"执行升级":"预检")),A("td",null,A("strong",null,"provider.upgrade"),A("code",null,r.id)),A("td",null,vt(r)),A("td",null,A(kG,{task:r})),A("td",null,It(r)),A("td",null,A("span",{className:"version-chip"},pG(r))),A("td",null,A("span",{className:`upgrade-outcome ${String(r.status||"").toLowerCase()}`},CG(r))),A("td",null,Nu(r.updatedAt)),A("td",null,A(Cf,{title:`Provider Upgrade Task ${r.id}`,data:O$(r),onOpen:f})))))))}function NS({provider:u,tasks:f,onRaw:l,limit:r=5}){let y=xG(f,u.providerId).slice(0,r);return A(au,{title:"远程更新记录",eyebrow:u.providerId,actions:A(f_,{node:u}),className:"provider-upgrade-records-panel"},A("div",{"data-testid":`provider-upgrade-records-${bl(u.providerId)}`},A(vG,{records:y,onRaw:l,compact:!0})))}function zS({nodes:u,tasks:f,onRaw:l}){let r=H$(()=>u.map((i)=>{let _=xG(f,i.providerId);return{node:i,records:_,latest:kt(_),capabilities:PG(i)}}),[u,f]),y=r.reduce((i,_)=>i+_.records.length,0);return A("div",{className:"gateway-page","data-testid":"gateway-version-page"},A(au,{title:"Provider Gateway 版本",eyebrow:`${u.length} Providers / ${y} 更新记录`},u.length===0?A(Ff,{title:"暂无 Provider 节点",text:"等待 provider-gateway 注册后显示版本号和升级记录"}):A("div",{className:"table-wrap gateway-version-table-wrap"},A("table",{className:"gateway-version-table"},A("thead",null,A("tr",null,A("th",null,"状态"),A("th",null,"Provider"),A("th",null,"Gateway 版本"),A("th",null,"升级策略"),A("th",null,"运维可用性"),A("th",null,"运行时间"),A("th",null,"能力"),A("th",null,"最近远程更新"),A("th",null,"操作"))),A("tbody",null,r.map((i)=>A("tr",{key:i.node.providerId},A("td",null,A(Nf,{status:i.node.status})),A("td",null,A("strong",null,i.node.name),A("code",null,i.node.providerId)),A("td",null,A(f_,{node:i.node})),A("td",null,Z$(i.node)),A("td",null,A(Pj,{node:i.node})),A("td",null,KG(i.node)?Nu(KG(i.node)):"待新版上报"),A("td",null,A("div",{className:"capability-row"},i.capabilities.length===0?A("span",{className:"muted"},"未声明"):i.capabilities.slice(0,5).map((_)=>A("span",{key:_,className:"data-chip"},_)))),A("td",null,i.latest?A("div",{className:"latest-upgrade-cell"},A(Nf,{status:i.latest.status}),A("span",null,`${W8(i.latest)==="schedule"?"执行升级":"预检"} / ${Nu(i.latest.updatedAt)}`),A("small",null,`Gateway ${pG(i.latest)}`),A("small",null,CG(i.latest))):A("span",{className:"muted"},"暂无记录")),A("td",null,A(Cf,{title:`Provider ${i.node.providerId}`,data:i.node,onOpen:l})))))))),A(au,{title:"远程更新记录",eyebrow:"Structured provider.upgrade records"},u.length===0?A(Ff,{title:"暂无记录",text:"没有 provider 节点时不会生成远程更新记录"}):A("div",{className:"gateway-record-grid"},r.map((i)=>A("article",{key:i.node.providerId,className:"gateway-record-card","data-testid":`gateway-records-${bl(i.node.providerId)}`},A("div",{className:"gateway-record-head"},A("div",null,A("strong",null,i.node.name),A("code",null,i.node.providerId)),A(f_,{node:i.node})),A("div",{className:"gateway-record-meta"},A("span",null,`心跳 ${Nu(i.node.lastHeartbeat)}`),A("span",null,`策略 ${Z$(i.node)}`),A("span",null,`${i.records.length} 条记录`)),A(vG,{records:i.records.slice(0,8),onRaw:l,compact:!0}))))))}function GS(u){if(u==="running")return"online";if(u==="paused"||u==="restarting")return"warn";if(u==="exited"||u==="dead")return"offline";return"internal"}function IG(u){return/^[a-f0-9]{48,64}$/i.test(u)}function T$(u){let f=String(u?.name||""),l=String(u?.labels||"");return f==="unidesk_pgdata_10gb"||l.includes("com.docker.compose.volume=unidesk_pgdata_10gb")||f.toLowerCase().includes("pgdata")}function HG(u){let f=String(u?.name||""),l=String(u?.labels||"");if(T$(u))return 0;if(l.includes("com.docker.compose.project=unidesk"))return 1;if(!IG(f))return 2;return 3}function KS(u){return[...u].sort((f,l)=>{let r=HG(f)-HG(l);if(r!==0)return r;return String(f.name||"").localeCompare(String(l.name||""))})}function LS({nodes:u,dockerStatuses:f,onRaw:l}){let[r,y]=pu(""),i=H$(()=>u.map((N)=>{let c=f.find((z)=>z.providerId===N.providerId);return{...N,dockerStatus:c?.dockerStatus||null,dockerUpdatedAt:c?.updatedAt||null}}),[u,f]),_=i.find((N)=>N.providerId===r)||i[0]||null;if(A0(()=>{if(!r&&i[0])y(i[0].providerId)},[i.length,r]),!_)return A(Ff,{title:"暂无 Docker 节点",text:"等待 provider 上报 Docker daemon 状态"});let n=_.dockerStatus,$=_.providerId==="main-server",j=n?.counts||{},F=n?.daemon||{},J=n?.containers||[],U=n?.images||[],q=KS(n?.volumes||[]),W=$?q.find(T$):null,G=n?.networks||[],K=J.filter((N)=>N.state==="running"),Q=J.filter((N)=>N.state!=="running");return A("div",{className:"docker-page","data-testid":"docker-status-page"},A("div",{className:"docker-node-strip"},i.map((N)=>A("button",{key:N.providerId,type:"button",className:`docker-node-tile ${_.providerId===N.providerId?"active":""}`,onClick:()=>y(N.providerId)},A("span",{className:`pulse ${N.status}`}),A("strong",null,N.name),A("code",null,N.providerId),A("span",null,N.dockerStatus?`Docker ${N.dockerStatus.ok?"ready":"degraded"}`:"等待上报")))),A("div",{className:"docker-layout"},A(au,{title:"Docker Desktop 视图",eyebrow:_.name,className:"docker-main-panel",actions:n?A(Cf,{title:`Docker ${_.providerId}`,data:n,onOpen:l}):null},!n?A(Ff,{title:"Docker 状态未上报",text:"provider-gateway 会在连接后周期性采集 docker info / ps / images / volume / network"}):A("div",null,A("div",{className:"docker-hero"},A("div",null,A("p",{className:"panel-eyebrow"},"Daemon"),A("h3",null,F.name||_.providerId),A("div",{className:"docker-meta"},A("span",null,F.serverVersion?`Engine ${F.serverVersion}`:"Engine --"),A("span",null,F.operatingSystem||"OS --"),A("span",null,F.architecture||"arch --"),A("span",null,`${F.cpus||0} CPU / ${Nl(F.memoryBytes)}`))),A(Nf,{status:n.ok?"online":"warn"},n.ok?"Docker Ready":"Docker Degraded")),A("div",{className:"docker-metrics"},A($f,{label:"Containers",value:j.containers??J.length,hint:`${j.running??K.length} running / ${j.stopped??Q.length} stopped`,tone:"ok"}),A($f,{label:"Images",value:j.images??U.length,hint:`${j.daemonImages??j.images??U.length} daemon images`}),A($f,{label:"Volumes",value:j.volumes??q.length,hint:$?W?"database volume visible":"database volume missing":"node local volumes",tone:W?"ok":""}),A($f,{label:"Networks",value:j.networks??G.length,hint:F.driver?`driver ${F.driver}`:"docker networks"})),$?A(wS,{volume:W,volumeCount:q.length}):null,A("div",{className:"docker-section-head"},A("h3",null,"Containers"),A("span",null,`updated ${Nu(_.dockerUpdatedAt||n.collectedAt)}`)),A("div",{className:"docker-container-table table-wrap","data-testid":"docker-container-table"},A("table",null,A("thead",null,A("tr",null,A("th",null,"状态"),A("th",null,"容器"),A("th",null,"镜像"),A("th",null,"端口"),A("th",null,"运行时间"),A("th",null,"重启策略"),A("th",null,"PID"),A("th",null,"大小"))),A("tbody",null,J.length===0?A("tr",null,A("td",{colSpan:8},"暂无容器")):J.map((N)=>A("tr",{key:`${N.id}-${N.name}`},A("td",null,A(Nf,{status:GS(N.state)},N.state||"unknown")),A("td",null,A("strong",null,N.name||"--"),A("code",null,N.id||"--")),A("td",null,N.image||"--"),A("td",null,N.ports||A("span",{className:"muted"},"未发布")),A("td",null,N.runningFor||N.status||"--"),A("td",null,N.restartPolicy?A(Nf,{status:N.restartPolicy==="always"?"online":"warn"},N.restartPolicy):"--"),A("td",null,N.pidMode?A("code",null,N.pidMode):"--"),A("td",null,N.size||"--")))))))),A("div",{className:"docker-side-stack"},A(Xj,{title:"Images",items:U,render:(N)=>A("article",{key:`${N.id}-${N.repository}`,className:"docker-side-row"},A("strong",null,`${N.repository}:${N.tag}`),A("span",null,N.size||"--"),A("code",null,N.id||"--"))}),A(Xj,{title:"Volumes",items:q,limit:q.length,render:(N)=>A("article",{key:N.name,className:`docker-side-row volume-row ${$&&T$(N)?"database-volume":""}`,"data-testid":$&&T$(N)?"database-volume-row":void 0},A("strong",null,N.name),A("span",null,$&&T$(N)?"PostgreSQL":IG(String(N.name||""))?"anonymous":"named"),A("code",null,N.mountpoint||N.driver||N.scope||"--"))}),A(Xj,{title:"Networks",items:G,render:(N)=>A("article",{key:N.id||N.name,className:"docker-side-row"},A("strong",null,N.name),A("span",null,N.driver||"--"),A("code",null,N.id||"--"))}))))}function wS({volume:u,volumeCount:f}){return A("section",{className:`docker-volume-focus ${u?"ready":"missing"}`,"data-testid":"database-volume-card"},A("div",{className:"volume-focus-head"},A("span",{className:"panel-eyebrow"},"Database Named Volume"),A(Nf,{status:u?"online":"warn"},u?"FOUND":"MISSING")),u?A("div",{className:"volume-focus-body"},A("strong",null,u.name),A("span",null,"PostgreSQL data volume for unidesk-database"),A("div",{className:"volume-route"},A("code",null,u.mountpoint||"/var/lib/docker/volumes/unidesk_pgdata_10gb/_data"),A("span",null,"->"),A("code",null,"unidesk-database:/var/lib/postgresql/data")),A("div",{className:"docker-meta compact"},A("span",null,`driver ${u.driver||"--"}`),A("span",null,`scope ${u.scope||"--"}`),A("span",null,`${f} volumes reported`))):A("div",{className:"volume-focus-body"},A("strong",null,"unidesk_pgdata_10gb"),A("span",null,"当前 Docker 快照没有发现数据库命名卷;请检查 provider-gateway 的 Docker volume 上报。")))}function Xj({title:u,items:f,render:l,limit:r}){let y=f.slice(0,r??12),i=Math.max(0,f.length-y.length);return A(au,{title:u,eyebrow:`${f.length} items`,className:"docker-side-panel"},f.length===0?A(Ff,{title:`暂无 ${u}`,text:"等待 Docker 状态采集"}):A("div",{className:"docker-side-list"},y.map(l),i>0?A("div",{className:"docker-side-more"},`+ ${i} more`):null))}function ES({microservices:u,onRaw:f,onNavigate:l}){let r=u.filter((y)=>wG(y).public===!1);return A("div",{className:"microservice-page","data-testid":"microservice-catalog-page"},A(au,{title:"用户服务目录",eyebrow:"Provider Mounted User Services"},A("div",{className:"metric-grid"},A($f,{label:"服务总数",value:u.length,hint:"config.json 用户服务登记"}),A($f,{label:"私有后端",value:r.length,hint:"不直接暴露公网",tone:"ok"}),A($f,{label:"D601 服务",value:u.filter((y)=>y.providerId==="D601").length,hint:"compute-node docker"}),A($f,{label:"集成前端",value:u.filter((y)=>y.frontend?.integrated).length,hint:"UniDesk React 页面"}))),A(au,{title:"服务映射",eyebrow:"Repo Reference + Runtime"},u.length===0?A(Ff,{title:"暂无用户服务",text:"在 config.json 的 microservices 中登记用户服务的 provider、仓库引用和后端映射"}):A("div",{className:"table-wrap"},A("table",{className:"microservice-table"},A("thead",null,A("tr",null,A("th",null,"服务"),A("th",null,"Provider"),A("th",null,"代码引用"),A("th",null,"Docker 引用"),A("th",null,"后端映射"),A("th",null,"开发入口"),A("th",null,"运行态"),A("th",null,"操作"))),A("tbody",null,u.map((y)=>{let i=RG(y),_=gt(y),n=wG(y),$=i.availability||{},j=$.status||(i.providerStatus==="online"?"unknown":"unhealthy");return A("tr",{key:y.id,"data-testid":`microservice-row-${bl(y.id)}`},A("td",null,A("strong",null,y.name),A("code",null,y.id)),A("td",null,A("strong",null,i.providerName||y.providerId),A("code",null,y.providerId)),A("td",null,A("span",null,_.url||"--"),A("code",null,_.commitId||"--")),A("td",null,A("span",null,_.composeFile||"--"),A("code",null,`${_.composeService||"--"} / ${_.containerName||"--"}`)),A("td",null,A(Nf,{status:n.public?"warn":"online"},n.public?"public":"private"),A("code",null,`${n.nodeBindHost||"--"}:${n.nodePort||"--"} -> ${n.proxyMode||"--"}`)),A("td",null,A("span",null,y.development?.sshPassthrough?"SSH 透传":"未配置"),A("code",null,y.development?.worktreePath||"--")),A("td",null,A(Nf,{status:j==="healthy"?"online":j==="unknown"?"warn":"failed"},j),A("span",null,$.reason||i.providerStatus||"unknown"),A(m1,{data:i.container,empty:"容器快照未上报"})),A("td",null,A("div",{className:"microservice-actions"},y.id==="findjob"?A("button",{type:"button",className:"ghost-btn",onClick:()=>l("apps","findjob"),"data-testid":"open-findjob-button"},"打开"):null,y.id==="pipeline"?A("button",{type:"button",className:"ghost-btn",onClick:()=>l("apps","pipeline"),"data-testid":"open-pipeline-button"},"打开"):null,y.id==="todo-note"?A("button",{type:"button",className:"ghost-btn",onClick:()=>l("apps","todo-note"),"data-testid":"open-todo-note-button"},"打开"):null,y.id==="met-nonlinear"?A("button",{type:"button",className:"ghost-btn",onClick:()=>l("apps","met-nonlinear"),"data-testid":"open-met-nonlinear-button"},"打开"):null,y.id==="claudeqq"?A("button",{type:"button",className:"ghost-btn",onClick:()=>l("apps","claudeqq"),"data-testid":"open-claudeqq-button"},"打开"):null,y.id==="baidu-netdisk"?A("button",{type:"button",className:"ghost-btn",onClick:()=>l("apps","baidu-netdisk"),"data-testid":"open-baidu-netdisk-button"},"打开"):null,y.id==="code-queue"?A("button",{type:"button",className:"ghost-btn",onClick:()=>l("apps","code-queue"),"data-testid":"open-code-queue-button"},"打开"):null,y.id==="project-manager"?A("button",{type:"button",className:"ghost-btn",onClick:()=>l("apps","project-manager"),"data-testid":"open-project-manager-button"},"打开"):null,A(Cf,{title:`用户服务 ${y.id}`,data:y,onOpen:f}))))}))))))}function TS({nodes:u,onDispatched:f,onRaw:l}){let r=u.filter((Y)=>Y.status==="online"),[y,i]=pu(r[0]?.providerId||u[0]?.providerId||""),[_,n]=pu("docker.ps"),[$,j]=pu("frontend"),[F,J]=pu("operator-check"),[U,q]=pu("normal"),[W,G]=pu(!1),[K,Q]=pu(""),[N,c]=pu(!1),[z,w]=pu(null),[H,B]=pu("");A0(()=>{if(!y&&(r[0]?.providerId||u[0]?.providerId))i(r[0]?.providerId||u[0].providerId)},[u.length,r.length,y]);function T(){return{source:$,note:F,priority:U}}function X(){Q(JSON.stringify(T(),null,2)),G(!0)}async function R(Y){Y.preventDefault(),c(!0),B("");try{let P=W?JSON.parse(K||"{}"):T(),t=await Xu(`${Iu.apiBaseUrl}/dispatch`,{method:"POST",body:JSON.stringify({providerId:y,command:_,payload:P})});w(t),await f()}catch(P){B(Bu(P,"下发失败"))}finally{c(!1)}}return A("div",{className:"page-grid dispatch-grid"},A(au,{title:"下发任务",eyebrow:"Real WebSocket Dispatch"},A("form",{className:"dispatch-form",onSubmit:R},A("label",null,"Provider",A("select",{value:y,onChange:(Y)=>i(Y.target.value)},u.map((Y)=>A("option",{key:Y.providerId,value:Y.providerId},`${Y.name} / ${Y.providerId}`)))),A("label",null,"Command",A("select",{value:_,onChange:(Y)=>n(Y.target.value)},A("option",{value:"docker.ps"},"docker.ps"),A("option",{value:"host.ssh"},"host.ssh"),A("option",{value:"microservice.http"},"microservice.http"),A("option",{value:"echo"},"echo"))),A("label",null,"来源",A("input",{value:$,onChange:(Y)=>j(Y.target.value)})),A("label",null,"备注",A("input",{value:F,onChange:(Y)=>J(Y.target.value)})),A("label",null,"优先级",A("select",{value:U,onChange:(Y)=>q(Y.target.value)},A("option",{value:"normal"},"normal"),A("option",{value:"low"},"low"),A("option",{value:"urgent"},"urgent"))),A("div",{className:"dispatch-actions"},A("button",{type:"button",className:"ghost-btn",onClick:X},"查看原始JSON"),A("button",{type:"submit",disabled:N||!y},N?"下发中":"下发任务")),W?A("label",{className:"raw-editor-label"},"高级 Payload",A("textarea",{className:"raw-editor",value:K,onChange:(Y)=>Q(Y.target.value)})):null,A(jf,{error:H,wide:!0}))),A(au,{title:"下发结果",eyebrow:"Response"},z?A("div",{className:"result-card"},A(Nf,{status:z.status||"queued"},z.status||"queued"),A("dl",null,A("dt",null,"Task ID"),A("dd",null,A("code",null,z.taskId||"--")),A("dt",null,"Provider 在线"),A("dd",null,By(z.providerOnline))),A(Cf,{title:"Dispatch Response",data:z,onOpen:l})):A(Ff,{title:"等待操作",text:"任务响应会以结构化结果卡展示"})))}function OG({task:u,onRaw:f}){return A("article",{className:"compact-row"},A(Nf,{status:u.status}),A("div",null,A("strong",null,u.command),A("code",null,u.id)),A("span",null,l_(u)?`已等待 ${Dj(u.updatedAt)}`:`耗时 ${S0(YG(u)??0)}`),A(Cf,{title:`Task ${u.id}`,data:O$(u),onOpen:f}))}function kG({task:u}){let f=YG(u),l=l_(u);return A("div",{className:"task-duration"},A("strong",null,f===null?"--":S0(f)),A("span",null,l?`已运行 / 创建 ${Nu(u.createdAt)}`:`创建 ${Nu(u.createdAt)}`))}function ZS({task:u}){let f=String(u?.status||"").toLowerCase(),l=u?.result,r=l&&typeof l==="object"&&!Array.isArray(l)?l:{},i=["exitCode","code","signal","timeoutMs","previousStatus","mode"].filter((_)=>r[_]!==void 0&&r[_]!==null);if(f==="failed"){let _=DG(u);return A("div",{className:"task-diagnostic failed"},A("b",null,"失败原因"),A("span",{className:"diagnostic-reason"},By(_)),i.length>0?A("div",{className:"diagnostic-meta"},i.map((n)=>A("span",{key:n,className:"data-chip"},A("b",null,n),A("span",null,By(r[n]))))):null)}if(l_(u))return A("div",{className:"task-diagnostic warn"},A("b",null,"等待终态"),A("span",null,`最后更新 ${Dj(u.updatedAt)} 前`));return A("div",{className:"task-diagnostic ok"},A("b",null,"完成摘要"),A(m1,{data:l,empty:"无执行输出"}))}function HS({tasks:u,onRaw:f}){let l=u.filter(l_);return A("div",{"data-testid":"pending-task-page"},A(au,{title:"待处理任务",eyebrow:`${l.length} Pending`},l.length===0?A(Ff,{title:"当前无待处理任务",text:"queued / dispatched / running 会在超时后自动转为 failed;历史记录仍可在任务历史中查看"}):A("div",{className:"table-wrap","data-testid":"pending-task-table"},A("table",null,A("thead",null,A("tr",null,A("th",null,"状态"),A("th",null,"任务"),A("th",null,"Provider"),A("th",null,"已等待"),A("th",null,"载荷摘要"),A("th",null,"操作"))),A("tbody",null,l.map((r)=>A("tr",{key:r.id},A("td",null,A(Nf,{status:r.status})),A("td",null,A("strong",null,r.command),A("code",null,r.id)),A("td",null,A("code",null,r.providerId)),A("td",null,Dj(r.updatedAt)),A("td",null,A(m1,{data:r.payload})),A("td",null,A(Cf,{title:`Pending Task ${r.id}`,data:O$(r),onOpen:f})))))))))}function OS({tasks:u,onRaw:f}){return A("div",{"data-testid":"task-history-page"},A(au,{title:"任务历史",eyebrow:`${u.length} Tasks`},u.length===0?A(Ff,{title:"暂无任务",text:"下发任务后会在这里看到生命周期"}):A("div",{className:"table-wrap"},A("table",{className:"task-history-table"},A("thead",null,A("tr",null,A("th",null,"状态"),A("th",null,"任务"),A("th",null,"Provider"),A("th",null,"任务耗时"),A("th",null,"载荷摘要"),A("th",null,"诊断信息"),A("th",null,"更新时间"),A("th",null,"操作"))),A("tbody",null,u.map((l)=>A("tr",{key:l.id,"data-testid":`task-row-${bl(l.id)}`},A("td",null,A(Nf,{status:l.status})),A("td",null,A("strong",null,l.command),A("code",null,l.id)),A("td",null,A("code",null,l.providerId)),A("td",null,A(kG,{task:l})),A("td",null,A(m1,{data:l.payload})),A("td",null,A(ZS,{task:l})),A("td",null,Nu(l.updatedAt)),A("td",null,A(Cf,{title:`Task ${l.id}`,data:O$(l),onOpen:f})))))))))}function BS({tasks:u,onRaw:f}){let l=u.filter((r)=>["succeeded","failed"].includes(r.status));return A(au,{title:"执行结果",eyebrow:"Finished Tasks"},l.length===0?A(Ff,{title:"暂无结果",text:"任务完成后展示 provider 返回的结构化摘要"}):A("div",{className:"result-grid"},l.map((r)=>A("article",{key:r.id,className:"result-card"},A("div",{className:"node-card-head"},A("strong",null,r.command),A(Nf,{status:r.status})),A("code",null,r.id),A(m1,{data:r.result,empty:"无执行输出"}),A(Cf,{title:`Task Result ${r.id}`,data:O$(r),onOpen:f})))))}function VS(u){if(!u||typeof u!=="object")return"--";if(u.type==="interval")return`每 ${S0(Number(u.everySeconds||0))}`;return`每天 ${u.timeOfDay||"03:00"} UTC`}function XS(u){if(!u||typeof u!=="object")return"--";if(u.type==="pgdata_backup")return`PGDATA -> ${u.remoteBaseDir||"/SERVER_DATA/UNIDESK_PG_DATA"}`;if(u.type==="dispatch")return`${u.providerId||"--"} / ${u.command||"--"}`;return String(u.type||"--")}function YS(u){let f=String(u||"").toLowerCase();if(f==="succeeded")return"online";if(f==="failed")return"failed";if(f==="running"||f==="queued")return"warn";return f}function DS(u){let f=Number(u?.durationMs);if(Number.isFinite(f)&&f>=0)return S0(f/1000);let l=j0(u?.startedAt||u?.createdAt);if(l===null)return"--";let y=j0(u?.finishedAt)??Date.now();return S0(Math.max(0,(y-l)/1000))}function BG(u){return{id:"unidesk-pgdata-baidu-daily",name:"PGDATA daily Baidu Netdisk backup",description:"Daily PostgreSQL physical base backup uploaded to Baidu Netdisk /SERVER_DATA with monthly rotation.",enabled:!0,timeOfDay:"03:30",actionType:"pgdata_backup",providerId:u[0]?.providerId||"main-server",command:"echo",payloadJson:JSON.stringify({source:"scheduled-task",message:"hello from scheduler"},null,2),remoteBaseDir:"/SERVER_DATA/UNIDESK_PG_DATA",stagingSubdir:"server-data/unidesk-pg-data",timeoutMs:"3600000"}}function tS({schedules:u,scheduleRuns:f,nodes:l,refresh:r,onRaw:y}){let[i,_]=pu(BG(l||[])),[n,$]=pu(!1),[j,F]=pu(""),[J,U]=pu(""),q=[...f||[]].sort((z,w)=>(j0(w.updatedAt)??0)-(j0(z.updatedAt)??0));function W(z,w){_((H)=>({...H,[z]:w}))}function G(z){let w=z?.action||{};_({id:z?.id||"",name:z?.name||"",description:z?.description||"",enabled:z?.enabled!==!1,timeOfDay:z?.schedule?.timeOfDay||"03:30",actionType:w.type||"dispatch",providerId:w.providerId||l[0]?.providerId||"main-server",command:w.command||"echo",payloadJson:JSON.stringify(w.payload||{source:"scheduled-task"},null,2),remoteBaseDir:w.remoteBaseDir||"/SERVER_DATA/UNIDESK_PG_DATA",stagingSubdir:w.stagingSubdir||"server-data/unidesk-pg-data",timeoutMs:String(w.timeoutMs||3600000)}),U(`正在编辑 ${z?.id||""}`)}function K(){let z={id:i.id,name:i.name,description:i.description,enabled:i.enabled,concurrencyPolicy:"skip",schedule:{type:"daily",timeOfDay:i.timeOfDay,timezone:"Etc/UTC"}};if(i.actionType==="pgdata_backup")return{...z,action:{type:"pgdata_backup",volumeName:"unidesk_pgdata_10gb",remoteBaseDir:i.remoteBaseDir,stagingSubdir:i.stagingSubdir,timeoutMs:Number(i.timeoutMs)||3600000,cleanupLocal:!0}};return{...z,action:{type:"dispatch",providerId:i.providerId,command:i.command,payload:JSON.parse(i.payloadJson||"{}"),timeoutMs:Number(i.timeoutMs)||600000}}}async function Q(z){z.preventDefault(),$(!0),F(""),U("");try{let w=K(),H=encodeURIComponent(String(w.id));await Xu(`${Iu.apiBaseUrl}/schedules/${H}`,{method:"PUT",body:JSON.stringify(w)}),U("定时任务已保存"),await r()}catch(w){F(Bu(w,"保存定时任务失败"))}finally{$(!1)}}async function N(z){if(!z?.id)return;$(!0),F(""),U("");try{await Xu(`${Iu.apiBaseUrl}/schedules/${encodeURIComponent(z.id)}`,{method:"DELETE"}),U(`已删除 ${z.id}`),await r()}catch(w){F(Bu(w,"删除定时任务失败"))}finally{$(!1)}}async function c(z){if(!z?.id)return;$(!0),F(""),U("");try{let w=await Xu(`${Iu.apiBaseUrl}/schedules/${encodeURIComponent(z.id)}/run`,{method:"POST",body:"{}"});U(`已触发 ${z.id} / ${w?.run?.id||"run"}`),await r()}catch(w){F(Bu(w,"触发定时任务失败"))}finally{$(!1)}}return A("div",{className:"page-grid scheduled-task-page","data-testid":"scheduled-task-page"},A(au,{title:"定时任务",eyebrow:`${(u||[]).length} Schedules`},(u||[]).length===0?A(Ff,{title:"暂无定时任务",text:"创建 daily / dispatch / PGDATA backup 任务后会在这里展示下一次执行时间和最近结果"}):A("div",{className:"schedule-card-grid"},(u||[]).map((z)=>A("article",{key:z.id,className:"schedule-card","data-testid":`schedule-row-${bl(z.id)}`},A("div",{className:"node-card-head"},A("strong",null,z.name||z.id),A(Nf,{status:z.enabled?"online":"warn"},z.enabled?"enabled":"disabled")),A("code",null,z.id),A("dl",null,A("dt",null,"计划"),A("dd",null,VS(z.schedule)),A("dt",null,"动作"),A("dd",null,XS(z.action)),A("dt",null,"下次执行"),A("dd",null,Nu(z.nextRunAt)),A("dt",null,"最近执行"),A("dd",null,z.lastRunAt?`${Nu(z.lastRunAt)} / ${z.lastRunId||"--"}`:"--")),A("div",{className:"dispatch-actions"},A("button",{type:"button",className:"ghost-btn",disabled:n,onClick:()=>G(z)},"编辑"),A("button",{type:"button",className:"ghost-btn",disabled:n,onClick:()=>c(z),"data-testid":`schedule-run-${bl(z.id)}`},"手动触发"),A("button",{type:"button",className:"ghost-btn danger",disabled:n,onClick:()=>N(z)},"删除"),A(Cf,{title:`Schedule ${z.id}`,data:z,onOpen:y})))))),A(au,{title:i.id?"配置定时任务":"新建定时任务",eyebrow:"CRUD"},A("form",{className:"dispatch-form schedule-form",onSubmit:Q},A("label",null,"ID",A("input",{value:i.id,onChange:(z)=>W("id",z.target.value)})),A("label",null,"名称",A("input",{value:i.name,onChange:(z)=>W("name",z.target.value)})),A("label",null,"每日执行时间 UTC",A("input",{value:i.timeOfDay,placeholder:"03:30",onChange:(z)=>W("timeOfDay",z.target.value)})),A("label",null,"启用",A("select",{value:i.enabled?"true":"false",onChange:(z)=>W("enabled",z.target.value==="true")},A("option",{value:"true"},"enabled"),A("option",{value:"false"},"disabled"))),A("label",null,"动作类型",A("select",{value:i.actionType,onChange:(z)=>W("actionType",z.target.value)},A("option",{value:"pgdata_backup"},"PGDATA 备份到百度网盘"),A("option",{value:"dispatch"},"Provider Dispatch"))),i.actionType==="pgdata_backup"?[A("label",{key:"remote"},"网盘根目录",A("input",{value:i.remoteBaseDir,onChange:(z)=>W("remoteBaseDir",z.target.value)})),A("label",{key:"staging"},"本地 staging 子目录",A("input",{value:i.stagingSubdir,onChange:(z)=>W("stagingSubdir",z.target.value)}))]:[A("label",{key:"provider"},"Provider",A("select",{value:i.providerId,onChange:(z)=>W("providerId",z.target.value)},(l||[]).map((z)=>A("option",{key:z.providerId,value:z.providerId},`${z.name} / ${z.providerId}`)))),A("label",{key:"command"},"Command",A("select",{value:i.command,onChange:(z)=>W("command",z.target.value)},A("option",{value:"echo"},"echo"),A("option",{value:"docker.ps"},"docker.ps"),A("option",{value:"host.ssh"},"host.ssh"),A("option",{value:"microservice.http"},"microservice.http"))),A("label",{key:"payload",className:"raw-editor-label"},"Payload JSON",A("textarea",{className:"raw-editor",value:i.payloadJson,onChange:(z)=>W("payloadJson",z.target.value)}))],A("label",null,"超时 ms",A("input",{value:i.timeoutMs,onChange:(z)=>W("timeoutMs",z.target.value)})),A("label",{className:"raw-editor-label"},"描述",A("textarea",{className:"raw-editor compact",value:i.description,onChange:(z)=>W("description",z.target.value)})),A("div",{className:"dispatch-actions"},A("button",{type:"button",className:"ghost-btn",disabled:n,onClick:()=>_(BG(l||[]))},"重置"),A("button",{type:"submit",disabled:n||!i.id},n?"保存中":"保存任务")),J?A("p",{className:"muted paragraph"},J):null,A(jf,{error:j,wide:!0}))),A(au,{title:"历史执行记录",eyebrow:`${q.length} Runs`},q.length===0?A(Ff,{title:"暂无执行记录",text:"定时触发或手动触发后会生成 run history"}):A("div",{className:"table-wrap"},A("table",{className:"task-history-table schedule-run-table"},A("thead",null,A("tr",null,A("th",null,"状态"),A("th",null,"任务"),A("th",null,"触发"),A("th",null,"耗时"),A("th",null,"结果摘要"),A("th",null,"更新时间"),A("th",null,"操作"))),A("tbody",null,q.map((z)=>A("tr",{key:z.id,"data-testid":`schedule-run-row-${bl(z.id)}`},A("td",null,A(Nf,{status:YS(z.status)},z.status)),A("td",null,A("strong",null,z.scheduleId),A("code",null,z.id),z.taskId?A("code",null,z.taskId):null),A("td",null,z.trigger||"--"),A("td",null,DS(z)),A("td",null,A(m1,{data:z.result||z.error,empty:"无结果"})),A("td",null,Nu(z.updatedAt)),A("td",null,A(Cf,{title:`Schedule Run ${z.id}`,data:z,onOpen:y})))))))))}function SS({data:u}){let f=u.overview||{};return A("div",{className:"page-grid topology-grid"},A(au,{title:"公开入口",eyebrow:"Public"},A("div",{className:"endpoint-list"},A("article",null,A("b",null,"Frontend"),A("span",null,Iu.frontendPublicUrl||window.location.origin),A(Nf,{status:"online"},"public")),A("article",null,A("b",null,"Provider Ingress"),A("span",null,Iu.providerIngressPublicUrl||"ws://public/ws/provider"),A(Nf,{status:"online"},"public")))),A(au,{title:"内部服务",eyebrow:"Docker Network Only"},A("div",{className:"endpoint-list"},A("article",null,A("b",null,"backend-core API"),A("span",null,"http://backend-core:8080"),A(Nf,{status:"internal"},"internal")),A("article",null,A("b",null,"database"),A("span",null,"postgres://database:5432/unidesk"),A(Nf,{status:"internal"},"internal")))),A(au,{title:"运行态",eyebrow:"Runtime"},A("div",{className:"metric-grid"},A($f,{label:"DB Ready",value:f.dbReady?"YES":"NO",hint:"internal health"}),A($f,{label:"Online Nodes",value:f.onlineNodeCount??0,hint:"provider-gateway self-link"}))))}function PS({session:u}){return A(au,{title:"认证策略",eyebrow:"Frontend Login"},A("div",{className:"policy-grid"},A("article",null,A("span",null,"默认账号"),A("strong",null,Iu.authUsername||"admin")),A("article",null,A("span",null,"当前会话"),A("strong",null,u?.user?.username||"--")),A("article",null,A("span",null,"Session TTL"),A("strong",null,`${Iu.sessionTtlSeconds||0}s`)),A("article",null,A("span",null,"API 访问"),A("strong",null,"同源 Cookie 保护"))),A("p",{className:"muted paragraph"},"浏览器只访问 frontend 同源接口;frontend 容器使用 Docker 内网代理 backend-core API。"))}function MS(){return A(au,{title:"安全边界",eyebrow:"Exposure Rule"},A("div",{className:"security-board"},A("article",{className:"allow"},A("b",null,"允许公网"),A("span",null,"frontend 登录入口"),A("span",null,"provider ingress WebSocket/health")),A("article",{className:"deny"},A("b",null,"禁止公网"),A("span",null,"backend-core REST API"),A("span",null,"PostgreSQL database")),A("article",null,A("b",null,"数据库卷"),A("span",null,"named volume unidesk_pgdata_10gb"),A("span",null,"CLI stop/start 不删除数据卷"))))}function mS({activeModule:u,activeTab:f,data:l,session:r,refresh:y,onRaw:i,onNavigate:_}){if(u==="ops"&&f==="status")return A(fS,{data:l,onRaw:i,onNavigate:_});if(u==="ops"&&f==="performance")return A(WS,{onRaw:i});if(u==="ops"&&f==="events")return A(rS,{events:l.events,onRaw:i});if(u==="ops"&&f==="logs")return A(yS,{logs:l.logs,onRaw:i});if(u==="nodes"&&f==="list")return A(iS,{nodes:l.nodes,onRaw:i});if(u==="nodes"&&f==="monitor")return A($S,{nodes:l.nodes,systemStatuses:l.systemStatuses,tasks:l.tasks,onRaw:i,refresh:y});if(u==="nodes"&&f==="docker")return A(LS,{nodes:l.nodes,dockerStatuses:l.dockerStatuses,onRaw:i});if(u==="nodes"&&f==="gateway")return A(zS,{nodes:l.nodes,tasks:l.tasks,onRaw:i});if(u==="nodes"&&f==="labels")return A(_S,{nodes:l.nodes});if(u==="nodes"&&f==="heartbeats")return A(nS,{nodes:l.nodes});if(u==="tasks"&&f==="dispatch")return A(TS,{nodes:l.nodes,onDispatched:y,onRaw:i});if(u==="tasks"&&f==="scheduled")return A(tS,{schedules:l.schedules,scheduleRuns:l.scheduleRuns,nodes:l.nodes,refresh:y,onRaw:i});if(u==="tasks"&&f==="pending")return A(HS,{tasks:l.pendingTasks,onRaw:i});if(u==="tasks"&&f==="history")return A(OS,{tasks:l.tasks,onRaw:i});if(u==="tasks"&&f==="results")return A(BS,{tasks:l.tasks,onRaw:i});if(u==="apps"&&f==="catalog")return A(ES,{microservices:l.microservices,onRaw:i,onNavigate:_});if(u==="apps"&&f==="todo-note")return A(QG,{microservices:l.microservices,onRaw:i,apiBaseUrl:Iu.apiBaseUrl});if(u==="apps"&&f==="findjob")return A(nW,{microservices:l.microservices,onRaw:i,apiBaseUrl:Iu.apiBaseUrl});if(u==="apps"&&f==="pipeline")return A(_G,{microservices:l.microservices,onRaw:i,apiBaseUrl:Iu.apiBaseUrl});if(u==="apps"&&f==="met-nonlinear")return A(JW,{microservices:l.microservices,onRaw:i,apiBaseUrl:Iu.apiBaseUrl});if(u==="apps"&&f==="claudeqq")return A(RQ,{microservices:l.microservices,onRaw:i,apiBaseUrl:Iu.apiBaseUrl});if(u==="apps"&&f==="baidu-netdisk")return A(pQ,{microservices:l.microservices,onRaw:i,apiBaseUrl:Iu.apiBaseUrl});if(u==="apps"&&f==="filebrowser")return A(_W,{microservices:l.microservices,onRaw:i,apiBaseUrl:Iu.apiBaseUrl});if(u==="apps"&&f==="code-queue")return A(uW,{microservices:l.microservices,onRaw:i,apiBaseUrl:Iu.apiBaseUrl,initialTasksData:Mt});if(u==="apps"&&f==="project-manager")return A(AG,{microservices:l.microservices,onRaw:i,apiBaseUrl:Iu.apiBaseUrl});if(u==="config"&&f==="topology")return A(SS,{data:l});if(u==="config"&&f==="auth")return A(PS,{session:r});if(u==="config"&&f==="security")return A(MS);return A(Ff,{title:"未找到页面",text:"请选择左侧主模块和顶部子功能标签"})}function pS({session:u,onLogout:f}){let l=IA(Zr,window.location.pathname),[r,y]=pu(l.moduleId),[i,_]=pu({...tn,[l.moduleId]:l.tabId}),[n,$]=pu({overview:null,nodes:[],systemStatuses:[],dockerStatuses:[],microservices:[],events:[],tasks:[],pendingTasks:[],schedules:[],scheduleRuns:[],logs:[]}),[j,F]=pu({ok:!1,text:"连接中"}),[J,U]=pu(null),[q,W]=pu(new Date),[G,K]=pu(null),[Q,N]=pu(!1),[c,z]=pu(!1),w=M1.default.useRef(!1),H=Zr.moduleById[r]||Zr.modules[0],B=i[r]||tn[r]||H.tabs[0].id,T=Array.isArray(n.microservices)?n.microservices:[],X=T.length===0&&r==="apps"&&B==="code-queue"?[mt]:T,R=X===T?n:{...n,microservices:X},Y=r==="apps"?X.find((o)=>String(o?.id||"")===B):null,P=Y?RG(Y):{},t=H.tabs.find((o)=>o.id===B)?.label||B,O=Y?[{key:"microservice",label:"用户服务",value:`${t} ${P.providerStatus==="online"?"在线":P.providerStatus||"未知"}`,tone:P.providerStatus==="online"?"ok":"warn",testId:"active-microservice-status"}]:[];async function M(){if(w.current)return;w.current=!0,z(!0);try{let o=[],s=(Fu,Ku)=>{o.push([Fu,Xu(Ku)])},x=r==="ops"&&B==="status",uu=x||r==="config"&&B==="topology",nu=x||r==="nodes"||r==="tasks"&&(B==="dispatch"||B==="scheduled"),$u=r==="apps"&&B!=="code-queue";if(uu)s("overview",`${Iu.apiBaseUrl}/overview`);if(nu)s("nodes",`${Iu.apiBaseUrl}/nodes`);if(r==="nodes"&&B==="monitor")s("systemStatuses",`${Iu.apiBaseUrl}/nodes/system-status?limit=60`),s("tasks",`${Iu.apiBaseUrl}/tasks?limit=120&summary=1`);else if(r==="nodes"&&B==="docker")s("dockerStatuses",`${Iu.apiBaseUrl}/nodes/docker-status`);else if(r==="nodes"&&B==="gateway")s("tasks",`${Iu.apiBaseUrl}/tasks?limit=300&summary=1`);else if(r==="tasks"&&B==="scheduled")s("schedules",`${Iu.apiBaseUrl}/schedules?limit=100`),s("scheduleRuns",`${Iu.apiBaseUrl}/schedules/runs?limit=100`);else if(r==="tasks"&&B==="pending")s("pendingTasks",`${Iu.apiBaseUrl}/tasks?status=pending&limit=100&summary=1`);else if(r==="tasks"&&(B==="history"||B==="results"))s("tasks",`${Iu.apiBaseUrl}/tasks?limit=300&summary=1`);else if(x)s("tasks",`${Iu.apiBaseUrl}/tasks?limit=8&lite=1`),s("pendingTasks",`${Iu.apiBaseUrl}/tasks?status=pending&limit=20&lite=1`);if($u)s("microservices",`${Iu.apiBaseUrl}/microservices`);if(r==="ops"&&B==="events")s("events",`${Iu.apiBaseUrl}/events?limit=100`);if(r==="ops"&&B==="logs")s("logs","/logs?limit=100");await Promise.all(o.map(async([Fu,Ku])=>{let Wu=await Ku,m={};if(Fu==="overview")m.overview=Wu;if(Fu==="nodes")m.nodes=Wu.nodes||[];if(Fu==="systemStatuses")m.systemStatuses=Wu.systemStatuses||[];if(Fu==="dockerStatuses")m.dockerStatuses=Wu.dockerStatuses||[];if(Fu==="microservices")m.microservices=Wu.microservices||[];if(Fu==="events")m.events=Wu.events||[];if(Fu==="tasks")m.tasks=Wu.tasks||[];if(Fu==="pendingTasks")m.pendingTasks=Wu.tasks||[];if(Fu==="schedules")m.schedules=Wu.schedules||[];if(Fu==="scheduleRuns")m.scheduleRuns=Wu.runs||[];if(Fu==="logs")m.logs=Wu.logs||[];$((d)=>({...d,...m}))})),F({ok:!0,text:"核心在线"}),U(new Date)}catch(o){if(F({ok:!1,text:Bu(o,"连接失败")}),o.status===401)f(!1)}finally{w.current=!1,z(!1)}}A0(()=>{let o=()=>{if(!GG())return;M()};o();let s=setInterval(o,pt(r,B)),x=()=>{if(GG())o()};return document.addEventListener("visibilitychange",x),()=>{clearInterval(s),document.removeEventListener("visibilitychange",x)}},[r,B]),A0(()=>{let o=setInterval(()=>W(new Date),1000);return()=>clearInterval(o)},[]),A0(()=>{let o=WW(Zr,window.location.pathname);if(o&&window.location.pathname!==o)window.history.replaceState(null,"",o)},[]),A0(()=>{let o=()=>{let s=IA(Zr,window.location.pathname);y(s.moduleId),_((x)=>({...x,[s.moduleId]:s.tabId})),K(null)};return window.addEventListener("popstate",o),()=>window.removeEventListener("popstate",o)},[]),A0(()=>{window.scrollTo({top:0,left:0,behavior:"auto"})},[r,B]);function S(o,s,x="push"){let uu=Zr.moduleById[o]?o:Zr.fallbackTarget.moduleId,nu=Zr.moduleById[uu]?.tabs.some((Fu)=>Fu.id===s)?s:tn[uu]||Zr.moduleById[uu]?.tabs[0]?.id||Zr.fallbackTarget.tabId;y(uu),_((Fu)=>({...Fu,[uu]:nu}));let $u=k6(Zr,uu,nu);if(window.location.pathname!==$u){let Fu=x==="replace"?"replaceState":"pushState";window.history[Fu](null,"",$u)}}function b(o,s){K({title:o,data:s})}let[Z,D]=pu(!1),{unreadCount:I,notifications:k}=wl(),h=k.length>0?k[k.length-1]:null;return A("div",{className:`shell ${Q?"rail-collapsed":""}`,"data-testid":"app-shell"},A(et,{activeModule:r,activeTabs:i,onNavigate:S,collapsed:Q,onToggle:()=>N((o)=>!o)}),A("main",{className:"workspace"},A(ot,{connection:j,lastRefresh:J,onRefresh:M,onLogout:()=>f(!0),session:u,clock:q,activeStatusItems:O,onNotificationToggle:()=>D((o)=>!o),unreadCount:I}),A(uS,{module:H,activeTab:B,onNavigate:S}),A(Yj.Provider,{value:c},A(mS,{activeModule:r,activeTab:B,data:R,session:u,refresh:M,onRaw:b,onNavigate:S}))),A(st,{raw:G,onClose:()=>K(null)}),h&&A(zG,{key:h.id,notification:h}),Z&&A(NG,{onClose:()=>D(!1)}))}function CS(){let[u,f]=pu(!0),[l,r]=pu(null);async function y(){f(!0);try{let _=await Xu("/api/session");r(_.authenticated?_:null)}catch{r(null)}finally{f(!1)}}async function i(_){if(_)try{await Xu("/logout",{method:"POST"})}catch{}r(null)}if(A0(()=>{y()},[]),u)return A("main",{className:"loading-screen"},A("div",{className:"brand-mark"},"UD"),A("span",null,"加载会话"));if(!l)return A(at,{onLogin:r});return A(mQ,null,A(pS,{session:l,onLogout:i}))}var gG=document.getElementById("root");if(gG===null)throw Error("root element not found");VG.createRoot(gG).render(A(CS));})(); diff --git a/src/components/frontend/public/style.css b/src/components/frontend/public/style.css index 6d2407d9..9e570aa7 100644 --- a/src/components/frontend/public/style.css +++ b/src/components/frontend/public/style.css @@ -351,7 +351,7 @@ h2 { font-size: 14px; text-transform: uppercase; letter-spacing: 0.08em; } align-items: start; } -.overview-grid .panel:nth-child(n+3), .dispatch-grid .panel:first-child, .scheduled-task-page .panel:first-child, .scheduled-task-page .panel:nth-child(3), .topology-grid .panel:nth-child(3) { grid-column: 1 / -1; } +.overview-grid .panel:nth-child(n+3), .dispatch-grid .panel:first-child, .scheduled-task-page .panel:first-child, .scheduled-task-page .panel:nth-child(2), .scheduled-task-page .panel:nth-child(3), .topology-grid .panel:nth-child(3) { grid-column: 1 / -1; } .panel { min-width: 0; @@ -381,8 +381,8 @@ h2 { font-size: 14px; text-transform: uppercase; letter-spacing: 0.08em; } } .metric-card { - min-height: 76px; - padding: 10px; + min-height: 52px; + padding: 7px; border: 1px solid var(--line-soft); background: var(--panel-2); } @@ -405,9 +405,9 @@ h2 { font-size: 14px; text-transform: uppercase; letter-spacing: 0.08em; } letter-spacing: 0.12em; } .metric-value { - margin-top: 8px; + margin-top: 4px; color: var(--text); - font-size: 23px; + font-size: 16px; font-weight: 760; } .metric-hint { margin-top: 3px; color: var(--muted); font-size: 11px; } @@ -1330,10 +1330,12 @@ td { color: var(--text); } display: grid; grid-template-columns: repeat(auto-fill, minmax(180px, 1fr)); gap: 8px; + min-width: 0; } -.label-card { padding: 8px; } -.label-card span { display: block; color: var(--muted); font-size: 11px; text-transform: uppercase; letter-spacing: 0.1em; } -.label-card strong { display: block; margin: 5px 0; } +.label-card { padding: 8px; min-width: 0; } +.label-card span { display: block; color: var(--muted); font-size: 11px; text-transform: uppercase; letter-spacing: 0.1em; overflow-wrap: anywhere; } +.label-card strong { display: block; margin: 5px 0; overflow-wrap: anywhere; } +.label-card code { overflow-wrap: anywhere; white-space: normal; } .dispatch-form { display: grid; @@ -2349,7 +2351,7 @@ input:focus, select:focus, textarea:focus { border-color: var(--accent-2); } grid-template-areas: "queue-select queue-select" "rename rename" - ". create"; + "merge create"; gap: 6px; min-width: 0; align-items: center; @@ -2358,6 +2360,7 @@ input:focus, select:focus, textarea:focus { border-color: var(--accent-2); } grid-area: queue-select; } .codex-rename-queue-btn, +.codex-merge-queue-btn, .codex-create-queue-btn { min-height: 32px; white-space: nowrap; @@ -2370,6 +2373,9 @@ input:focus, select:focus, textarea:focus { border-color: var(--accent-2); } .codex-create-queue-btn { grid-area: create; } +.codex-merge-queue-btn { + grid-area: merge; +} .codex-reference-field { display: grid; gap: 5px; @@ -5365,9 +5371,10 @@ input:focus, select:focus, textarea:focus { border-color: var(--accent-2); } grid-template-areas: "queue-select" "rename" + "merge" "create"; } - .codex-rename-queue-btn, .codex-create-queue-btn { width: 100%; } + .codex-rename-queue-btn, .codex-merge-queue-btn, .codex-create-queue-btn { width: 100%; } .codex-session-title-toggle { min-height: 40px; padding: 9px 15px; font-size: 14px; } .codex-attempt-cycle-head { align-items: flex-start; } .codex-attempt-cycle-head code { diff --git a/src/components/frontend/src/baidu-netdisk.tsx b/src/components/frontend/src/baidu-netdisk.tsx index 0cf976b2..f3831344 100644 --- a/src/components/frontend/src/baidu-netdisk.tsx +++ b/src/components/frontend/src/baidu-netdisk.tsx @@ -378,6 +378,38 @@ export function BaiduNetdiskPage({ microservices, onRaw, apiBaseUrl = "/api" }: h(MetricCard, { label: "Quota", value: fmtBytes(quota.used), hint: quota.total ? `${quota.usedPercent || 0}% / ${fmtBytes(quota.total)}` : "授权后刷新" }), h(MetricCard, { label: "Transfers", value: numberText(jobs.length), hint: `running ${state.transfers?.counts?.running || 0} / failed ${state.transfers?.counts?.failed || 0}` }), ), + h(Panel, { title: "文件浏览器", eyebrow: currentDir, className: "baidu-files-panel", loading: state.loading, + actions: h("div", { className: "panel-actions inline-actions" }, + h("button", { type: "button", className: "ghost-btn", onClick: () => { const parent = pathParent(currentDir, appRoot); setCurrentDir(parent); void loadFiles(parent); }, disabled: !loggedIn || currentDir === appRoot }, "上级"), + h("button", { type: "button", className: "ghost-btn", onClick: () => loadFiles(currentDir), disabled: !loggedIn }, "刷新文件"), + h(RawButton, { title: "Baidu Files", data: state.files, onOpen: onRaw, testId: "raw-baidu-files" }), + ), + }, + h("form", { className: "baidu-pathbar", onSubmit: (event: any) => { event.preventDefault(); void loadFiles(currentDir); } }, + h("input", { value: currentDir, onChange: (event: any) => setCurrentDir(event.target.value), disabled: !loggedIn }), + h("button", { type: "submit", className: "ghost-btn", disabled: !loggedIn }, "打开路径"), + ), + h("form", { className: "baidu-pathbar", onSubmit: createFolder }, + h("input", { value: folderName, onChange: (event: any) => setFolderName(event.target.value), placeholder: "新文件夹名称", disabled: !loggedIn }), + h("button", { type: "submit", className: "primary-btn", disabled: !loggedIn || !folderName.trim() }, "新建文件夹"), + ), + !loggedIn ? h(EmptyState, { title: "等待授权", text: "登录后通过 /api/files 读取工作目录文件列表" }) : files.length === 0 ? h(EmptyState, { title: "目录为空", text: "可以从 staging 目录上传文件或新建文件夹" }) : + h("div", { className: "table-wrap", "data-testid": "baidu-netdisk-file-table" }, h("table", null, + h("thead", null, h("tr", null, h("th", null, "名称"), h("th", null, "类型"), h("th", null, "大小"), h("th", null, "修改时间"), h("th", null, "fs_id"), h("th", null, "操作"))), + h("tbody", null, files.map((file: any) => h("tr", { key: file.fsId || file.path }, + h("td", null, h("strong", null, file.serverFilename || file.path), h("code", null, file.path || "--")), + h("td", null, h(StatusBadge, { status: file.isDir ? "queued" : "private" }, file.isDir ? "DIR" : "FILE")), + h("td", null, file.isDir ? "--" : fmtBytes(file.size)), + h("td", null, file.serverMtime ? fmtDate(file.serverMtime * 1000) : "--"), + h("td", null, h("code", null, file.fsId || "--")), + h("td", null, h("div", { className: "inline-actions" }, + file.isDir ? h("button", { type: "button", className: "ghost-btn", onClick: () => { setCurrentDir(file.path); void loadFiles(file.path); } }, "打开") : + h("button", { type: "button", className: "ghost-btn", onClick: () => setDownloadForm((prev: any) => ({ ...prev, fsId: file.fsId })) }, "填入下载"), + h("button", { type: "button", className: "ghost-btn", onClick: () => deleteRemote(file.path), disabled: state.actionLoading }, "删除"), + )), + ))), + )), + ), h("div", { className: "baidu-netdisk-grid" }, h(Panel, { title: "配置与文档", @@ -474,38 +506,6 @@ export function BaiduNetdiskPage({ microservices, onRaw, apiBaseUrl = "/api" }: h("div", { className: "microservice-ref-card" }, h("span", null, "Quota"), h("strong", null, `${fmtBytes(quota.used)} / ${fmtBytes(quota.total)}`), h("code", null, `${quota.usedPercent || 0}% used`)), ) : h(EmptyState, { title: "尚未登录", text: "扫码授权后这里会显示账号、UID、会员状态和容量" }), ), - h(Panel, { title: "文件浏览器", eyebrow: currentDir, className: "baidu-files-panel", loading: state.loading, - actions: h("div", { className: "panel-actions inline-actions" }, - h("button", { type: "button", className: "ghost-btn", onClick: () => { const parent = pathParent(currentDir, appRoot); setCurrentDir(parent); void loadFiles(parent); }, disabled: !loggedIn || currentDir === appRoot }, "上级"), - h("button", { type: "button", className: "ghost-btn", onClick: () => loadFiles(currentDir), disabled: !loggedIn }, "刷新文件"), - h(RawButton, { title: "Baidu Files", data: state.files, onOpen: onRaw, testId: "raw-baidu-files" }), - ), - }, - h("form", { className: "baidu-pathbar", onSubmit: (event: any) => { event.preventDefault(); void loadFiles(currentDir); } }, - h("input", { value: currentDir, onChange: (event: any) => setCurrentDir(event.target.value), disabled: !loggedIn }), - h("button", { type: "submit", className: "ghost-btn", disabled: !loggedIn }, "打开路径"), - ), - h("form", { className: "baidu-pathbar", onSubmit: createFolder }, - h("input", { value: folderName, onChange: (event: any) => setFolderName(event.target.value), placeholder: "新文件夹名称", disabled: !loggedIn }), - h("button", { type: "submit", className: "primary-btn", disabled: !loggedIn || !folderName.trim() }, "新建文件夹"), - ), - !loggedIn ? h(EmptyState, { title: "等待授权", text: "登录后通过 /api/files 读取工作目录文件列表" }) : files.length === 0 ? h(EmptyState, { title: "目录为空", text: "可以从 staging 目录上传文件或新建文件夹" }) : - h("div", { className: "table-wrap", "data-testid": "baidu-netdisk-file-table" }, h("table", null, - h("thead", null, h("tr", null, h("th", null, "名称"), h("th", null, "类型"), h("th", null, "大小"), h("th", null, "修改时间"), h("th", null, "fs_id"), h("th", null, "操作"))), - h("tbody", null, files.map((file: any) => h("tr", { key: file.fsId || file.path }, - h("td", null, h("strong", null, file.serverFilename || file.path), h("code", null, file.path || "--")), - h("td", null, h(StatusBadge, { status: file.isDir ? "queued" : "private" }, file.isDir ? "DIR" : "FILE")), - h("td", null, file.isDir ? "--" : fmtBytes(file.size)), - h("td", null, file.serverMtime ? fmtDate(file.serverMtime * 1000) : "--"), - h("td", null, h("code", null, file.fsId || "--")), - h("td", null, h("div", { className: "inline-actions" }, - file.isDir ? h("button", { type: "button", className: "ghost-btn", onClick: () => { setCurrentDir(file.path); void loadFiles(file.path); } }, "打开") : - h("button", { type: "button", className: "ghost-btn", onClick: () => setDownloadForm((prev: any) => ({ ...prev, fsId: file.fsId })) }, "填入下载"), - h("button", { type: "button", className: "ghost-btn", onClick: () => deleteRemote(file.path), disabled: state.actionLoading }, "删除"), - )), - ))), - )), - ), h(Panel, { title: "传输任务", eyebrow: "staging path jobs", className: "baidu-transfers-panel", loading: state.actionLoading, actions: h("div", { className: "panel-actions inline-actions" }, h("button", { type: "button", className: "primary-btn", onClick: runSelfTest, disabled: !loggedIn || state.actionLoading, "data-testid": "baidu-netdisk-self-test" }, "运行自测"), diff --git a/src/components/frontend/src/code-queue.tsx b/src/components/frontend/src/code-queue.tsx index 826fc87e..76c54976 100644 --- a/src/components/frontend/src/code-queue.tsx +++ b/src/components/frontend/src/code-queue.tsx @@ -150,6 +150,10 @@ function codexApi(apiBaseUrl: string, path: string): string { return `${apiBaseUrl}/code-queue-direct${path}`; } +function codexNoCacheOptions(): AnyRecord { + return { headers: { "cache-control": "no-cache", "x-unidesk-no-cache": "1" } }; +} + function taskRows(data: any): any[] { return Array.isArray(data?.tasks) ? data.tasks : []; } @@ -163,6 +167,19 @@ function taskSortValue(task: any): number { return Number.isFinite(time) ? time : 0; } +function taskQueueOrderValue(task: any): number { + const time = timestampMs(task?.queueEnteredAt) ?? timestampMs(task?.createdAt) ?? timestampMs(task?.updatedAt); + return time ?? 0; +} + +function compareTaskQueueOrder(left: any, right: any): number { + const queueDelta = taskQueueOrderValue(left) - taskQueueOrderValue(right); + if (queueDelta !== 0) return queueDelta; + const createdDelta = (timestampMs(left?.createdAt) ?? 0) - (timestampMs(right?.createdAt) ?? 0); + if (createdDelta !== 0) return createdDelta; + return String(left?.id || "").localeCompare(String(right?.id || "")); +} + function mergeTaskRows(groups: any[][], activeTaskId = ""): any[] { const byId = new Map(); for (const group of groups) { @@ -292,39 +309,25 @@ function queueRunnableTaskId(queueRows: any[], queueId: string, rows: any[]): st return String(rows.find((task: any) => String(task?.status || "") === "queued" || String(task?.status || "") === "retry_wait")?.id || ""); } -async function loadTaskQueue(apiBaseUrl: string, healthResult: any, queueId = allQueuesId, searchQuery = ""): Promise { - const suffix = taskListQuerySuffix(queueId, searchQuery); - try { - return await requestJson(codexApi(apiBaseUrl, `/api/tasks?limit=${codexInitialTaskLimit}&lite=1&devReady=0${suffix}`)); - } catch { - const statuses = ["running", "judging", "retry_wait", "queued"]; - const results = await Promise.all(statuses.map(async (status) => { - try { - return await requestJson(codexApi(apiBaseUrl, `/api/tasks?status=${encodeURIComponent(status)}&limit=80&lite=1&devReady=0${suffix}`)); - } catch { - return null; - } - })); - const historyResult = await requestJson(codexApi(apiBaseUrl, `/api/tasks?limit=${codexInitialTaskLimit}&lite=1&devReady=0${suffix}`)).catch(() => null); - const queue = results.find((item) => item?.queue)?.queue || historyResult?.queue || healthResult?.queue || healthResult?.body?.queue || {}; - const rows = mergeTaskRows([...results.map((item) => taskRows(item)), taskRows(historyResult)], String(queue?.activeTaskId || "")); - if (rows.length > 0) return { ok: true, queue, statistics: historyResult?.statistics || results.find((item) => item?.statistics)?.statistics || null, tasks: rows }; - return requestJson(codexApi(apiBaseUrl, `/api/tasks?limit=5&lite=1&devReady=0${suffix}`)); - } +async function loadTaskList(apiBaseUrl: string, queueId = allQueuesId, searchQuery = ""): Promise { + return requestJson(codexApi( + apiBaseUrl, + `/api/tasks/overview?limit=${codexInitialTaskLimit}&transcriptLimit=1&compact=1&selected=0${taskListQuerySuffix(queueId, searchQuery)}`, + ), codexNoCacheOptions()); } async function loadTaskOverview(apiBaseUrl: string, preferId: string, afterSeq = 0, queueId = allQueuesId, searchQuery = ""): Promise { return requestJson(codexApi( apiBaseUrl, `/api/tasks/overview?limit=${codexInitialTaskLimit}&transcriptLimit=3&compact=1&afterSeq=${encodeURIComponent(String(Math.max(0, afterSeq)))}&preferId=${encodeURIComponent(preferId)}${taskListQuerySuffix(queueId, searchQuery)}`, - )); + ), codexNoCacheOptions()); } async function loadTaskPage(apiBaseUrl: string, queueId: string, beforeId: string, limit = codexMoreTaskLimit, searchQuery = ""): Promise { return requestJson(codexApi( apiBaseUrl, `/api/tasks/overview?limit=${encodeURIComponent(String(limit))}&transcriptLimit=1&compact=1&selected=0&includeActive=0&stats=0&beforeId=${encodeURIComponent(beforeId)}${taskListQuerySuffix(queueId, searchQuery)}`, - )); + ), codexNoCacheOptions()); } async function loadTaskTraceSummary(apiBaseUrl: string, taskId: string): Promise { @@ -564,7 +567,14 @@ function taskExecutionSummary(task: any): AnyRecord { return execution && typeof execution === "object" && !Array.isArray(execution) ? execution : {}; } -function rawTaskStepCount(task: any): number { +function nonNegativeCount(value: any): number { + const numeric = Number(value); + return Number.isFinite(numeric) && numeric >= 0 ? Math.floor(numeric) : 0; +} + +function canonicalTaskStepCount(task: any): number { + const summary = taskTraceSummary(task); + if (summary !== null) return traceSummaryStepCount(summary); const value = Number(task?.stepCount ?? task?.llmStepCount ?? 0); return Number.isFinite(value) && value >= 0 ? Math.floor(value) : 0; } @@ -572,7 +582,7 @@ function rawTaskStepCount(task: any): number { function traceSummaryStepCount(summary: AnyRecord | null): number { const execution = objectRecord(summary?.execution) || {}; const value = Number(summary?.stepCount ?? summary?.llmStepCount ?? execution.stepCount ?? execution.llmStepCount ?? execution.toolCallCount ?? 0); - return Number.isFinite(value) && value >= 0 ? Math.floor(value) : 0; + return nonNegativeCount(value); } function traceSummaryIsCurrent(task: any): boolean { @@ -589,8 +599,7 @@ function traceSummaryIsCurrent(task: any): boolean { return false; } } - const rawSteps = rawTaskStepCount(task); - return rawSteps <= 0 || traceSummaryStepCount(summary) >= rawSteps; + return true; } function taskBasePromptText(task: any): string { @@ -618,16 +627,6 @@ function objectRecord(value: any): AnyRecord | null { function taskProgressiveAttempts(task: any): any[] { const summaryAttempts = taskTraceSummary(task)?.attempts; if (Array.isArray(summaryAttempts) && summaryAttempts.length > 0) return summaryAttempts; - const attempts = taskAttempts(task); - if (attempts.length > 0) { - return attempts.map((attempt: any, index: number) => ({ - ...attempt, - index: Number(attempt?.index || index + 1), - execution: index === attempts.length - 1 ? taskExecutionSummary(task) : objectRecord(attempt?.execution) || {}, - finalResponse: String(attempt?.finalResponse || attempt?.finalResponsePreview || (index === attempts.length - 1 ? taskFinalResponseText(task) : "")), - judge: objectRecord(attempt?.judge) || (index === attempts.length - 1 ? taskLastJudge(task) : null), - })); - } const execution = taskExecutionSummary(task); const finalResponse = taskFinalResponseText(task); const judge = taskLastJudge(task); @@ -743,6 +742,25 @@ function taskTraceSteps(task: any, attemptIndex: any = null): any[] { return Array.isArray(task?._traceSteps) ? task._traceSteps : []; } +function traceStepSeqValue(step: any): number { + const candidates = [step?.seq, ...(Array.isArray(step?.rawSeqs) ? step.rawSeqs : [])].map((value) => Number(value)); + const finite = candidates.filter((value) => Number.isFinite(value)); + return finite.length > 0 ? Math.max(...finite) : 0; +} + +function traceStepsMaxSeq(steps: any[]): number { + return (Array.isArray(steps) ? steps : []).reduce((max, step) => Math.max(max, traceStepSeqValue(step)), 0); +} + +function mergeTraceStepRows(existing: any[], incoming: any[]): any[] { + const byKey = new Map(); + for (const step of [...(Array.isArray(existing) ? existing : []), ...(Array.isArray(incoming) ? incoming : [])]) { + const key = String(step?.seq ?? `${step?.title || "step"}:${step?.at || ""}`); + byKey.set(key, { ...(byKey.get(key) || {}), ...step }); + } + return Array.from(byKey.values()).sort((left, right) => traceStepSeqValue(left) - traceStepSeqValue(right)); +} + function traceStepSummaryLines(step: any): string[] { return (Array.isArray(step?.summaryLines) ? step.summaryLines : []).map((line: any) => String(line || "")); } @@ -834,39 +852,9 @@ function coalesceFileChangeTraceSteps(steps: any[]): any[] { return merged; } -function toolStepCountFromExecution(execution: AnyRecord): number { - const value = Number(execution?.toolCallCount); - if (Number.isFinite(value) && value >= 0) return Math.floor(value); - const total = Number(execution?.readCount || 0) + Number(execution?.editCount || 0) + Number(execution?.runCount || 0); - return Number.isFinite(total) && total >= 0 ? Math.floor(total) : 0; -} - -function toolStepCountsFromTraceSteps(steps: any[]): AnyRecord { - const rows = Array.isArray(steps) ? steps : []; - const counts = rows.reduce((memo: AnyRecord, step: any) => { - const kind = String(step?.kind || ""); - if (kind === "explored") memo.readCount += 1; - else if (kind === "edited") memo.editCount += 1; - else if (kind === "ran") memo.runCount += 1; - return memo; - }, { readCount: 0, editCount: 0, runCount: 0 }); - counts.toolCallCount = counts.readCount + counts.editCount + counts.runCount; - return counts; -} - -function executionSummaryWithDisplayedSteps(execution: AnyRecord, steps: any[]): AnyRecord { - if (steps.length === 0) { - const stepCount = toolStepCountFromExecution(execution); - return { ...execution, stepCount, llmStepCount: stepCount }; - } - const counts = toolStepCountsFromTraceSteps(steps); - return { - ...execution, - ...counts, - stepCount: counts.toolCallCount, - llmStepCount: counts.toolCallCount, - traceLineCount: steps.length, - }; +function canonicalExecutionSummary(execution: AnyRecord): AnyRecord { + const stepCount = nonNegativeCount(execution?.stepCount ?? execution?.llmStepCount ?? execution?.toolCallCount); + return { ...execution, stepCount, llmStepCount: stepCount }; } function taskTraceStepsLoaded(task: any, attemptIndex: any = null): boolean { @@ -1120,7 +1108,7 @@ function mergeTaskPatch(existingTask: any, patch: AnyRecord): AnyRecord { merged._transcriptPreview = Object.prototype.hasOwnProperty.call(patch, "_transcriptPreview") ? patch._transcriptPreview : existingTask?._transcriptPreview; - for (const key of ["_traceSummary", "_traceSummaryLoaded", "_traceSteps", "_traceStepsLoaded", "_traceStepsByAttempt", "_traceStepsLoadedByAttempt", "_traceStepDetails", "_promptDetails"]) { + for (const key of ["_traceSummary", "_traceSummaryLoaded", "_traceSteps", "_traceStepsLoaded", "_traceStepsByAttempt", "_traceStepsLoadedByAttempt", "_traceStepsNextAfterSeqByAttempt", "_traceStepDetails", "_promptDetails"]) { if (!Object.prototype.hasOwnProperty.call(patch, key) && Object.prototype.hasOwnProperty.call(existingTask || {}, key)) { merged[key] = existingTask[key]; } @@ -1222,15 +1210,7 @@ function providerDefaultWorkdir(queue: any, providerId: string): string { } function taskStepCount(task: any): number { - const attempts = taskProgressiveAttempts(task).filter((attempt: any) => !isSyntheticAttemptSegment(attempt, attempt?.index)); - if (attempts.length > 0) { - const attemptTotal = attempts.reduce((sum: number, attempt: any) => sum + toolStepCountFromExecution(attemptExecutionSummary(task, attempt)), 0); - if (attemptTotal > 0) return attemptTotal; - } - const executionTotal = toolStepCountFromExecution(taskExecutionSummary(task)); - if (executionTotal > 0) return executionTotal; - const apiTotal = Number(task?.stepCount ?? task?.llmStepCount ?? 0); - return Number.isFinite(apiTotal) && apiTotal >= 0 ? Math.floor(apiTotal) : 0; + return canonicalTaskStepCount(task); } function TaskCard({ task, selected, onSelect, onCopy, onReference, onMarkRead, copied, markingRead }: AnyRecord) { @@ -1556,14 +1536,13 @@ function ProgressivePromptBlock({ task, loading, onLoadPromptPart, testId = "cod function ProgressiveExecutionSummary({ task, attempt, attemptIndex, loading, onLoadSteps, onLoadStep, testId = "codex-execution-summary" }: AnyRecord) { const steps = coalesceFileChangeTraceSteps(taskTraceSteps(task, attemptIndex)); - const execution = executionSummaryWithDisplayedSteps(attemptExecutionSummary(task, attempt), steps); + const execution = canonicalExecutionSummary(attemptExecutionSummary(task, attempt)); const summary = taskTraceSummary(task); const stepDetails = taskTraceStepDetails(task); const stepsLoaded = taskTraceStepsLoaded(task, attemptIndex); const errorCount = Number(attempt?.errorCount ?? summary?.errorCount ?? traceStepErrorCount(steps)); - const toolCount = Number(execution.toolCallCount || 0); - const summaryStepCountValue = Number(execution.stepCount ?? execution.llmStepCount ?? 0); - const summaryStepCount = Number.isFinite(summaryStepCountValue) && summaryStepCountValue >= 0 ? Math.floor(summaryStepCountValue) : 0; + const toolCount = nonNegativeCount(execution.toolCallCount); + const stepCount = nonNegativeCount(execution.stepCount ?? execution.llmStepCount ?? execution.toolCallCount); const editedFiles = Array.isArray(execution.editedFiles) ? execution.editedFiles : []; const commands = Array.isArray(execution.commands) ? execution.commands : []; const synthetic = isSyntheticAttemptSegment(attempt, attemptIndex); @@ -1571,11 +1550,6 @@ function ProgressiveExecutionSummary({ task, attempt, attemptIndex, loading, onL const updatedAt = attemptExecutionUpdatedAt(task, attempt, attemptIndex, execution); const recentUpdateLabel = `最近更新: ${fmtRelativeAge(updatedAt)}`; const running = attemptExecutionIsRunning(task, attempt, attemptIndex); - const rawSteps = rawTaskStepCount(task); - const realAttemptCount = taskProgressiveAttempts(task).filter((item: any) => !isSyntheticAttemptSegment(item, item?.index)).length; - const canUseTaskStepFloor = !synthetic && steps.length === 0 && rawSteps > 0 && realAttemptCount <= 1; - const stepCount = canUseTaskStepFloor ? Math.max(summaryStepCount, rawSteps) : summaryStepCount; - const displayedToolCount = canUseTaskStepFloor ? Math.max(toolCount, stepCount) : toolCount; return h("details", { className: `codex-progressive-card codex-execution-summary ${running ? "running" : ""}`, "data-testid": testId, @@ -1591,13 +1565,13 @@ function ProgressiveExecutionSummary({ task, attempt, attemptIndex, loading, onL h("strong", null, `执行过程摘要${labelSuffix}`), running ? h("span", { className: "codex-summary-running-pill", "data-testid": `${testId}-running` }, "执行中") : null, h("code", { title: updatedAt ? `最近更新: ${fmtDate(updatedAt)}` : recentUpdateLabel }, - `${fmtDuration(execution.durationMs ?? execution.totalElapsedMs)} / ${displayedToolCount} tools / ${recentUpdateLabel}`), + `${fmtDuration(execution.durationMs ?? execution.totalElapsedMs)} / ${toolCount} tools / ${recentUpdateLabel}`), ), h("div", { className: "codex-execution-digest" }, h("span", null, `read ${Number(execution.readCount || 0)}`), h("span", null, `edit ${Number(execution.editCount || 0)}`), h("span", null, `run ${Number(execution.runCount || 0)}`), - h("span", null, `STEP ${Number.isFinite(stepCount) ? Math.max(0, Math.floor(stepCount)) : 0}`), + h("span", null, `STEP ${stepCount}`), errorCount > 0 ? h("span", { className: "codex-execution-error-pill", "data-testid": `${testId}-error-count` }, `Error ${errorCount}`) : null, ), ), @@ -1853,6 +1827,9 @@ export function CodeQueuePage({ microservices, onRaw, apiBaseUrl = "/api", initi const traceStepsInFlightRef = useRef>>(new Map()); const traceStepInFlightRef = useRef>>(new Map()); const autoTraceLoadKeysRef = useRef>(new Set()); + const eventRefreshTimerRef = useRef(null); + const traceEventRefreshTimerRef = useRef(null); + const traceEventRefreshPendingStepsRef = useRef(false); const trackedLoadInFlightRef = useRef(false); const initialLoadSkippedRef = useRef(Boolean(initialTasksData)); const locallyReadTaskIdsRef = useRef>(new Map()); @@ -1931,7 +1908,7 @@ export function CodeQueuePage({ microservices, onRaw, apiBaseUrl = "/api", initi const searchPagination = taskPagination(searchTasksData); const sidebarTasks = searchActive ? searchTasks : tasks; const unreadTerminalTasks = sidebarTasks.filter(taskIsUnreadTerminal); - const queuedTasks = sidebarTasks.filter((task: any) => !taskIsTerminal(task)); + const queuedTasks = sidebarTasks.filter((task: any) => !taskIsTerminal(task)).sort(compareTaskQueueOrder); const historyTasks = sidebarTasks.filter((task: any) => taskIsTerminal(task) && !taskIsUnreadTerminal(task)); const sidebarPagination = searchActive ? searchPagination : pagination; const sidebarTotalTaskCount = searchActive ? Number(searchPagination.total ?? searchTasks.length) : totalTaskCount; @@ -2071,7 +2048,7 @@ export function CodeQueuePage({ microservices, onRaw, apiBaseUrl = "/api", initi const timer = window.setTimeout(() => { void (async () => { try { - const result = await loadTaskQueue(apiBaseUrl, {}, selectedQueueId, query); + const result = await loadTaskList(apiBaseUrl, selectedQueueId, query); if (token !== searchLoadTokenRef.current) return; setSearchTasksData(applyLocalReadStateToResult(result)); } catch (err) { @@ -2146,28 +2123,21 @@ export function CodeQueuePage({ microservices, onRaw, apiBaseUrl = "/api", initi const result = await loadTaskTraceSummary(apiBaseUrl, taskId); if (token !== detailLoadTokenRef.current || selectedIdRef.current !== taskId) return; const summary = result?.summary || {}; - const currentTask = sessionCacheRef.current.get(taskId)?.task || {}; const summaryUpdatedAt = String(summary.updatedAt || ""); - const currentUpdatedAt = String(currentTask?.updatedAt || ""); - const summaryBehind = timestampIsAfter(currentUpdatedAt, summaryUpdatedAt) || rawTaskStepCount(currentTask) > traceSummaryStepCount(summary); - if (summaryBehind) inFlight.refreshAfter = true; - const effectiveUpdatedAt = summaryBehind - ? latestTimestampValue(currentUpdatedAt, summaryUpdatedAt) - : summaryUpdatedAt || currentUpdatedAt; publishCachedTask(taskId, { id: taskId, - status: summaryBehind ? (currentTask?.status || summary.status) : summary.status, - updatedAt: effectiveUpdatedAt, - startedAt: summary.startedAt || currentTask?.startedAt, - finishedAt: summaryBehind ? (currentTask?.finishedAt || summary.finishedAt) : summary.finishedAt, - currentAttempt: summary.currentAttempt ?? currentTask?.currentAttempt, - maxAttempts: summary.maxAttempts ?? currentTask?.maxAttempts, - finalResponse: summaryBehind ? preferLongerText(currentTask, summary, "finalResponse") : summary.finalResponse, - lastJudge: summaryBehind ? (currentTask?.lastJudge || summary.lastJudge) : summary.lastJudge, - lastError: summaryBehind ? (currentTask?.lastError || summary.lastError) : summary.lastError, - attempts: summaryBehind - ? preferRicherArray(currentTask, { attempts: Array.isArray(summary.attempts) ? summary.attempts : [] }, "attempts") - : Array.isArray(summary.attempts) ? summary.attempts : [], + status: summary.status, + updatedAt: summaryUpdatedAt, + startedAt: summary.startedAt, + finishedAt: summary.finishedAt, + currentAttempt: summary.currentAttempt, + maxAttempts: summary.maxAttempts, + finalResponse: summary.finalResponse, + lastJudge: summary.lastJudge, + lastError: summary.lastError, + attempts: Array.isArray(summary.attempts) ? summary.attempts : [], + stepCount: summary.stepCount, + llmStepCount: summary.llmStepCount, timing: summary.timing, _traceSummary: summary, _traceSummaryLoaded: true, @@ -2232,29 +2202,37 @@ export function CodeQueuePage({ microservices, onRaw, apiBaseUrl = "/api", initi await promise; } - async function ensureTraceSteps(attemptIndex: any = null): Promise { + async function ensureTraceSteps(attemptIndex: any = null, options: AnyRecord = {}): Promise { const taskId = selectedIdRef.current; if (!service || !taskId) return; const cachedTask = sessionCacheRef.current.get(taskId)?.task; const attemptKey = attemptIndex === null || attemptIndex === undefined || String(attemptIndex).length === 0 ? "" : String(attemptIndex); - if (taskTraceStepsLoaded(cachedTask, attemptKey || null)) return; - const key = `${taskId}:${attemptKey || "all"}`; + const loaded = taskTraceStepsLoaded(cachedTask, attemptKey || null); + const force = Boolean(options.force); + const incremental = Boolean(options.incremental); + if (loaded && !force) return; + const existingSteps = taskTraceSteps(cachedTask, attemptKey || null); + const afterSeq = incremental && existingSteps.length > 0 ? traceStepsMaxSeq(existingSteps) : 0; + const key = `${taskId}:${attemptKey || "all"}:${afterSeq}`; const existing = traceStepsInFlightRef.current.get(key); if (existing) return existing; const token = detailLoadTokenRef.current; if (selectedIdRef.current === taskId) setSelectedDetailLoading(true); const promise = (async () => { try { - const result = await loadTaskTraceSteps(apiBaseUrl, taskId, 0, 500, attemptKey || null); + const result = await loadTaskTraceSteps(apiBaseUrl, taskId, afterSeq, 500, attemptKey || null); if (token !== detailLoadTokenRef.current || selectedIdRef.current !== taskId) return; - const steps = Array.isArray(result?.steps) ? result.steps : []; + const incomingSteps = Array.isArray(result?.steps) ? result.steps : []; + const steps = afterSeq > 0 ? mergeTraceStepRows(existingSteps, incomingSteps) : incomingSteps; if (attemptKey) { const currentTask = sessionCacheRef.current.get(taskId)?.task; const byAttempt = objectRecord(currentTask?._traceStepsByAttempt) || {}; const loadedByAttempt = objectRecord(currentTask?._traceStepsLoadedByAttempt) || {}; + const nextSeqByAttempt = objectRecord(currentTask?._traceStepsNextAfterSeqByAttempt) || {}; publishCachedTask(taskId, { _traceStepsByAttempt: { ...byAttempt, [attemptKey]: steps }, _traceStepsLoadedByAttempt: { ...loadedByAttempt, [attemptKey]: true }, + _traceStepsNextAfterSeqByAttempt: { ...nextSeqByAttempt, [attemptKey]: result?.nextAfterSeq }, }, token); } else { publishCachedTask(taskId, { @@ -2303,6 +2281,19 @@ export function CodeQueuePage({ microservices, onRaw, apiBaseUrl = "/api", initi await promise; } + function refreshLoadedTraceSteps(taskId: string): void { + if (selectedIdRef.current !== taskId) return; + const cachedTask = sessionCacheRef.current.get(taskId)?.task; + if (!cachedTask) return; + if (taskTraceStepsLoaded(cachedTask, null)) { + void ensureTraceSteps(null, { force: true, incremental: true }).catch((err) => setError(errorText(err, "增量刷新 Trace Steps 失败"))); + } + const loadedByAttempt = objectRecord(cachedTask?._traceStepsLoadedByAttempt) || {}; + for (const attemptKey of Object.keys(loadedByAttempt).filter((key) => loadedByAttempt[key])) { + void ensureTraceSteps(attemptKey, { force: true, incremental: true }).catch((err) => setError(errorText(err, "增量刷新 Attempt Trace Steps 失败"))); + } + } + async function loadTaskDetail(taskId: string, loadStartedAt?: number, queueMs?: number): Promise { if (!service || !taskId) return; const detailStartedAt = performance.now(); @@ -2405,19 +2396,14 @@ export function CodeQueuePage({ microservices, onRaw, apiBaseUrl = "/api", initi const requestedCached = requestedId ? sessionCacheRef.current.get(requestedId) : null; const requestedTranscript = Array.isArray(requestedCached?.task?.transcript) ? requestedCached.task.transcript : []; const overviewAfterSeq = transcriptResumeSeq(requestedTranscript); - const healthResult = health || {}; let tasksResult = null; - try { - tasksResult = await loadTaskOverview(apiBaseUrl, requestedId, overviewAfterSeq, queueFilterId); - } catch { - tasksResult = await loadTaskQueue(apiBaseUrl, healthResult, queueFilterId); - } + tasksResult = await loadTaskOverview(apiBaseUrl, requestedId, overviewAfterSeq, queueFilterId); if (token !== queueLoadTokenRef.current) { if (trackLoad) trackedLoadInFlightRef.current = false; return; } const queueMs = performance.now() - startedAt; - setHealth(healthResult); + setHealth(health || {}); const resultQueue = tasksResult?.queue || {}; const activeSortId = String(resultQueue?.activeTaskId || activeTaskIds(resultQueue)[0] || ""); let mergedTasksResult = tasksResult; @@ -2447,9 +2433,7 @@ export function CodeQueuePage({ microservices, onRaw, apiBaseUrl = "/api", initi const overviewSelected = mergedTasksResult?.selected || null; const overviewTask = overviewSelected?.task || null; const overviewTranscript = Array.isArray(overviewSelected?.transcript) ? overviewSelected.transcript : null; - const nextId = latestRequestedId && (rows.some((task: any) => task.id === latestRequestedId) || String(overviewTask?.id || "") === latestRequestedId) - ? latestRequestedId - : (queuePrimaryId || queueRunnableId || rows[0]?.id || ""); + const nextId = latestRequestedId || queuePrimaryId || queueRunnableId || rows[0]?.id || ""; const previousId = selectedIdRef.current; if (previousId !== nextId) detailLoadTokenRef.current += 1; selectedIdRef.current = nextId; @@ -2774,6 +2758,41 @@ export function CodeQueuePage({ microservices, onRaw, apiBaseUrl = "/api", initi }, "修改 Codex queue 名称失败"); } + async function mergeQueue(): Promise { + const targetQueueId = String(queueId || "default").trim() || "default"; + const candidates = queueRows.filter((row: any) => String(row?.id || "") !== targetQueueId); + if (candidates.length === 0) { + const msg = "没有可合并的其他 queue;请先创建或选择另一个 queue。"; + setNotice(msg); + return; + } + const proposed = typeof window === "undefined" + ? "" + : window.prompt(`将源 queue 合并到当前 queue=${targetQueueId};源 queue 记录会保留且不会删除。请输入源 queue ID:`, String(candidates[0]?.id || "")); + const sourceQueueId = String(proposed || "").trim(); + if (!sourceQueueId) return; + if (sourceQueueId === targetQueueId) { + setError("源 queue 和目标 queue 不能相同。"); + return; + } + const confirmed = typeof window === "undefined" ? true : window.confirm(`确认把 queue=${sourceQueueId} 的全部任务合并到 queue=${targetQueueId}?源 queue 不会删除;任务会按原 queueEnteredAt/createdAt 时间顺序进入目标 queue。`); + if (!confirmed) return; + await guarded(async () => { + const result = await requestJson(codexApi(apiBaseUrl, `/api/queues/${encodeURIComponent(targetQueueId)}/merge`), { method: "POST", body: { sourceQueueId } }); + if (result?.summary) { + setTasksData((previous: any) => previous ? { ...previous, queue: result.summary } : previous); + } + setQueueId(targetQueueId); + setSelectedQueueId(targetQueueId); + setTasksData(null); + const count = Number(result?.mergedTaskCount || 0); + const msg = `已将 queue=${sourceQueueId} 合并到 ${targetQueueId},移动 ${count} 个任务;源 queue 已保留。`; + setNotice(msg); + addNotification("success", msg); + await load(selectedIdRef.current, true, targetQueueId); + }, "合并 Codex queue 失败"); + } + async function enqueue(event: any): Promise { event.preventDefault(); if (enqueueInFlightRef.current) { @@ -2853,6 +2872,7 @@ export function CodeQueuePage({ microservices, onRaw, apiBaseUrl = "/api", initi _traceStepsLoaded: false, _traceStepsByAttempt: {}, _traceStepsLoadedByAttempt: {}, + _traceStepsNextAfterSeqByAttempt: {}, _traceStepDetails: {}, }; sessionCacheRef.current.set(taskId, { ...(sessionCacheRef.current.get(taskId) || {}), task: updatedTask, complete: false, completeUpdatedAt: "" }); @@ -2956,6 +2976,82 @@ export function CodeQueuePage({ microservices, onRaw, apiBaseUrl = "/api", initi if (isMobileQueueViewport()) setQueueSidebarOpen(false); } + function patchRowsForTaskEvent(data: any, taskId: string, patch: AnyRecord): any { + if (!data || !Array.isArray(data?.tasks) || taskId.length === 0 || Object.keys(patch).length === 0) return data; + let changed = false; + const rows = taskRows(data).map((task: any) => { + if (String(task?.id || "") !== taskId) return task; + changed = true; + return taskWithLocalReadState(mergeTaskPatch(task, patch)); + }); + return changed ? { ...data, tasks: rows } : data; + } + + function patchSidebarTaskFromEvent(taskId: string, patch: AnyRecord): void { + setTasksData((previous: any) => patchRowsForTaskEvent(previous, taskId, patch)); + setSearchTasksData((previous: any) => patchRowsForTaskEvent(previous, taskId, patch)); + } + + function taskEventNeedsOverviewRefresh(event: AnyRecord, taskId: string, previousTask: any): boolean { + const type = String(event?.type || ""); + if (type === "queue-updated") return true; + if (taskId.length === 0) return true; + if (!previousTask) return type !== "task-step"; + if (event?.queueId && String(event.queueId) !== taskQueueLabel(previousTask)) return true; + if (event?.status && String(event.status) !== String(previousTask?.status || "")) return true; + return type !== "task-step" && String(event?.reason || "") !== "output"; + } + + function scheduleEventDrivenOverviewRefresh(): void { + if (!service || !isDocumentVisible()) return; + if (eventRefreshTimerRef.current !== null) window.clearTimeout(eventRefreshTimerRef.current); + eventRefreshTimerRef.current = window.setTimeout(() => { + eventRefreshTimerRef.current = null; + // SSE refreshes should update the sidebar data around the user's current + // selection, not jump to whichever task emitted the latest event. + void load(selectedIdRef.current, false).catch((err) => setError(errorText(err, "Code Queue 事件刷新失败"))); + }, 120); + } + + function scheduleSelectedTraceEventRefresh(taskId: string, includeSteps: boolean): void { + if (!service || !isDocumentVisible() || selectedIdRef.current !== taskId) return; + traceEventRefreshPendingStepsRef.current = traceEventRefreshPendingStepsRef.current || includeSteps; + if (traceEventRefreshTimerRef.current !== null) return; + traceEventRefreshTimerRef.current = window.setTimeout(() => { + traceEventRefreshTimerRef.current = null; + const refreshSteps = traceEventRefreshPendingStepsRef.current; + traceEventRefreshPendingStepsRef.current = false; + void ensureTraceSummary(taskId, true).catch((err) => setError(errorText(err, "事件刷新 Trace Summary 失败"))); + if (refreshSteps) refreshLoadedTraceSteps(taskId); + }, 250); + } + + function applyCodeQueueEvent(event: AnyRecord): void { + const taskId = String(event?.taskId || ""); + const stepCount = nonNegativeCount(event?.stepCount); + const patch: AnyRecord = {}; + const previousTask = taskId.length > 0 + ? taskRows(tasksDataRef.current).find((task: any) => String(task?.id || "") === taskId) + : null; + if (taskId.length > 0) { + if (event?.status) patch.status = String(event.status); + if (event?.updatedAt) patch.updatedAt = String(event.updatedAt); + if (event?.queueId) patch.queueId = String(event.queueId); + if (Number.isFinite(Number(event?.stepCount))) { + patch.stepCount = stepCount; + patch.llmStepCount = stepCount; + } + if (Object.keys(patch).length > 0 && (sessionCacheRef.current.has(taskId) || selectedIdRef.current === taskId)) { + publishCachedTask(taskId, patch, detailLoadTokenRef.current); + } + if (Object.keys(patch).length > 0) patchSidebarTaskFromEvent(taskId, patch); + if (selectedIdRef.current === taskId && (event?.type === "task-step" || event?.type === "task-updated")) { + scheduleSelectedTraceEventRefresh(taskId, event?.type === "task-step"); + } + } + if (taskEventNeedsOverviewRefresh(event, taskId, previousTask)) scheduleEventDrivenOverviewRefresh(); + } + useEffect(() => { if (initialLoadSkippedRef.current) { initialLoadSkippedRef.current = false; @@ -2965,23 +3061,35 @@ export function CodeQueuePage({ microservices, onRaw, apiBaseUrl = "/api", initi }, [service?.id, selectedQueueId]); useEffect(() => { - if (!service) return undefined; - const tick = (): void => { - if (!isDocumentVisible()) return; - void load(selectedIdRef.current, false).catch((err) => setError(errorText(err, "Code Queue 轮询失败"))); + if (!service || typeof EventSource === "undefined") return undefined; + const source = new EventSource(codexApi(apiBaseUrl, "/api/events"), { withCredentials: true }); + const onEvent = (message: MessageEvent): void => { + try { + applyCodeQueueEvent(JSON.parse(String(message.data || "{}"))); + } catch (err) { + setError(errorText(err, "解析 Code Queue 事件失败")); + } }; - const timer = window.setInterval(() => { - tick(); - }, 1500); const onVisible = (): void => { - if (isDocumentVisible()) tick(); + if (isDocumentVisible()) scheduleEventDrivenOverviewRefresh(); }; + source.addEventListener("task-step", onEvent); + source.addEventListener("task-updated", onEvent); + source.addEventListener("queue-updated", onEvent); document.addEventListener("visibilitychange", onVisible); return () => { - window.clearInterval(timer); + source.close(); document.removeEventListener("visibilitychange", onVisible); + if (eventRefreshTimerRef.current !== null) { + window.clearTimeout(eventRefreshTimerRef.current); + eventRefreshTimerRef.current = null; + } + if (traceEventRefreshTimerRef.current !== null) { + window.clearTimeout(traceEventRefreshTimerRef.current); + traceEventRefreshTimerRef.current = null; + } }; - }, [service?.id, selectedQueueId]); + }, [service?.id, apiBaseUrl, selectedQueueId]); useEffect(() => { if (!service || !selectedTask || selectedDetailLoading) return; @@ -2989,7 +3097,7 @@ export function CodeQueuePage({ microservices, onRaw, apiBaseUrl = "/api", initi if (!taskId) return; const updatedAt = String(selectedTask.updatedAt || ""); if (traceSummaryIsCurrent(selectedTask)) return; - const key = `${taskId}:${updatedAt || "unknown"}:${rawTaskStepCount(selectedTask)}:${traceSummaryStepCount(taskTraceSummary(selectedTask))}`; + const key = `${taskId}:${updatedAt || "unknown"}:${String(selectedTask?._traceSummaryUpdatedAt || "")}`; if (autoTraceLoadKeysRef.current.has(key)) return; autoTraceLoadKeysRef.current.add(key); void ensureTraceSummary(taskId, true).catch((err) => setError(errorText(err, "自动加载 Trace Summary 失败"))); @@ -3188,6 +3296,7 @@ export function CodeQueuePage({ microservices, onRaw, apiBaseUrl = "/api", initi queueRows.map((row: any) => h("option", { key: String(row?.id || ""), value: String(row?.id || "") }, queueOptionLabel(row))), ), h("button", { type: "button", className: "ghost-btn codex-rename-queue-btn", onClick: () => void renameQueue(), disabled: busy || submitting || !queueId, title: "修改当前 queue 的显示名称,ID 不变", "data-testid": "codex-rename-queue-button" }, "改名"), + h("button", { type: "button", className: "ghost-btn codex-merge-queue-btn", onClick: () => void mergeQueue(), disabled: busy || submitting || queueRows.length < 2, title: "把其他 queue 合并到当前 queue;源 queue 记录会保留,不会删除", "data-testid": "codex-merge-queue-button" }, "合并 queue"), h("button", { type: "button", className: "ghost-btn codex-create-queue-btn", onClick: () => void createQueue(), disabled: busy || submitting, "data-testid": "codex-create-queue-button" }, "创建 queue"), ), ), diff --git a/src/components/frontend/src/index.ts b/src/components/frontend/src/index.ts index 02dc9393..34990de1 100644 --- a/src/components/frontend/src/index.ts +++ b/src/components/frontend/src/index.ts @@ -707,9 +707,12 @@ async function proxyCodeQueueDirect(req: Request, url: URL): Promise { } const overviewCacheKey = `${suffix}${url.search}`; const canUseOverviewCache = req.method === "GET" && suffix === "/api/tasks/overview"; - const expectsJsonResponse = suffix === "/health" || suffix.startsWith("/api/"); + const isEventStreamRequest = req.method === "GET" && suffix === "/api/events"; + const cacheControl = req.headers.get("cache-control") || ""; + const bypassOverviewCache = /\bno-cache\b|\bno-store\b/iu.test(cacheControl) || req.headers.get("x-unidesk-no-cache") === "1"; + const expectsJsonResponse = !isEventStreamRequest && (suffix === "/health" || suffix.startsWith("/api/")); if (req.method !== "GET" && req.method !== "HEAD") invalidateCodeQueueOverviewCache(); - if (canUseOverviewCache) { + if (canUseOverviewCache && !bypassOverviewCache) { const cached = cachedCodeQueueOverview(overviewCacheKey); if (cached !== null) { recordOperationPerformance("frontend", "code_queue_direct_proxy_cache", 0, true, overviewCacheKey); @@ -733,6 +736,13 @@ async function proxyCodeQueueDirect(req: Request, url: URL): Promise { const responseHeaders = new Headers(); const upstreamContentType = upstream.headers.get("content-type"); if (upstreamContentType !== null) responseHeaders.set("content-type", upstreamContentType); + if (isEventStreamRequest) { + responseHeaders.set("cache-control", upstream.headers.get("cache-control") || "no-store, no-transform"); + responseHeaders.set("connection", "keep-alive"); + const buffering = upstream.headers.get("x-accel-buffering"); + if (buffering !== null) responseHeaders.set("x-accel-buffering", buffering); + return new Response(upstream.body, { status: upstream.status, headers: responseHeaders }); + } const upstreamBody = await upstream.arrayBuffer(); const isJsonResponse = (upstreamContentType ?? "").toLowerCase().includes("json"); let parsedJson: unknown = null; @@ -786,7 +796,7 @@ async function proxyCodeQueueDirect(req: Request, url: URL): Promise { } if (expectsJsonResponse) { const text = jsonText; - if (canUseOverviewCache && upstream.ok && typeof parsedJson === "object" && parsedJson !== null) { + if (canUseOverviewCache && !bypassOverviewCache && upstream.ok && typeof parsedJson === "object" && parsedJson !== null) { codeQueueOverviewCache.set(codeQueueOverviewCacheKey(overviewCacheKey), { at: Date.now(), payload: parsedJson as JsonValue, text }); } return new Response(text, { status: upstream.status, headers: responseHeaders }); diff --git a/src/components/microservices/code-queue/src/code-agent/opencode.ts b/src/components/microservices/code-queue/src/code-agent/opencode.ts index cb0727e2..0d003a07 100644 --- a/src/components/microservices/code-queue/src/code-agent/opencode.ts +++ b/src/components/microservices/code-queue/src/code-agent/opencode.ts @@ -129,11 +129,22 @@ function remoteOpenCodeRunCommand(task: QueueTask, prompt: string): string { `mkdir -p ${ctx().shellQuote(task.cwd)}`, `cd ${ctx().shellQuote(task.cwd)}`, envExports, - `exec ${shellJoin(openCodeRunArgs(task, prompt))}`, + `exec opencode ${shellJoin(openCodeRunArgs(task, prompt))}`, ].join("; "); return `docker exec -i ${ctx().shellQuote(plan.containerName)} bash -lc ${ctx().shellQuote(inner)}`; } +export function remoteOpenCodeRunCommandForTest(task: QueueTask, prompt: string): string { + return remoteOpenCodeRunCommand(task, prompt); +} + +export function openCodeTransportClosedBeforeTerminal(exitOk: boolean, hasFinalResponse: boolean, stepFinished: boolean): boolean { + // Some OpenCode JSON streams can exit cleanly with visible assistant text but + // without a step_finish event. Treat exit=0 plus a current final response as + // terminal; otherwise the judge safety gate will retry a completed turn. + return !exitOk || (!hasFinalResponse && !stepFinished); +} + function openCodeSessionIdFromRecord(record: Record, part: Record | null): string | null { const top = ctx().recordStringField(record, ["sessionID", "sessionId", "session_id"]); if (top.length > 0) return top; @@ -326,7 +337,7 @@ async function runOpenCodeTurnOnce(task: QueueTask, prompt: string): Promise 0 ? app.finalResponse : ""; const exitOk = exit.code === 0; const hasFinal = finalResponse.trim().length > 0; const status: TerminalStatus = exitOk && hasFinal ? "completed" : "failed"; @@ -372,7 +383,7 @@ async function runOpenCodeTurnOnce(task: QueueTask, prompt: string): Promise 0 ? app.finalResponse : "", terminalStatus: "failed", terminalError: message, transportClosedBeforeTerminal: true, diff --git a/src/components/microservices/code-queue/src/dev-containers.ts b/src/components/microservices/code-queue/src/dev-containers.ts index 83fd1e0c..5f9c42ac 100644 --- a/src/components/microservices/code-queue/src/dev-containers.ts +++ b/src/components/microservices/code-queue/src/dev-containers.ts @@ -26,7 +26,7 @@ export interface DevContainerContext { remoteContainerStartScript: (plan: DevContainerPlan, forceRecreate: boolean) => string; remoteHostWorkdirForTask: (task: QueueTask) => string; remoteKeyInstallScript: (plan: DevContainerPlan, privateKeyBase64: string) => string; - runCodeQueueSsh: (providerId: string, script: string, timeoutMs: number, name: string) => DevContainerCommandLog; + runCodeQueueSsh: (providerId: string, script: string, timeoutMs: number, name: string) => Promise; safePreview: (value: string, max?: number) => string; shellQuote: (value: string) => string; throwIfCommandFailed: (command: DevContainerCommandLog) => void; @@ -51,29 +51,29 @@ async function startDevContainerPlan(plan: DevContainerPlan, options: { forceRec verification?: Record; }> { const commands: DevContainerCommandLog[] = []; - const run = (targetProviderId: string, script: string, timeoutMs: number, name: string): DevContainerCommandLog => { - const command = ctx().runCodeQueueSsh(targetProviderId, script, timeoutMs, name); + const run = async (targetProviderId: string, script: string, timeoutMs: number, name: string): Promise => { + const command = await ctx().runCodeQueueSsh(targetProviderId, script, timeoutMs, name); commands.push(command); ctx().throwIfCommandFailed(command); return command; }; - run("main-server", ctx().masterKeySetupScript(plan), 45_000, "master-key-setup"); - const keyRead = run("main-server", ctx().masterKeyReadScript(plan), 15_000, "master-key-read"); + await run("main-server", ctx().masterKeySetupScript(plan), 45_000, "master-key-setup"); + const keyRead = await run("main-server", ctx().masterKeyReadScript(plan), 15_000, "master-key-read"); const keyBase64 = keyRead.stdout.trim(); if (!/^[A-Za-z0-9+/=\r\n]+$/u.test(keyBase64) || keyBase64.length < 40) throw new Error("master key read returned invalid base64"); keyRead.stdout = "[redacted private tunnel key]\n"; - run(plan.providerId, ctx().remoteKeyInstallScript(plan, keyBase64), 30_000, "remote-key-install"); - run(plan.providerId, ctx().remoteCodexConfigInstallScript(plan), 30_000, "remote-codex-config-install"); - run(plan.providerId, ctx().remoteContainerStartScript(plan, options.forceRecreate), 60_000, "remote-container-start"); - run("main-server", ctx().masterProxyPrepareScript(plan), 30_000, "master-proxy-prepare"); - run(plan.providerId, ctx().containerTunnelStartScript(plan), 45_000, "remote-tunnel-start"); - run("main-server", ctx().masterProxyFinishScript(plan), 30_000, "master-proxy-finish"); - if (options.prepareRuntime) run(plan.providerId, ctx().remoteCodexRuntimePrepareScript(plan), 180_000, "remote-codex-runtime-prepare"); + await run(plan.providerId, ctx().remoteKeyInstallScript(plan, keyBase64), 30_000, "remote-key-install"); + await run(plan.providerId, ctx().remoteCodexConfigInstallScript(plan), 30_000, "remote-codex-config-install"); + await run(plan.providerId, ctx().remoteContainerStartScript(plan, options.forceRecreate), 60_000, "remote-container-start"); + await run("main-server", ctx().masterProxyPrepareScript(plan), 30_000, "master-proxy-prepare"); + await run(plan.providerId, ctx().containerTunnelStartScript(plan), 45_000, "remote-tunnel-start"); + await run("main-server", ctx().masterProxyFinishScript(plan), 30_000, "master-proxy-finish"); + if (options.prepareRuntime) await run(plan.providerId, ctx().remoteCodexRuntimePrepareScript(plan), 600_000, "remote-codex-runtime-prepare"); const verification: Record = {}; if (options.verifyPing) { - const before = run("main-server", ctx().masterProxyEvidenceScript(plan), 15_000, "master-proxy-evidence-before-ping"); - const ping = run(plan.providerId, ctx().devContainerPingScript(plan), 20_000, "remote-container-ping-google"); - const after = run("main-server", ctx().masterProxyEvidenceScript(plan), 15_000, "master-proxy-evidence-after-ping"); + const before = await run("main-server", ctx().masterProxyEvidenceScript(plan), 15_000, "master-proxy-evidence-before-ping"); + const ping = await run(plan.providerId, ctx().devContainerPingScript(plan), 20_000, "remote-container-ping-google"); + const after = await run("main-server", ctx().masterProxyEvidenceScript(plan), 15_000, "master-proxy-evidence-after-ping"); verification.pingGoogleOk = ping.exitCode === 0 && /0% packet loss|1 packets received|1 received/iu.test(ping.stdout); verification.directPingEvidence = commands.find((command) => command.name === "remote-tunnel-start")?.stdout.includes("direct_ping=failed_expected") === true ? `direct ${plan.providerId} container ping failed before tunnel` @@ -175,8 +175,8 @@ docker inspect "$CONTAINER" --format 'container={{.Name}} state={{.State.Status} if docker inspect "$CONTAINER" >/dev/null 2>&1; then docker exec "$CONTAINER" bash -lc 'export PATH=/tmp/unidesk-tools:$PATH; echo default=$(ip route show default | head -1); echo resolv=$(tr "\\n" " " /dev/null || true' || true fi`; - commands.push(ctx().runCodeQueueSsh(providerId, statusScript, 15_000, "remote-container-status")); - commands.push(ctx().runCodeQueueSsh("main-server", ctx().masterProxyEvidenceScript(plan), 15_000, "master-proxy-status")); + commands.push(await ctx().runCodeQueueSsh(providerId, statusScript, 15_000, "remote-container-status")); + commands.push(await ctx().runCodeQueueSsh("main-server", ctx().masterProxyEvidenceScript(plan), 15_000, "master-proxy-status")); return ctx().jsonResponse({ ok: commands.every((command) => command.exitCode === 0), providerId, diff --git a/src/components/microservices/code-queue/src/index.ts b/src/components/microservices/code-queue/src/index.ts index ae30d160..dd1f06f7 100644 --- a/src/components/microservices/code-queue/src/index.ts +++ b/src/components/microservices/code-queue/src/index.ts @@ -123,6 +123,8 @@ import { statsDaysFromUrl, taskForMetaResponse, taskForResponse, + taskListStepCount, + taskOutputMaxSeq as taskViewOutputMaxSeq, taskStatisticsSummary, taskSummaryResponse, timestampMs, @@ -148,10 +150,36 @@ const retryBackoffMaxMs = 10 * 60 * 1000; const queueIdPattern = /^[A-Za-z0-9][A-Za-z0-9_.-]{0,63}$/u; const queueNameMaxLength = 80; const config = readConfig(); + +type CodeQueueEventType = "hello" | "task-updated" | "task-step" | "queue-updated"; + +interface CodeQueueEvent { + sequence: number; + type: CodeQueueEventType; + at: string; + reason: string; + taskId?: string; + queueId?: string; + status?: TaskStatus; + updatedAt?: string; + stepCount?: number; + outputMaxSeq?: number; +} + +interface CodeQueueEventClient { + enqueue: (chunk: string) => void; + close: () => void; +} + +const codeQueueEventClients = new Set(); +const codeQueueEventEncoder = new TextEncoder(); +const taskEventSnapshots = new Map(); +let codeQueueEventSequence = 0; const logger = createLogger("code-queue", config.logFile); const state = emptyState(); let processing = false; const processingQueues = new Set(); +const mergingQueues = new Set(); const activeRuns = new Map(); const activeRunSlotReservations = new Set(); const activeRunSlotWaiters: ActiveRunSlotWaiter[] = []; @@ -582,6 +610,142 @@ function nowIso(): string { return new Date().toISOString(); } +function sseChunk(event: CodeQueueEvent): string { + return [ + `id: ${event.sequence}`, + `event: ${event.type}`, + `data: ${JSON.stringify(event)}`, + "", + "", + ].join("\n"); +} + +function emitCodeQueueEvent(event: Omit & { at?: string }): void { + const payload: CodeQueueEvent = { + ...event, + sequence: ++codeQueueEventSequence, + at: event.at || nowIso(), + }; + if (codeQueueEventClients.size === 0) return; + const chunk = sseChunk(payload); + for (const client of Array.from(codeQueueEventClients)) { + try { + client.enqueue(chunk); + } catch { + client.close(); + } + } +} + +function taskOutputMaxSeq(task: QueueTask): number { + return taskViewOutputMaxSeq(task); +} + +function publishTaskEvent(task: QueueTask, reason: string, options: { onlyStepChange?: boolean; stepChanged?: boolean } = {}): void { + // Hot path: never build full transcripts or read output archives here. + const stepCount = taskListStepCount(task); + const outputMaxSeq = taskOutputMaxSeq(task); + const previous = taskEventSnapshots.get(task.id); + const stepChanged = options.stepChanged ?? (previous === undefined ? stepCount > 0 : stepCount > previous.stepCount); + if (options.onlyStepChange === true && !stepChanged) { + taskEventSnapshots.set(task.id, { stepCount, outputMaxSeq, status: task.status, updatedAt: task.updatedAt }); + return; + } + const type: CodeQueueEventType = stepChanged ? "task-step" : "task-updated"; + taskEventSnapshots.set(task.id, { stepCount, outputMaxSeq, status: task.status, updatedAt: task.updatedAt }); + emitCodeQueueEvent({ + type, + reason, + taskId: task.id, + queueId: queueIdOf(task), + status: task.status, + updatedAt: task.updatedAt, + stepCount, + outputMaxSeq, + }); +} + +function publishQueueEvent(reason: string, queueId = ""): void { + emitCodeQueueEvent({ type: "queue-updated", reason, queueId: queueId || undefined }); +} + +function outputCanChangeStepCount(output: LiveOutput): boolean { + return output.channel === "command" || output.channel === "diff" || output.channel === "tool"; +} + +function outputStartsTraceStep(output: LiveOutput): boolean { + if (output.channel === "diff" || output.channel === "tool") return true; + if (output.channel !== "command") return false; + const method = String(output.method || ""); + return method === "item/started" || (method !== "item/commandExecution/outputDelta" && method !== "item/completed"); +} + +function recordTaskOutputMetrics(task: QueueTask, output: LiveOutput, op: "set" | "append"): boolean { + task.outputMaxSeq = Math.max(taskOutputMaxSeq(task), Number.isFinite(Number(output.seq)) ? Number(output.seq) : 0); + if (op === "append" || !outputStartsTraceStep(output)) return false; + const storedStepCount = Number(task.stepCount ?? task.llmStepCount); + const nextStepCount = Number.isFinite(storedStepCount) && storedStepCount >= 0 + ? Math.floor(storedStepCount) + 1 + : task.output.reduce((count, item) => count + (outputStartsTraceStep(item) ? 1 : 0), 0); + task.stepCount = nextStepCount; + task.llmStepCount = nextStepCount; + return true; +} + +function codeQueueEventsResponse(): Response { + let heartbeat: ReturnType | null = null; + let client: CodeQueueEventClient | null = null; + const stream = new ReadableStream({ + start(controller) { + client = { + enqueue(chunk: string) { + controller.enqueue(codeQueueEventEncoder.encode(chunk)); + }, + close() { + if (heartbeat !== null) { + clearInterval(heartbeat); + heartbeat = null; + } + if (client !== null) codeQueueEventClients.delete(client); + client = null; + try { + controller.close(); + } catch { + // The browser may have already closed the EventSource connection. + } + }, + }; + codeQueueEventClients.add(client); + controller.enqueue(codeQueueEventEncoder.encode("retry: 1000\n\n")); + client.enqueue(sseChunk({ + sequence: codeQueueEventSequence, + type: "hello", + at: nowIso(), + reason: "connected", + })); + heartbeat = setInterval(() => { + try { + controller.enqueue(codeQueueEventEncoder.encode(`: heartbeat ${nowIso()}\n\n`)); + } catch { + client?.close(); + } + }, 25_000); + heartbeat.unref?.(); + }, + cancel() { + client?.close(); + }, + }); + return new Response(stream, { + headers: { + "content-type": "text/event-stream; charset=utf-8", + "cache-control": "no-store, no-transform", + "connection": "keep-alive", + "x-accel-buffering": "no", + }, + }); +} + function resolveReasoningEffort(model: string, explicit?: string | null): string | null { const requested = explicit?.trim(); if (requested) return requested; @@ -704,6 +868,15 @@ function pruneTaskHotState(task: QueueTask): void { } } +function taskRetainedTraceStepCount(task: QueueTask): number { + return task.output.reduce((count, output) => count + (outputStartsTraceStep(output) ? 1 : 0), 0); +} + +function normalizeTaskMetric(value: unknown): number | null { + const parsed = Number(value); + return Number.isFinite(parsed) && parsed >= 0 ? Math.floor(parsed) : null; +} + function normalizeTask(task: QueueTask): QueueTask { task.queueId = safeQueueId(task.queueId); task.queueEnteredAt = taskQueueEnteredAt(task); @@ -726,6 +899,11 @@ function normalizeTask(task: QueueTask): QueueTask { task.judgeFailCount = Number.isInteger(task.judgeFailCount) && task.judgeFailCount >= 0 ? task.judgeFailCount : judgeFailCountFromOutput(task); const persistedPromptHistory = Array.isArray(task.promptHistory) ? task.promptHistory : []; task.promptHistory = mergePromptHistory([...persistedPromptHistory, ...outputPromptHistory(task)]); + const storedStepCount = normalizeTaskMetric(task.stepCount) ?? normalizeTaskMetric(task.llmStepCount); + const stepCount = storedStepCount ?? taskRetainedTraceStepCount(task); + task.stepCount = stepCount; + task.llmStepCount = stepCount; + task.outputMaxSeq = Math.max(normalizeTaskMetric(task.outputMaxSeq) ?? 0, taskViewOutputMaxSeq(task)); pruneTaskHotState(task); return task; } @@ -779,6 +957,7 @@ function markTaskDirty(taskId: string): void { function persistTaskState(task: QueueTask): void { markTaskDirty(task.id); persistState(false); + publishTaskEvent(task, "persist"); } function markQueueDirty(queueId: string): void { @@ -815,14 +994,12 @@ function taskTimestamp(value: string | null): string | null { } function lastOutputSeq(task: QueueTask): number { - return task.output.at(-1)?.seq ?? 0; + return taskOutputMaxSeq(task); } function updateNextSeqFromTasks(): void { let nextSeq = Math.max(1, Number.isFinite(state.nextSeq) ? Math.floor(state.nextSeq) : 1); - for (const task of state.tasks) { - for (const output of task.output) nextSeq = Math.max(nextSeq, Number(output.seq) + 1); - } + for (const task of state.tasks) nextSeq = Math.max(nextSeq, lastOutputSeq(task) + 1); state.nextSeq = nextSeq; } @@ -1603,6 +1780,7 @@ function addEvent(task: QueueTask, event: CodexEventSummary): void { task.events.push(event); if (config.maxInMemoryEventRecords > 0 && task.events.length > config.maxInMemoryEventRecords) task.events.splice(0, task.events.length - config.maxInMemoryEventRecords); markTaskDirty(task.id); + publishTaskEvent(task, "agent-event", { onlyStepChange: true }); } function taskReferencesEqual(left: string[], right: string[]): boolean { @@ -1789,6 +1967,12 @@ configureTaskOutput({ logger, markTaskDirty, nowIso, + onOutputAppended: (task, output, op) => { + const archiveOp = op === "append" ? "append" : "set"; + const stepChanged = recordTaskOutputMetrics(task, output, archiveOp); + if (archiveOp === "append" && !outputCanChangeStepCount(output)) return; + publishTaskEvent(task, "output", { onlyStepChange: archiveOp === "append", stepChanged }); + }, schedulePersistState, }); @@ -2223,7 +2407,7 @@ async function runTask(task: QueueTask): Promise { } const finishedAt = nowIso(); task.finalResponse = result.finalResponse || task.finalResponse; - task.attempts.push(attemptFromResult(task, mode, startedAt, finishedAt, result, attemptStartOutput?.seq ?? null, taskFullOutput(task).at(-1)?.seq ?? null, recoveryPrompt)); + task.attempts.push(attemptFromResult(task, mode, startedAt, finishedAt, result, attemptStartOutput?.seq ?? null, taskOutputMaxSeq(task), recoveryPrompt)); task.status = "judging"; task.activeTurnId = null; task.updatedAt = nowIso(); @@ -2510,6 +2694,9 @@ function queuedStatusReason(task: QueueTask, tasks: QueueTask[] = state.tasks): if (!serviceReady) { return queuedReason("service", "SERVICE", "Code Queue is still starting and has not enabled scheduling yet."); } + if (mergingQueues.has(queueId)) { + return queuedReason("queue_merge", "MERGING", "Queue merge is rewriting queue membership; scheduling will resume immediately after it finishes."); + } const memoryPressure = activeRunMemoryPressure(); if (memoryPressure !== null) { @@ -2592,6 +2779,7 @@ function scheduleQueue(queueId?: string): void { if (!serviceReady || shutdownRequested) return; const ids = queueId === undefined ? runnableQueueIds() : [queueId]; for (const id of ids) { + if (mergingQueues.has(id)) continue; if (processingQueues.has(id)) continue; void processQueue(id).catch((error) => { logger("error", "queue_loop_failed", { queueId: id, error: error instanceof Error ? error.stack ?? error.message : String(error) }); @@ -2705,6 +2893,8 @@ function requestErrorResponse(error: unknown): Response | null { error.message === "request body must be an object" || error.message === "prompt is required" || error.message === "a task cannot reference itself while editing prompt" + || error.message === "sourceQueueId is required" + || error.message === "source queue must be different from target queue" || error.message.startsWith("referenceTaskIds supports at most ") || error.message.startsWith("queueId must match ") || error.message.startsWith("queue name must be ") @@ -2738,6 +2928,8 @@ async function createTasks(req: Request): Promise { for (const task of tasks) appendOutput(task, "user", `${task.prompt}\n`, "enqueue"); state.tasks.push(...tasks); if (tasks.length > 0) armIdleNotification(); + for (const task of tasks) publishTaskEvent(task, "enqueue"); + for (const id of new Set(tasks.map(queueIdOf))) publishQueueEvent("enqueue", id); persistState(); logger("info", "tasks_enqueued", { count: tasks.length, ids: tasks.map((task) => task.id), queueIds: Array.from(new Set(tasks.map(queueIdOf))), providerIds: Array.from(new Set(tasks.map((task) => task.providerId))) }); scheduleQueue(); @@ -2865,6 +3057,7 @@ async function markTaskRead(task: QueueTask): Promise { task.readAt = nowIso(); markTaskDirty(task.id); persistState(false); + publishTaskEvent(task, "read"); logger("info", "task_marked_read", { taskId: task.id, queueId: queueIdOf(task), status: task.status }); } await flushDirtyTasksToDatabase(true); @@ -2907,7 +3100,10 @@ async function markTaskReadById(taskId: string): Promise { AND read_at IS NULL `; const hotTask = findTask(taskId); - if (hotTask !== null) hotTask.readAt = readAt; + if (hotTask !== null) { + hotTask.readAt = readAt; + publishTaskEvent(hotTask, "read"); + } logger("info", "task_marked_read", { taskId, queueId: safeQueueId(row.queue_id), status: row.status }); } return compactJsonResponse({ @@ -2952,6 +3148,7 @@ async function markTerminalTasksRead(url: URL): Promise { for (const task of state.tasks) { if (!ids.has(task.id)) continue; task.readAt = readAt; + publishTaskEvent(task, "read-all"); } if (ids.size > 0) { logger("info", "terminal_tasks_marked_read", { count: ids.size, queueId }); @@ -2964,6 +3161,7 @@ async function markTerminalTasksRead(url: URL): Promise { if (!terminalTaskUnread(task)) continue; task.readAt = readAt; markTaskDirty(task.id); + publishTaskEvent(task, "read-all"); count += 1; } if (count > 0) { @@ -2983,6 +3181,7 @@ async function createQueue(req: Request): Promise { queue.updatedAt = nowIso(); markQueueDirty(queue.id); persistState(false); + publishQueueEvent("queue-created", queue.id); logger("info", "queue_created", { queueId, name: queue.name, existed: beforeCount === state.queues.length }); await flushDirtyTasksToDatabase(true); const tasks = await loadAllTasksForRead(); @@ -3003,12 +3202,154 @@ async function updateQueue(queueIdValue: string, req: Request): Promise queue.id === queueId) ?? null; +} + +function queueHasKnownTasks(queueId: string): boolean { + return state.tasks.some((task) => queueIdOf(task) === queueId); +} + +function queueMergeBlocker(queueId: string): string | null { + if (processingQueues.has(queueId)) return "queue processor is currently active"; + if (activeRuns.has(queueId)) return "queue has an active agent run"; + if (activeRunSlotReservations.has(queueId)) return "queue is reserving an active run slot"; + if (activeRunSlotWaiters.some((waiter) => waiter.queueId === queueId)) return "queue is waiting for an active run slot"; + const activeTask = state.tasks.find((task) => queueIdOf(task) === queueId && (task.status === "running" || task.status === "judging")); + return activeTask === undefined ? null : `task ${activeTask.id} is ${activeTask.status}`; +} + +function parseSourceQueueIds(record: Record, targetQueueId: string): string[] { + const raw = record.sourceQueueIds ?? record.sources ?? record.sourceQueueId ?? record.fromQueueId ?? record.from ?? record.queueId ?? record.id; + const values = Array.isArray(raw) + ? raw + : typeof raw === "string" + ? raw.split(/[,\s]+/u) + : []; + const ids: string[] = []; + const seen = new Set(); + for (const value of values) { + const id = normalizeQueueId(value); + if (id === targetQueueId) throw new Error("source queue must be different from target queue"); + if (seen.has(id)) continue; + seen.add(id); + ids.push(id); + } + if (ids.length === 0) throw new Error("sourceQueueId is required"); + return ids; +} + +async function mergeDatabaseQueueTasks(sourceQueueIds: string[], targetQueueId: string): Promise { + if (!databaseReady || sourceQueueIds.length === 0) return []; + const rows = await sql>` + UPDATE unidesk_code_queue_tasks + SET + queue_id = ${targetQueueId}, + task_json = jsonb_set( + jsonb_set( + task_json, + '{queueId}', + to_jsonb(${targetQueueId}::text), + true + ), + '{queueEnteredAt}', + to_jsonb(COALESCE(NULLIF(task_json->>'queueEnteredAt', ''), to_char(created_at AT TIME ZONE 'UTC', 'YYYY-MM-DD"T"HH24:MI:SS.MS"Z"'))::text), + true + ) + WHERE queue_id IN ${sql(sourceQueueIds)} + RETURNING id + `; + return rows.map((row) => row.id); +} + +async function mergeQueues(targetQueueIdValue: string | null, req: Request): Promise { + const body = await readJson(req); + const record = typeof body === "object" && body !== null && !Array.isArray(body) ? body as Record : {}; + const targetQueueId = normalizeQueueId(targetQueueIdValue ?? record.targetQueueId ?? record.intoQueueId ?? record.into); + const sourceQueueIds = parseSourceQueueIds(record, targetQueueId); + const missingSources = sourceQueueIds.filter((id) => knownQueue(id) === null && !queueHasKnownTasks(id)); + if (missingSources.length > 0) return jsonResponse({ ok: false, error: `source queue not found: ${missingSources.join(", ")}` }, 404); + + const mergeQueueIds = Array.from(new Set([targetQueueId, ...sourceQueueIds])); + for (const id of mergeQueueIds) mergingQueues.add(id); + try { + for (const id of mergeQueueIds) { + const blocker = queueMergeBlocker(id); + if (blocker !== null) { + return jsonResponse({ ok: false, error: `cannot merge queue ${id}: ${blocker}` }, 409); + } + } + + const mergedAt = nowIso(); + const targetQueue = ensureQueue(targetQueueId); + const sourceQueues = sourceQueueIds.map((id) => ensureQueue(id)); + targetQueue.updatedAt = mergedAt; + markQueueDirty(targetQueue.id); + for (const queue of sourceQueues) { + queue.updatedAt = mergedAt; + markQueueDirty(queue.id); + } + + const sourceSet = new Set(sourceQueueIds); + const hotMovedTasks: QueueTask[] = []; + for (const task of state.tasks) { + const previousQueueId = queueIdOf(task); + if (!sourceSet.has(previousQueueId)) continue; + task.queueEnteredAt = taskQueueEnteredAt(task); + task.queueId = targetQueueId; + hotMovedTasks.push(task); + markTaskDirty(task.id); + publishTaskEvent(task, "queue-merged"); + } + const databaseMovedTaskIds = await mergeDatabaseQueueTasks(sourceQueueIds, targetQueueId); + persistState(false); + publishQueueEvent("queue-merged", targetQueueId); + for (const sourceQueueId of sourceQueueIds) publishQueueEvent("queue-merged", sourceQueueId); + if (hotMovedTasks.some((task) => task.status === "queued" || task.status === "retry_wait")) armIdleNotification(); + logger("info", "queues_merged", { + targetQueueId, + sourceQueueIds, + hotMovedTaskCount: hotMovedTasks.length, + databaseMovedTaskCount: databaseReady ? databaseMovedTaskIds.length : null, + }); + for (const id of mergeQueueIds) mergingQueues.delete(id); + scheduleQueue(targetQueueId); + await flushDirtyTasksToDatabase(true); + const tasks = await loadAllTasksForRead(); + const movedIdSet = new Set(databaseReady ? databaseMovedTaskIds : hotMovedTasks.map((task) => task.id)); + const orderedMovedTaskIds = tasks + .filter((task) => movedIdSet.has(task.id)) + .sort(compareTaskQueueOrder) + .map((task) => task.id); + const targetTaskOrder = tasks + .filter((task) => queueIdOf(task) === targetQueueId) + .sort(compareTaskQueueOrder) + .map((task) => ({ id: task.id, queueEnteredAt: taskQueueEnteredAt(task), createdAt: task.createdAt, status: task.status })); + return jsonResponse({ + ok: true, + targetQueueId, + sourceQueueIds, + mergedTaskCount: databaseReady ? databaseMovedTaskIds.length : hotMovedTasks.length, + movedTaskIds: orderedMovedTaskIds.slice(0, 500), + targetTaskOrder: targetTaskOrder.slice(0, 500), + order: "merged tasks keep their original queueEnteredAt/createdAt ordering; source queue records are retained and never deleted", + targetQueue, + sourceQueues, + queues: perQueueSummaries(tasks), + summary: queueSummary(false, tasks), + }, 202); + } finally { + for (const id of mergeQueueIds) mergingQueues.delete(id); + } +} + async function moveTaskToQueue(task: QueueTask, req: Request): Promise { if (task.status === "running" || task.status === "judging") { return jsonResponse({ ok: false, error: `cannot move active task ${task.id} while status=${task.status}`, task: taskForResponse(task) }, 409); @@ -3027,6 +3368,8 @@ async function moveTaskToQueue(task: QueueTask, req: Request): Promise appendOutput(task, "system", `moved from queue=${previousQueueId} to queue=${queueId}\n`, "queue/move"); if (task.status === "queued" || task.status === "retry_wait") armIdleNotification(); persistState(); + publishQueueEvent("task-moved", previousQueueId); + publishQueueEvent("task-moved", queueId); logger("info", "task_moved_queue", { taskId: task.id, previousQueueId, queueId, status: task.status }); if (task.status === "queued" || task.status === "retry_wait") scheduleQueue(queueId); await flushDirtyTasksToDatabase(true); @@ -3039,6 +3382,7 @@ async function route(req: Request): Promise { try { if (url.pathname === "/" || url.pathname === "/health") return jsonResponse({ ok: true, service: "code-queue", queue: await queueSummaryForHealth(), startedAt: serviceStartedAt }); if (url.pathname === "/logs") return jsonResponse({ ok: true, logs: recentLogs.slice(-parseLimit(url)) }); + if (url.pathname === "/api/events" && req.method === "GET") return codeQueueEventsResponse(); if (url.pathname === "/api/dev-ready" && req.method === "GET") return jsonResponse({ ok: true, devReady: collectDevReady() }); if (url.pathname === "/api/dev-containers" && req.method === "GET") { const plan = buildDevContainerPlan(normalizeProviderId(config.devContainerDefaultProviderId) ?? "D601", {}); @@ -3091,6 +3435,9 @@ async function route(req: Request): Promise { return jsonResponse({ ok: true, queues: perQueueSummaries(tasks), queue: queueSummary(false, tasks) }); } if (url.pathname === "/api/queues" && req.method === "POST") return await createQueue(req); + if (url.pathname === "/api/queues/merge" && req.method === "POST") return await mergeQueues(null, req); + const queueMergeMatch = url.pathname.match(/^\/api\/queues\/([^/]+)\/merge$/u); + if (queueMergeMatch !== null && req.method === "POST") return await mergeQueues(decodeURIComponent(queueMergeMatch[1] ?? ""), req); const queueMatch = url.pathname.match(/^\/api\/queues\/([^/]+)$/u); if (queueMatch !== null && (req.method === "PATCH" || req.method === "PUT" || req.method === "POST")) return await updateQueue(decodeURIComponent(queueMatch[1] ?? ""), req); if (url.pathname === "/api/tasks/read-all" && req.method === "POST") return await markTerminalTasksRead(url); diff --git a/src/components/microservices/code-queue/src/judge-probes.ts b/src/components/microservices/code-queue/src/judge-probes.ts index 90cc6f67..87264b2f 100644 --- a/src/components/microservices/code-queue/src/judge-probes.ts +++ b/src/components/microservices/code-queue/src/judge-probes.ts @@ -20,6 +20,23 @@ export const defaultJudgeProbeCases: JudgeProbeCase[] = [ ], events: [{ at: nowIso(), method: "turn/completed", status: "completed" }], }, + { + id: "completed_with_tool_evidence_but_no_current_final_response_should_retry", + prompt: "调查 /mnt/f/Work/ConStart/docs/MDTODO 的最新进展,只读,并在最终回复中总结。", + finalResponse: "", + expected: "retry", + expectedContinuePromptIncludes: [ + "最终 assistant response", + "不能只执行工具", + ], + terminalStatus: "completed", + outputs: [ + { channel: "user", text: "调查 /mnt/f/Work/ConStart/docs/MDTODO 的最新进展,只读,并在最终回复中总结。\n", method: "enqueue" }, + { channel: "tool", text: "opencode/tool: read /mnt/f/Work/ConStart/docs/MDTODO/20260419_频率判断.md status=completed; R1/R2 completed, R3 pending", method: "opencode/tool" }, + { channel: "system", text: "opencode completed status=completed exit=0 signal=null\n", method: "opencode/complete" }, + ], + events: [{ at: nowIso(), method: "opencode/step_finish", status: "completed" }], + }, { id: "completed_but_plan_only", prompt: "Create /root/unidesk/tmp/judge_probe.txt containing exactly judge-probe-ok, then summarize the file path.", diff --git a/src/components/microservices/code-queue/src/judge.ts b/src/components/microservices/code-queue/src/judge.ts index 570f97c2..56465521 100644 --- a/src/components/microservices/code-queue/src/judge.ts +++ b/src/components/microservices/code-queue/src/judge.ts @@ -588,20 +588,63 @@ function originalRequirementOnlyFeedbackPrompt(task: QueueTask, reason: string): return `未完成原始需求:${originalTask || "原始任务尚未完成"}。继续按照原始需求完成剩余任务。`; } -function applyFallbackSafetyOverrides(task: QueueTask, result: CodexRunResult, judge: JudgeResult): JudgeResult { - // Non-LLM string/regex overrides are a last-resort fallback only. Never call - // this on a successful MiniMax judge result; MiniMax is the authoritative judge. - if (judge.source !== "fallback") return judge; +function missingFinalResponseFeedbackPrompt(task: QueueTask, reason: string): string { + return [ + retryInstruction, + `上一次 attempt 未完成:${judgeReasonForPrompt(reason)}`, + "本轮必须在最终 assistant response 中给出可见交付结果;不能只执行工具、输出 reasoning 或依赖旧 finalResponse。", + "原始任务摘要/按需查询:", + compactRetryTaskContext(task), + ].join("\n\n"); +} + +function applyJudgeSafetyOverrides(task: QueueTask, result: CodexRunResult, judge: JudgeResult): JudgeResult { const currentFinalText = result.finalResponse || ""; - if (judge.decision === "retry" && rateLimitFeedbackNeedsOriginalRequirementOnly(task, result)) { - const reason = judge.reason || "任务因限流/传输中断,原始需求尚未完成。"; + if (result.terminalStatus === "interrupted" && explicitUserInterrupt(task, result)) { return { ...judge, + decision: "fail", + confidence: Math.max(judge.confidence, 0.9), + reason: "Codex turn 被用户请求打断。", + raw: { previous: judge.raw ?? null, _safetyOverride: "explicit_user_interrupt" }, + }; + } + if (rateLimitFeedbackNeedsOriginalRequirementOnly(task, result)) { + const reason = judge.reason || result.terminalError || "任务因限流/传输中断,原始需求尚未完成。"; + return { + ...judge, + decision: "retry", + confidence: Math.max(judge.confidence, 0.9), reason, continuePrompt: originalRequirementOnlyFeedbackPrompt(task, reason), raw: { previous: judge.raw ?? null, _safetyOverride: "original_requirement_only_feedback" }, }; } + if (result.terminalStatus === "interrupted") return judge; + if (result.terminalStatus === "failed" || result.terminalStatus === null || result.transportClosedBeforeTerminal) { + const reason = result.terminalError + ? `当前 attempt 未完成:${result.terminalError}` + : "当前 attempt 未正常完成。"; + return { + ...judge, + decision: "retry", + confidence: Math.max(judge.confidence, 0.9), + reason, + continuePrompt: missingFinalResponseFeedbackPrompt(task, reason), + raw: { previous: judge.raw ?? null, _safetyOverride: "terminal_not_completed" }, + }; + } + if (result.finalResponse.trim().length === 0) { + const reason = "当前 attempt 没有生成新的最终 assistant response,不能复用旧 finalResponse 判定完成。"; + return { + ...judge, + decision: "retry", + confidence: Math.max(judge.confidence, 0.92), + reason, + continuePrompt: missingFinalResponseFeedbackPrompt(task, reason), + raw: { previous: judge.raw ?? null, _safetyOverride: "missing_current_final_response" }, + }; + } if (asksToConfirmConcurrentFileInsteadOfDelivery(currentFinalText)) { const reason = "最终回复停下来询问用户如何处理并发修改/无关文件,而不是自主完成自己的变更交付范围。"; return { @@ -628,7 +671,7 @@ function applyFallbackSafetyOverrides(task: QueueTask, result: CodexRunResult, j } export async function judgeTask(task: QueueTask, result: CodexRunResult): Promise { - if (config().minimaxApiKey.length === 0) return applyFallbackSafetyOverrides(task, result, fallbackJudge(result)); + if (config().minimaxApiKey.length === 0) return applyJudgeSafetyOverrides(task, result, fallbackJudge(result)); const judgePromptContent = judgePrompt(task, result); try { let lastParseError: string | null = null; @@ -654,9 +697,7 @@ export async function judgeTask(task: QueueTask, result: CodexRunResult): Promis source: "minimax", raw: { ...(parsed as Record), _parseSource: parsedResult.source, _repairAttempt: repairAttempt }, }; - // No local hard-gate validation or safety override is applied to a - // successful MiniMax result. Fallback rules are only for MiniMax failure. - return judge; + return applyJudgeSafetyOverrides(task, result, judge); } catch (error) { lastParseError = error instanceof Error ? error.message : String(error); if (repairAttempt >= config().judgeRepairAttempts) throw new Error(lastParseError); @@ -674,7 +715,7 @@ export async function judgeTask(task: QueueTask, result: CodexRunResult): Promis } catch (error) { const message = error instanceof Error ? error.message : String(error); logger("warn", "judge_failed_fallback", { taskId: task.id, error: message }); - return applyFallbackSafetyOverrides(task, result, fallbackJudge(result, message)); + return applyJudgeSafetyOverrides(task, result, fallbackJudge(result, message)); } } diff --git a/src/components/microservices/code-queue/src/provider-runtime.ts b/src/components/microservices/code-queue/src/provider-runtime.ts index fe1fb3ba..0678dc5a 100644 --- a/src/components/microservices/code-queue/src/provider-runtime.ts +++ b/src/components/microservices/code-queue/src/provider-runtime.ts @@ -1,6 +1,6 @@ // 重构前 index.ts 只读参考:commit 6a04144d3f5103014f75b637d7e6bc2f45bf007f,blob 56e590c1a6b5ca7ad128bf2c992f60e46c355a58;可用 `git show 6a04144d3f5103014f75b637d7e6bc2f45bf007f:src/components/microservices/code-queue/src/index.ts` 查看。 -import { spawnSync } from "node:child_process"; +import { spawn } from "node:child_process"; import { existsSync, readFileSync } from "node:fs"; import { resolve } from "node:path"; import { opencodeNpmPackage } from "./code-agent/common"; @@ -124,27 +124,66 @@ function buildDevContainerPlan(providerId: string, body: Record }; } -function runCodeQueueSsh(providerId: string, script: string, timeoutMs: number, name: string): DevContainerCommandLog { +function appendLimited(buffer: string, chunk: Buffer | string, maxBytes: number): { value: string; truncated: boolean } { + const text = typeof chunk === "string" ? chunk : chunk.toString("utf8"); + if (buffer.length >= maxBytes) return { value: buffer, truncated: true }; + const remaining = maxBytes - buffer.length; + if (text.length <= remaining) return { value: buffer + text, truncated: false }; + return { value: buffer + text.slice(0, remaining), truncated: true }; +} + +function runCodeQueueSsh(providerId: string, script: string, timeoutMs: number, name: string): Promise { const started = Date.now(); - const result = spawnSync("bun", ["scripts/cli.ts", "ssh", providerId, "bash -s"], { - cwd: ctx().config.defaultWorkdir, - input: script, - encoding: "utf8", - timeout: timeoutMs, - maxBuffer: 8 * 1024 * 1024, + const maxBuffer = 8 * 1024 * 1024; + return new Promise((resolveLog) => { + let stdout = ""; + let stderr = ""; + let truncated = false; + let timedOut = false; + let spawnError: Error | null = null; + const child = spawn("bun", ["scripts/cli.ts", "ssh", providerId, "bash -s"], { + cwd: ctx().config.defaultWorkdir, + stdio: ["pipe", "pipe", "pipe"], + }); + const timer = setTimeout(() => { + timedOut = true; + child.kill("SIGTERM"); + setTimeout(() => child.kill("SIGKILL"), 2_000).unref?.(); + }, timeoutMs); + timer.unref?.(); + child.stdout.on("data", (chunk: Buffer) => { + const next = appendLimited(stdout, chunk, maxBuffer); + stdout = next.value; + truncated ||= next.truncated; + }); + child.stderr.on("data", (chunk: Buffer) => { + const next = appendLimited(stderr, chunk, maxBuffer); + stderr = next.value; + truncated ||= next.truncated; + }); + child.on("error", (error) => { + spawnError = error; + }); + child.stdin.on("error", () => undefined); + child.on("close", (code, signal) => { + clearTimeout(timer); + const errorParts: string[] = []; + if (stderr.length > 0) errorParts.push(stderr); + if (timedOut) errorParts.push(`Error: command timed out after ${timeoutMs}ms`); + if (spawnError !== null) errorParts.push(`${spawnError.name}: ${spawnError.message}`); + if (truncated) errorParts.push(`output truncated at ${maxBuffer} bytes`); + resolveLog({ + name, + providerId, + exitCode: timedOut && code === 0 ? null : code, + signal: signal as NodeJS.Signals | null, + durationMs: Date.now() - started, + stdout, + stderr: errorParts.join("\n").trim(), + }); + }); + child.stdin.end(script); }); - const stdout = typeof result.stdout === "string" ? result.stdout : String(result.stdout ?? ""); - const stderr = typeof result.stderr === "string" ? result.stderr : String(result.stderr ?? ""); - const errorText = result.error === undefined ? "" : `${result.error.name}: ${result.error.message}`; - return { - name, - providerId, - exitCode: result.status, - signal: result.signal, - durationMs: Date.now() - started, - stdout, - stderr: errorText.length > 0 ? `${stderr}\n${errorText}`.trim() : stderr, - }; } function throwIfCommandFailed(command: DevContainerCommandLog): void { @@ -246,6 +285,8 @@ IMAGE="$REQUESTED_IMAGE" SSH_DIR="\${UNIDESK_HOST_ROOT_SSH_DIR:-$HOME/.ssh}" SSH_MOUNT_ARGS=() if [ -d "$SSH_DIR" ]; then SSH_MOUNT_ARGS=(-v "$SSH_DIR":/root/.ssh:ro); fi +HOST_PATH_MOUNT_ARGS=() +if [ -d /mnt ]; then HOST_PATH_MOUNT_ARGS+=(-v /mnt:/mnt); fi if ! docker image inspect "$IMAGE" >/dev/null 2>&1 && docker image inspect "$CODEX_IMAGE" >/dev/null 2>&1; then IMAGE="$CODEX_IMAGE" fi @@ -295,6 +336,7 @@ cid=$(docker run -d \\ -v "$KEY_DIR/codex-home":${shellQuote(plan.remoteCodexHome)} \\ -v "$KEY_DIR/opencode-xdg":${shellQuote(plan.remoteOpencodeXdgDir)} \\ "\${SSH_MOUNT_ARGS[@]}" \\ + "\${HOST_PATH_MOUNT_ARGS[@]}" \\ -v "$WORKDIR":"$CONTAINER_WORKDIR" \\ -v "$WORKDIR":/root/unidesk \\ -w "$CONTAINER_WORKDIR" \\ @@ -341,14 +383,45 @@ KNOWN_HOSTS=/tmp/unidesk-dev-proxy-known_hosts cp /run/unidesk-dev-proxy/known_hosts "$KNOWN_HOSTS" chmod 600 "$KNOWN_HOSTS" DEFAULT_LINE=$(ip route show default | head -1) -ORIG_GW=$(printf '%s\\n' "$DEFAULT_LINE" | sed -n 's/^default via \\([^ ]*\\) dev \\([^ ]*\\).*/\\1/p') -ORIG_DEV=$(printf '%s\\n' "$DEFAULT_LINE" | sed -n 's/^default via \\([^ ]*\\) dev \\([^ ]*\\).*/\\2/p') -if [ -z "$ORIG_GW" ] || [ -z "$ORIG_DEV" ]; then echo "cannot parse default route: $DEFAULT_LINE" >&2; exit 1; fi +DEFAULT_GW=$(printf '%s\\n' "$DEFAULT_LINE" | sed -n 's/^default via \\([^ ]*\\) dev \\([^ ]*\\).*/\\1/p') +DEFAULT_DEV=$(printf '%s\\n' "$DEFAULT_LINE" | sed -n 's/^default via \\([^ ]*\\) dev \\([^ ]*\\).*/\\2/p') +LINK_ROUTE=$(ip route show | awk '$2=="dev" && $3 !~ /^tun/ { print; exit }') +ORIG_DEV=$(printf '%s\\n' "$LINK_ROUTE" | awk '{print $3}') +if [ -n "$DEFAULT_GW" ] && [ -n "$DEFAULT_DEV" ] && [ "$DEFAULT_DEV" != "$TUN" ]; then + ORIG_GW="$DEFAULT_GW" + ORIG_DEV="$DEFAULT_DEV" +else + ORIG_IP=$(ip addr show "$ORIG_DEV" | sed -n 's/.*inet \\([0-9.]*\\)\\/.*/\\1/p' | head -1) + ORIG_GW=$(printf '%s\\n' "$ORIG_IP" | awk -F. 'NF==4 { printf "%s.%s.%s.1", $1, $2, $3 }') +fi +if [ -z "$ORIG_GW" ] || [ -z "$ORIG_DEV" ]; then echo "cannot detect docker bridge route: default=$DEFAULT_LINE link=$LINK_ROUTE" >&2; exit 1; fi ( ping -c 1 -W 3 google.com >/tmp/direct-ping.log 2>&1 && echo direct_ping=unexpected_ok ) || echo direct_ping=failed_expected +if command -v pkill >/dev/null 2>&1; then + pkill -f "ssh .* -w $TUN_ID:$TUN_ID .*$MASTER" >/dev/null 2>&1 || true +elif command -v busybox >/dev/null 2>&1; then + busybox ps | while read -r pid user command args; do + case "$command $args" in + *"ssh -f -N -w $TUN_ID:$TUN_ID"*|*"ssh -N -w $TUN_ID:$TUN_ID"*) kill "$pid" >/dev/null 2>&1 || true ;; + esac + done +fi +ip link delete "$TUN" >/dev/null 2>&1 || true ip route replace $MASTER/32 via "$ORIG_GW" dev "$ORIG_DEV" -if command -v pkill >/dev/null 2>&1; then pkill -f "ssh .* -w $TUN_ID:$TUN_ID .*$MASTER" >/dev/null 2>&1 || true; fi -ssh -f -N -w $TUN_ID:$TUN_ID -o Tunnel=point-to-point -o ExitOnForwardFailure=yes -o ServerAliveInterval=15 -o ServerAliveCountMax=2 -o StrictHostKeyChecking=yes -o UserKnownHostsFile="$KNOWN_HOSTS" -i /run/unidesk-dev-proxy/id_ed25519 root@$MASTER -for i in 1 2 3 4 5; do ip link show "$TUN" >/dev/null 2>&1 && break; sleep 1; done +ip route replace default via "$ORIG_GW" dev "$ORIG_DEV" +SSH_LOG=/tmp/unidesk-dev-proxy-ssh.log +rm -f "$SSH_LOG" +if ! ssh -f -N -w $TUN_ID:$TUN_ID -o Tunnel=point-to-point -o ExitOnForwardFailure=yes -o ServerAliveInterval=15 -o ServerAliveCountMax=2 -o StrictHostKeyChecking=yes -o UserKnownHostsFile="$KNOWN_HOSTS" -i /run/unidesk-dev-proxy/id_ed25519 root@$MASTER 2>"$SSH_LOG"; then + cat "$SSH_LOG" >&2 2>/dev/null || true + exit 1 +fi +for i in 1 2 3 4 5 6 7 8 9 10; do ip link show "$TUN" >/dev/null 2>&1 && break; sleep 1; done +if ! ip link show "$TUN" >/dev/null 2>&1; then + echo "ssh tunnel did not create $TUN via $ORIG_GW/$ORIG_DEV" >&2 + cat "$SSH_LOG" >&2 2>/dev/null || true + if command -v busybox >/dev/null 2>&1; then busybox ps >&2 || true; fi + ip route show >&2 || true + exit 1 +fi ip addr replace $CLIENT_IP peer $SERVER_IP dev "$TUN" ip link set "$TUN" up ip route replace default via $SERVER_IP dev "$TUN" diff --git a/src/components/microservices/code-queue/src/queue-api.ts b/src/components/microservices/code-queue/src/queue-api.ts index 274f2c6a..57130282 100644 --- a/src/components/microservices/code-queue/src/queue-api.ts +++ b/src/components/microservices/code-queue/src/queue-api.ts @@ -5,7 +5,7 @@ import { codeAgentPortForModel, codeAgentPortInfo, codeModelPorts as codeModelPo import { claudeQqNotificationOutboxStats, notificationTargetConfigured, notificationTargetLabel } from "./notifications"; import { executionProviderOptions } from "./provider-runtime"; import { taskFullOutput } from "./task-output"; -import { buildCompactTaskTranscript, buildTaskTranscript, cachedPreviewTranscript, fullTranscript, prefixPreview, safePreview, statsDaysFromUrl, taskForCompactMetaResponse, taskForMetaResponse, taskLlmStepCount, taskStatisticsSummary, taskTiming, timestampMs } from "./task-view"; +import { buildCompactTaskTranscript, buildTaskTranscript, cachedPreviewTranscript, fullTranscript, prefixPreview, safePreview, statsDaysFromUrl, taskForCompactMetaResponse, taskForMetaResponse, taskListStepCount, taskStatisticsSummary, taskTiming, timestampMs } from "./task-view"; import { userPromptForDisplay } from "./prompts"; import type { ActiveRun, ActiveRunSlotWaiter } from "./code-agent/common"; import type { JsonValue, QueueRecord, QueuedStatusReason, QueueTask, RuntimeConfig, TaskStatus, TranscriptLine } from "./types"; @@ -143,7 +143,7 @@ function outputChunkResponse(task: QueueTask, url: URL): Response { function taskForListResponse(task: QueueTask, lite = false, queueTasks?: QueueTask[]): JsonValue { const timing = taskTiming(task); const displayPrompt = task.basePrompt || userPromptForDisplay(task.prompt); - const stepCount = taskLlmStepCount(task); + const stepCount = taskListStepCount(task); if (lite) { return { id: task.id, diff --git a/src/components/microservices/code-queue/src/self-tests.ts b/src/components/microservices/code-queue/src/self-tests.ts index 94fe8207..faa8a837 100644 --- a/src/components/microservices/code-queue/src/self-tests.ts +++ b/src/components/microservices/code-queue/src/self-tests.ts @@ -1,6 +1,7 @@ // 重构前 index.ts 只读参考:commit 6a04144d3f5103014f75b637d7e6bc2f45bf007f,blob 56e590c1a6b5ca7ad128bf2c992f60e46c355a58;可用 `git show 6a04144d3f5103014f75b637d7e6bc2f45bf007f:src/components/microservices/code-queue/src/index.ts` 查看。 import { minimaxM27Model } from "./code-agent/common"; +import { openCodeTransportClosedBeforeTerminal, remoteOpenCodeRunCommandForTest } from "./code-agent/opencode"; import { continuePromptSourceBudgetChars, miniMaxJudgeMessages, parsedContinuePromptForJudge, parseJudgeJson, queueRecoveryRetryPrompt, retryPrompt } from "./judge"; import { codeQueueEnvironmentHintTitle, injectCodeQueueEnvironmentHint, promptWithCodeQueueEnvironmentHint, userPromptForDisplay } from "./prompts"; import { buildTaskTranscript, safePreview, transcriptLineSummaryLines } from "./task-view"; @@ -201,12 +202,19 @@ function runQueueOrderingSelfTest(): JsonValue { const queuedBehindRunning = queueOrderTestTask("codex_4101_queued", "queued", "2026-05-11T10:01:00.000Z", "2026-05-11T10:01:00.000Z"); const terminalAhead = queueOrderTestTask("codex_4200_done", "succeeded", "2026-05-11T11:00:00.000Z", "2026-05-11T11:00:00.000Z"); const queuedAfterTerminal = queueOrderTestTask("codex_4201_queued", "queued", "2026-05-11T11:01:00.000Z", "2026-05-11T11:01:00.000Z"); + const mergeTargetEarly = queueOrderTestTask("codex_4300_target_early", "queued", "2026-05-11T12:00:00.000Z", "2026-05-11T12:00:00.000Z"); + const mergeSourceMiddle = queueOrderTestTask("codex_4301_source_middle", "queued", "2026-05-11T12:01:00.000Z", "2026-05-11T12:01:00.000Z"); + const mergeTargetLate = queueOrderTestTask("codex_4302_target_late", "queued", "2026-05-11T12:02:00.000Z", "2026-05-11T12:02:00.000Z"); + mergeTargetEarly.queueId = "queue_merge_target"; + mergeSourceMiddle.queueId = "queue_merge_target"; + mergeTargetLate.queueId = "queue_merge_target"; const originalMaxActiveQueues = ctx().config.maxActiveQueues; assertReferenceTest(ctx().queueHeadTask("queue_order_test", blockedByRetry)?.id === activeRetry.id, "retry_wait head must keep blocking a moved older-created task"); assertReferenceTest(ctx().nextRunnableTaskFrom("queue_order_test", blockedByRetry)?.id === activeRetry.id, "next runnable should be the retry_wait head"); assertReferenceTest(ctx().nextRunnableTaskFrom("queue_order_test", [queuedBehindRunning, runningHead]) === null, "running head must block queued tasks behind it"); assertReferenceTest(ctx().nextRunnableTaskFrom("queue_order_test", [queuedAfterTerminal, terminalAhead])?.id === queuedAfterTerminal.id, "terminal head should not block later queued task"); + assertReferenceTest(ctx().queueHeadTask("queue_merge_target", [mergeTargetLate, mergeSourceMiddle, mergeTargetEarly])?.id === mergeTargetEarly.id, "merged queue should keep the earliest queueEnteredAt task first"); assertReferenceTest(ctx().queuedStatusReason(queuedBehindRunning, [runningHead, queuedBehindRunning])?.label === "PREV TASK", "queued task behind an active same-queue task should expose PREV TASK reason"); assertReferenceTest(ctx().availableQueueStartSlotsFor(8, 0) === Number.POSITIVE_INFINITY, "maxActiveQueues=0 should leave queue-to-queue concurrency unbounded"); assertReferenceTest(ctx().availableQueueStartSlotsFor(0, 1) === 1, "empty active run slots should leave one slot available"); @@ -245,6 +253,7 @@ function runQueueOrderingSelfTest(): JsonValue { { name: "retry_wait_head_blocks_moved_older_created_task", ok: true, head: activeRetry.id, moved: movedOlderCreated.id }, { name: "running_head_blocks_later_queued_task", ok: true }, { name: "terminal_task_does_not_block_queue", ok: true }, + { name: "queue_merge_preserves_chronological_task_order", ok: true }, { name: "queued_reason_prev_task", ok: true }, { name: "max_active_queues_zero_is_unbounded", ok: true }, { name: "idle_processing_queue_does_not_consume_active_run_slot", ok: true }, @@ -335,6 +344,16 @@ function runTracePortSelfTest(): JsonValue { assertReferenceTest(String(edited.bodyPreview || "").includes("+const after = true;"), "opencode edit should use metadata diff for line diff display"); assertReferenceTest(!transcript.some((line) => line.status === "opencode/step-start" || line.status === "opencode/step-finish"), "opencode step boundaries should stay out of trace"); assertReferenceTest(!transcript.some((line) => String(line.bodyPreview || "").includes("hidden reasoning")), "reasoning-only opencode assistant text should not duplicate reasoning"); + const remoteTask = testTask("codex_5001_remote_opencode", "remote command prompt", "", [], "2026-05-12T00:01:00.000Z"); + remoteTask.providerId = "D601"; + remoteTask.cwd = "/home/ubuntu"; + remoteTask.model = minimaxM27Model; + const remoteCommand = remoteOpenCodeRunCommandForTest(remoteTask, "hello 'world'"); + assertReferenceTest(remoteCommand.includes("exec opencode"), "remote opencode command must exec the opencode binary, not the run subcommand"); + assertReferenceTest(!remoteCommand.includes("exec 'run'") && !remoteCommand.includes("exec run --format"), "remote opencode command must not regress to exec run"); + assertReferenceTest(!openCodeTransportClosedBeforeTerminal(true, true, false), "exit=0 plus current final response must be terminal even without step_finish"); + assertReferenceTest(openCodeTransportClosedBeforeTerminal(true, false, false), "exit=0 without final response and step_finish is not a completed turn"); + assertReferenceTest(openCodeTransportClosedBeforeTerminal(false, true, true), "non-zero exit remains a transport failure even with partial text"); return { ok: true, cases: [ @@ -345,6 +364,10 @@ function runTracePortSelfTest(): JsonValue { { name: "step_boundaries_filtered", ok: true }, { name: "reasoning_duplicate_filtered", ok: true }, { name: "duration_preserved", ok: true, durationMs: explored?.durationMs ?? null }, + { name: "remote_opencode_exec_includes_binary", ok: true }, + { name: "opencode_exit0_final_without_step_finish_is_terminal", ok: true }, + { name: "opencode_exit0_without_final_or_step_finish_is_transport_closed", ok: true }, + { name: "opencode_nonzero_exit_is_transport_closed", ok: true }, ], transcript: transcript.filter((line) => line.seq >= 2).map((line) => ({ seq: line.seq, diff --git a/src/components/microservices/code-queue/src/task-output.ts b/src/components/microservices/code-queue/src/task-output.ts index 140d01bd..8aaa2c6d 100644 --- a/src/components/microservices/code-queue/src/task-output.ts +++ b/src/components/microservices/code-queue/src/task-output.ts @@ -11,10 +11,12 @@ export interface TaskOutputContext { logger: (level: "debug" | "info" | "warn" | "error", message: string, data?: JsonValue) => void; markTaskDirty: (taskId: string) => void; nowIso: () => string; + onOutputAppended?: (task: QueueTask, output: LiveOutput, op: ArchivedLiveOutput["op"]) => void; schedulePersistState: () => void; } const outputArchiveSeededTasks = new Set(); +const archivedOutputCache = new Map(); let context: TaskOutputContext | null = null; export function configureTaskOutput(runtimeContext: TaskOutputContext): void { @@ -56,6 +58,7 @@ function ensureTaskOutputArchiveSeeded(task: QueueTask): void { function appendOutputArchive(task: QueueTask, output: LiveOutput, op: ArchivedLiveOutput["op"], text: string): void { try { + archivedOutputCache.delete(task.id); mkdirSync(ctx().config.outputArchiveDir, { recursive: true }); appendFileSync(taskOutputArchivePath(task.id), serializeArchivedOutput(output, op, text), "utf8"); } catch (error) { @@ -84,6 +87,9 @@ function archiveRecordToOutput(value: unknown): ArchivedLiveOutput | null { function archivedTaskOutput(task: QueueTask): LiveOutput[] { const path = taskOutputArchivePath(task.id); if (!existsSync(path)) return []; + const signature = outputArchiveSignature(task); + const cached = archivedOutputCache.get(task.id); + if (cached?.signature === signature) return cached.output; const bySeq = new Map(); try { const text = readFileSync(path, "utf8"); @@ -107,7 +113,13 @@ function archivedTaskOutput(task: QueueTask): LiveOutput[] { ctx().logger("warn", "codex_output_archive_read_failed", { taskId: task.id, error: ctx().errorToJson(error) }); return []; } - return Array.from(bySeq.values()).sort((left, right) => Number(left.seq) - Number(right.seq)); + const output = Array.from(bySeq.values()).sort((left, right) => Number(left.seq) - Number(right.seq)); + archivedOutputCache.set(task.id, { signature, output }); + while (archivedOutputCache.size > 80) { + const firstKey = archivedOutputCache.keys().next().value; + if (typeof firstKey === "string") archivedOutputCache.delete(firstKey); + } + return output; } function taskFullOutput(task: QueueTask): LiveOutput[] { @@ -151,6 +163,7 @@ function appendOutput(task: QueueTask, channel: OutputChannel, text: string, met task.updatedAt = ctx().nowIso(); ctx().markTaskDirty(task.id); ctx().schedulePersistState(); + ctx().onOutputAppended?.(task, output, archiveOp); return output; } diff --git a/src/components/microservices/code-queue/src/task-view.ts b/src/components/microservices/code-queue/src/task-view.ts index 35e55c02..519274a1 100644 --- a/src/components/microservices/code-queue/src/task-view.ts +++ b/src/components/microservices/code-queue/src/task-view.ts @@ -1206,15 +1206,53 @@ function fullTranscript(task: QueueTask): TranscriptLine[] { return cachedFullTranscript(task); } +function nonNegativeInteger(value: unknown): number | null { + const parsed = Number(value); + return Number.isFinite(parsed) && parsed >= 0 ? Math.floor(parsed) : null; +} + +function retainedOutputStartsTraceStep(output: LiveOutput): boolean { + if (output.channel === "diff" || output.channel === "tool") return true; + if (output.channel !== "command") return false; + const method = String(output.method || ""); + return method === "item/started" || (method !== "item/commandExecution/outputDelta" && method !== "item/completed"); +} + +function retainedTaskStepCount(task: QueueTask): number { + return (Array.isArray(task.output) ? task.output : []).reduce((count, output) => count + (retainedOutputStartsTraceStep(output) ? 1 : 0), 0); +} + +function taskStoredStepCount(task: QueueTask): number | null { + return nonNegativeInteger(task.stepCount) ?? nonNegativeInteger(task.llmStepCount); +} + +// Used by overview/list responses and SSE patches. It must stay archive-free; +// trace/detail endpoints compute exact counts from the full transcript on demand. +function taskListStepCount(task: QueueTask): number { + return taskStoredStepCount(task) ?? retainedTaskStepCount(task); +} + +function taskOutputMaxSeq(task: QueueTask): number { + const output = Array.isArray(task.output) ? task.output : []; + const promptHistory = Array.isArray(task.promptHistory) ? task.promptHistory : []; + const attempts = Array.isArray(task.attempts) ? task.attempts : []; + const values = [ + nonNegativeInteger(task.outputMaxSeq), + nonNegativeInteger(output.at(-1)?.seq), + nonNegativeInteger(promptHistory.at(-1)?.seq), + ...attempts.map((attempt) => nonNegativeInteger(attempt.outputEndSeq)), + ].filter((value): value is number => value !== null); + return values.length > 0 ? Math.max(...values) : 0; +} + function taskLlmStepCount(task: QueueTask): number { - return taskStepCountFromTranscript(task, cachedPreviewTranscript(task)); + return taskStoredStepCount(task) ?? taskStepCountFromTranscript(task, cachedPreviewTranscript(task)); } function taskForMetaResponse(task: QueueTask): JsonValue { - const fullOutput = taskFullOutput(task); - const lastOutputSeq = fullOutput.at(-1)?.seq ?? 0; + const lastOutputSeq = taskOutputMaxSeq(task); const displayPrompt = task.basePrompt || userPromptForDisplay(task.prompt); - const stepCount = taskLlmStepCount(task); + const stepCount = taskListStepCount(task); return { id: task.id, queueId: ctx().queueIdOf(task), @@ -1260,7 +1298,7 @@ function taskForMetaResponse(task: QueueTask): JsonValue { cancelRequested: task.cancelRequested, terminalUnread: terminalTaskUnread(task), nextMode: task.nextMode, - outputCount: fullOutput.length, + outputCount: task.output.length, retainedOutputCount: task.output.length, eventCount: task.events.length, transcriptCount: null, @@ -1274,8 +1312,8 @@ function taskForMetaResponse(task: QueueTask): JsonValue { function taskForCompactMetaResponse(task: QueueTask): JsonValue { const displayPrompt = task.basePrompt || userPromptForDisplay(task.prompt); - const lastOutputSeq = task.output.at(-1)?.seq ?? 0; - const stepCount = taskLlmStepCount(task); + const lastOutputSeq = taskOutputMaxSeq(task); + const stepCount = taskListStepCount(task); return { id: task.id, queueId: ctx().queueIdOf(task), @@ -2093,7 +2131,9 @@ export { setAttemptInputPrompt, statsDaysFromUrl, taskExecutionSummary, + taskListStepCount, taskLlmStepCount, + taskOutputMaxSeq, taskForCompactMetaResponse, taskForMetaResponse, taskForResponse, diff --git a/src/components/microservices/code-queue/src/types.ts b/src/components/microservices/code-queue/src/types.ts index 49f95e49..f287c0a4 100644 --- a/src/components/microservices/code-queue/src/types.ts +++ b/src/components/microservices/code-queue/src/types.ts @@ -261,6 +261,9 @@ export interface QueueTask { codexThreadId: string | null; activeTurnId: string | null; finalResponse: string; + stepCount?: number; + llmStepCount?: number; + outputMaxSeq?: number; lastError: string | null; lastJudge: JudgeResult | null; judgeFailCount: number;