feat: add deepseek-harness workbench plugin and console diagnosis API

- console: GET /api/workflows/{id}, /runs/{run_id}, /runs/{run_id}/diagnosis
  (journal trace + sanitized bounded log tails, workflow/run pairing enforced)
- workbench/: dsh 宿主插件(7 个工作流工具、中文系统提示词、失败监控器、
  本机回环桥接服务)+ 侧边栏面板客户端包(sidebar.footer.action 与
  shell.overlay 追加插槽)+ 降级独立面板 + 一键启动脚本
- adapters/browser: 收敛 looks_like_login_url 到共享层,修复
  jd_main_image_collector 对 gyxx_flow.accounts 的越层导入
- tests: 新端点覆盖;replay_policy 断言对齐已迁移的 catalog(repeatable)
This commit is contained in:
wangyunlong committed 2026-09-04 11:10:16 +08:00
1 parent b124d757b0
commit 01218b2907
26 files changed
+4347 -8

No files matched your search

+566
View File
@@ -0,0 +1,566 @@
window.__ModuleLoader__.load({ id: "@gyxx/dsh-plugin-gyxx-workbench", factory: (require) => {
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
// client/src/index.jsx
var index_exports = {};
__export(index_exports, {
apply: () => apply,
inject: () => inject
});
module.exports = __toCommonJS(index_exports);
var import_react4 = require("react");
// client/src/Panel.jsx
var import_react = require("react");
// client/src/store.js
var listeners = /* @__PURE__ */ new Set();
var state = {
open: false,
loading: false,
error: null,
generatedAt: null,
summary: null,
workflows: [],
selectedId: null,
detail: null,
detailLoading: false,
runs: [],
diagnosis: null,
diagnosisLoading: false,
question: "",
businessDate: defaultBusinessDate(),
alerts: [],
seenAlertIds: {},
toasts: []
};
function defaultBusinessDate() {
const now = /* @__PURE__ */ new Date();
now.setDate(now.getDate() - 1);
const pad = (value) => String(value).padStart(2, "0");
return `${now.getFullYear()}-${pad(now.getMonth() + 1)}-${pad(now.getDate())}`;
}
function getState() {
return state;
}
function update(patch) {
state = { ...state, ...patch };
for (const listener of listeners) listener();
}
function subscribe(listener) {
listeners.add(listener);
return () => listeners.delete(listener);
}
function pushToast(toast) {
const id = `t-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 6)}`;
update({ toasts: [...state.toasts, { id, ...toast }] });
return id;
}
function dismissToast(id) {
update({ toasts: state.toasts.filter((toast) => toast.id !== id) });
}
// client/src/api.js
function bridgeBase() {
if (typeof window !== "undefined") {
if (window.__GYXX_WB_BRIDGE__) return window.__GYXX_WB_BRIDGE__;
try {
const saved = window.localStorage?.getItem("gyxx.wb.bridge");
if (saved) return saved;
} catch {
}
}
return "http://127.0.0.1:8790";
}
async function request(method, path, body) {
const response = await fetch(`${bridgeBase()}${path}`, {
method,
headers: {
accept: "application/json",
...body !== void 0 ? { "content-type": "application/json", "x-gyxx-workbench": "1" } : {}
},
body: body === void 0 ? void 0 : JSON.stringify(body)
});
let payload;
try {
payload = await response.json();
} catch {
payload = { ok: false, error: `\u6865\u63A5\u670D\u52A1\u8FD4\u56DE\u4E86\u975E JSON \u5185\u5BB9\uFF08HTTP ${response.status}\uFF09` };
}
if (!response.ok) {
throw new Error(payload?.error ?? `\u6865\u63A5\u670D\u52A1\u9519\u8BEF\uFF08HTTP ${response.status}\uFF09`);
}
return payload;
}
var api = {
listWorkflows: () => request("GET", "/bridge/workflows"),
workflowDetail: (workflowId) => request("GET", `/bridge/workflows/${encodeURIComponent(workflowId)}`),
workflowRuns: (workflowId, limit = 6) => request("GET", `/bridge/workflows/${encodeURIComponent(workflowId)}/runs?limit=${limit}`),
diagnosis: (workflowId, runId) => request(
"GET",
`/bridge/workflows/${encodeURIComponent(workflowId)}/diagnosis${runId ? `?run_id=${encodeURIComponent(runId)}` : ""}`
),
alerts: () => request("GET", "/bridge/alerts"),
markAlertSeen: (id) => request("POST", "/bridge/alerts/seen", { id }),
trigger: (payload) => request("POST", "/bridge/trigger", payload),
cancel: (payload) => request("POST", "/bridge/cancel", payload),
ask: (payload) => request("POST", "/bridge/ask", payload)
};
// client/src/Panel.jsx
var import_jsx_runtime = require("react/jsx-runtime");
function useWorkbench() {
return (0, import_react.useSyncExternalStore)(subscribe, getState);
}
var STATUS_LABELS = {
success: "\u6210\u529F",
failed: "\u5931\u8D25",
running: "\u8FD0\u884C\u4E2D",
cancelled: "\u5DF2\u505C\u6B62",
none: "\u672A\u8FD0\u884C"
};
function statusOf(workflow) {
if (workflow.active_run) return "running";
return workflow.last_run?.status ?? "none";
}
function formatTime(value) {
if (!value) return "\u2014";
const date = new Date(value);
if (Number.isNaN(date.getTime())) return String(value);
const pad = (n) => String(n).padStart(2, "0");
return `${pad(date.getMonth() + 1)}-${pad(date.getDate())} ${pad(date.getHours())}:${pad(date.getMinutes())}`;
}
function formatDuration(seconds) {
if (seconds == null) return "";
if (seconds < 60) return `${seconds}s`;
return `${Math.floor(seconds / 60)}m${seconds % 60 ? `${seconds % 60}s` : ""}`;
}
async function refreshWorkflows() {
update({ loading: true, error: null });
try {
const payload = await api.listWorkflows();
update({
loading: false,
workflows: payload.workflows ?? [],
summary: payload.summary ?? null,
generatedAt: payload.generated_at ?? null
});
} catch (error) {
update({ loading: false, error: error.message });
}
}
async function selectWorkflow(workflowId) {
update({ selectedId: workflowId, detailLoading: true, diagnosis: null, runs: [] });
try {
const [detail, runs] = await Promise.all([
api.workflowDetail(workflowId).catch(() => null),
api.workflowRuns(workflowId, 6).catch(() => ({ runs: [] }))
]);
update({ detailLoading: false, detail, runs: runs.runs ?? [] });
} catch (error) {
update({ detailLoading: false, error: error.message });
}
}
async function loadDiagnosis(workflowId, runId) {
update({ diagnosisLoading: true });
try {
const payload = await api.diagnosis(workflowId, runId);
update({ diagnosisLoading: false, diagnosis: payload });
} catch (error) {
update({ diagnosisLoading: false });
pushToast({ kind: "error", text: `\u8BCA\u65AD\u6570\u636E\u52A0\u8F7D\u5931\u8D25\uFF1A${error.message}` });
}
}
async function doAsk(action) {
const s = getState();
if (!s.selectedId) return;
const question = s.question.trim();
try {
const payload = await api.ask({
workflow_id: s.selectedId,
action,
question
});
const label = { ask: "\u63D0\u95EE", diagnose: "\u8BCA\u65AD", repair: "\u4FEE\u590D" }[action] ?? "\u4F1A\u8BDD";
pushToast({
kind: "ok",
text: `\u5DF2\u521B\u5EFA${label}\u4F1A\u8BDD\uFF08${String(payload.session_id).slice(0, 18)}\u2026\uFF09\uFF0C\u8BF7\u5728\u5DE6\u4FA7\u4F1A\u8BDD\u5217\u8868\u4E2D\u67E5\u770B`
});
update({ question: "" });
} catch (error) {
pushToast({ kind: "error", text: `\u521B\u5EFA\u4F1A\u8BDD\u5931\u8D25\uFF1A${error.message}` });
}
}
async function doTrigger(execute) {
const s = getState();
if (!s.selectedId) return;
if (execute) {
const ok = window.confirm(
`\u6B63\u5F0F\u6267\u884C ${s.selectedId}\uFF08\u4E1A\u52A1\u65E5\u671F ${s.businessDate}\uFF09\u4F1A\u5BF9\u5916\u90E8\u7CFB\u7EDF\u4EA7\u751F\u771F\u5B9E\u5199\u5165\u3002\u786E\u8BA4\u7EE7\u7EED\uFF1F`
);
if (!ok) return;
}
try {
await api.trigger({
workflow_id: s.selectedId,
business_date: s.businessDate,
execute,
confirmed: execute
});
pushToast({ kind: "ok", text: execute ? "\u5DF2\u53D1\u8D77\u6B63\u5F0F\u6267\u884C" : "\u5DF2\u53D1\u8D77\u8BD5\u8FD0\u884C\uFF08\u65E0\u5916\u90E8\u526F\u4F5C\u7528\uFF09" });
setTimeout(refreshWorkflows, 1500);
} catch (error) {
pushToast({ kind: "error", text: `\u542F\u52A8\u5931\u8D25\uFF1A${error.message}` });
}
}
async function doCancel() {
const s = getState();
const active = s.detail?.workflow?.active_run;
if (!s.selectedId) return;
try {
if (active?.operation_id) {
await api.cancel({ workflow_id: s.selectedId, operation_id: active.operation_id });
} else {
await api.cancel({ workflow_id: s.selectedId, scheduled: true });
}
pushToast({ kind: "ok", text: "\u5DF2\u53D1\u9001\u505C\u6B62\u6307\u4EE4" });
setTimeout(refreshWorkflows, 1500);
} catch (error) {
pushToast({ kind: "error", text: `\u505C\u6B62\u5931\u8D25\uFF1A${error.message}` });
}
}
function SummaryPills({ summary, workflows }) {
const failed = workflows.filter((w) => statusOf(w) === "failed").length;
const running = workflows.filter((w) => w.active_run).length;
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "gyxxwb-pills", children: [
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { className: "gyxxwb-pill", children: [
"\u5171 ",
summary?.total ?? workflows.length
] }),
running > 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { className: "gyxxwb-pill gyxxwb-pill-running", children: [
"\u8FD0\u884C\u4E2D ",
running
] }),
failed > 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { className: "gyxxwb-pill gyxxwb-pill-failed", children: [
"\u5931\u8D25 ",
failed
] })
] });
}
function WorkflowRow({ workflow, selected, onSelect }) {
const status = statusOf(workflow);
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
"button",
{
type: "button",
className: `gyxxwb-row ${selected ? "gyxxwb-row-selected" : ""}`,
onClick: () => onSelect(workflow.id),
children: [
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: `gyxxwb-dot gyxxwb-dot-${status}` }),
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { className: "gyxxwb-row-main", children: [
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "gyxxwb-row-name", children: workflow.name }),
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "gyxxwb-row-id", children: workflow.id })
] }),
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "gyxxwb-row-meta", children: workflow.last_run ? formatTime(workflow.last_run.ended_at ?? workflow.last_run.started_at) : "\u2014" })
]
}
);
}
function RunList({ runs, onDiagnose }) {
if (!runs.length) return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "gyxxwb-empty", children: "\u6682\u65E0\u8FD0\u884C\u8BB0\u5F55" });
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "gyxxwb-runs", children: runs.map((run) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
"button",
{
type: "button",
className: "gyxxwb-run",
onClick: () => onDiagnose(run.run_id),
title: "\u70B9\u51FB\u67E5\u770B\u8BCA\u65AD\u8BE6\u60C5",
children: [
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: `gyxxwb-dot gyxxwb-dot-${run.status}` }),
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: run.business_date }),
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "gyxxwb-run-mode", children: run.mode === "execute" ? "\u6B63\u5F0F" : "\u8BD5\u8FD0\u884C" }),
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: formatDuration(run.duration_seconds) }),
run.error && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "gyxxwb-run-error", children: run.error.slice(0, 60) })
]
},
run.run_id
)) });
}
function DiagnosisView({ diagnosis, loading }) {
if (loading) return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "gyxxwb-empty", children: "\u6B63\u5728\u52A0\u8F7D\u8BCA\u65AD\u6570\u636E\u2026" });
if (!diagnosis) return null;
if (diagnosis.message) return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "gyxxwb-empty", children: diagnosis.message });
const run = diagnosis.run ?? {};
const steps = Array.isArray(run.steps) ? run.steps : [];
const logs = Array.isArray(diagnosis.logs) ? diagnosis.logs : [];
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "gyxxwb-diagnosis", children: [
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "gyxxwb-diagnosis-head", children: [
"\u8BCA\u65AD\uFF1A",
run.run_id,
"\uFF08",
run.status,
"\uFF09"
] }),
steps.filter((step) => step.status === "failed").map((step) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "gyxxwb-step-fail", children: [
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "gyxxwb-step-id", children: [
"\u2717 ",
step.id,
"\uFF08\u9000\u51FA\u7801 ",
step.exit_code ?? "\u2014",
"\uFF09"
] }),
step.error && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("pre", { className: "gyxxwb-pre", children: step.error })
] }, step.id)),
logs.map((log) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "gyxxwb-log", children: [
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "gyxxwb-log-path", children: log.path }),
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("pre", { className: "gyxxwb-pre", children: log.tail })
] }, log.path)),
!steps.some((s) => s.status === "failed") && !logs.length && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "gyxxwb-empty", children: "\u8BE5\u8FD0\u884C\u6CA1\u6709\u5931\u8D25\u6B65\u9AA4\u6216\u65E5\u5FD7" })
] });
}
function WorkflowPanel() {
const s = useWorkbench();
(0, import_react.useEffect)(() => {
if (!s.open) return void 0;
refreshWorkflows();
const timer = setInterval(refreshWorkflows, 1e4);
return () => clearInterval(timer);
}, [s.open]);
const onSelect = (0, import_react.useCallback)((workflowId) => {
selectWorkflow(workflowId);
}, []);
const groups = [];
const byModule = /* @__PURE__ */ new Map();
for (const workflow of s.workflows) {
const key = workflow.module_label ?? workflow.module;
if (!byModule.has(key)) byModule.set(key, []);
byModule.get(key).push(workflow);
}
for (const [label, items] of byModule) groups.push({ label, items });
const selected = s.workflows.find((w) => w.id === s.selectedId) ?? null;
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: `gyxxwb-panel ${s.open ? "gyxxwb-panel-open" : ""}`, children: [
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "gyxxwb-panel-head", children: [
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "gyxxwb-title", children: "GYXX \u5DE5\u4F5C\u6D41" }),
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(SummaryPills, { summary: s.summary, workflows: s.workflows }),
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { type: "button", className: "gyxxwb-icon-btn", title: "\u5237\u65B0", onClick: refreshWorkflows, children: "\u27F3" }),
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
"button",
{
type: "button",
className: "gyxxwb-icon-btn",
title: "\u5173\u95ED",
onClick: () => update({ open: false }),
children: "\u2715"
}
)
] }),
s.error && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "gyxxwb-error", children: [
"\u65E0\u6CD5\u8FDE\u63A5\u5DE5\u4F5C\u53F0\u6865\u63A5\u670D\u52A1\uFF1A",
s.error,
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("br", {}),
"\u8BF7\u786E\u8BA4 dsh \u5DF2\u901A\u8FC7 workbench/cordis.yml \u542F\u52A8\u3002"
] }),
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "gyxxwb-panel-body", children: [
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "gyxxwb-list", children: [
groups.map((group) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "gyxxwb-group", children: [
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "gyxxwb-group-label", children: group.label }),
group.items.map((workflow) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
WorkflowRow,
{
workflow,
selected: workflow.id === s.selectedId,
onSelect
},
workflow.id
))
] }, group.label)),
!s.loading && !s.workflows.length && !s.error && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "gyxxwb-empty", children: "\u672A\u53D1\u73B0\u5DE5\u4F5C\u6D41" })
] }),
selected && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "gyxxwb-detail", children: [
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "gyxxwb-detail-title", children: [
selected.name,
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: `gyxxwb-status gyxxwb-status-${statusOf(selected)}`, children: STATUS_LABELS[statusOf(selected)] })
] }),
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "gyxxwb-detail-sub", children: [
selected.id,
" \xB7 \u8C03\u5EA6",
" ",
selected.schedule ? `${selected.schedule.enabled ? "\u542F\u7528" : "\u505C\u7528"} ${Array.isArray(selected.schedule.at) ? selected.schedule.at.join("/") : selected.schedule.at ?? ""}` : "\u65E0",
selected.next_run_at ? ` \xB7 \u4E0B\u6B21 ${formatTime(selected.next_run_at)}` : ""
] }),
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "gyxxwb-actions", children: [
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { type: "button", onClick: () => doAsk("diagnose"), children: "\u8BCA\u65AD" }),
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { type: "button", onClick: () => doAsk("repair"), children: "\u4FEE\u590D" }),
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { type: "button", onClick: () => doTrigger(false), children: "\u8BD5\u8FD0\u884C" }),
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { type: "button", className: "gyxxwb-danger", onClick: () => doTrigger(true), children: "\u6B63\u5F0F\u8FD0\u884C" }),
selected.active_run && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { type: "button", className: "gyxxwb-danger", onClick: doCancel, children: "\u505C\u6B62" })
] }),
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "gyxxwb-ask", children: [
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
"input",
{
value: s.question,
placeholder: "\u5C31\u8FD9\u4E2A\u5DE5\u4F5C\u6D41\u63D0\u95EE\uFF0C\u4F8B\u5982\uFF1A\u6628\u5929\u4E3A\u4EC0\u4E48\u5931\u8D25\uFF1F",
onChange: (event) => update({ question: event.target.value }),
onKeyDown: (event) => {
if (event.key === "Enter") doAsk("ask");
}
}
),
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { type: "button", onClick: () => doAsk("ask"), children: "\u63D0\u95EE" })
] }),
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "gyxxwb-date-row", children: [
"\u4E1A\u52A1\u65E5\u671F",
" ",
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
"input",
{
value: s.businessDate,
onChange: (event) => update({ businessDate: event.target.value }),
pattern: "\\d{4}-\\d{2}-\\d{2}"
}
)
] }),
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "gyxxwb-section-label", children: "\u6700\u8FD1\u8FD0\u884C" }),
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(RunList, { runs: s.runs, onDiagnose: (runId) => loadDiagnosis(selected.id, runId) }),
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(DiagnosisView, { diagnosis: s.diagnosis, loading: s.diagnosisLoading })
] })
] })
] });
}
// client/src/Toasts.jsx
var import_react2 = require("react");
var import_react3 = require("react");
var import_jsx_runtime2 = require("react/jsx-runtime");
function useWorkbench2() {
return (0, import_react3.useSyncExternalStore)(subscribe, getState);
}
function Toasts() {
const s = useWorkbench2();
(0, import_react2.useEffect)(() => {
let stopped = false;
let timer = null;
const poll = async () => {
try {
const payload = await api.alerts();
const fresh = (payload.alerts ?? []).filter(
(alert) => !alert.seen && !getState().seenAlertIds[alert.id]
);
if (fresh.length) {
const seen = { ...getState().seenAlertIds };
for (const alert of fresh) {
seen[alert.id] = true;
pushToast({ kind: "failed", text: `\u5DE5\u4F5C\u6D41\u300C${alert.name}\u300D\u8FD0\u884C\u5931\u8D25`, alert });
}
update({ seenAlertIds: seen });
}
} catch {
}
if (!stopped) timer = setTimeout(poll, 3e4);
};
timer = setTimeout(poll, 8e3);
return () => {
stopped = true;
if (timer) clearTimeout(timer);
};
}, []);
if (!s.toasts.length) return null;
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "gyxxwb-toasts", children: s.toasts.map((toast) => /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: `gyxxwb-toast gyxxwb-toast-${toast.kind}`, children: [
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "gyxxwb-toast-text", children: toast.text }),
toast.alert && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
"button",
{
type: "button",
onClick: async () => {
try {
await api.ask({ workflow_id: toast.alert.workflow_id, action: "diagnose" });
await api.markAlertSeen(toast.alert.id).catch(() => {
});
pushToast({ kind: "ok", text: "\u5DF2\u521B\u5EFA\u8BCA\u65AD\u4F1A\u8BDD\uFF0C\u8BF7\u5728\u5DE6\u4FA7\u4F1A\u8BDD\u5217\u8868\u67E5\u770B" });
} catch (error) {
pushToast({ kind: "error", text: `\u521B\u5EFA\u4F1A\u8BDD\u5931\u8D25\uFF1A${error.message}` });
}
dismissToast(toast.id);
},
children: "\u7ACB\u5373\u8BCA\u65AD"
}
),
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("button", { type: "button", title: "\u5173\u95ED", onClick: () => dismissToast(toast.id), children: "\u2715" })
] }, toast.id)) });
}
// client/src/styles.css
var styles_default = "/* GYXX \u5DE5\u4F5C\u53F0\u9762\u677F\u6837\u5F0F \u2014\u2014 \u4EE5\u6587\u672C\u5F62\u5F0F\u5185\u8054\u8FDB\u5BA2\u6237\u7AEF\u5305\uFF0C\u8FD0\u884C\u65F6\u6CE8\u5165 <style>\u3002 */\n\n.gyxxwb-overlay {\n position: fixed;\n inset: 0;\n pointer-events: none;\n z-index: 70;\n font-family:\n -apple-system, BlinkMacSystemFont, 'Segoe UI', 'PingFang SC',\n 'Hiragino Sans GB', 'Microsoft YaHei', sans-serif;\n}\n\n.gyxxwb-panel {\n position: absolute;\n top: 0;\n bottom: 0;\n left: 264px;\n width: 380px;\n display: none;\n flex-direction: column;\n background: #ffffff;\n border-right: 1px solid #e4e4e7;\n box-shadow: 8px 0 24px rgba(0, 0, 0, 0.08);\n pointer-events: auto;\n color: #18181b;\n}\n\n.gyxxwb-panel-open {\n display: flex;\n}\n\n.gyxxwb-panel-head {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 10px 12px;\n border-bottom: 1px solid #e4e4e7;\n}\n\n.gyxxwb-title {\n font-weight: 600;\n font-size: 14px;\n}\n\n.gyxxwb-pills {\n display: flex;\n gap: 4px;\n flex: 1;\n}\n\n.gyxxwb-pill {\n font-size: 11px;\n padding: 1px 8px;\n border-radius: 999px;\n background: #f4f4f5;\n color: #52525b;\n}\n\n.gyxxwb-pill-failed {\n background: #fef2f2;\n color: #b91c1c;\n}\n\n.gyxxwb-pill-running {\n background: #eff6ff;\n color: #1d4ed8;\n}\n\n.gyxxwb-icon-btn {\n border: none;\n background: transparent;\n cursor: pointer;\n font-size: 14px;\n color: #71717a;\n padding: 4px 6px;\n border-radius: 6px;\n}\n\n.gyxxwb-icon-btn:hover {\n background: #f4f4f5;\n}\n\n.gyxxwb-error {\n margin: 10px 12px;\n padding: 10px;\n border-radius: 8px;\n background: #fef2f2;\n color: #b91c1c;\n font-size: 12px;\n line-height: 1.6;\n}\n\n.gyxxwb-panel-body {\n flex: 1;\n overflow-y: auto;\n display: flex;\n flex-direction: column;\n}\n\n.gyxxwb-group-label {\n padding: 10px 12px 4px;\n font-size: 12px;\n color: #71717a;\n}\n\n.gyxxwb-row {\n display: flex;\n align-items: center;\n gap: 8px;\n width: 100%;\n padding: 7px 12px;\n border: none;\n background: transparent;\n cursor: pointer;\n text-align: left;\n}\n\n.gyxxwb-row:hover {\n background: #f4f4f5;\n}\n\n.gyxxwb-row-selected {\n background: #eef2ff;\n}\n\n.gyxxwb-row-main {\n flex: 1;\n min-width: 0;\n display: flex;\n flex-direction: column;\n}\n\n.gyxxwb-row-name {\n font-size: 13px;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.gyxxwb-row-id {\n font-size: 11px;\n color: #a1a1aa;\n}\n\n.gyxxwb-row-meta {\n font-size: 11px;\n color: #71717a;\n}\n\n.gyxxwb-dot {\n width: 8px;\n height: 8px;\n border-radius: 50%;\n background: #d4d4d8;\n flex: none;\n}\n\n.gyxxwb-dot-success {\n background: #16a34a;\n}\n\n.gyxxwb-dot-failed {\n background: #dc2626;\n}\n\n.gyxxwb-dot-running {\n background: #2563eb;\n animation: gyxxwb-pulse 1.2s ease-in-out infinite;\n}\n\n.gyxxwb-dot-cancelled,\n.gyxxwb-dot-none {\n background: #a1a1aa;\n}\n\n@keyframes gyxxwb-pulse {\n 50% {\n opacity: 0.35;\n }\n}\n\n.gyxxwb-detail {\n border-top: 1px solid #e4e4e7;\n padding: 12px;\n background: #fafafa;\n}\n\n.gyxxwb-detail-title {\n font-size: 14px;\n font-weight: 600;\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.gyxxwb-status {\n font-size: 11px;\n padding: 1px 8px;\n border-radius: 999px;\n background: #f4f4f5;\n}\n\n.gyxxwb-status-failed {\n background: #fef2f2;\n color: #b91c1c;\n}\n\n.gyxxwb-status-running {\n background: #eff6ff;\n color: #1d4ed8;\n}\n\n.gyxxwb-status-success {\n background: #f0fdf4;\n color: #15803d;\n}\n\n.gyxxwb-detail-sub {\n font-size: 11px;\n color: #71717a;\n margin: 4px 0 10px;\n}\n\n.gyxxwb-actions {\n display: flex;\n flex-wrap: wrap;\n gap: 6px;\n}\n\n.gyxxwb-actions button,\n.gyxxwb-ask button {\n border: 1px solid #e4e4e7;\n background: #ffffff;\n border-radius: 6px;\n font-size: 12px;\n padding: 4px 10px;\n cursor: pointer;\n}\n\n.gyxxwb-actions button:hover,\n.gyxxwb-ask button:hover {\n background: #f4f4f5;\n}\n\n.gyxxwb-actions .gyxxwb-danger {\n border-color: #fecaca;\n color: #b91c1c;\n}\n\n.gyxxwb-ask {\n display: flex;\n gap: 6px;\n margin-top: 8px;\n}\n\n.gyxxwb-ask input {\n flex: 1;\n border: 1px solid #e4e4e7;\n border-radius: 6px;\n padding: 5px 8px;\n font-size: 12px;\n}\n\n.gyxxwb-date-row {\n margin-top: 8px;\n font-size: 11px;\n color: #71717a;\n display: flex;\n align-items: center;\n gap: 6px;\n}\n\n.gyxxwb-date-row input {\n border: 1px solid #e4e4e7;\n border-radius: 6px;\n padding: 3px 6px;\n font-size: 11px;\n width: 110px;\n}\n\n.gyxxwb-section-label {\n margin: 12px 0 4px;\n font-size: 12px;\n color: #71717a;\n}\n\n.gyxxwb-run {\n display: flex;\n align-items: center;\n gap: 8px;\n width: 100%;\n padding: 6px 8px;\n border: none;\n background: transparent;\n cursor: pointer;\n font-size: 12px;\n text-align: left;\n border-radius: 6px;\n}\n\n.gyxxwb-run:hover {\n background: #f4f4f5;\n}\n\n.gyxxwLine truncated
// client/src/index.jsx
var inject = ["slots"];
function useWorkbench3() {
return (0, import_react4.useSyncExternalStore)(subscribe, getState);
}
function injectStyles() {
if (typeof document === "undefined") return;
if (document.getElementById("gyxxwb-styles")) return;
const style = document.createElement("style");
style.id = "gyxxwb-styles";
style.textContent = styles_default;
document.head.appendChild(style);
}
function WorkbenchFooterAction() {
const s = useWorkbench3();
const failed = s.workflows.filter((w) => !w.active_run && w.last_run?.status === "failed").length;
const running = s.workflows.filter((w) => w.active_run).length;
const tone = failed > 0 ? "failed" : running > 0 ? "running" : "success";
return (0, import_react4.createElement)(
"button",
{
type: "button",
className: `gyxxwb-footer-btn${s.open ? " gyxxwb-footer-btn-active" : ""}`,
title: "GYXX \u5DE5\u4F5C\u6D41\u5DE5\u4F5C\u53F0",
onClick: () => {
const next = !getState().open;
update({ open: next });
if (next) refreshWorkflows();
}
},
(0, import_react4.createElement)("span", { className: `gyxxwb-dot gyxxwb-dot-${tone}` }),
(0, import_react4.createElement)("span", null, "\u5DE5\u4F5C\u6D41")
);
}
function WorkbenchOverlay() {
return (0, import_react4.createElement)(
"div",
{ className: "gyxxwb-overlay" },
(0, import_react4.createElement)(WorkflowPanel, null),
(0, import_react4.createElement)(Toasts, null)
);
}
function apply(ctx) {
injectStyles();
ctx.effect(
() => ctx.slots.register({ name: "sidebar.footer.action" }, WorkbenchFooterAction),
"gyxx-workbench: footer action"
);
ctx.effect(
() => ctx.slots.register({ name: "shell.overlay" }, WorkbenchOverlay),
"gyxx-workbench: overlay"
);
}
return module.exports; } });
//# sourceMappingURL=client.js.map
+7
View File
@@ -0,0 +1,7 @@
{
"version": 3,
"sources": ["../client/src/index.jsx", "../client/src/Panel.jsx", "../client/src/store.js", "../client/src/api.js", "../client/src/Toasts.jsx", "../client/src/styles.css"],
"sourcesContent": ["/**\n * GYXX \u5DE5\u4F5C\u53F0\u5BA2\u6237\u7AEF\u63D2\u4EF6\u5165\u53E3\u3002\n * \u7531 esbuild \u6253\u5305\u4E3A CJS \u5E76\u901A\u8FC7 window.__ModuleLoader__ \u6CE8\u518C\uFF08\u89C1 scripts/build-client.mjs\uFF09\u3002\n * \u8FD0\u884C\u65F6\u53EA\u4F9D\u8D56 dsh \u5E73\u53F0\u5171\u4EAB\u6A21\u5757\u8868\u4E2D\u7684 react\u3002\n */\n\nimport { createElement, useSyncExternalStore } from 'react'\nimport { WorkflowPanel, refreshWorkflows } from './Panel.jsx'\nimport { Toasts } from './Toasts.jsx'\nimport { getState, subscribe, update } from './store.js'\nimport stylesText from './styles.css'\n\nexport const inject = ['slots']\n\nfunction useWorkbench() {\n return useSyncExternalStore(subscribe, getState)\n}\n\nfunction injectStyles() {\n if (typeof document === 'undefined') return\n if (document.getElementById('gyxxwb-styles')) return\n const style = document.createElement('style')\n style.id = 'gyxxwb-styles'\n style.textContent = stylesText\n document.head.appendChild(style)\n}\n\n/** \u4FA7\u8FB9\u680F\u5E95\u90E8\u52A8\u4F5C\uFF1A\u5DE5\u4F5C\u6D41\u9762\u677F\u5F00\u5173 + \u805A\u5408\u72B6\u6001\u70B9\u3002 */\nfunction WorkbenchFooterAction() {\n const s = useWorkbench()\n const failed = s.workflows.filter((w) => !w.active_run && w.last_run?.status === 'failed').length\n const running = s.workflows.filter((w) => w.active_run).length\n const tone = failed > 0 ? 'failed' : running > 0 ? 'running' : 'success'\n return createElement(\n 'button',\n {\n type: 'button',\n className: `gyxxwb-footer-btn${s.open ? ' gyxxwb-footer-btn-active' : ''}`,\n title: 'GYXX \u5DE5\u4F5C\u6D41\u5DE5\u4F5C\u53F0',\n onClick: () => {\n const next = !getState().open\n update({ open: next })\n if (next) refreshWorkflows()\n },\n },\n createElement('span', { className: `gyxxwb-dot gyxxwb-dot-${tone}` }),\n createElement('span', null, '\u5DE5\u4F5C\u6D41'),\n )\n}\n\n/** \u8986\u76D6\u5C42\u6839\uFF1A\u5DE6\u4FA7\u62BD\u5C49\u9762\u677F + \u5931\u8D25 toast\u3002 */\nfunction WorkbenchOverlay() {\n return createElement(\n 'div',\n { className: 'gyxxwb-overlay' },\n createElement(WorkflowPanel, null),\n createElement(Toasts, null),\n )\n}\n\nexport function apply(ctx) {\n injectStyles()\n ctx.effect(\n () => ctx.slots.register({ name: 'sidebar.footer.action' }, WorkbenchFooterAction),\n 'gyxx-workbench: footer action',\n )\n ctx.effect(\n () => ctx.slots.register({ name: 'shell.overlay' }, WorkbenchOverlay),\n 'gyxx-workbench: overlay',\n )\n}\n", "/** \u5DE5\u4F5C\u6D41\u9762\u677F\uFF1A\u4FA7\u8FB9\u62BD\u5C49\uFF0C\u5217\u51FA\u5168\u90E8\u5DE5\u4F5C\u6D41\uFF0C\u9009\u4E2D\u540E\u53EF\u63D0\u95EE / \u8BCA\u65AD / \u4FEE\u590D / \u542F\u505C\u3002 */\n\nimport { useSyncExternalStore, useEffect, useCallback } from 'react'\nimport { getState, subscribe, update, pushToast } from './store.js'\nimport { api } from './api.js'\n\nfunction useWorkbench() {\n return useSyncExternalStore(subscribe, getState)\n}\n\nconst STATUS_LABELS = {\n success: '\u6210\u529F',\n failed: '\u5931\u8D25',\n running: '\u8FD0\u884C\u4E2D',\n cancelled: '\u5DF2\u505C\u6B62',\n none: '\u672A\u8FD0\u884C',\n}\n\nfunction statusOf(workflow) {\n if (workflow.active_run) return 'running'\n return workflow.last_run?.status ?? 'none'\n}\n\nfunction formatTime(value) {\n if (!value) return '\u2014'\n const date = new Date(value)\n if (Number.isNaN(date.getTime())) return String(value)\n const pad = (n) => String(n).padStart(2, '0')\n return `${pad(date.getMonth() + 1)}-${pad(date.getDate())} ${pad(date.getHours())}:${pad(date.getMinutes())}`\n}\n\nfunction formatDuration(seconds) {\n if (seconds == null) return ''\n if (seconds < 60) return `${seconds}s`\n return `${Math.floor(seconds / 60)}m${seconds % 60 ? `${seconds % 60}s` : ''}`\n}\n\nexport async function refreshWorkflows() {\n update({ loading: true, error: null })\n try {\n const payload = await api.listWorkflows()\n update({\n loading: false,\n workflows: payload.workflows ?? [],\n summary: payload.summary ?? null,\n generatedAt: payload.generated_at ?? null,\n })\n } catch (error) {\n update({ loading: false, error: error.message })\n }\n}\n\nasync function selectWorkflow(workflowId) {\n update({ selectedId: workflowId, detailLoading: true, diagnosis: null, runs: [] })\n try {\n const [detail, runs] = await Promise.all([\n api.workflowDetail(workflowId).catch(() => null),\n api.workflowRuns(workflowId, 6).catch(() => ({ runs: [] })),\n ])\n update({ detailLoading: false, detail, runs: runs.runs ?? [] })\n } catch (error) {\n update({ detailLoading: false, error: error.message })\n }\n}\n\nasync function loadDiagnosis(workflowId, runId) {\n update({ diagnosisLoading: true })\n try {\n const payload = await api.diagnosis(workflowId, runId)\n update({ diagnosisLoading: false, diagnosis:Line truncated
"mappings": "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 truncated
"names": ["import_react", "import_react", "import_jsx_runtime", "useWorkbench", "useWorkbench"]
}