@ljwei-stak/dsh-model-route-bot 0.64.0 → 0.65.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.dsh-plugin/client.js +694 -407
- package/README.i18n.yaml +2 -2
- package/README.md +209 -147
- package/README.zh.md +208 -146
- package/apps/integration-client/bot-attention.mjs +2 -2
- package/apps/integration-client/panels.jsx +239 -134
- package/apps/integration-client/product.css +36 -0
- package/apps/integration-client/routing-submissions.mjs +68 -0
- package/apps/integration-client/task-progress.mjs +46 -0
- package/apps/integration-client/tasks-panel.jsx +147 -0
- package/modules/bot-runtime/read-model.mjs +2 -2
- package/package.json +6 -87
- package/packages/model-router-plugin/README.md +39 -15
- package/packages/model-router-plugin/README.zh.md +40 -16
- package/packages/model-router-plugin/package.json +1 -1
- package/packages/orchestration/src/bot-routing-candidates.mjs +6 -6
- package/packages/orchestration/src/bot-routing-service.mjs +30 -5
- package/packages/orchestration/src/bot-routing.mjs +6 -4
- package/packages/orchestration/src/product-composition.mjs +18 -24
- package/packages/orchestration/src/task-journal.mjs +23 -0
- package/packages/orchestration/src/task-product.mjs +49 -0
- package/remote-computer-agent/build.mjs +48 -13
- package/CHANGELOG.md +0 -456
- package/docs/INSTALLATION_GUIDE.zh.md +0 -150
- package/docs/MANUAL_TASK_ASSIGNMENT.zh.md +0 -46
- package/docs/ROUTING_ADAPTIVE_LEARNING.zh.md +0 -153
- package/docs/ROUTING_ALGORITHM_OPTIMIZATION.zh.md +0 -91
- package/docs/ROUTING_DERIVATION_EXPERIMENTS.zh.md +0 -684
- package/docs/ROUTING_LIVEBENCH_DATA_SEARCH.zh.md +0 -74
- package/docs/ROUTING_LIVEBENCH_VALIDATION.zh.md +0 -154
- package/docs/ROUTING_MATURITY.zh.md +0 -76
- package/docs/ROUTING_RESEARCH.zh.md +0 -59
- package/docs/ROUTING_SELFTEST_STEPS.zh.md +0 -192
- package/docs/WORKBENCH_USER_GUIDE.zh.md +0 -293
- package/docs/archive/MIGRATION.md +0 -53
- package/docs/archive/README.md +0 -21
- package/docs/assets/candidate-pruning.svg +0 -80
- package/docs/assets/desktop-official-tools-0.9.0.png +0 -0
- package/docs/assets/router-only-0.12.0.png +0 -0
- package/docs/assets/routing-workflow.svg +0 -96
- package/docs/assets/workbench-budget-reservations.png +0 -0
- package/docs/assets/workbench-run-progress.png +0 -0
- package/docs/assets/workbench-run-timeout.png +0 -0
- package/docs/assets/workbench-subscription-usage.png +0 -0
- package/docs/assets/workbench-task-preview.jpg +0 -0
- package/docs/assets/workbench-usage.svg +0 -119
- package/docs/releases/0.20.0-validation.md +0 -26
- package/docs/releases/0.22.0-validation.md +0 -28
- package/docs/releases/0.23.0-validation.md +0 -30
- package/docs/releases/0.23.1-validation.md +0 -23
- package/docs/releases/0.24.0-validation.md +0 -41
- package/docs/releases/0.25.0-validation.md +0 -41
- package/docs/releases/0.25.1-validation.md +0 -36
- package/docs/releases/0.25.2-validation.md +0 -48
- package/docs/releases/0.25.3-validation.md +0 -50
- package/docs/releases/0.25.4-validation.md +0 -41
- package/docs/releases/0.25.5-validation.md +0 -40
- package/docs/releases/0.26.0-preview.0-validation.md +0 -23
- package/docs/releases/0.26.0-preview.1-f-difference.json +0 -6845
- package/docs/releases/0.26.0-preview.1-f-difference.md +0 -85
- package/docs/releases/0.26.0-preview.1-validation.md +0 -103
- package/docs/releases/0.63.0-validation.md +0 -51
package/.dsh-plugin/client.js
CHANGED
|
@@ -38,7 +38,7 @@ __export(index_exports, {
|
|
|
38
38
|
productSlots: () => productSlots
|
|
39
39
|
});
|
|
40
40
|
module.exports = __toCommonJS(index_exports);
|
|
41
|
-
var
|
|
41
|
+
var import_react69 = __toESM(require("react"), 1);
|
|
42
42
|
|
|
43
43
|
// modules/bot-runtime/vendor/ds-bot/src/client/i18n.js
|
|
44
44
|
var NAMESPACE = "ds-bot", ZH = {
|
|
@@ -1341,8 +1341,8 @@ function hostText(message2) {
|
|
|
1341
1341
|
return message2;
|
|
1342
1342
|
}
|
|
1343
1343
|
function language() {
|
|
1344
|
-
let
|
|
1345
|
-
return typeof
|
|
1344
|
+
let active2 = service?.getLocale?.().active;
|
|
1345
|
+
return typeof active2 == "string" ? active2 : "en";
|
|
1346
1346
|
}
|
|
1347
1347
|
var dateLocale = () => language().startsWith("zh") ? "zh-CN" : "en-US";
|
|
1348
1348
|
|
|
@@ -1939,17 +1939,17 @@ function mentionTarget(event) {
|
|
|
1939
1939
|
function clock(ms2) {
|
|
1940
1940
|
return new Date(ms2).toLocaleTimeString(dateLocale(), { hour: "numeric", minute: "2-digit" });
|
|
1941
1941
|
}
|
|
1942
|
-
var midnight = (value) => new Date(value.getFullYear(), value.getMonth(), value.getDate()).getTime(), daysBefore = (
|
|
1942
|
+
var midnight = (value) => new Date(value.getFullYear(), value.getMonth(), value.getDate()).getTime(), daysBefore = (date2, now) => Math.round((midnight(new Date(now)) - midnight(date2)) / 864e5);
|
|
1943
1943
|
function dayLabel(ms2) {
|
|
1944
|
-
let
|
|
1945
|
-
return
|
|
1944
|
+
let date2 = new Date(ms2), today = /* @__PURE__ */ new Date();
|
|
1945
|
+
return date2.toDateString() === today.toDateString() ? t("Today {time}", { time: clock(ms2) }) : `${date2.toLocaleDateString(dateLocale(), { weekday: "short", month: "short", day: "numeric" })} ${clock(ms2)}`;
|
|
1946
1946
|
}
|
|
1947
1947
|
function clockLabel(time, now = Date.now()) {
|
|
1948
|
-
let
|
|
1948
|
+
let date2 = new Date(time), days = daysBefore(date2, now), stamp = clock(time);
|
|
1949
1949
|
if (days === 0) return t("Today {time}", { time: stamp });
|
|
1950
1950
|
if (days === 1) return t("Yesterday {time}", { time: stamp });
|
|
1951
|
-
let sameYear =
|
|
1952
|
-
return `${
|
|
1951
|
+
let sameYear = date2.getFullYear() === new Date(now).getFullYear();
|
|
1952
|
+
return `${date2.toLocaleDateString(dateLocale(), { weekday: "short", month: "short", day: "numeric", ...sameYear ? {} : { year: "numeric" } })} ${stamp}`;
|
|
1953
1953
|
}
|
|
1954
1954
|
function messageClock(time, now = Date.now()) {
|
|
1955
1955
|
return daysBefore(new Date(time), now) === 0 ? clock(time) : clockLabel(time, now);
|
|
@@ -5203,7 +5203,7 @@ function valueAxis(values, zero) {
|
|
|
5203
5203
|
let pad3 = (high - low) * 0.1 || Math.abs(high) * 0.1 || 1;
|
|
5204
5204
|
return niceTicks(low - pad3, high + pad3);
|
|
5205
5205
|
}
|
|
5206
|
-
function columns({ categories, series, unit, kind }, width,
|
|
5206
|
+
function columns({ categories, series, unit, kind }, width, active2, shown) {
|
|
5207
5207
|
let visible = series.filter((_2, index) => shown[index]), ticks = valueAxis(visible.flatMap((item) => item.values), kind !== "line"), lo2 = ticks[0], hi2 = ticks.at(-1), left = Math.ceil(Math.max(...ticks.map((tick) => textWidth(withUnit(tick, unit), TICK)))) + 10, top = 8, height = 220, plot = { x: left, y: top, w: Math.max(40, width - left - 4), h: height - top - 24 }, y = (value) => plot.y + plot.h - (value - lo2) / (hi2 - lo2) * plot.h, band = plot.w / categories.length, parts = [];
|
|
5208
5208
|
for (let tick of ticks)
|
|
5209
5209
|
parts.push((0, import_react11.createElement)("line", { key: `g${tick}`, className: "dv-chart-grid", x1: plot.x, x2: plot.x + plot.w, y1: y(tick), y2: y(tick) })), parts.push((0, import_react11.createElement)("text", { key: `t${tick}`, className: "dv-chart-tick", x: plot.x - 8, y: y(tick) + 3, textAnchor: "end" }, withUnit(tick, unit)));
|
|
@@ -5216,7 +5216,7 @@ function columns({ categories, series, unit, kind }, width, active, shown) {
|
|
|
5216
5216
|
categories.forEach((_2, at2) => {
|
|
5217
5217
|
visible.forEach((item, row) => {
|
|
5218
5218
|
let value = item.values[at2], x = plot.x + band * at2 + (band - group) / 2 + row * (barW + gap), top2 = Math.min(y(value), zero), tall = Math.max(1, Math.abs(y(value) - zero)), r = Math.min(4, barW / 2, tall), d = value >= 0 ? `M${x},${top2 + tall}V${top2 + r}q0,-${r} ${r},-${r}h${barW - 2 * r}q${r},0 ${r},${r}V${top2 + tall}z` : `M${x},${top2}V${top2 + tall - r}q0,${r} ${r},${r}h${barW - 2 * r}q${r},0 ${r},-${r}V${top2}z`;
|
|
5219
|
-
parts.push((0, import_react11.createElement)("path", { key: `b${at2}-${row}`, className: "dv-chart-mark", "data-dim":
|
|
5219
|
+
parts.push((0, import_react11.createElement)("path", { key: `b${at2}-${row}`, className: "dv-chart-mark", "data-dim": active2 !== null && active2 !== at2 ? "" : void 0, d, style: { fill: item.color } }));
|
|
5220
5220
|
});
|
|
5221
5221
|
});
|
|
5222
5222
|
} else {
|
|
@@ -5228,14 +5228,14 @@ function columns({ categories, series, unit, kind }, width, active, shown) {
|
|
|
5228
5228
|
parts.push((0, import_react11.createElement)("path", { key: `a${row}`, className: "dv-chart-area", d: `${line}L${xs2.at(-1)},${base}L${xs2[0]},${base}z`, style: { fill: item.color } }));
|
|
5229
5229
|
}
|
|
5230
5230
|
parts.push((0, import_react11.createElement)("path", { key: `l${row}`, className: "dv-chart-line", d: line, style: { stroke: item.color } })), item.values.forEach((value, at2) => {
|
|
5231
|
-
parts.push((0, import_react11.createElement)("circle", { key: `p${row}-${at2}`, className: "dv-chart-dot", cx: xs2[at2], cy: y(value), r:
|
|
5231
|
+
parts.push((0, import_react11.createElement)("circle", { key: `p${row}-${at2}`, className: "dv-chart-dot", cx: xs2[at2], cy: y(value), r: active2 === at2 ? 4 : 2.5, style: { fill: item.color } }));
|
|
5232
5232
|
});
|
|
5233
|
-
}),
|
|
5233
|
+
}), active2 !== null && parts.unshift((0, import_react11.createElement)("line", { key: "guide", className: "dv-chart-guide", x1: xs2[active2], x2: xs2[active2], y1: plot.y, y2: plot.y + plot.h }));
|
|
5234
5234
|
}
|
|
5235
5235
|
let hits = categories.map((_2, at2) => ({ x: plot.x + band * at2, y: plot.y, w: band, h: plot.h }));
|
|
5236
5236
|
return { parts, height, points, hits };
|
|
5237
5237
|
}
|
|
5238
|
-
function rows({ categories, series, unit }, width,
|
|
5238
|
+
function rows({ categories, series, unit }, width, active2, shown) {
|
|
5239
5239
|
let visible = series.filter((_2, index) => shown[index]), ticks = valueAxis(visible.flatMap((item) => item.values), !0), lo2 = ticks[0], hi2 = ticks.at(-1), labelW = Math.min(width * 0.38, Math.ceil(Math.max(...categories.map((label) => textWidth(label, LABEL)))) + 10), valueW = Math.ceil(Math.max(...visible.flatMap((item) => item.values).map((value) => textWidth(withUnit(value, unit), LABEL)))) + 10, barH = 14, rowH = 10 + visible.length * barH + (visible.length - 1) * 2, top = 4, height = top + rowH * categories.length + 22, plot = { x: labelW, y: top, w: Math.max(40, width - labelW - valueW), h: rowH * categories.length }, x = (value) => plot.x + (value - lo2) / (hi2 - lo2) * plot.w, parts = [];
|
|
5240
5240
|
for (let tick of ticks)
|
|
5241
5241
|
parts.push((0, import_react11.createElement)("line", { key: `g${tick}`, className: "dv-chart-grid", x1: x(tick), x2: x(tick), y1: plot.y, y2: plot.y + plot.h })), parts.push((0, import_react11.createElement)("text", { key: `t${tick}`, className: "dv-chart-tick", x: x(tick), y: height - 6, textAnchor: "middle" }, withUnit(tick, unit)));
|
|
@@ -5244,19 +5244,19 @@ function rows({ categories, series, unit }, width, active, shown) {
|
|
|
5244
5244
|
let rowY = plot.y + rowH * at2 + 5;
|
|
5245
5245
|
parts.push((0, import_react11.createElement)("text", { key: `c${at2}`, className: "dv-chart-label", x: labelW - 10, y: rowY + (rowH - 10) / 2 + 4, textAnchor: "end" }, fit(label, labelW - 12, LABEL))), visible.forEach((item, row) => {
|
|
5246
5246
|
let value = item.values[at2], by = rowY + row * (barH + 2), left = Math.min(x(value), zero), long = Math.max(1, Math.abs(x(value) - zero));
|
|
5247
|
-
parts.push((0, import_react11.createElement)("rect", { key: `b${at2}-${row}`, className: "dv-chart-mark", "data-dim":
|
|
5247
|
+
parts.push((0, import_react11.createElement)("rect", { key: `b${at2}-${row}`, className: "dv-chart-mark", "data-dim": active2 !== null && active2 !== at2 ? "" : void 0, x: left, y: by, width: long, height: barH, rx: Math.min(4, long / 2), style: { fill: item.color } })), parts.push((0, import_react11.createElement)("text", { key: `v${at2}-${row}`, className: "dv-chart-value", x: left + long + 6, y: by + barH - 3 }, withUnit(value, unit)));
|
|
5248
5248
|
}), points.push({ x: Math.max(...visible.map((item) => x(item.values[at2])), zero), y: rowY });
|
|
5249
5249
|
});
|
|
5250
5250
|
let hits = categories.map((_2, at2) => ({ x: 0, y: plot.y + rowH * at2, w: width, h: rowH }));
|
|
5251
5251
|
return { parts, height, points, hits };
|
|
5252
5252
|
}
|
|
5253
|
-
function donut({ categories, series }, width,
|
|
5253
|
+
function donut({ categories, series }, width, active2, hover) {
|
|
5254
5254
|
let values = (series[0]?.values ?? []).map((value) => Math.max(0, value)), total = values.reduce((sum, value) => sum + value, 0), size = Math.min(180, Math.max(120, width * 0.42)), r = size / 2, inner = r * 0.62, cx = r, cy = r, parts = [], points = [], angle = -Math.PI / 2;
|
|
5255
5255
|
return values.forEach((value, at2) => {
|
|
5256
5256
|
let sweep = total > 0 ? value / total * Math.PI * 2 : 0, end = angle + sweep, mid = angle + sweep / 2;
|
|
5257
5257
|
if (points.push({ x: cx + Math.cos(mid) * (r - (r - inner) / 2), y: cy + Math.sin(mid) * (r - (r - inner) / 2) }), sweep > 0) {
|
|
5258
5258
|
let large = sweep > Math.PI ? 1 : 0, full2 = sweep >= Math.PI * 2 - 1e-6, p = (radius, theta) => `${cx + Math.cos(theta) * radius},${cy + Math.sin(theta) * radius}`, d = full2 ? `M${p(r, angle)}A${r},${r} 0 1 1 ${p(r, angle + Math.PI)}A${r},${r} 0 1 1 ${p(r, angle)}M${p(inner, angle)}A${inner},${inner} 0 1 0 ${p(inner, angle + Math.PI)}A${inner},${inner} 0 1 0 ${p(inner, angle)}z` : `M${p(r, angle)}A${r},${r} 0 ${large} 1 ${p(r, end)}L${p(inner, end)}A${inner},${inner} 0 ${large} 0 ${p(inner, angle)}z`;
|
|
5259
|
-
parts.push((0, import_react11.createElement)("path", { key: `s${at2}`, className: "dv-chart-mark", "data-dim":
|
|
5259
|
+
parts.push((0, import_react11.createElement)("path", { key: `s${at2}`, className: "dv-chart-mark", "data-dim": active2 !== null && active2 !== at2 ? "" : void 0, d, fillRule: "evenodd", style: { fill: colorAt(at2) }, onPointerEnter: () => hover(at2) }));
|
|
5260
5260
|
}
|
|
5261
5261
|
angle = end;
|
|
5262
5262
|
}), { parts, height: size, size, points, total, values, categories };
|
|
@@ -5321,18 +5321,18 @@ function ChartTable({ data }) {
|
|
|
5321
5321
|
);
|
|
5322
5322
|
}
|
|
5323
5323
|
function WidgetChart({ node, lookup, registerChart, refreshCharts }) {
|
|
5324
|
-
let ui3 = useViewUi(), data = chartData(node, lookup), { kind, categories, series, unit } = data, box = (0, import_react11.useRef)(null), svg = (0, import_react11.useRef)(null), width = useWidth(box, 520), [
|
|
5324
|
+
let ui3 = useViewUi(), data = chartData(node, lookup), { kind, categories, series, unit } = data, box = (0, import_react11.useRef)(null), svg = (0, import_react11.useRef)(null), width = useWidth(box, 520), [active2, setActive] = (0, import_react11.useState)(null), [hidden, setHidden] = (0, import_react11.useState)([]), [asTable, setAsTable] = (0, import_react11.useState)(!1), [copied, setCopied] = (0, import_react11.useState)(!1), labelId = (0, import_react11.useId)(), menuKey = (0, import_react11.useId)(), table = (0, import_react11.useRef)(asTable);
|
|
5325
5325
|
table.current = asTable;
|
|
5326
5326
|
let shown = series.map((_2, index) => !hidden.includes(index)), toggle = (index) => {
|
|
5327
5327
|
hidden.includes(index) ? setHidden(hidden.filter((item) => item !== index)) : shown.filter(Boolean).length > 1 && setHidden([...hidden, index]);
|
|
5328
|
-
}, label = typeof node.caption == "string" && node.caption !== "" ? node.caption : ui3.t("Chart"), isDonut = kind === "donut", legendBeside = isDonut && width >= 360, drawn = isDonut ? donut(data, legendBeside ? width - 200 : width,
|
|
5328
|
+
}, label = typeof node.caption == "string" && node.caption !== "" ? node.caption : ui3.t("Chart"), isDonut = kind === "donut", legendBeside = isDonut && width >= 360, drawn = isDonut ? donut(data, legendBeside ? width - 200 : width, active2, setActive) : kind === "hbar" ? rows(data, width, active2, shown) : columns(data, width, active2, shown), svgWidth = isDonut ? drawn.size : width, move = (event) => {
|
|
5329
5329
|
let keys = { ArrowRight: 1, ArrowDown: 1, ArrowLeft: -1, ArrowUp: -1 };
|
|
5330
5330
|
if (event.key === "Escape") {
|
|
5331
5331
|
setActive(null);
|
|
5332
5332
|
return;
|
|
5333
5333
|
}
|
|
5334
5334
|
keys[event.key] !== void 0 && (event.preventDefault(), setActive((current) => current === null ? 0 : (current + keys[event.key] + categories.length) % categories.length));
|
|
5335
|
-
}, point =
|
|
5335
|
+
}, point = active2 === null ? null : drawn.points[active2], share = (at2) => unit === "%" ? withUnit(drawn.values[at2], unit) : `${withUnit(drawn.values[at2], unit)} · ${drawn.total > 0 ? Math.round(drawn.values[at2] / drawn.total * 100) : 0}%`, tipRows = active2 === null || isDonut ? [] : series.filter((_2, index) => shown[index]).map((item) => ({ color: item.color, name: item.name, value: withUnit(item.values[active2], unit) })), copy2 = () => {
|
|
5336
5336
|
navigator.clipboard?.writeText(chartCsv(data, ui3.t)).then(() => {
|
|
5337
5337
|
setCopied(!0), setTimeout(() => setCopied(!1), 1200);
|
|
5338
5338
|
});
|
|
@@ -5357,7 +5357,7 @@ function WidgetChart({ node, lookup, registerChart, refreshCharts }) {
|
|
|
5357
5357
|
{
|
|
5358
5358
|
key: at2,
|
|
5359
5359
|
className: "dv-chart-key",
|
|
5360
|
-
"data-dim":
|
|
5360
|
+
"data-dim": active2 !== null && active2 !== at2 ? "" : void 0,
|
|
5361
5361
|
onPointerEnter: () => setActive(at2),
|
|
5362
5362
|
onPointerLeave: () => setActive(null)
|
|
5363
5363
|
},
|
|
@@ -5389,17 +5389,17 @@ function WidgetChart({ node, lookup, registerChart, refreshCharts }) {
|
|
|
5389
5389
|
onPointerLeave: () => setActive(null)
|
|
5390
5390
|
},
|
|
5391
5391
|
drawn.parts,
|
|
5392
|
-
isDonut ?
|
|
5392
|
+
isDonut ? active2 === null ? (0, import_react11.createElement)("text", { className: "dv-chart-center", x: svgWidth / 2, y: drawn.height / 2 + 5, textAnchor: "middle" }, unit === "%" ? "" : withUnit(drawn.total, unit)) : (0, import_react11.createElement)(
|
|
5393
5393
|
import_react11.Fragment,
|
|
5394
5394
|
null,
|
|
5395
|
-
(0, import_react11.createElement)("text", { className: "dv-chart-center-name", x: svgWidth / 2, y: drawn.height / 2 - 4, textAnchor: "middle" }, fit(categories[
|
|
5396
|
-
(0, import_react11.createElement)("text", { className: "dv-chart-center", x: svgWidth / 2, y: drawn.height / 2 + 14, textAnchor: "middle" }, share(
|
|
5395
|
+
(0, import_react11.createElement)("text", { className: "dv-chart-center-name", x: svgWidth / 2, y: drawn.height / 2 - 4, textAnchor: "middle" }, fit(categories[active2], drawn.size * 0.56, LABEL)),
|
|
5396
|
+
(0, import_react11.createElement)("text", { className: "dv-chart-center", x: svgWidth / 2, y: drawn.height / 2 + 14, textAnchor: "middle" }, share(active2))
|
|
5397
5397
|
) : drawn.hits.map((hit, at2) => (0, import_react11.createElement)("rect", { key: `h${at2}`, className: "dv-chart-hit", x: hit.x, y: hit.y, width: hit.w, height: hit.h, onPointerEnter: () => setActive(at2) }))
|
|
5398
5398
|
),
|
|
5399
5399
|
point && !asTable && !isDonut ? (0, import_react11.createElement)(
|
|
5400
5400
|
"div",
|
|
5401
5401
|
{ className: "dv-chart-tip", role: "status", style: { left: point.x, top: point.y } },
|
|
5402
|
-
(0, import_react11.createElement)("b", null, categories[
|
|
5402
|
+
(0, import_react11.createElement)("b", null, categories[active2]),
|
|
5403
5403
|
tipRows.map((row, index) => (0, import_react11.createElement)("span", { key: index }, (0, import_react11.createElement)("i", { style: { background: row.color } }), row.name ? `${row.name} ` : "", row.value))
|
|
5404
5404
|
) : null
|
|
5405
5405
|
), body = asTable ? (0, import_react11.createElement)(ChartTable, { data }) : isDonut ? (0, import_react11.createElement)("div", { className: legendBeside ? "dv-chart-donut dv-chart-donut-beside" : "dv-chart-donut", onPointerLeave: () => setActive(null) }, plot, legend) : (0, import_react11.createElement)(import_react11.Fragment, null, legend, plot);
|
|
@@ -6437,7 +6437,7 @@ function SecretDock({ sessionId, useRoster, useCards, useHeldCards, actions }) {
|
|
|
6437
6437
|
return waiting.length === 0 ? null : (0, import_react16.createElement)("div", { className: "bt-q-dock bt-secret-dock" }, waiting.map((request) => (0, import_react16.createElement)(SecretCard, { key: JSON.stringify([sessionId, request.id, request.kind]), sessionId, bot, request, roster, actions })));
|
|
6438
6438
|
}
|
|
6439
6439
|
function ScopeEditor({ secret, roster, onSave }) {
|
|
6440
|
-
let [mode, setMode] = (0, import_react16.useState)(secret.scope === "all" ? "all" : "some"), [picked, setPicked] = (0, import_react16.useState)(secret.scope === "all" ? [] : secret.scope), toggle = (id2) => setPicked((list) => list.includes(id2) ? list.filter((item) => item !== id2) : [...list, id2]),
|
|
6440
|
+
let [mode, setMode] = (0, import_react16.useState)(secret.scope === "all" ? "all" : "some"), [picked, setPicked] = (0, import_react16.useState)(secret.scope === "all" ? [] : secret.scope), toggle = (id2) => setPicked((list) => list.includes(id2) ? list.filter((item) => item !== id2) : [...list, id2]), same2 = mode === "all" ? secret.scope === "all" : secret.scope !== "all" && [...picked].sort().join() === [...secret.scope].sort().join();
|
|
6441
6441
|
return (0, import_react16.createElement)(
|
|
6442
6442
|
"div",
|
|
6443
6443
|
{ className: "bt-secret-edit-block" },
|
|
@@ -6462,12 +6462,12 @@ function ScopeEditor({ secret, roster, onSave }) {
|
|
|
6462
6462
|
(0, import_react16.createElement)(
|
|
6463
6463
|
"div",
|
|
6464
6464
|
{ className: "bt-secret-row-actions" },
|
|
6465
|
-
(0, import_react16.createElement)("button", { type: "button", className: "bt-soft bt-soft-sm", disabled:
|
|
6465
|
+
(0, import_react16.createElement)("button", { type: "button", className: "bt-soft bt-soft-sm", disabled: same2, onClick: () => onSave(mode === "all" ? "all" : picked) }, t("Save access"))
|
|
6466
6466
|
)
|
|
6467
6467
|
);
|
|
6468
6468
|
}
|
|
6469
6469
|
function PurposeEditor({ secret, onSave }) {
|
|
6470
|
-
let [purpose, setPurpose] = (0, import_react16.useState)(secret.purpose ?? ""),
|
|
6470
|
+
let [purpose, setPurpose] = (0, import_react16.useState)(secret.purpose ?? ""), same2 = purpose.trim() === (secret.purpose ?? "");
|
|
6471
6471
|
return (0, import_react16.createElement)(
|
|
6472
6472
|
"div",
|
|
6473
6473
|
{ className: "bt-secret-edit-block" },
|
|
@@ -6476,7 +6476,7 @@ function PurposeEditor({ secret, onSave }) {
|
|
|
6476
6476
|
"div",
|
|
6477
6477
|
{ className: "bt-secret-inline" },
|
|
6478
6478
|
(0, import_react16.createElement)("input", { className: "bt-input", "aria-label": t("What it is for"), placeholder: t("What it is for"), value: purpose, spellCheck: !1, autoComplete: "off", onChange: (event) => setPurpose(event.target.value) }),
|
|
6479
|
-
(0, import_react16.createElement)("button", { type: "button", className: "bt-soft bt-soft-sm", disabled:
|
|
6479
|
+
(0, import_react16.createElement)("button", { type: "button", className: "bt-soft bt-soft-sm", disabled: same2, onClick: () => onSave(purpose.trim()) }, t("Save"))
|
|
6480
6480
|
)
|
|
6481
6481
|
);
|
|
6482
6482
|
}
|
|
@@ -7950,10 +7950,10 @@ function findHost() {
|
|
|
7950
7950
|
let node = document.querySelector("[data-chat-flow] [data-chat-running]") ?? document.querySelector("[data-chat-flow]");
|
|
7951
7951
|
return node === null && !mountMissed && (mountMissed = !0, noteClientError("activity row", new Error("[data-chat-flow] not found"))), node;
|
|
7952
7952
|
}
|
|
7953
|
-
function useRunningHost(
|
|
7953
|
+
function useRunningHost(active2) {
|
|
7954
7954
|
let [host, setHost] = (0, import_react20.useState)(null);
|
|
7955
7955
|
return (0, import_react20.useEffect)(() => {
|
|
7956
|
-
if (!
|
|
7956
|
+
if (!active2) {
|
|
7957
7957
|
setHost(null);
|
|
7958
7958
|
return;
|
|
7959
7959
|
}
|
|
@@ -7968,7 +7968,7 @@ function useRunningHost(active) {
|
|
|
7968
7968
|
return observer.observe(document.querySelector("[data-conversation-scroll]") ?? document.body, { childList: !0, subtree: !0 }), find(), () => {
|
|
7969
7969
|
cancelAnimationFrame(frame), observer.disconnect();
|
|
7970
7970
|
};
|
|
7971
|
-
}, [
|
|
7971
|
+
}, [active2]), host;
|
|
7972
7972
|
}
|
|
7973
7973
|
function useRowEntrances(replacing) {
|
|
7974
7974
|
let check = (0, import_react20.useRef)(replacing);
|
|
@@ -8213,10 +8213,10 @@ function installFrameWatch(frame) {
|
|
|
8213
8213
|
}
|
|
8214
8214
|
|
|
8215
8215
|
// modules/bot-runtime/vendor/ds-bot/src/client/sidebar.js
|
|
8216
|
-
function useMarkedUnread(id2,
|
|
8216
|
+
function useMarkedUnread(id2, active2, marked, actions) {
|
|
8217
8217
|
(0, import_react21.useEffect)(() => {
|
|
8218
|
-
|
|
8219
|
-
}, [
|
|
8218
|
+
active2 && marked && actions.clearUnread(id2);
|
|
8219
|
+
}, [active2, marked]);
|
|
8220
8220
|
}
|
|
8221
8221
|
var PinMark = () => (0, import_react21.createElement)("span", { className: "bt-pin", "aria-hidden": !0 }, (0, import_react21.createElement)(PinMarkIcon)), nameIfCut = (event) => {
|
|
8222
8222
|
let row = event.currentTarget, name = row.querySelector(".bt-row-title");
|
|
@@ -8226,10 +8226,10 @@ var PinMark = () => (0, import_react21.createElement)("span", { className: "bt-p
|
|
|
8226
8226
|
return names.length === 0 ? "" : t("Waiting for {names}", { names: names.join(t(" and ")) });
|
|
8227
8227
|
};
|
|
8228
8228
|
function BotRow({ bot, roster, actions, useSessions, useSessionStatus, useSessionRetainInfo, useActivity, useWork, wide, marked }) {
|
|
8229
|
-
let id2 = bot.id, part = currentPart(bot), preview = useSessions((list) => previewOf(list, part, roster.exchangeTurns[part])), running = useSessionStatus((map) => map.get(part)?.running === !0),
|
|
8230
|
-
useMarkedUnread(id2,
|
|
8229
|
+
let id2 = bot.id, part = currentPart(bot), preview = useSessions((list) => previewOf(list, part, roster.exchangeTurns[part])), running = useSessionStatus((map) => map.get(part)?.running === !0), active2 = useSessionRetainInfo(part, (info) => (info?.retainedBy?.mainView ?? 0) > 0), unread = useSessionStatus((map) => map.get(part)?.completionUnread === !0 || map.get(part)?.pendingInteraction !== void 0) || marked && !active2;
|
|
8230
|
+
useMarkedUnread(id2, active2, marked, actions);
|
|
8231
8231
|
let main = isMainOf(roster, id2), tile = roster.mainBotId === id2, approval = useApproval(useWork, (entry) => entry.botId === id2), alert = roster.questions?.[part] !== void 0 || approval, doing = useActivity((map) => map[id2]), groups = workKeys(useGroupWork(useWork, (rooms) => Object.entries(rooms).flatMap(([roomId, entries2]) => entries2.filter((entry) => entry.botId === id2).map((entry) => ({ id: roomId, ...doingOf(entry) }))))), away = !running && groups.length > 0, state = botState(running || away, doing, alert), runningLine = running && doing ? doingLine(doing) : null, awayLine = away ? workLine(roster.roomsById[groups[0].id]?.name ?? t("a group chat"), groups[0], groups.length - 1) : null, waits = workKeys(useWork ? useWork((work) => JSON.stringify(work.waiting?.[id2] ?? null)) : "null"), waitsFor = state === "waiting" ? waitingFor(roster, waits) : "";
|
|
8232
|
-
if (bot.hidden && !
|
|
8232
|
+
if (bot.hidden && !active2 && !main) return null;
|
|
8233
8233
|
let onContextMenu = (event) => {
|
|
8234
8234
|
event.preventDefault(), actions.openMenu({ kind: "bot", id: id2, x: event.clientX, y: event.clientY });
|
|
8235
8235
|
}, pinned = bot.pinned === !0 && !tile, label = [bot.name, main ? t("Main Bot") : "", pinned ? t("Pinned") : "", running || away ? t("Working") : "", waitsFor, approval ? t("Waiting for your approval") : alert ? t("Waiting for your answer") : "", unread ? t("Unread activity") : ""].filter(Boolean).join(", ");
|
|
@@ -8239,7 +8239,7 @@ function BotRow({ bot, roster, actions, useSessions, useSessionStatus, useSessio
|
|
|
8239
8239
|
type: "button",
|
|
8240
8240
|
className: "bt-tile",
|
|
8241
8241
|
"aria-label": label,
|
|
8242
|
-
"aria-current":
|
|
8242
|
+
"aria-current": active2 ? "page" : void 0,
|
|
8243
8243
|
"data-bot-id": id2,
|
|
8244
8244
|
title: preview || bot.name,
|
|
8245
8245
|
onClick: () => actions.openSession(id2),
|
|
@@ -8254,7 +8254,7 @@ function BotRow({ bot, roster, actions, useSessions, useSessionStatus, useSessio
|
|
|
8254
8254
|
type: "button",
|
|
8255
8255
|
className: "bt-row",
|
|
8256
8256
|
"aria-label": label,
|
|
8257
|
-
"aria-current":
|
|
8257
|
+
"aria-current": active2 ? "page" : void 0,
|
|
8258
8258
|
"data-bot-id": id2,
|
|
8259
8259
|
title: wide ? void 0 : bot.name,
|
|
8260
8260
|
onMouseEnter: wide ? nameIfCut : void 0,
|
|
@@ -8269,14 +8269,14 @@ function BotRow({ bot, roster, actions, useSessions, useSessionStatus, useSessio
|
|
|
8269
8269
|
(0, import_react21.createElement)("span", { className: "bt-row-name" }, (0, import_react21.createElement)("span", { className: "bt-row-title" }, bot.name), pinned ? (0, import_react21.createElement)(PinMark) : null),
|
|
8270
8270
|
runningLine ? (0, import_react21.createElement)("span", { className: "bt-row-preview" }, runningLine) : awayLine ? (0, import_react21.createElement)("span", { className: "bt-row-preview" }, awayLine) : waitsFor ? (0, import_react21.createElement)("span", { className: "bt-row-preview" }, waitsFor) : preview ? (0, import_react21.createElement)("span", { className: "bt-row-preview" }, preview) : null
|
|
8271
8271
|
) : null,
|
|
8272
|
-
wide && unread && !
|
|
8272
|
+
wide && unread && !active2 ? (0, import_react21.createElement)("span", { className: "bt-unread", "aria-hidden": !0 }) : !wide && !active2 && (alert || unread) ? (0, import_react21.createElement)("span", { className: `bt-dot${alert ? " bt-dot-wait" : ""}`, "aria-hidden": !0 }) : null
|
|
8273
8273
|
);
|
|
8274
8274
|
}
|
|
8275
8275
|
function RoomRow({ room: room2, roster, actions, useSessions, useSessionStatus, useSessionRetainInfo, useWork, wide, marked }) {
|
|
8276
|
-
let id2 = room2.id, sessionId = room2.sessionId ?? id2, fallback = useSessions((list) => previewOf(list, sessionId)), preview = room2.preview?.replace(/\s+/g, " ").trim() || fallback,
|
|
8277
|
-
useMarkedUnread(id2,
|
|
8276
|
+
let id2 = room2.id, sessionId = room2.sessionId ?? id2, fallback = useSessions((list) => previewOf(list, sessionId)), preview = room2.preview?.replace(/\s+/g, " ").trim() || fallback, active2 = useSessionRetainInfo(sessionId, (info) => (info?.retainedBy?.mainView ?? 0) > 0), unread = useSessionStatus((map) => map.get(sessionId)?.completionUnread === !0) || marked && !active2;
|
|
8277
|
+
useMarkedUnread(id2, active2, marked, actions);
|
|
8278
8278
|
let approval = useApproval(useWork, (entry) => entry.roomId === id2), members = workKeys(useGroupWork(useWork, (rooms) => (rooms[id2] ?? []).filter((entry) => entry.botId !== void 0).map((entry) => ({ id: entry.botId, ...doingOf(entry) })))), first = roster.byId[members[0]?.id], workingLine = first ? workLine(first.name, members[0], members.length - 1) : null;
|
|
8279
|
-
if (room2.hidden && !
|
|
8279
|
+
if (room2.hidden && !active2) return null;
|
|
8280
8280
|
let pinned = room2.pinned === !0, label = [room2.name, pinned ? t("Pinned") : "", members.length > 0 ? t("Working") : "", approval ? t("Waiting for your approval") : ""].filter(Boolean).join(", ");
|
|
8281
8281
|
return (0, import_react21.createElement)(
|
|
8282
8282
|
"button",
|
|
@@ -8284,7 +8284,7 @@ function RoomRow({ room: room2, roster, actions, useSessions, useSessionStatus,
|
|
|
8284
8284
|
type: "button",
|
|
8285
8285
|
className: "bt-row",
|
|
8286
8286
|
"aria-label": label,
|
|
8287
|
-
"aria-current":
|
|
8287
|
+
"aria-current": active2 ? "page" : void 0,
|
|
8288
8288
|
"data-room-id": id2,
|
|
8289
8289
|
title: wide ? void 0 : room2.name,
|
|
8290
8290
|
onMouseEnter: wide ? nameIfCut : void 0,
|
|
@@ -8301,7 +8301,7 @@ function RoomRow({ room: room2, roster, actions, useSessions, useSessionStatus,
|
|
|
8301
8301
|
(0, import_react21.createElement)("span", { className: "bt-row-name" }, (0, import_react21.createElement)("span", { className: "bt-row-title" }, room2.name), pinned ? (0, import_react21.createElement)(PinMark) : null),
|
|
8302
8302
|
workingLine ? (0, import_react21.createElement)("span", { className: "bt-row-preview" }, workingLine) : preview ? (0, import_react21.createElement)("span", { className: "bt-row-preview" }, preview) : null
|
|
8303
8303
|
) : null,
|
|
8304
|
-
wide && approval && !
|
|
8304
|
+
wide && approval && !active2 ? (0, import_react21.createElement)("span", { className: "bt-unread bt-unread-wait", "aria-hidden": !0 }) : wide && unread && !active2 ? (0, import_react21.createElement)("span", { className: "bt-unread", "aria-hidden": !0 }) : !wide && !active2 && (approval || unread) ? (0, import_react21.createElement)("span", { className: `bt-dot${approval ? " bt-dot-wait" : ""}`, "aria-hidden": !0 }) : null
|
|
8305
8305
|
);
|
|
8306
8306
|
}
|
|
8307
8307
|
function AgentSessionRow({ session, agent, actions, renaming, index }) {
|
|
@@ -8373,9 +8373,9 @@ function AgentRow({ agent, actions, useSessions, useSessionStatus, useUi, wide,
|
|
|
8373
8373
|
running: statuses[session.id]?.running ?? session.running,
|
|
8374
8374
|
unread: statuses[session.id]?.unread ?? !1,
|
|
8375
8375
|
title: session.title === "" ? t("New session") : session.title
|
|
8376
|
-
})), renaming = useUi((value) => value.renameAgent),
|
|
8377
|
-
useMarkedUnread(agent.id,
|
|
8378
|
-
let preview = sessions[0]?.title ?? t("New session"), label = ["DSH Agent", running ? t("Working") : "", unread ? t("Unread activity") : ""].filter(Boolean).join(", "), open =
|
|
8376
|
+
})), renaming = useUi((value) => value.renameAgent), active2 = sessions.some((session) => session.active), running = sessions.some((session) => session.running), unread = sessions.some((session) => session.unread) || marked && !active2;
|
|
8377
|
+
useMarkedUnread(agent.id, active2, marked, actions);
|
|
8378
|
+
let preview = sessions[0]?.title ?? t("New session"), label = ["DSH Agent", running ? t("Working") : "", unread ? t("Unread activity") : ""].filter(Boolean).join(", "), open = active2 && wide;
|
|
8379
8379
|
return (0, import_react21.createElement)(
|
|
8380
8380
|
"div",
|
|
8381
8381
|
{ className: "bt-agent" },
|
|
@@ -8385,7 +8385,7 @@ function AgentRow({ agent, actions, useSessions, useSessionStatus, useUi, wide,
|
|
|
8385
8385
|
type: "button",
|
|
8386
8386
|
className: "bt-row",
|
|
8387
8387
|
"aria-label": label,
|
|
8388
|
-
"aria-current":
|
|
8388
|
+
"aria-current": active2 ? "page" : void 0,
|
|
8389
8389
|
"data-agent-id": agent.id,
|
|
8390
8390
|
title: wide ? void 0 : "DSH Agent",
|
|
8391
8391
|
onClick: () => actions.openAgent(agent.id),
|
|
@@ -8400,7 +8400,7 @@ function AgentRow({ agent, actions, useSessions, useSessionStatus, useUi, wide,
|
|
|
8400
8400
|
(0, import_react21.createElement)("span", { className: "bt-row-name" }, "DSH Agent"),
|
|
8401
8401
|
preview ? (0, import_react21.createElement)("span", { className: "bt-row-preview" }, preview) : null
|
|
8402
8402
|
) : null,
|
|
8403
|
-
wide && unread && !
|
|
8403
|
+
wide && unread && !active2 ? (0, import_react21.createElement)("span", { className: "bt-unread", "aria-hidden": !0 }) : !wide && unread && !active2 ? (0, import_react21.createElement)("span", { className: "bt-dot", "aria-hidden": !0 }) : null
|
|
8404
8404
|
),
|
|
8405
8405
|
(0, import_react21.createElement)(
|
|
8406
8406
|
"div",
|
|
@@ -9380,7 +9380,7 @@ function ComposerPlus({ sessionId, inputActions, useInput, useRoster, actions })
|
|
|
9380
9380
|
setOpen(null), fileInput()?.click();
|
|
9381
9381
|
}, schedule = () => {
|
|
9382
9382
|
setOpen(null), actions.openSettings("schedules", target);
|
|
9383
|
-
},
|
|
9383
|
+
}, reference2 = () => {
|
|
9384
9384
|
setOpen(null), actions.referenceChat(sessionId, inputActions?.captureInsertion?.());
|
|
9385
9385
|
}, canReference = typeof inputActions?.captureInsertion == "function" && actions.canReferenceChat(), room2 = roster.roomsById?.[sessionId], goal = () => {
|
|
9386
9386
|
setOpen(null), actions.composeGoal(room2.id);
|
|
@@ -9410,7 +9410,7 @@ function ComposerPlus({ sessionId, inputActions, useInput, useRoster, actions })
|
|
|
9410
9410
|
"data-leaving": leaving || void 0
|
|
9411
9411
|
},
|
|
9412
9412
|
shown.files ? (0, import_react23.createElement)("button", { type: "button", role: "menuitem", onClick: attach }, (0, import_react23.createElement)(PaperclipIcon), (0, import_react23.createElement)("span", { className: "bt-menu-label" }, t("Add files"))) : null,
|
|
9413
|
-
canReference ? (0, import_react23.createElement)("button", { type: "button", role: "menuitem", onMouseDown: keepComposerFocus, onClick:
|
|
9413
|
+
canReference ? (0, import_react23.createElement)("button", { type: "button", role: "menuitem", onMouseDown: keepComposerFocus, onClick: reference2 }, (0, import_react23.createElement)(ChatsIcon), (0, import_react23.createElement)("span", { className: "bt-menu-label" }, t("Reference a chat"))) : null,
|
|
9414
9414
|
canSetGoal(room2, roster) ? (0, import_react23.createElement)("button", { type: "button", role: "menuitem", onClick: goal }, (0, import_react23.createElement)(GoalIcon), (0, import_react23.createElement)("span", { className: "bt-menu-label" }, t("Set a goal"))) : null,
|
|
9415
9415
|
(0, import_react23.createElement)("button", { type: "button", role: "menuitem", onClick: schedule }, (0, import_react23.createElement)(ClockIcon), (0, import_react23.createElement)("span", { className: "bt-menu-label" }, t("Scheduled task")))
|
|
9416
9416
|
), document.body) : null
|
|
@@ -10511,12 +10511,12 @@ function CommandPalette({ start, token, roster, actions, useSessions }) {
|
|
|
10511
10511
|
{ key: "cmd:settings", icon: (0, import_react27.createElement)(GearIcon), title: t("Bot settings"), run: () => actions.openSettings("general") }
|
|
10512
10512
|
].filter((command) => matchesName(command.title));
|
|
10513
10513
|
commands.length && sections.push([t("Commands"), commands]);
|
|
10514
|
-
let rows2 = sections.flatMap(([, items]) => items),
|
|
10515
|
-
`), glide = useGlide(`${
|
|
10514
|
+
let rows2 = sections.flatMap(([, items]) => items), active2 = Math.min(cursor, Math.max(rows2.length - 1, 0)), shown = rows2.map((row) => row.key).join(`
|
|
10515
|
+
`), glide = useGlide(`${active2}
|
|
10516
10516
|
${shown}`, { axis: "y", ...QUICK_EDGES }), listRef = glide.box;
|
|
10517
10517
|
useFlip(listRef, shown, "[data-flip]"), (0, import_react27.useEffect)(() => {
|
|
10518
10518
|
listRef.current?.querySelector("[aria-selected=true]")?.scrollIntoView({ block: "nearest" });
|
|
10519
|
-
}, [
|
|
10519
|
+
}, [active2, query]);
|
|
10520
10520
|
let choose = (row) => {
|
|
10521
10521
|
!row || leaving || (Promise.resolve(row.run()).catch((error) => actions.reportError(error, "menu")), close());
|
|
10522
10522
|
}, index = -1;
|
|
@@ -10543,7 +10543,7 @@ ${shown}`, { axis: "y", ...QUICK_EDGES }), listRef = glide.box;
|
|
|
10543
10543
|
setQuery(event.target.value), setCursor(0);
|
|
10544
10544
|
},
|
|
10545
10545
|
onKeyDown: (event) => {
|
|
10546
|
-
event.nativeEvent.isComposing || (event.key === "ArrowDown" ? (event.preventDefault(), setCursor(Math.min(
|
|
10546
|
+
event.nativeEvent.isComposing || (event.key === "ArrowDown" ? (event.preventDefault(), setCursor(Math.min(active2 + 1, rows2.length - 1))) : event.key === "ArrowUp" ? (event.preventDefault(), setCursor(Math.max(active2 - 1, 0))) : event.key === "Enter" && (event.preventDefault(), choose(rows2[active2])));
|
|
10547
10547
|
}
|
|
10548
10548
|
}),
|
|
10549
10549
|
query ? (0, import_react27.createElement)("button", { type: "button", className: "bt-palette-clear", "aria-label": t("Clear search"), onClick: () => {
|
|
@@ -10574,7 +10574,7 @@ ${shown}`, { axis: "y", ...QUICK_EDGES }), listRef = glide.box;
|
|
|
10574
10574
|
type: "button",
|
|
10575
10575
|
role: "option",
|
|
10576
10576
|
className: "bt-palette-row",
|
|
10577
|
-
"aria-selected": at2 ===
|
|
10577
|
+
"aria-selected": at2 === active2,
|
|
10578
10578
|
"data-flip": row.key,
|
|
10579
10579
|
onMouseMove: () => {
|
|
10580
10580
|
cursor !== at2 && setCursor(at2);
|
|
@@ -10826,8 +10826,8 @@ function TaskRow2({ task, actions, onView, showBot, roster }) {
|
|
|
10826
10826
|
}
|
|
10827
10827
|
var pad = (number) => String(number).padStart(2, "0");
|
|
10828
10828
|
function inAnHour() {
|
|
10829
|
-
let
|
|
10830
|
-
return
|
|
10829
|
+
let date2 = new Date(Date.now() + 36e5);
|
|
10830
|
+
return date2.setMinutes(0, 0, 0), `${date2.getFullYear()}-${pad(date2.getMonth() + 1)}-${pad(date2.getDate())}T${pad(date2.getHours())}:00`;
|
|
10831
10831
|
}
|
|
10832
10832
|
var KINDS = [["at", "Once"], ["daily", "Every day"], ["weekly", "Every week"], ["every", "Repeat"]], UNITS = [["minutes", 1, "minutes"], ["hours", 60, "hours"], ["days", 1440, "days"]];
|
|
10833
10833
|
function TaskForm({ roster, actions, start, onDone, onCancel }) {
|
|
@@ -12315,8 +12315,8 @@ function NewChat({ mode, roster, actions }) {
|
|
|
12315
12315
|
for (let bot of matches)
|
|
12316
12316
|
options.push({ key: bot.id, bot, label: bot.name, hint: choosingAdmin ? t("Make admin") : group || picked.length > 0 ? t("Add to group chat") : void 0, run: () => openBot(bot) });
|
|
12317
12317
|
wanted !== "" && !exact && mode !== "search" && options.push({ key: "create", icon: (0, import_react35.createElement)(PlusIcon), label: t("Create new Bot “{name}”", { name: query.trim() }), run: createBot });
|
|
12318
|
-
let
|
|
12319
|
-
`), glide = useGlide(`${
|
|
12318
|
+
let active2 = Math.min(cursor, Math.max(options.length - 1, 0)), listed = options.map((option) => option.key).join(`
|
|
12319
|
+
`), glide = useGlide(`${active2}
|
|
12320
12320
|
${listed}`, { axis: "y", ...QUICK_EDGES });
|
|
12321
12321
|
useFlip(glide.box, listed, "[data-flip]");
|
|
12322
12322
|
let drop = (0, import_react35.useRef)(null);
|
|
@@ -12375,7 +12375,7 @@ ${listed}`, { axis: "y", ...QUICK_EDGES });
|
|
|
12375
12375
|
setQuery(event.target.value), setCursor(0);
|
|
12376
12376
|
},
|
|
12377
12377
|
onKeyDown: (event) => {
|
|
12378
|
-
event.nativeEvent.isComposing || (event.key === "ArrowDown" ? (event.preventDefault(), setCursor(Math.min(
|
|
12378
|
+
event.nativeEvent.isComposing || (event.key === "ArrowDown" ? (event.preventDefault(), setCursor(Math.min(active2 + 1, options.length - 1))) : event.key === "ArrowUp" ? (event.preventDefault(), setCursor(Math.max(active2 - 1, 0))) : event.key === "Enter" && options[active2] ? (event.preventDefault(), options[active2].run()) : event.key === "Backspace" && query === "" && unpick());
|
|
12379
12379
|
}
|
|
12380
12380
|
}),
|
|
12381
12381
|
group && admin !== null ? (0, import_react35.createElement)("button", {
|
|
@@ -12398,14 +12398,14 @@ ${listed}`, { axis: "y", ...QUICK_EDGES });
|
|
|
12398
12398
|
type: "button",
|
|
12399
12399
|
role: "option",
|
|
12400
12400
|
className: "bt-option",
|
|
12401
|
-
"aria-selected": index ===
|
|
12401
|
+
"aria-selected": index === active2,
|
|
12402
12402
|
"data-flip": option.key,
|
|
12403
12403
|
onMouseEnter: () => setCursor(index),
|
|
12404
12404
|
onClick: option.run
|
|
12405
12405
|
},
|
|
12406
12406
|
option.bot ? (0, import_react35.createElement)(BotMark, { bot: option.bot, size: 22 }) : (0, import_react35.createElement)("span", { className: "bt-option-icon" }, option.icon),
|
|
12407
12407
|
(0, import_react35.createElement)("span", { className: "bt-option-label" }, option.label),
|
|
12408
|
-
option.hint && index ===
|
|
12408
|
+
option.hint && index === active2 ? (0, import_react35.createElement)("span", { className: "bt-option-hint" }, option.hint) : null
|
|
12409
12409
|
))
|
|
12410
12410
|
)),
|
|
12411
12411
|
(0, import_react35.createElement)("div", { className: "bt-nc-spacer" }),
|
|
@@ -13401,7 +13401,7 @@ function Profile({ face, share, range }) {
|
|
|
13401
13401
|
);
|
|
13402
13402
|
}
|
|
13403
13403
|
var monthOf = (ms2) => Date.UTC(yearOf(ms2), new Date(ms2).getUTCMonth(), 1), addMonths = (ms2, count) => Date.UTC(yearOf(ms2), new Date(ms2).getUTCMonth() + count, 1);
|
|
13404
|
-
function SpanPicker({ span, today, oldest, active, near, onPick, onClose }) {
|
|
13404
|
+
function SpanPicker({ span, today, oldest, active: active2, near, onPick, onClose }) {
|
|
13405
13405
|
let box = (0, import_react41.useRef)(null), todayMs = hourMs(today), thisMonth = monthOf(todayMs), [right, setRight] = (0, import_react41.useState)(() => Math.max(addMonths(oldest, 1), monthOf(hourMs(span?.to ?? today)))), [anchor, setAnchor] = (0, import_react41.useState)(null), [hover, setHover] = (0, import_react41.useState)(null);
|
|
13406
13406
|
(0, import_react41.useEffect)(() => {
|
|
13407
13407
|
let onDown = (event) => {
|
|
@@ -13437,7 +13437,7 @@ function SpanPicker({ span, today, oldest, active, near, onPick, onClose }) {
|
|
|
13437
13437
|
"data-l": flag(weekday === 0 || day === 1),
|
|
13438
13438
|
"data-r": flag(weekday === 6 || day === length),
|
|
13439
13439
|
"data-today": flag(key === today),
|
|
13440
|
-
"data-has": flag(
|
|
13440
|
+
"data-has": flag(active2.has(key)),
|
|
13441
13441
|
onMouseEnter: () => setHover(key),
|
|
13442
13442
|
onClick: () => press(key)
|
|
13443
13443
|
}, (0, import_react41.createElement)("b", null, day)));
|
|
@@ -13503,7 +13503,7 @@ function Heat({ view, keep, paint, index }) {
|
|
|
13503
13503
|
let tipSide = hover ? {
|
|
13504
13504
|
...hover.week >= HEAT_WEEKS / 2 ? { right: `calc(${(HEAT_WEEKS - hover.week) / HEAT_WEEKS * 100}% + 8px)` } : { left: `calc(${(hover.week + 1) / HEAT_WEEKS * 100}% + 8px)` },
|
|
13505
13505
|
...hover.day < 4 ? { top: `calc(${hover.day / 7 * 100}% - 2px)` } : { top: "auto", bottom: `calc(${(6 - hover.day) / 7 * 100}% - 2px)` }
|
|
13506
|
-
} : null,
|
|
13506
|
+
} : null, active2 = [...daily.values()].filter((value) => value > 0).length, summary = active2 === 1 ? t("Active on 1 day in the last year") : t("Active on {count} days in the last year", { count: active2 });
|
|
13507
13507
|
return (0, import_react41.createElement)(
|
|
13508
13508
|
"section",
|
|
13509
13509
|
{ className: "bt-us-card bt-us-heat", style: { "--i": index } },
|
|
@@ -14114,8 +14114,8 @@ function download(name, text7) {
|
|
|
14114
14114
|
}
|
|
14115
14115
|
var copy = (text7) => navigator.clipboard === void 0 ? Promise.resolve(!1) : navigator.clipboard.writeText(text7).then(() => !0, () => !1);
|
|
14116
14116
|
function whenText(time) {
|
|
14117
|
-
let
|
|
14118
|
-
return today ? clock4 : `${
|
|
14117
|
+
let date2 = new Date(time), today = (/* @__PURE__ */ new Date()).toDateString() === date2.toDateString(), clock4 = date2.toLocaleTimeString(dateLocale(), { hour: "2-digit", minute: "2-digit" });
|
|
14118
|
+
return today ? clock4 : `${date2.toLocaleDateString(dateLocale(), { month: "short", day: "numeric" })} ${clock4}`;
|
|
14119
14119
|
}
|
|
14120
14120
|
function entrySummary(entry) {
|
|
14121
14121
|
return entry.source === "turn" ? failureLabel(entry.code, entry.text) : entry.text;
|
|
@@ -15884,12 +15884,12 @@ function menuItemFor(key, actions, subject) {
|
|
|
15884
15884
|
}
|
|
15885
15885
|
}
|
|
15886
15886
|
var sideTitle = (chat) => chat?.entries?.[0]?.question?.trim() || t("Side chat");
|
|
15887
|
-
function PanelStrip({ bot, subject, view, ids, active, sides, side, canBrowse, reading, onView, actions, useBrowserPages }) {
|
|
15887
|
+
function PanelStrip({ bot, subject, view, ids, active: active2, sides, side, canBrowse, reading, onView, actions, useBrowserPages }) {
|
|
15888
15888
|
let pages = useBrowserPages((map) => map), wrap = (0, import_react52.useRef)(null), ind = (0, import_react52.useRef)(null), spot = (0, import_react52.useRef)(null), under = (0, import_react52.useRef)(null), watcher = (0, import_react52.useRef)(null);
|
|
15889
15889
|
(0, import_react52.useLayoutEffect)(() => {
|
|
15890
15890
|
let box = wrap.current, capsule = ind.current;
|
|
15891
15891
|
if (!box || !capsule) return;
|
|
15892
|
-
let node = view === "details" ? box.querySelector(".bt-ptab-bot") : view === "side" ? box.querySelector(`[data-side="${side}"]`) : box.querySelector(`[data-tab="${
|
|
15892
|
+
let node = view === "details" ? box.querySelector(".bt-ptab-bot") : view === "side" ? box.querySelector(`[data-side="${side}"]`) : box.querySelector(`[data-tab="${active2}"]`);
|
|
15893
15893
|
if (under.current !== node && (under.current && watcher.current?.unobserve(under.current), under.current = node, node && watcher.current?.observe(node)), !node) {
|
|
15894
15894
|
capsule.style.opacity = "0", spot.current = null;
|
|
15895
15895
|
return;
|
|
@@ -15944,7 +15944,7 @@ function PanelStrip({ bot, subject, view, ids, active, sides, side, canBrowse, r
|
|
|
15944
15944
|
key: tabId,
|
|
15945
15945
|
type: "button",
|
|
15946
15946
|
role: "tab",
|
|
15947
|
-
"aria-selected": view === "browser" && tabId ===
|
|
15947
|
+
"aria-selected": view === "browser" && tabId === active2,
|
|
15948
15948
|
"data-tab": tabId,
|
|
15949
15949
|
className: "bt-ptab",
|
|
15950
15950
|
title: page.url || t("New tab"),
|
|
@@ -16319,7 +16319,7 @@ function ImportCard({ flow, page, busy, onApply, onCancel, onCloseAndImport, onD
|
|
|
16319
16319
|
));
|
|
16320
16320
|
}
|
|
16321
16321
|
function BotPanel({ pane, leaving, room: room2, overlay, roster, actions, useSessions, useSessionStatus, useActivity, useWork, useBrowserTabs, useBrowserPages, useBrowserHolds }) {
|
|
16322
|
-
let bot = roster.byId[pane.id], canBrowse = !!(bot && roster.browser === !0 && actions.browserShow), sideChats = bot ? sideChatsOf(roster, bot.id) : [], sideChat = sideChats.find((chat) => chat?.id === pane.side), view = pane.view === "browser" && canBrowse ? "browser" : pane.view === "side" && sideChat !== void 0 ? "side" : "details", tabState = useBrowserTabs((map) => bot ? map[bot.id] ?? EMPTY_TABS2 : EMPTY_TABS2),
|
|
16322
|
+
let bot = roster.byId[pane.id], canBrowse = !!(bot && roster.browser === !0 && actions.browserShow), sideChats = bot ? sideChatsOf(roster, bot.id) : [], sideChat = sideChats.find((chat) => chat?.id === pane.side), view = pane.view === "browser" && canBrowse ? "browser" : pane.view === "side" && sideChat !== void 0 ? "side" : "details", tabState = useBrowserTabs((map) => bot ? map[bot.id] ?? EMPTY_TABS2 : EMPTY_TABS2), active2 = tabState.active, page = useBrowserPages((pages) => (active2 ? pages[active2] : null) ?? EMPTY_PAGE), hold = useBrowserHolds?.((map) => bot ? map[bot.id] ?? null : null) ?? null, root = (0, import_react52.useRef)(null), fly = (0, import_react52.useRef)(null), [landed, setLanded] = (0, import_react52.useState)(!1), [settling, setSettling] = (0, import_react52.useState)(!1), [width, setWidth] = (0, import_react52.useState)(savedWidth), [dragging, setDragging] = (0, import_react52.useState)(!1), [resizing, setResizing] = (0, import_react52.useState)(!1), instant = dragging || resizing, [reading, setReading] = (0, import_react52.useState)(!1), panelWidth = fitWidth(width ?? (view === "browser" ? DEFAULT_WIDTH : DETAILS_WIDTH), widthRange(view, room2));
|
|
16323
16323
|
(0, import_react52.useLayoutEffect)(() => {
|
|
16324
16324
|
view === "browser" && width === null && setWidth(DEFAULT_WIDTH);
|
|
16325
16325
|
}, [view, width]), (0, import_react52.useLayoutEffect)(() => {
|
|
@@ -16353,8 +16353,8 @@ function BotPanel({ pane, leaving, room: room2, overlay, roster, actions, useSes
|
|
|
16353
16353
|
}, []), (0, import_react52.useEffect)(() => {
|
|
16354
16354
|
canBrowse && actions.browserEnsure(bot.id);
|
|
16355
16355
|
}, [bot?.id, canBrowse]), (0, import_react52.useEffect)(() => {
|
|
16356
|
-
view === "browser" && (
|
|
16357
|
-
}, [view,
|
|
16356
|
+
view === "browser" && (active2 === null || !tabState.ids.includes(active2)) && actions.setPanelView("details");
|
|
16357
|
+
}, [view, active2, tabState.ids.length]), (0, import_react52.useEffect)(() => {
|
|
16358
16358
|
pane.view === "side" && sideChat === void 0 && actions.setPanelView("details");
|
|
16359
16359
|
}, [pane.view, sideChat]), (0, import_react52.useEffect)(() => {
|
|
16360
16360
|
(view !== "browser" || leaving) && actions.browserShow?.(null);
|
|
@@ -16471,8 +16471,8 @@ function BotPanel({ pane, leaving, room: room2, overlay, roster, actions, useSes
|
|
|
16471
16471
|
// Over the whole window while dragging: the cursor stays a resize cursor and the
|
|
16472
16472
|
// pages underneath (the chat, the guest) see no pointer.
|
|
16473
16473
|
dragging ? (0, import_react_dom8.createPortal)((0, import_react52.createElement)("div", { className: "bt-drag-shield", "aria-hidden": !0 }), document.body) : null,
|
|
16474
|
-
hasStrip ? (0, import_react52.createElement)(PanelStrip, { bot, subject: pane.id, view, ids: tabState.ids, active, sides: sideChats, side: pane.side, canBrowse, reading, onView: switchView, actions: panelActions, useBrowserPages }) : null,
|
|
16475
|
-
view === "browser" && bot ? (0, import_react52.createElement)(BrowserView, { key: `browser:${
|
|
16474
|
+
hasStrip ? (0, import_react52.createElement)(PanelStrip, { bot, subject: pane.id, view, ids: tabState.ids, active: active2, sides: sideChats, side: pane.side, canBrowse, reading, onView: switchView, actions: panelActions, useBrowserPages }) : null,
|
|
16475
|
+
view === "browser" && bot ? (0, import_react52.createElement)(BrowserView, { key: `browser:${active2}`, bot, tabId: active2, leaving, landed: landed && !settling, actions, useBrowserPages, hold }) : view === "side" && sideChat ? (0, import_react52.createElement)("div", { key: `side:${sideChat.id}`, className: "bt-panel-view" }, (0, import_react52.createElement)(SideChatView, { subject: pane.id, chat: sideChat, roster, actions: panelActions })) : (0, import_react52.createElement)(
|
|
16476
16476
|
"div",
|
|
16477
16477
|
{ key: `details:${pane.id}:${pane.renaming ? "rename" : ""}:${pane.tab ?? ""}`, className: "bt-panel-view" },
|
|
16478
16478
|
(0, import_react52.createElement)(DetailsDrawer, {
|
|
@@ -17071,9 +17071,9 @@ function createBotBrowsers({ bridge: bridge2, createSource: createSource2, stora
|
|
|
17071
17071
|
});
|
|
17072
17072
|
}, ensureTabs = (botId) => {
|
|
17073
17073
|
if (tabs.getSnapshot()[botId] !== void 0) return;
|
|
17074
|
-
let entries2 = saved[botId]?.tabs ?? [], ids = entries2.map((entry) => entry.id),
|
|
17074
|
+
let entries2 = saved[botId]?.tabs ?? [], ids = entries2.map((entry) => entry.id), active2 = ids.includes(saved[botId]?.active) ? saved[botId].active : ids.at(-1) ?? null;
|
|
17075
17075
|
for (let entry of entries2) owner.set(entry.id, botId);
|
|
17076
|
-
tabs.set((state) => ({ ...state, [botId]: { ids, active } }));
|
|
17076
|
+
tabs.set((state) => ({ ...state, [botId]: { ids, active: active2 } }));
|
|
17077
17077
|
for (let entry of entries2) publish2(entry.id, { url: entry.url ?? "", title: entry.title ?? "", live: !1 });
|
|
17078
17078
|
}, ensureLayer = () => (layer?.isConnected || (layer = doc.createElement("div"), layer.className = "bt-browser-layer", Object.assign(layer.style, { position: "fixed", inset: "0", zIndex: "41", pointerEvents: "none" }), doc.body.append(layer)), layer), place = (entry) => {
|
|
17079
17079
|
let box = rect ?? { left: 0, top: 0, width: 800, height: 600 };
|
|
@@ -17202,8 +17202,8 @@ function createBotBrowsers({ bridge: bridge2, createSource: createSource2, stora
|
|
|
17202
17202
|
}), shown === tabId && await show2(null), views.get(tabId)?.appView ? (await bridge2.views.close(botId, tabId), views.get(tabId)?.stop(), views.delete(tabId)) : await release(tabId), tabs.set((snapshot) => {
|
|
17203
17203
|
let current = snapshot[botId];
|
|
17204
17204
|
if (current === void 0 || !current.ids.includes(tabId)) return snapshot;
|
|
17205
|
-
let at2 = current.ids.indexOf(tabId), ids = current.ids.filter((id2) => id2 !== tabId),
|
|
17206
|
-
return ids.length === 0 ? delete next[botId] : next[botId] = { ids, active }, next;
|
|
17205
|
+
let at2 = current.ids.indexOf(tabId), ids = current.ids.filter((id2) => id2 !== tabId), active2 = current.active === tabId ? ids[Math.min(at2, ids.length - 1)] ?? null : current.active, next = { ...snapshot };
|
|
17206
|
+
return ids.length === 0 ? delete next[botId] : next[botId] = { ids, active: active2 }, next;
|
|
17207
17207
|
}), owner.delete(tabId), pages.set((snapshot) => {
|
|
17208
17208
|
if (snapshot[tabId] === void 0) return snapshot;
|
|
17209
17209
|
let { [tabId]: _2, ...rest } = snapshot;
|
|
@@ -20143,7 +20143,7 @@ function reasoningDecision(row, task) {
|
|
|
20143
20143
|
};
|
|
20144
20144
|
}
|
|
20145
20145
|
function candidateUtility(row, task, weights, cacheReadRatio = 0, cacheWriteRatio = 0, text7 = "", complexity = "balanced") {
|
|
20146
|
-
let quality = qualityForTask(row, task.type), rawPreference = row.preferenceAdjustments?.[task.type], preferenceAdjustment = Number.isFinite(rawPreference) ? clamp(rawPreference, -0.1, 0.1) : 0, floor = Number(task.qualityFloor ?? taskQualityFloor("complex", task)), qualityGap = Math.max(0, floor - quality), reasoning = reasoningDecision(row, task),
|
|
20146
|
+
let quality = qualityForTask(row, task.type), rawPreference = row.preferenceAdjustments?.[task.type], preferenceAdjustment = Number.isFinite(rawPreference) ? clamp(rawPreference, -0.1, 0.1) : 0, floor = Number(task.qualityFloor ?? taskQualityFloor("complex", task)), qualityGap = Math.max(0, floor - quality), reasoning = reasoningDecision(row, task), reference2 = taskCost({ pricing: COST_REFERENCE_PRICING, reasoningKnown: !0, reasoningEfforts: [] }, task, text7, complexity, cacheReadRatio, cacheWriteRatio), cost = row.pricing === null ? 0 : 1 / (1 + taskCost(row, task, text7, complexity, cacheReadRatio, cacheWriteRatio) / Math.max(reference2, 1e-12)), resources = resourceTokenBudget(row, task, text7, complexity, cacheReadRatio, cacheWriteRatio), latencyUtility = Number.isFinite(resources.estimatedLatencyMs) ? 1 / (1 + resources.estimatedLatencyMs / 1e4) : 1 - clamp(row.latency * reasoning.multiplier.latency);
|
|
20147
20147
|
return { score: weights.quality * quality + weights.cost * cost + weights.latency * latencyUtility + weights.specialty * specialtyForTask(row, task.type) + (weights.reasoning ?? 0) * reasoning.reasoningFit - weights.risk * row.risk - qualityGap * (task.criticality ?? 0.75) + preferenceAdjustment, floor, qualityGap, preferenceAdjustment, ...reasoning };
|
|
20148
20148
|
}
|
|
20149
20149
|
function taskCost(row, task, text7, complexity, cacheReadRatio = 0, cacheWriteRatio = 0) {
|
|
@@ -21474,8 +21474,8 @@ function rerunSupport(run2, ledger = null) {
|
|
|
21474
21474
|
var pad2 = (value) => String(value).padStart(2, "0");
|
|
21475
21475
|
function formatResetTime(at2) {
|
|
21476
21476
|
if (!Number.isFinite(at2)) return "";
|
|
21477
|
-
let
|
|
21478
|
-
return `${
|
|
21477
|
+
let date2 = new Date(at2);
|
|
21478
|
+
return `${date2.getMonth() + 1}-${date2.getDate()} ${pad2(date2.getHours())}:${pad2(date2.getMinutes())}`;
|
|
21479
21479
|
}
|
|
21480
21480
|
var BILLING_CHANNEL_LABEL = Object.freeze({ subscription: "订阅", api: "API Key", unknown: "计费方式待核对" });
|
|
21481
21481
|
function billingRows(billing) {
|
|
@@ -21623,8 +21623,8 @@ function publicEndpointDraft(key, value) {
|
|
|
21623
21623
|
}
|
|
21624
21624
|
function feedbackRatingArguments(run2, item, direction) {
|
|
21625
21625
|
if (!["up", "down"].includes(direction)) throw new TypeError("Unknown rating direction");
|
|
21626
|
-
let
|
|
21627
|
-
return [run2?.id, item?.id,
|
|
21626
|
+
let active2 = direction === "up" ? item?.rating === 1 : item?.rating === -1;
|
|
21627
|
+
return [run2?.id, item?.id, active2 ? "clear" : direction, item?.finishedAt];
|
|
21628
21628
|
}
|
|
21629
21629
|
var nonnegative3 = (value) => Number.isFinite(value) && value >= 0 ? value : 0;
|
|
21630
21630
|
function learningView(learning, settings = {}) {
|
|
@@ -22108,25 +22108,25 @@ function RunLauncher({ task, mode, directRoute, budgetUsd, defaultPreset, ledger
|
|
|
22108
22108
|
phase.kind === "preview" && confirmRef.current?.focus();
|
|
22109
22109
|
}, [phase.kind]);
|
|
22110
22110
|
let acceptSnapshot = import_react58.default.useCallback((value, token, sequence, cancelAcknowledged = !1) => {
|
|
22111
|
-
let
|
|
22112
|
-
if (!mounted.current || !
|
|
22111
|
+
let active2 = activeRun.current;
|
|
22112
|
+
if (!mounted.current || !active2 || active2.token !== token || active2.terminal || value.jobId !== active2.jobId) return !1;
|
|
22113
22113
|
if (!isJobSnapshot(value)) throw new Error("暂时无法读取执行进度。");
|
|
22114
22114
|
let terminal = !LIVE_STATUSES.has(value.status);
|
|
22115
|
-
if (!terminal && sequence <
|
|
22116
|
-
return cancelAcknowledged ? (
|
|
22115
|
+
if (!terminal && sequence < active2.appliedSequence)
|
|
22116
|
+
return cancelAcknowledged ? (active2.cancelRequested = !0, setPhase((previous) => previous.kind === "running" ? {
|
|
22117
22117
|
...previous,
|
|
22118
22118
|
job: { ...previous.job, status: "cancelling", cancelRequested: !0 },
|
|
22119
22119
|
cancelPending: !1,
|
|
22120
22120
|
cancelError: ""
|
|
22121
22121
|
} : previous), !0) : !1;
|
|
22122
|
-
|
|
22122
|
+
active2.appliedSequence = Math.max(active2.appliedSequence, sequence), active2.cancelRequested ||= cancelAcknowledged || value.cancelRequested || value.status === "cancelling";
|
|
22123
22123
|
let job = {
|
|
22124
22124
|
...value,
|
|
22125
|
-
cancelRequested: !!
|
|
22126
|
-
status: !terminal &&
|
|
22125
|
+
cancelRequested: !!active2.cancelRequested,
|
|
22126
|
+
status: !terminal && active2.cancelRequested ? "cancelling" : value.status
|
|
22127
22127
|
};
|
|
22128
22128
|
if (terminal) {
|
|
22129
|
-
|
|
22129
|
+
active2.terminal = !0, launching.current = !1, forgetJob(value.jobId);
|
|
22130
22130
|
let result = value.result ?? { status: value.status };
|
|
22131
22131
|
setPhase({ kind: "done", value: result, job }), onFinished.current?.(result.runId);
|
|
22132
22132
|
} else
|
|
@@ -22142,23 +22142,23 @@ function RunLauncher({ task, mode, directRoute, budgetUsd, defaultPreset, ledger
|
|
|
22142
22142
|
}, []), runningJobId = phase.kind === "running" ? phase.job?.jobId : null;
|
|
22143
22143
|
import_react58.default.useEffect(() => {
|
|
22144
22144
|
if (!runningJobId || typeof runStatus != "function") return;
|
|
22145
|
-
let
|
|
22146
|
-
if (!
|
|
22145
|
+
let active2 = activeRun.current;
|
|
22146
|
+
if (!active2 || active2.jobId !== runningJobId) return;
|
|
22147
22147
|
let disposed = !1, timer, poll = async () => {
|
|
22148
|
-
if (disposed || activeRun.current !==
|
|
22149
|
-
let sequence = ++
|
|
22148
|
+
if (disposed || activeRun.current !== active2 || active2.terminal) return;
|
|
22149
|
+
let sequence = ++active2.requestSequence;
|
|
22150
22150
|
try {
|
|
22151
22151
|
let value = unwrapRemote(await waitForRemote((signal) => runStatus({ jobId: runningJobId }, signal), pendingRemotes.current), "暂时无法读取执行进度。");
|
|
22152
22152
|
if (disposed) return;
|
|
22153
22153
|
if (!isJobSnapshot(value) || value.jobId !== runningJobId) throw new Error("暂时无法读取执行进度。");
|
|
22154
|
-
acceptSnapshot(value,
|
|
22154
|
+
acceptSnapshot(value, active2.token, sequence);
|
|
22155
22155
|
} catch (error) {
|
|
22156
|
-
!disposed && mounted.current && activeRun.current ===
|
|
22156
|
+
!disposed && mounted.current && activeRun.current === active2 && !active2.terminal && (unknownJob(error) ? (active2.terminal = !0, launching.current = !1, forgetJob(runningJobId), setPhase({ kind: "error", message: "无法找到此前的执行,可能已过期或工作台已重新启动。请刷新下方执行记录核对结果。" })) : setPhase((previous) => previous.kind === "running" && previous.job?.jobId === runningJobId ? { ...previous, restoring: !1, pollError: "暂时无法更新执行进度,将自动重试;任务可能仍在执行。" } : previous));
|
|
22157
22157
|
} finally {
|
|
22158
|
-
!disposed && activeRun.current ===
|
|
22158
|
+
!disposed && activeRun.current === active2 && !active2.terminal && (timer = setTimeout(poll, 1e3));
|
|
22159
22159
|
}
|
|
22160
22160
|
};
|
|
22161
|
-
return timer = setTimeout(poll,
|
|
22161
|
+
return timer = setTimeout(poll, active2.restoring ? 0 : 1e3), active2.restoring = !1, () => {
|
|
22162
22162
|
disposed = !0, clearTimeout(timer);
|
|
22163
22163
|
};
|
|
22164
22164
|
}, [runningJobId, runStatus, acceptSnapshot]), import_react58.default.useEffect(() => {
|
|
@@ -22202,7 +22202,7 @@ function RunLauncher({ task, mode, directRoute, budgetUsd, defaultPreset, ledger
|
|
|
22202
22202
|
if (launching.current || pendingLaunch || currentPhase.current !== phase || blocked || phase.kind !== "preview" || phase.signature !== latestSignature.current || phase.value.status === "blocked") return;
|
|
22203
22203
|
let shown = phase.value, snapshot = phase.request, signature2 = phase.signature;
|
|
22204
22204
|
launching.current = !0;
|
|
22205
|
-
let identity2 = /* @__PURE__ */ Symbol("launch"),
|
|
22205
|
+
let identity2 = /* @__PURE__ */ Symbol("launch"), active2 = {
|
|
22206
22206
|
token: ++launchSequence.current,
|
|
22207
22207
|
launchIdentity: identity2,
|
|
22208
22208
|
jobId: null,
|
|
@@ -22212,40 +22212,40 @@ function RunLauncher({ task, mode, directRoute, budgetUsd, defaultPreset, ledger
|
|
|
22212
22212
|
requestSequence: 0,
|
|
22213
22213
|
appliedSequence: 0
|
|
22214
22214
|
};
|
|
22215
|
-
activeRun.current =
|
|
22215
|
+
activeRun.current = active2, pendingLaunch = identity2, notifyLaunch({ kind: "pending", identity: identity2 }), setPhase({ kind: "running", value: shown, request: snapshot, signature: signature2 });
|
|
22216
22216
|
try {
|
|
22217
22217
|
let value = unwrapRemote(await startRun({ ...snapshot, confirmedReasons: (shown.reasons ?? []).map((item) => item.code) }), "执行失败。");
|
|
22218
|
-
if (settleLaunch(identity2, value), !mounted.current || activeRun.current !==
|
|
22218
|
+
if (settleLaunch(identity2, value), !mounted.current || activeRun.current !== active2) return;
|
|
22219
22219
|
if (isJobSnapshot(value)) {
|
|
22220
|
-
|
|
22220
|
+
active2.jobId = value.jobId, acceptSnapshot(value, active2.token, ++active2.requestSequence);
|
|
22221
22221
|
return;
|
|
22222
22222
|
}
|
|
22223
|
-
if (
|
|
22223
|
+
if (active2.terminal = !0, launching.current = !1, value.status === "needs-confirmation") {
|
|
22224
22224
|
setPhase(signature2 === latestSignature.current ? { kind: "preview", value, request: snapshot, signature: signature2, changed: !0 } : { kind: "idle" });
|
|
22225
22225
|
return;
|
|
22226
22226
|
}
|
|
22227
22227
|
setPhase({ kind: "done", value }), onStarted?.(value.runId);
|
|
22228
22228
|
} catch (error) {
|
|
22229
|
-
settleLaunch(identity2, null, text2(error?.message) || "执行失败。"), mounted.current && activeRun.current ===
|
|
22229
|
+
settleLaunch(identity2, null, text2(error?.message) || "执行失败。"), mounted.current && activeRun.current === active2 && (active2.terminal = !0, launching.current = !1, setPhase({ kind: "error", message: text2(error?.message) || "执行失败。" }));
|
|
22230
22230
|
}
|
|
22231
22231
|
}, cancel = async () => {
|
|
22232
|
-
let
|
|
22233
|
-
if (!
|
|
22234
|
-
|
|
22235
|
-
let sequence = ++
|
|
22232
|
+
let active2 = activeRun.current;
|
|
22233
|
+
if (!active2?.jobId || active2.terminal || active2.cancelPending || active2.cancelRequested || typeof cancelRun != "function") return;
|
|
22234
|
+
active2.cancelPending = !0;
|
|
22235
|
+
let sequence = ++active2.requestSequence;
|
|
22236
22236
|
setPhase((previous) => previous.kind === "running" ? { ...previous, cancelPending: !0, cancelError: "" } : previous);
|
|
22237
22237
|
try {
|
|
22238
|
-
let value = unwrapRemote(await waitForRemote((signal) => cancelRun({ jobId:
|
|
22239
|
-
if (!isJobSnapshot(value) || value.jobId !==
|
|
22240
|
-
acceptSnapshot(value,
|
|
22238
|
+
let value = unwrapRemote(await waitForRemote((signal) => cancelRun({ jobId: active2.jobId }, signal), pendingRemotes.current), "取消请求未确认。");
|
|
22239
|
+
if (!isJobSnapshot(value) || value.jobId !== active2.jobId) throw new Error("取消请求未确认。");
|
|
22240
|
+
acceptSnapshot(value, active2.token, sequence, !0);
|
|
22241
22241
|
} catch {
|
|
22242
|
-
mounted.current && activeRun.current ===
|
|
22242
|
+
mounted.current && activeRun.current === active2 && !active2.terminal && setPhase((previous) => previous.kind === "running" ? {
|
|
22243
22243
|
...previous,
|
|
22244
22244
|
cancelPending: !1,
|
|
22245
22245
|
cancelError: "取消请求未确认,任务可能仍在执行。请重试取消。"
|
|
22246
22246
|
} : previous);
|
|
22247
22247
|
} finally {
|
|
22248
|
-
|
|
22248
|
+
active2.cancelPending = !1;
|
|
22249
22249
|
}
|
|
22250
22250
|
};
|
|
22251
22251
|
return /* @__PURE__ */ import_react58.default.createElement("section", { className: "mr-card", "aria-label": "在工作台执行" }, /* @__PURE__ */ import_react58.default.createElement("div", { className: "mr-card-head" }, /* @__PURE__ */ import_react58.default.createElement("div", null, /* @__PURE__ */ import_react58.default.createElement("h2", { className: "mr-card-title" }, "预览与执行"), /* @__PURE__ */ import_react58.default.createElement("p", { className: "mr-card-copy" }, "先预览,核对模型、工作区与费用,再确认开始。预览不会调用模型;确认执行才会启动模型或 CLI。"))), /* @__PURE__ */ import_react58.default.createElement("div", { className: "mr-card-body" }, /* @__PURE__ */ import_react58.default.createElement("div", { className: "mr-control-group mr-launch-workspace" }, /* @__PURE__ */ import_react58.default.createElement("label", { className: "mr-control-label", htmlFor: "mr-launch-workspace" }, "工作区(可选)"), /* @__PURE__ */ import_react58.default.createElement("input", { className: "mr-input", id: "mr-launch-workspace", value: workspace2, disabled: busy, placeholder: lastWorkspace ? `留空沿用上次运行:${lastWorkspace}` : "可填写项目绝对路径,最终使用的目录会显示在预览中", onChange: (event) => setWorkspace(event.target.value) })), /* @__PURE__ */ import_react58.default.createElement("details", { className: "mr-form-options" }, /* @__PURE__ */ import_react58.default.createElement("summary", null, "执行选项 · ", runExecutor === "official-team" ? "官方工具协作" : manual ? "手动分配" : "模型路由", " · ", runMode === "workspace-write" ? "编辑文件" : "只读", " · ", ROUTING_PRESETS[runPreset]?.label ?? runPreset), /* @__PURE__ */ import_react58.default.createElement("div", { className: "mr-controls" }, /* @__PURE__ */ import_react58.default.createElement("div", { className: "mr-control-group" }, /* @__PURE__ */ import_react58.default.createElement("span", { className: "mr-control-label", id: "mr-launch-executor" }, "执行方式"), /* @__PURE__ */ import_react58.default.createElement("div", { className: "mr-segment", role: "group", "aria-labelledby": "mr-launch-executor" }, /* @__PURE__ */ import_react58.default.createElement("button", { type: "button", "aria-pressed": runExecutor === "routed", disabled: busy, onClick: () => {
|
|
@@ -30933,7 +30933,7 @@ var xterm_default = `/**
|
|
|
30933
30933
|
`;
|
|
30934
30934
|
|
|
30935
30935
|
// .dsh-plugin/client/host-version.mjs
|
|
30936
|
-
var ROUTER_CLIENT_VERSION = "0.
|
|
30936
|
+
var ROUTER_CLIENT_VERSION = "0.65.0", STALE_HOST_MESSAGE = "插件后台版本较旧,请完全退出并重启 Harness(包括托盘图标)后再使用。";
|
|
30937
30937
|
function isMissingRemoteMethod(message2) {
|
|
30938
30938
|
let value = String(message2 ?? "");
|
|
30939
30939
|
return /transport failure for [^:]+: HTTP 404\b/.test(value) || /Remote method \S+ is no longer mounted/.test(value);
|
|
@@ -31267,7 +31267,7 @@ var THEME2 = Object.freeze({
|
|
|
31267
31267
|
cursor: "#d4d4d4",
|
|
31268
31268
|
selectionBackground: "#264f78"
|
|
31269
31269
|
});
|
|
31270
|
-
function TerminalPane({ api, session, active, onEnded, onStatus }) {
|
|
31270
|
+
function TerminalPane({ api, session, active: active2, onEnded, onStatus }) {
|
|
31271
31271
|
let host = import_react59.default.useRef(null), [error, setError] = import_react59.default.useState("");
|
|
31272
31272
|
return import_react59.default.useEffect(() => {
|
|
31273
31273
|
let term = new Dl({
|
|
@@ -31309,7 +31309,7 @@ function TerminalPane({ api, session, active, onEnded, onStatus }) {
|
|
|
31309
31309
|
return observer?.observe(host.current), refit(), connection.start(), term.focus(), () => {
|
|
31310
31310
|
observer?.disconnect(), input.dispose(), resized.dispose(), connection.stop(), term.dispose();
|
|
31311
31311
|
};
|
|
31312
|
-
}, [session.sessionId]), /* @__PURE__ */ import_react59.default.createElement("div", { className: "mr-term-pane", style: { display:
|
|
31312
|
+
}, [session.sessionId]), /* @__PURE__ */ import_react59.default.createElement("div", { className: "mr-term-pane", style: { display: active2 ? "block" : "none" } }, session.limitation && /* @__PURE__ */ import_react59.default.createElement("p", { className: "mr-caption mr-term-warning" }, session.limitation, session.ptyError ? `(${session.ptyError})` : ""), error && /* @__PURE__ */ import_react59.default.createElement("p", { className: "mr-caption mr-term-warning", role: "alert" }, error), /* @__PURE__ */ import_react59.default.createElement("div", { className: "mr-term-screen", ref: host }));
|
|
31313
31313
|
}
|
|
31314
31314
|
function CliTerminalCard({ api, health, settingsSignature = "" }) {
|
|
31315
31315
|
let [info, setInfo] = import_react59.default.useState({ status: "loading", value: null, error: "" }), [target, setTarget] = import_react59.default.useState("shell"), [mode, setMode] = import_react59.default.useState("interactive"), [cwd, setCwd] = import_react59.default.useState(storedCwd), [confirming, setConfirming] = import_react59.default.useState(!1), [starting, setStarting] = import_react59.default.useState(!1), [startError, setStartError] = import_react59.default.useState(""), [sessions, setSessions] = import_react59.default.useState([]), [activeId, setActiveId] = import_react59.default.useState(""), [tools, setTools] = import_react59.default.useState(health?.tools ?? []), mounted = import_react59.default.useRef(!0), refresher = import_react59.default.useRef(null);
|
|
@@ -31360,7 +31360,7 @@ function CliTerminalCard({ api, health, settingsSignature = "" }) {
|
|
|
31360
31360
|
onStatus(sessionId, status);
|
|
31361
31361
|
} catch {
|
|
31362
31362
|
}
|
|
31363
|
-
},
|
|
31363
|
+
}, active2 = sessions.find((item) => item.sessionId === activeId), history = info.value?.history ?? [];
|
|
31364
31364
|
return /* @__PURE__ */ import_react59.default.createElement("section", { className: "mr-card", "aria-label": "官方工具终端" }, /* @__PURE__ */ import_react59.default.createElement("style", null, xterm_default), /* @__PURE__ */ import_react59.default.createElement("div", { className: "mr-card-head" }, /* @__PURE__ */ import_react59.default.createElement("div", null, /* @__PURE__ */ import_react59.default.createElement("h2", { className: "mr-card-title" }, "官方工具终端"), /* @__PURE__ */ import_react59.default.createElement("p", { className: "mr-card-copy" }, "在工作台里交互式运行 PowerShell、已安装的 CLI(包括独立 ZCode CLI TUI)(多轮对话、实时输出,可用于 ", /* @__PURE__ */ import_react59.default.createElement("code", null, "codex login"), " 等登录)。启动入口与官方工具的安装方式和目录同步。终端不经过 Harness 沙箱,使用你自己的登录和环境变量。")), /* @__PURE__ */ import_react59.default.createElement("button", { className: "mr-button mr-button-secondary", type: "button", onClick: () => {
|
|
31365
31365
|
loadInfo();
|
|
31366
31366
|
} }, "刷新")), /* @__PURE__ */ import_react59.default.createElement("div", { className: "mr-card-body" }, info.status === "error" && /* @__PURE__ */ import_react59.default.createElement("div", { className: "mr-error", role: "alert" }, info.error), info.value && /* @__PURE__ */ import_react59.default.createElement("p", { className: "mr-caption" }, info.value.backend === "pty" ? "终端组件:伪终端(PTY),支持全屏界面、颜色和窗口大小同步。" : `终端组件:管道模式。${info.value.limitation ?? ""}${info.value.ptyError ? `(PTY 加载失败:${info.value.ptyError})` : ""}`), /* @__PURE__ */ import_react59.default.createElement("div", { className: "mr-controls" }, /* @__PURE__ */ import_react59.default.createElement("div", { className: "mr-control-group" }, /* @__PURE__ */ import_react59.default.createElement("label", { className: "mr-control-label", htmlFor: "mr-term-target" }, "启动"), /* @__PURE__ */ import_react59.default.createElement("select", { className: "mr-input", id: "mr-term-target", value: selected?.id ?? "shell", onChange: (event) => {
|
|
@@ -31387,7 +31387,7 @@ function CliTerminalCard({ api, health, settingsSignature = "" }) {
|
|
|
31387
31387
|
start();
|
|
31388
31388
|
} }, starting ? "正在启动…" : "确认启动"), /* @__PURE__ */ import_react59.default.createElement("button", { className: "mr-button mr-button-secondary", type: "button", disabled: starting, onClick: () => setConfirming(!1) }, "取消"))), startError && /* @__PURE__ */ import_react59.default.createElement("p", { className: "mr-error", role: "alert" }, startError), sessions.length > 0 && /* @__PURE__ */ import_react59.default.createElement("div", { className: "mr-term-tabs", role: "tablist", "aria-label": "终端会话" }, sessions.map((item) => /* @__PURE__ */ import_react59.default.createElement("div", { key: item.sessionId, className: "mr-term-tab", role: "tab", "aria-selected": item.sessionId === activeId }, /* @__PURE__ */ import_react59.default.createElement("button", { type: "button", className: "mr-term-tab-label", onClick: () => setActiveId(item.sessionId), title: `${item.display} · ${item.cwd}` }, item.label, item.mode === "login" ? " · 登录" : "", item.ended ? item.stopRequested && !item.stopConfirmed ? " · 已退出(派生进程未确认)" : " · 已结束" : item.stopRequested ? item.exited ? " · 宿主已退出(停止未确认)" : " · 停止中" : item.exited && item.treeTracking ? " · 宿主已退出(后代待确认)" : ""), item.ended ? /* @__PURE__ */ import_react59.default.createElement("button", { type: "button", className: "mr-term-tab-close", "aria-label": "关闭标签", onClick: () => closeTab(item.sessionId) }, "×") : /* @__PURE__ */ import_react59.default.createElement("button", { type: "button", className: "mr-term-tab-close", "aria-label": item.stopRequested ? "停止未确认" : "结束会话", title: item.stopRequested ? "停止已请求,等待实际退出" : "结束会话", disabled: item.stopRequested, onClick: () => {
|
|
31389
31389
|
stopSession(item.sessionId);
|
|
31390
|
-
} }, "■")))), sessions.map((item) => /* @__PURE__ */ import_react59.default.createElement(TerminalPane, { key: item.sessionId, api, session: item, active: item.sessionId === activeId, onEnded, onStatus })),
|
|
31390
|
+
} }, "■")))), sessions.map((item) => /* @__PURE__ */ import_react59.default.createElement(TerminalPane, { key: item.sessionId, api, session: item, active: item.sessionId === activeId, onEnded, onStatus })), active2 && /* @__PURE__ */ import_react59.default.createElement("p", { className: "mr-caption" }, active2.ended ? endDescription(active2.ended) : active2.stopRequested || active2.exited && active2.treeTracking ? endDescription(active2) : `${active2.display} · ${active2.cwd} · 选中文字后 Ctrl+C 复制,Ctrl+Shift+V 粘贴;拖动右下角可调整高度。`), history.length > 0 && /* @__PURE__ */ import_react59.default.createElement("details", { className: "mr-term-history" }, /* @__PURE__ */ import_react59.default.createElement("summary", null, "最近的终端会话(不记录输入、输出或环境变量)"), /* @__PURE__ */ import_react59.default.createElement("table", { className: "mr-term-table" }, /* @__PURE__ */ import_react59.default.createElement("thead", null, /* @__PURE__ */ import_react59.default.createElement("tr", null, /* @__PURE__ */ import_react59.default.createElement("th", null, "开始"), /* @__PURE__ */ import_react59.default.createElement("th", null, "工具"), /* @__PURE__ */ import_react59.default.createElement("th", null, "工作目录"), /* @__PURE__ */ import_react59.default.createElement("th", null, "时长"), /* @__PURE__ */ import_react59.default.createElement("th", null, "结果"))), /* @__PURE__ */ import_react59.default.createElement("tbody", null, history.map((item) => /* @__PURE__ */ import_react59.default.createElement("tr", { key: item.id }, /* @__PURE__ */ import_react59.default.createElement("td", null, item.startedAt ? new Date(item.startedAt).toLocaleString() : "—"), /* @__PURE__ */ import_react59.default.createElement("td", null, item.label, item.mode === "login" ? " · 登录" : "", item.backend === "pipe" ? " · 管道" : ""), /* @__PURE__ */ import_react59.default.createElement("td", { title: item.cwd }, item.cwd), /* @__PURE__ */ import_react59.default.createElement("td", null, formatDuration(item.durationMs)), /* @__PURE__ */ import_react59.default.createElement("td", null, endDescription(item)))))))));
|
|
31391
31391
|
}
|
|
31392
31392
|
|
|
31393
31393
|
// .dsh-plugin/client/router-main.css
|
|
@@ -31786,8 +31786,8 @@ var money2 = (value) => value == null ? "价格待配置" : `$${Number(value).to
|
|
|
31786
31786
|
value.allowManualReassign,
|
|
31787
31787
|
...Object.keys(ADAPTIVE_DEFAULTS).map((key) => value[key] ?? ADAPTIVE_DEFAULTS[key])
|
|
31788
31788
|
]);
|
|
31789
|
-
function RouterPanelIcon({ size = 20, active = !1 }) {
|
|
31790
|
-
return /* @__PURE__ */ import_react60.default.createElement("svg", { width: size, height: size, viewBox: "0 0 24 24", fill: "none", "aria-hidden": "true" }, /* @__PURE__ */ import_react60.default.createElement("path", { d: "M7 6.5h7M7 17.5h7M15 6.5v11", stroke: "currentColor", strokeWidth: "1.8", strokeLinecap: "round" }), /* @__PURE__ */ import_react60.default.createElement("circle", { cx: "5", cy: "6.5", r: "2", fill:
|
|
31789
|
+
function RouterPanelIcon({ size = 20, active: active2 = !1 }) {
|
|
31790
|
+
return /* @__PURE__ */ import_react60.default.createElement("svg", { width: size, height: size, viewBox: "0 0 24 24", fill: "none", "aria-hidden": "true" }, /* @__PURE__ */ import_react60.default.createElement("path", { d: "M7 6.5h7M7 17.5h7M15 6.5v11", stroke: "currentColor", strokeWidth: "1.8", strokeLinecap: "round" }), /* @__PURE__ */ import_react60.default.createElement("circle", { cx: "5", cy: "6.5", r: "2", fill: active2 ? "currentColor" : "none", stroke: "currentColor", strokeWidth: "1.6" }), /* @__PURE__ */ import_react60.default.createElement("circle", { cx: "5", cy: "17.5", r: "2", fill: active2 ? "currentColor" : "none", stroke: "currentColor", strokeWidth: "1.6" }), /* @__PURE__ */ import_react60.default.createElement("circle", { cx: "17", cy: "12", r: "3", fill: active2 ? "currentColor" : "none", stroke: "currentColor", strokeWidth: "1.7" }));
|
|
31791
31791
|
}
|
|
31792
31792
|
function RouteList({ routes, query }) {
|
|
31793
31793
|
let filtered = routes.filter((route2) => `${route2.providerName} ${route2.provider} ${route2.name} ${route2.model}`.toLowerCase().includes(query.toLowerCase()));
|
|
@@ -32003,8 +32003,8 @@ function OfficialToolsCard({ listOfficialTools, loadOfficialInstallSettings, ins
|
|
|
32003
32003
|
next !== previous && (previous = next, request.current += 1, setProbeSettingsStale(!0), setProbeState((previous2) => ({ ...previous2, status: "ready", probes: [], readiness: [], error: "" })), onProbes({ probes: [], capabilities: [], readiness: [] }), previewPendingRef.current = !0, setPreviewPending(!0), refreshInstallSettingsRef.current());
|
|
32004
32004
|
});
|
|
32005
32005
|
}, [settingsScope]), import_react60.default.useEffect(() => {
|
|
32006
|
-
let
|
|
32007
|
-
if (
|
|
32006
|
+
let active2 = Object.values(jobs).filter((job) => job?.status === "running").map((job) => job.tool);
|
|
32007
|
+
if (active2.length === 0 || typeof officialToolInstallStatus != "function") return;
|
|
32008
32008
|
let listening = !0, poll = async (id2) => {
|
|
32009
32009
|
if (!polling.current.has(id2)) {
|
|
32010
32010
|
polling.current.add(id2);
|
|
@@ -32028,7 +32028,7 @@ function OfficialToolsCard({ listOfficialTools, loadOfficialInstallSettings, ins
|
|
|
32028
32028
|
polling.current.delete(id2);
|
|
32029
32029
|
}
|
|
32030
32030
|
}
|
|
32031
|
-
}, timer = setInterval(() =>
|
|
32031
|
+
}, timer = setInterval(() => active2.forEach((id2) => {
|
|
32032
32032
|
poll(id2);
|
|
32033
32033
|
}), 1500);
|
|
32034
32034
|
return () => {
|
|
@@ -33277,7 +33277,10 @@ var TASK_STATES = Object.freeze({
|
|
|
33277
33277
|
}), money3 = (value) => typeof value == "number" && Number.isFinite(value) ? `USD ${value.toFixed(6)}` : "未知(待收据核对)", modelName = (model) => typeof model == "string" ? model : model?.provider && (model?.model ?? model?.id) ? `${model.provider}/${model.model ?? model.id}` : "尚未选择准确模型";
|
|
33278
33278
|
|
|
33279
33279
|
// apps/integration-client/panels.jsx
|
|
33280
|
-
var
|
|
33280
|
+
var import_react68 = __toESM(require("react"), 1);
|
|
33281
|
+
|
|
33282
|
+
// apps/integration-client/tasks-panel.jsx
|
|
33283
|
+
var import_react63 = __toESM(require("react"), 1);
|
|
33281
33284
|
|
|
33282
33285
|
// apps/integration-client/bot-attention.mjs
|
|
33283
33286
|
var BOT_ATTENTION_STAGES = Object.freeze(["reconcile", "approve", "remote-unknown", "budget", "failed", "blocked"]), STAGE_ORDER2 = new Map(BOT_ATTENTION_STAGES.map((stage, index) => [stage, index])), TERMINAL = /* @__PURE__ */ new Set(["cancelled", "succeeded", "failed", "skipped"]), short2 = (value, limit = 80) => {
|
|
@@ -33318,7 +33321,7 @@ function deriveBotAttention(snapshot, { limit = 6 } = {}) {
|
|
|
33318
33321
|
);
|
|
33319
33322
|
continue;
|
|
33320
33323
|
}
|
|
33321
|
-
if (task.state === "waiting-budget"
|
|
33324
|
+
if (task.state === "waiting-budget") {
|
|
33322
33325
|
add(
|
|
33323
33326
|
"budget",
|
|
33324
33327
|
`budget:${id2}`,
|
|
@@ -33369,6 +33372,157 @@ function botAttentionSummary(rows2 = []) {
|
|
|
33369
33372
|
return urgent > 0 ? `${count} 项需要你处理(${urgent} 项卡在确认上)` : `${count} 项需要你处理`;
|
|
33370
33373
|
}
|
|
33371
33374
|
|
|
33375
|
+
// apps/integration-client/task-progress.mjs
|
|
33376
|
+
var taskIdOf = (row) => row.taskId ?? row.id, taskKey = (row) => JSON.stringify([row.botId ?? "", taskIdOf(row)]), taskTitle = (row) => row.title || row.input?.task || taskIdOf(row) || "未命名任务", TASK_FILTERS = Object.freeze([["all", "全部"], ["active", "进行中"], ["attention", "待处理"], ["finished", "已结束"]]), active = /* @__PURE__ */ new Set(["queued", "ready", "running", "admitting", "cancelling"]), ended = /* @__PURE__ */ new Set(["succeeded", "cancelled", "skipped"]);
|
|
33377
|
+
function taskProgress(snapshot) {
|
|
33378
|
+
let items = snapshot?.tasks?.status === "available" && Array.isArray(snapshot.tasks.items) ? snapshot.tasks.items : [], attention = deriveBotAttention({ ...snapshot, tasks: { items } }, { limit: 1 / 0 }), attentionKeys = new Set(attention.map((row) => taskKey(row))), category = (row) => attentionKeys.has(taskKey(row)) ? "attention" : active.has(row.state) ? "active" : ended.has(row.state) ? "finished" : "other", bots = new Map((snapshot?.bots ?? []).map((bot) => [bot.id, { botId: bot.id, name: bot.name, all: 0, active: 0, attention: 0, finished: 0, other: 0 }])), counts2 = { all: items.length, active: 0, attention: 0, finished: 0, other: 0 };
|
|
33379
|
+
for (let row of items) {
|
|
33380
|
+
let kind = category(row);
|
|
33381
|
+
counts2[kind]++, bots.has(row.botId) || bots.set(row.botId, { botId: row.botId, name: row.botId || "未取得归属", all: 0, active: 0, attention: 0, finished: 0, other: 0 });
|
|
33382
|
+
let bot = bots.get(row.botId);
|
|
33383
|
+
bot.all++, bot[kind]++;
|
|
33384
|
+
}
|
|
33385
|
+
return { items, attention, counts: counts2, bots: [...bots.values()], category };
|
|
33386
|
+
}
|
|
33387
|
+
function filterTasks(progress, { botId = "", status = "all", query = "" } = {}) {
|
|
33388
|
+
let names = new Map(progress.bots.map((bot) => [bot.botId, bot.name])), text7 = query.trim().toLocaleLowerCase();
|
|
33389
|
+
return progress.items.filter((row) => (!botId || row.botId === botId) && (status === "all" || progress.category(row) === status) && (!text7 || [taskTitle(row), row.botId, names.get(row.botId), taskIdOf(row), row.planId, row.operationId, row.attemptId].some((value) => typeof value == "string" && value.toLocaleLowerCase().includes(text7))));
|
|
33390
|
+
}
|
|
33391
|
+
var TASK_EVENTS = Object.freeze({
|
|
33392
|
+
queued: "任务已排队",
|
|
33393
|
+
dispatched: "开始执行",
|
|
33394
|
+
"admission-prepared": "开始资金准入",
|
|
33395
|
+
"admission-reference-prepared": "执行引用已保存",
|
|
33396
|
+
"financial-admission-committed": "资金准入已提交",
|
|
33397
|
+
"execution-linked-before-admission": "已关联原执行记录",
|
|
33398
|
+
settled: "本次尝试已结算",
|
|
33399
|
+
"cancel-requested": "已请求停止,等待确认",
|
|
33400
|
+
"cancel-requested-unconfirmed": "已请求停止,原操作仍待核对",
|
|
33401
|
+
"plan-cancel-requested": "已请求停止整个计划",
|
|
33402
|
+
"cancelled-before-dispatch": "启动前已停止",
|
|
33403
|
+
"cancelled-while-waiting-budget": "等待预算期间已停止",
|
|
33404
|
+
"dependency-blocked": "前置任务失败,尚未执行",
|
|
33405
|
+
interrupted: "宿主中断,执行结果待核对",
|
|
33406
|
+
reconciled: "已核对原执行记录",
|
|
33407
|
+
blocked: "任务受阻",
|
|
33408
|
+
deadline: "已到任务期限",
|
|
33409
|
+
"budget-wait-expired": "预算等待已到期",
|
|
33410
|
+
"retry-fenced": "重试已被拦截",
|
|
33411
|
+
"admission-conflict": "资金准入记录冲突,需核对",
|
|
33412
|
+
"dispatch-closed-before-entry": "启动前已阻止派发",
|
|
33413
|
+
"admission-closed-not-dispatched": "已确认未派发",
|
|
33414
|
+
"admission-recovered-cancelled": "恢复时确认启动前已停止",
|
|
33415
|
+
"admission-recovered-not-dispatched": "恢复时确认原操作未派发"
|
|
33416
|
+
});
|
|
33417
|
+
|
|
33418
|
+
// apps/integration-client/ui-icons.jsx
|
|
33419
|
+
var import_react62 = __toESM(require("react"), 1), paths = {
|
|
33420
|
+
bot: ["M8 4h8l4 4v8l-4 4H8l-4-4V8Z", "M9 10v3m6-3v3"],
|
|
33421
|
+
team: ["M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2m20 0v-2a4 4 0 0 0-3-3.87", "M9 11a4 4 0 1 0 0-8 4 4 0 0 0 0 8m8-7.87a4 4 0 0 1 0 7.75"],
|
|
33422
|
+
tasks: ["M9 5H6a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7a2 2 0 0 0-2-2h-3", "M9 3h6v4H9Zm-1 10 2 2 5-5m-7 8h8"],
|
|
33423
|
+
computer: ["M4 4h16a1 1 0 0 1 1 1v11a1 1 0 0 1-1 1H4a1 1 0 0 1-1-1V5a1 1 0 0 1 1-1Z", "M8 21h8m-4-4v4"],
|
|
33424
|
+
folder: ["M3 7V5a2 2 0 0 1 2-2h5l2 3h7a2 2 0 0 1 2 2v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2Zm0 1h18"],
|
|
33425
|
+
repeat: ["m17 2 4 4-4 4M3 11V8a2 2 0 0 1 2-2h16M7 22l-4-4 4-4m14-1v3a2 2 0 0 1-2 2H3"],
|
|
33426
|
+
chart: ["M4 3v17h17M9 15V9m5 6V5m5 10v-4"],
|
|
33427
|
+
settings: ["M4 7h7m4 0h5M4 17h3m4 0h9", "M11 4v6m-4 4v6m8-16v6m-4 4v6"],
|
|
33428
|
+
refresh: ["M20 7v5h-5M4 17v-5h5", "M6.1 6.1A8 8 0 0 1 19.5 9M4.5 15a8 8 0 0 0 13.4 2.9"],
|
|
33429
|
+
search: ["M11 18a7 7 0 1 0 0-14 7 7 0 0 0 0 14m5-2 5 5"],
|
|
33430
|
+
upload: ["M12 16V3m-5 5 5-5 5 5M4 15v4a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2v-4"],
|
|
33431
|
+
plus: ["M12 5v14M5 12h14"],
|
|
33432
|
+
file: ["M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8Zm0 0v6h6", "M8 13h8m-8 4h5"],
|
|
33433
|
+
arrow: ["M7 17 17 7M7 7h10v10"],
|
|
33434
|
+
chevron: ["m9 5 7 7-7 7"],
|
|
33435
|
+
back: ["m12 5-7 7 7 7m-7-7h14"],
|
|
33436
|
+
expand: ["M8 3H3v5m13-5h5v5M3 16v5h5m13-5v5h-5"],
|
|
33437
|
+
check: ["m5 12 4 4L19 6"],
|
|
33438
|
+
play: ["m8 4 12 8-12 8Z"],
|
|
33439
|
+
lock: ["M5 10h14v11H5Zm3 0V7a4 4 0 0 1 8 0v3m-4 4v3"]
|
|
33440
|
+
};
|
|
33441
|
+
function UiIcon({ name, size = 18, className = "", ...props }) {
|
|
33442
|
+
return /* @__PURE__ */ import_react62.default.createElement(
|
|
33443
|
+
"svg",
|
|
33444
|
+
{
|
|
33445
|
+
className: `bp-icon ${className}`,
|
|
33446
|
+
width: size,
|
|
33447
|
+
height: size,
|
|
33448
|
+
viewBox: "0 0 24 24",
|
|
33449
|
+
fill: "none",
|
|
33450
|
+
stroke: "currentColor",
|
|
33451
|
+
strokeWidth: "1.65",
|
|
33452
|
+
strokeLinecap: "round",
|
|
33453
|
+
strokeLinejoin: "round",
|
|
33454
|
+
"aria-hidden": "true",
|
|
33455
|
+
focusable: "false",
|
|
33456
|
+
...props
|
|
33457
|
+
},
|
|
33458
|
+
(paths[name] ?? paths.bot).map((d, index) => /* @__PURE__ */ import_react62.default.createElement("path", { key: index, d }))
|
|
33459
|
+
);
|
|
33460
|
+
}
|
|
33461
|
+
|
|
33462
|
+
// apps/integration-client/tasks-panel.jsx
|
|
33463
|
+
var Tag2 = ({ children }) => /* @__PURE__ */ import_react63.default.createElement("span", { className: "bp-tag" }, children), date = (value) => value == null || !Number.isFinite(new Date(value).getTime()) ? "未取得" : new Date(value).toLocaleString("zh-CN"), Value = ({ label, children }) => /* @__PURE__ */ import_react63.default.createElement("div", { className: "bp-value" }, /* @__PURE__ */ import_react63.default.createElement("dt", null, label), /* @__PURE__ */ import_react63.default.createElement("dd", null, children ?? "未取得")), stopKnown = (row) => !row.result?.remote || row.result.remote.stopConfirmed === !0;
|
|
33464
|
+
function TaskActions({ row, actions, dispatch, busy }) {
|
|
33465
|
+
let pending = (0, import_react63.useRef)(!1), run2 = async (action) => {
|
|
33466
|
+
if (!(busy || pending.current || !dispatch || !actions.includes(action))) {
|
|
33467
|
+
pending.current = !0;
|
|
33468
|
+
try {
|
|
33469
|
+
await dispatch(action, { botId: row.botId, taskId: taskIdOf(row), ...action === "task.cancel" ? {} : { requestKey: crypto.randomUUID() } });
|
|
33470
|
+
} finally {
|
|
33471
|
+
pending.current = !1;
|
|
33472
|
+
}
|
|
33473
|
+
}
|
|
33474
|
+
};
|
|
33475
|
+
return /* @__PURE__ */ import_react63.default.createElement(import_react63.default.Fragment, null, actions.includes("task.cancel") && !["cancelled", "succeeded", "failed", "skipped"].includes(row.state) && /* @__PURE__ */ import_react63.default.createElement("button", { disabled: busy, onClick: () => {
|
|
33476
|
+
run2("task.cancel");
|
|
33477
|
+
} }, "停止"), actions.includes("task.retry") && ["failed", "cancelled", "waiting-budget"].includes(row.state) && /* @__PURE__ */ import_react63.default.createElement("button", { disabled: busy || !stopKnown(row), onClick: () => {
|
|
33478
|
+
stopKnown(row) && run2("task.retry");
|
|
33479
|
+
} }, "重试"), actions.includes("task.reconcile") && row.state === "needs-reconciliation" && /* @__PURE__ */ import_react63.default.createElement("button", { disabled: busy, onClick: () => {
|
|
33480
|
+
run2("task.reconcile");
|
|
33481
|
+
} }, "核对原收据"));
|
|
33482
|
+
}
|
|
33483
|
+
function RemoteNotice({ row }) {
|
|
33484
|
+
let remote = row.result?.remote;
|
|
33485
|
+
return remote ? stopKnown(row) ? remote.notStarted === !0 && remote.possiblyApplied !== !0 ? /* @__PURE__ */ import_react63.default.createElement("small", null, "原操作未启动。") : remote.status === "succeeded" ? /* @__PURE__ */ import_react63.default.createElement("small", null, "写入已确认。", row.state === "cancelled" ? "取消未撤销文件变更。" : "") : remote.possiblyApplied === !0 ? /* @__PURE__ */ import_react63.default.createElement("small", null, "操作已停止,文件可能已改变;重试不会撤销已有变更,请先核对产物。") : null : /* @__PURE__ */ import_react63.default.createElement("small", { role: "status" }, "写入或停止尚未确认,请核对原操作;不会自动重发,也暂不能重试。") : null;
|
|
33486
|
+
}
|
|
33487
|
+
function TaskDetail({ task, inspect, busy, actions, dispatch, onClose, bot, openSession }) {
|
|
33488
|
+
let [history, setHistory] = (0, import_react63.useState)(null), [failure, setFailure] = (0, import_react63.useState)(""), [loading, setLoading] = (0, import_react63.useState)(!1), [reload, setReload] = (0, import_react63.useState)(0), ref = (0, import_react63.useRef)(null), key = taskKey(task);
|
|
33489
|
+
(0, import_react63.useEffect)(() => {
|
|
33490
|
+
ref.current?.focus({ preventScroll: !0 }), ref.current?.scrollIntoView?.({ block: "nearest" });
|
|
33491
|
+
}, [key]), (0, import_react63.useEffect)(() => {
|
|
33492
|
+
let controller = new AbortController();
|
|
33493
|
+
return setHistory(null), setFailure(""), setLoading(!1), !inspect || !actions.includes("task.inspect") ? () => controller.abort() : (setLoading(!0), Promise.resolve().then(() => {
|
|
33494
|
+
if (!controller.signal.aborted) return inspect({ botId: task.botId, taskId: taskIdOf(task) }, controller.signal);
|
|
33495
|
+
}).then((value) => {
|
|
33496
|
+
if (!controller.signal.aborted) {
|
|
33497
|
+
if (!value?.task || taskKey(value.task) !== key || !Array.isArray(value.attempts) || !Array.isArray(value.timeline?.items) || task.updatedAt != null && (!Number.isFinite(value.task.updatedAt) || value.task.updatedAt < task.updatedAt)) throw new Error("返回记录与当前任务不一致,请刷新后再次读取。");
|
|
33498
|
+
setHistory(value);
|
|
33499
|
+
}
|
|
33500
|
+
}).catch((cause) => {
|
|
33501
|
+
controller.signal.aborted || setFailure(cause.message || "任务时间线读取失败。");
|
|
33502
|
+
}).finally(() => {
|
|
33503
|
+
controller.signal.aborted || setLoading(!1);
|
|
33504
|
+
}), () => controller.abort());
|
|
33505
|
+
}, [key, task.updatedAt, inspect, actions.includes("task.inspect"), reload]);
|
|
33506
|
+
let data = history?.task ?? task;
|
|
33507
|
+
return /* @__PURE__ */ import_react63.default.createElement("article", { className: "bp-card bp-task-detail", "aria-label": "任务详情", ref, tabIndex: -1 }, /* @__PURE__ */ import_react63.default.createElement("div", { className: "bp-card-title" }, /* @__PURE__ */ import_react63.default.createElement("div", null, /* @__PURE__ */ import_react63.default.createElement("h2", null, "任务详情"), /* @__PURE__ */ import_react63.default.createElement("p", null, taskTitle(task))), /* @__PURE__ */ import_react63.default.createElement("button", { type: "button", onClick: onClose }, "关闭")), /* @__PURE__ */ import_react63.default.createElement("div", { className: "bp-actions" }, /* @__PURE__ */ import_react63.default.createElement(Tag2, null, TASK_STATES[data.state] ?? data.state), /* @__PURE__ */ import_react63.default.createElement("span", null, bot?.name ?? task.botId ?? "未取得归属"), bot?.sessionId && openSession && /* @__PURE__ */ import_react63.default.createElement("button", { type: "button", onClick: () => openSession(bot.sessionId) }, "打开 Bot 私聊"), /* @__PURE__ */ import_react63.default.createElement(TaskActions, { row: data, actions, dispatch, busy })), /* @__PURE__ */ import_react63.default.createElement(RemoteNotice, { row: data }), /* @__PURE__ */ import_react63.default.createElement("dl", { className: "bp-facts" }, /* @__PURE__ */ import_react63.default.createElement(Value, { label: "创建" }, date(data.createdAt)), /* @__PURE__ */ import_react63.default.createElement(Value, { label: "最近更新" }, date(data.updatedAt)), /* @__PURE__ */ import_react63.default.createElement(Value, { label: "期限" }, date(data.deadlineAt))), /* @__PURE__ */ import_react63.default.createElement("h3", null, "任务时间线"), loading && /* @__PURE__ */ import_react63.default.createElement("p", { role: "status", className: "bp-muted" }, "正在读取原任务日志…"), failure && /* @__PURE__ */ import_react63.default.createElement("p", { role: "alert", className: "bp-error" }, failure), inspect && actions.includes("task.inspect") && /* @__PURE__ */ import_react63.default.createElement("button", { type: "button", disabled: loading, onClick: () => setReload((value) => value + 1) }, "重新读取时间线"), !actions.includes("task.inspect") && /* @__PURE__ */ import_react63.default.createElement("p", { className: "bp-muted" }, "此宿主尚未提供任务时间线,可在下方查看现有收据依据。"), history && /* @__PURE__ */ import_react63.default.createElement(import_react63.default.Fragment, null, /* @__PURE__ */ import_react63.default.createElement("p", { className: "bp-muted" }, history.attempts.length, " 次执行尝试 · ", history.timeline.total, " 条日志", history.timeline.truncated ? `,显示最近 ${history.timeline.items.length} 条` : "", "。停止请求需等待原操作确认。"), /* @__PURE__ */ import_react63.default.createElement("ol", { className: "bp-task-timeline" }, history.timeline.items.map((event) => /* @__PURE__ */ import_react63.default.createElement("li", { key: event.seq }, /* @__PURE__ */ import_react63.default.createElement("span", { className: "bp-timeline-dot", "aria-hidden": "true" }), /* @__PURE__ */ import_react63.default.createElement("div", null, /* @__PURE__ */ import_react63.default.createElement("strong", null, TASK_EVENTS[event.kind] ?? "任务状态更新"), /* @__PURE__ */ import_react63.default.createElement("small", null, /* @__PURE__ */ import_react63.default.createElement("time", null, date(event.at)), event.attemptNumber != null ? ` · 第 ${event.attemptNumber} 次尝试` : "", event.outcome ? ` · ${TASK_STATES[event.outcome] ?? (event.outcome === "unknown" ? "结果未知" : event.outcome)}` : ""), event.code && /* @__PURE__ */ import_react63.default.createElement("small", { className: "bp-code" }, event.code))))), history.timeline.items.length === 0 && /* @__PURE__ */ import_react63.default.createElement("p", { className: "bp-muted" }, "原日志中暂无事件。"), /* @__PURE__ */ import_react63.default.createElement("details", { className: "bp-technical" }, /* @__PURE__ */ import_react63.default.createElement("summary", null, "每次尝试的身份与时间"), /* @__PURE__ */ import_react63.default.createElement("ul", { className: "bp-checklist" }, history.attempts.map((attempt) => /* @__PURE__ */ import_react63.default.createElement("li", { key: attempt.attemptId }, /* @__PURE__ */ import_react63.default.createElement("strong", null, "第 ", attempt.number, " 次 · ", TASK_STATES[attempt.state] ?? attempt.state), /* @__PURE__ */ import_react63.default.createElement("small", null, "开始 ", date(attempt.startedAt), " · 结束 ", date(attempt.finishedAt)), /* @__PURE__ */ import_react63.default.createElement("small", { className: "bp-code" }, attempt.attemptId, " · ", attempt.operationId)))))), /* @__PURE__ */ import_react63.default.createElement("details", { className: "bp-technical" }, /* @__PURE__ */ import_react63.default.createElement("summary", null, "原任务与操作编号"), /* @__PURE__ */ import_react63.default.createElement("dl", { className: "bp-facts" }, /* @__PURE__ */ import_react63.default.createElement(Value, { label: "Task" }, taskIdOf(data)), /* @__PURE__ */ import_react63.default.createElement(Value, { label: "Package" }, data.packageId), /* @__PURE__ */ import_react63.default.createElement(Value, { label: "Attempt" }, data.attemptId), /* @__PURE__ */ import_react63.default.createElement(Value, { label: "Operation" }, data.operationId), /* @__PURE__ */ import_react63.default.createElement(Value, { label: "MR 运行" }, data.legacyRunIds?.join("、")))), /* @__PURE__ */ import_react63.default.createElement("details", { className: "bp-technical" }, /* @__PURE__ */ import_react63.default.createElement("summary", null, "执行与收据依据"), /* @__PURE__ */ import_react63.default.createElement("pre", null, JSON.stringify({ attempts: history?.attempts ?? task.attempts, executionRef: task.executionRef, remoteReceipt: data.result?.remote, reconciliation: data.reconciliation, packages: task.packages }, null, 2))));
|
|
33508
|
+
}
|
|
33509
|
+
function TaskWorkspace({ snapshot, dispatch, busy, scope, inspect, openSession, routingCard }) {
|
|
33510
|
+
let progress = (0, import_react63.useMemo)(() => taskProgress(snapshot), [snapshot]), [botId, setBotId] = (0, import_react63.useState)(""), [status, setStatus] = (0, import_react63.useState)("all"), [query, setQuery] = (0, import_react63.useState)(""), [expanded, setExpanded] = (0, import_react63.useState)(!1), [selection, setSelection] = (0, import_react63.useState)(null);
|
|
33511
|
+
(0, import_react63.useEffect)(() => {
|
|
33512
|
+
setBotId(""), setStatus("all"), setQuery(""), setExpanded(!1), setSelection(null);
|
|
33513
|
+
}, [scope]);
|
|
33514
|
+
let rows2 = filterTasks(progress, { botId, status, query }), task = selection && selection.scope === scope ? progress.items.find((row) => taskKey(row) === selection.key) : null, actions = snapshot.availableActions ?? [], select = (row) => setSelection({ scope, key: taskKey(row) }), attention = expanded ? progress.attention : progress.attention.slice(0, 6), [showPlans, setShowPlans] = (0, import_react63.useState)(!1);
|
|
33515
|
+
return /* @__PURE__ */ import_react63.default.createElement(import_react63.default.Fragment, null, /* @__PURE__ */ import_react63.default.createElement("section", { className: "bp-card bp-task-overview", "aria-label": "多 Bot 任务总览" }, /* @__PURE__ */ import_react63.default.createElement("div", { className: "bp-card-title" }, /* @__PURE__ */ import_react63.default.createElement("div", null, /* @__PURE__ */ import_react63.default.createElement("h2", null, "团队任务"), /* @__PURE__ */ import_react63.default.createElement("p", { className: "bp-muted" }, "按 Bot 查看进展,优先处理需要你介入的任务。")), /* @__PURE__ */ import_react63.default.createElement(Tag2, null, progress.items.length, " 条已加载")), snapshot.tasks.truncated && /* @__PURE__ */ import_react63.default.createElement("p", { role: "status", className: "bp-blocked" }, "已加载 ", progress.items.length, " / ", snapshot.tasks.total, " 条任务,优先显示待处理与进行中的记录。下方数量与筛选仅针对已加载任务。"), /* @__PURE__ */ import_react63.default.createElement("div", { className: "bp-task-counts", "aria-label": "按状态筛选任务" }, TASK_FILTERS.map(([value, label]) => /* @__PURE__ */ import_react63.default.createElement("button", { key: value, type: "button", "aria-pressed": status === value, onClick: () => setStatus(value) }, /* @__PURE__ */ import_react63.default.createElement("strong", null, progress.counts[value]), /* @__PURE__ */ import_react63.default.createElement("span", null, label)))), /* @__PURE__ */ import_react63.default.createElement("div", { className: "bp-task-bots", "aria-label": "按 Bot 筛选任务" }, /* @__PURE__ */ import_react63.default.createElement("button", { type: "button", "aria-pressed": !botId, onClick: () => setBotId("") }, "全部 Bot"), progress.bots.map((bot) => /* @__PURE__ */ import_react63.default.createElement("button", { key: bot.botId ?? "", type: "button", "aria-pressed": botId === bot.botId, onClick: () => setBotId(bot.botId ?? "") }, /* @__PURE__ */ import_react63.default.createElement(UiIcon, { name: "bot", size: 16 }), /* @__PURE__ */ import_react63.default.createElement("span", null, bot.name, /* @__PURE__ */ import_react63.default.createElement("small", null, bot.active, " 进行中 · ", bot.attention, " 待处理 · ", bot.all, " 条任务")))))), progress.attention.length > 0 && /* @__PURE__ */ import_react63.default.createElement("section", { className: "bp-card bp-attention", "aria-label": "需要你处理" }, /* @__PURE__ */ import_react63.default.createElement("div", { className: "bp-card-title" }, /* @__PURE__ */ import_react63.default.createElement("h2", null, "需要你处理"), /* @__PURE__ */ import_react63.default.createElement(Tag2, null, botAttentionSummary(progress.attention))), /* @__PURE__ */ import_react63.default.createElement("ul", { className: "bp-attention-list" }, attention.map((row) => {
|
|
33516
|
+
let original = progress.items.find((task2) => taskKey(task2) === taskKey(row));
|
|
33517
|
+
return /* @__PURE__ */ import_react63.default.createElement("li", { key: taskKey(row), className: `bp-attention-row bp-attention-${row.stage}` }, /* @__PURE__ */ import_react63.default.createElement("div", null, /* @__PURE__ */ import_react63.default.createElement("strong", null, row.title), /* @__PURE__ */ import_react63.default.createElement("p", { className: "bp-muted" }, row.detail), row.stage === "approve" && /* @__PURE__ */ import_react63.default.createElement("small", null, "打开 Bot 私聊查看原审批请求。"), remoteUncertain(original) && /* @__PURE__ */ import_react63.default.createElement("small", null, "原操作仍待核对,请查看任务详情。")), /* @__PURE__ */ import_react63.default.createElement("div", { className: "bp-actions" }, /* @__PURE__ */ import_react63.default.createElement("button", { type: "button", onClick: () => select(original) }, "打开任务"), row.stage === "approve" && openSession && snapshot.bots?.find((bot) => bot.id === row.botId)?.sessionId && /* @__PURE__ */ import_react63.default.createElement("button", { type: "button", onClick: () => openSession(snapshot.bots.find((bot) => bot.id === row.botId).sessionId) }, "打开审批会话"), row.stage === "reconcile" && actions.includes("task.reconcile") && /* @__PURE__ */ import_react63.default.createElement(TaskActions, { row: original, actions: ["task.reconcile"], dispatch, busy }), row.stage === "failed" && actions.includes("task.retry") && /* @__PURE__ */ import_react63.default.createElement(TaskActions, { row: original, actions: ["task.retry"], dispatch, busy })));
|
|
33518
|
+
})), progress.attention.length > 6 && /* @__PURE__ */ import_react63.default.createElement("button", { type: "button", "aria-expanded": expanded, onClick: () => setExpanded((value) => !value) }, expanded ? "收起待处理事项" : `查看全部 ${progress.attention.length} 项待处理`)), task && /* @__PURE__ */ import_react63.default.createElement(TaskDetail, { key: taskKey(task), task, inspect, busy, actions, dispatch, onClose: () => setSelection(null), bot: snapshot.bots?.find((bot) => bot.id === task.botId), openSession }), /* @__PURE__ */ import_react63.default.createElement("section", { className: "bp-card", "aria-label": "任务记录" }, /* @__PURE__ */ import_react63.default.createElement("div", { className: "bp-card-title" }, /* @__PURE__ */ import_react63.default.createElement("h2", null, "任务记录"), /* @__PURE__ */ import_react63.default.createElement("span", { className: "bp-muted", role: "status" }, "显示 ", rows2.length, " / ", progress.items.length, " 条")), /* @__PURE__ */ import_react63.default.createElement("div", { className: "bp-task-search" }, /* @__PURE__ */ import_react63.default.createElement("label", null, "搜索任务", /* @__PURE__ */ import_react63.default.createElement("input", { type: "search", value: query, placeholder: "任务名称、Bot 或任务 / 计划 / 操作编号", onChange: (event) => setQuery(event.target.value) })), (query || botId || status !== "all") && /* @__PURE__ */ import_react63.default.createElement("button", { type: "button", onClick: () => {
|
|
33519
|
+
setQuery(""), setBotId(""), setStatus("all");
|
|
33520
|
+
} }, "清除筛选")), progress.items.length ? rows2.length === 0 ? /* @__PURE__ */ import_react63.default.createElement("p", { className: "bp-empty" }, "没有符合当前筛选的任务。可清除筛选查看其他记录。") : /* @__PURE__ */ import_react63.default.createElement("div", { className: "bp-table-wrap" }, /* @__PURE__ */ import_react63.default.createElement("table", null, /* @__PURE__ */ import_react63.default.createElement("thead", null, /* @__PURE__ */ import_react63.default.createElement("tr", null, /* @__PURE__ */ import_react63.default.createElement("th", null, "任务"), /* @__PURE__ */ import_react63.default.createElement("th", null, "Bot"), /* @__PURE__ */ import_react63.default.createElement("th", null, "状态"), /* @__PURE__ */ import_react63.default.createElement("th", null, "执行尝试"), /* @__PURE__ */ import_react63.default.createElement("th", null, "操作"))), /* @__PURE__ */ import_react63.default.createElement("tbody", null, rows2.map((row) => /* @__PURE__ */ import_react63.default.createElement("tr", { key: taskKey(row) }, /* @__PURE__ */ import_react63.default.createElement("td", null, /* @__PURE__ */ import_react63.default.createElement("button", { className: "bp-text-button", onClick: () => select(row) }, taskTitle(row)), /* @__PURE__ */ import_react63.default.createElement("small", null, "更新 ", date(row.updatedAt))), /* @__PURE__ */ import_react63.default.createElement("td", null, snapshot.bots?.find((bot) => bot.id === row.botId)?.name ?? row.botId ?? "未取得归属"), /* @__PURE__ */ import_react63.default.createElement("td", null, /* @__PURE__ */ import_react63.default.createElement(Tag2, null, TASK_STATES[row.state] ?? row.state), row.blockedReason && /* @__PURE__ */ import_react63.default.createElement("small", null, row.blockedReason), /* @__PURE__ */ import_react63.default.createElement(RemoteNotice, { row })), /* @__PURE__ */ import_react63.default.createElement("td", null, Number.isSafeInteger(row.attempts) ? row.attempts : row.attempts?.length ?? row.attemptCount ?? "未知"), /* @__PURE__ */ import_react63.default.createElement("td", { className: "bp-actions" }, /* @__PURE__ */ import_react63.default.createElement(TaskActions, { row, actions, dispatch, busy }))))))) : /* @__PURE__ */ import_react63.default.createElement("p", { className: "bp-empty" }, "尚无持久任务。在 Main 私聊中提出目标后,可在这里查看工作包、执行尝试与收据。")), snapshot.tasks.plans?.length > 0 && /* @__PURE__ */ import_react63.default.createElement("section", { className: "bp-task-plans" }, /* @__PURE__ */ import_react63.default.createElement("button", { type: "button", "aria-expanded": showPlans, onClick: () => setShowPlans((value) => !value) }, showPlans ? "收起协作计划" : `查看 ${snapshot.tasks.plans.length} 个协作计划`), snapshot.tasks.plans.filter((plan) => showPlans || plan.needsReconciliation || !["succeeded", "cancelled", "failed"].includes(plan.state)).map((plan, index) => /* @__PURE__ */ import_react63.default.createElement("article", { className: "bp-card", key: plan.planId }, /* @__PURE__ */ import_react63.default.createElement("div", { className: "bp-card-title" }, /* @__PURE__ */ import_react63.default.createElement("div", null, /* @__PURE__ */ import_react63.default.createElement("h2", null, "协作计划 ", index + 1), /* @__PURE__ */ import_react63.default.createElement("p", { className: "bp-muted" }, plan.packages.length, " 个工作包 · ", plan.packages.filter((item) => item.state === "succeeded").length, " 个已完成")), /* @__PURE__ */ import_react63.default.createElement("div", { className: "bp-actions" }, /* @__PURE__ */ import_react63.default.createElement(Tag2, null, TASK_STATES[plan.state] ?? plan.state), actions.includes("task.plan.cancel") && !["succeeded", "cancelled"].includes(plan.state) && /* @__PURE__ */ import_react63.default.createElement("button", { disabled: busy, onClick: () => dispatch("task.plan.cancel", { botId: plan.ownerBotId, planId: plan.planId }) }, "停止整个计划"))), plan.needsReconciliation && /* @__PURE__ */ import_react63.default.createElement("p", { role: "status" }, "有工作包停止尚未确认,请核对原收据;计划尚未完成停止。"), /* @__PURE__ */ import_react63.default.createElement("ul", { className: "bp-plan-list" }, plan.packages.map((item, step) => {
|
|
33521
|
+
let linked = progress.items.find((row) => taskIdOf(row) === item.taskId && row.botId === item.targetBotId);
|
|
33522
|
+
return /* @__PURE__ */ import_react63.default.createElement("li", { key: item.id }, /* @__PURE__ */ import_react63.default.createElement("span", { className: "bp-plan-step" }, item.state === "succeeded" ? /* @__PURE__ */ import_react63.default.createElement(UiIcon, { name: "check", size: 13 }) : step + 1), /* @__PURE__ */ import_react63.default.createElement("div", { className: "bp-plan-copy" }, linked ? /* @__PURE__ */ import_react63.default.createElement("button", { className: "bp-text-button", onClick: () => select(linked) }, taskTitle(linked)) : /* @__PURE__ */ import_react63.default.createElement("strong", null, plan.plan?.packages?.find((pkg) => pkg.id === item.id)?.objective ?? `工作包 ${step + 1}`), /* @__PURE__ */ import_react63.default.createElement("small", null, snapshot.bots?.find((bot) => bot.id === item.targetBotId)?.name ?? item.targetBotId, item.dependsOn.length > 0 && ` · 前置:${item.dependsOn.join("、")}`, item.result?.code === "DEPENDENCY_FAILED" && " · 前置包失败,尚未执行")), /* @__PURE__ */ import_react63.default.createElement(Tag2, null, TASK_STATES[item.state] ?? item.state));
|
|
33523
|
+
})), /* @__PURE__ */ import_react63.default.createElement("details", { className: "bp-technical bp-plan-id" }, /* @__PURE__ */ import_react63.default.createElement("summary", null, "计划编号"), /* @__PURE__ */ import_react63.default.createElement("p", { className: "bp-code" }, plan.planId))))), routingCard);
|
|
33524
|
+
}
|
|
33525
|
+
|
|
33372
33526
|
// apps/integration-client/pairing.mjs
|
|
33373
33527
|
var TOKEN = /^[A-Za-z0-9_-]{43}$/, ID = /^[A-Za-z0-9_.-]{1,128}$/, pick2 = (value, key) => {
|
|
33374
33528
|
let raw = value?.[key];
|
|
@@ -33470,11 +33624,11 @@ function framePoint({ clientX, clientY, rect, frame }) {
|
|
|
33470
33624
|
}
|
|
33471
33625
|
|
|
33472
33626
|
// apps/integration-client/binding-editor.jsx
|
|
33473
|
-
var
|
|
33627
|
+
var import_react64 = __toESM(require("react"), 1);
|
|
33474
33628
|
var route = (model) => model ? `${model.provider}/${model.model}` : "", workspace = (ref) => ref ? `${ref.machineId}/${ref.rootId}` : "";
|
|
33475
33629
|
function BotBindingEditor({ bot, record: record3, accounts, dispatch, busy }) {
|
|
33476
|
-
let [form, setForm] = (0,
|
|
33477
|
-
(0,
|
|
33630
|
+
let [form, setForm] = (0, import_react64.useState)(null);
|
|
33631
|
+
(0, import_react64.useEffect)(() => {
|
|
33478
33632
|
if (!record3) {
|
|
33479
33633
|
setForm(null);
|
|
33480
33634
|
return;
|
|
@@ -33507,8 +33661,8 @@ function BotBindingEditor({ bot, record: record3, accounts, dispatch, busy }) {
|
|
|
33507
33661
|
}
|
|
33508
33662
|
});
|
|
33509
33663
|
}, [bot.id, record3?.revision]);
|
|
33510
|
-
let model = (0,
|
|
33511
|
-
if (!record3 || !form) return /* @__PURE__ */
|
|
33664
|
+
let model = (0, import_react64.useMemo)(() => record3?.catalog.models.find((item) => route(item) === form?.model) ?? null, [record3, form?.model]), account = accounts.items.find((item) => item.provider === model?.provider);
|
|
33665
|
+
if (!record3 || !form) return /* @__PURE__ */ import_react64.default.createElement(Blocked, { value: { reason: "此 Bot 尚未取得绑定目录。" } });
|
|
33512
33666
|
let change = (key, value) => setForm((current) => ({ ...current, [key]: value })), selectedMachine = form.workspace.split("/")[0], selectedRoot = form.workspace.split("/").slice(1).join("/"), routing = form.routing ?? { preset: "", dailyBudgetUsd: "", monthlyBudgetUsd: "" }, enableAccount = () => dispatch("funding.account.save", {
|
|
33513
33667
|
scopeId: account.id,
|
|
33514
33668
|
expectedRevision: account.revision,
|
|
@@ -33544,74 +33698,28 @@ function BotBindingEditor({ bot, record: record3, accounts, dispatch, busy }) {
|
|
|
33544
33698
|
};
|
|
33545
33699
|
return dispatch("binding.save", { botId: bot.id, expectedRevision: record3.revision, settings });
|
|
33546
33700
|
}, cliMappings = (model?.cliModels ?? []).filter((item, index, items) => items.findIndex((other) => other.toolId === item.toolId && other.model === item.model) === index);
|
|
33547
|
-
return /* @__PURE__ */
|
|
33701
|
+
return /* @__PURE__ */ import_react64.default.createElement("details", { className: "bp-card", open: record3.status !== "available" }, /* @__PURE__ */ import_react64.default.createElement("summary", null, "配置并启用此 Bot"), /* @__PURE__ */ import_react64.default.createElement("form", { className: "bp-form", onSubmit: save }, /* @__PURE__ */ import_react64.default.createElement("label", null, "准确模型", /* @__PURE__ */ import_react64.default.createElement("select", { "aria-label": `${bot.name} 的绑定模型`, value: form.model, onChange: (event) => {
|
|
33548
33702
|
change("model", event.target.value), change("officialTools", []);
|
|
33549
|
-
}, required: !0 }, /* @__PURE__ */
|
|
33703
|
+
}, required: !0 }, /* @__PURE__ */ import_react64.default.createElement("option", { value: "", disabled: !0 }, "请选择"), record3.catalog.models.map((item) => /* @__PURE__ */ import_react64.default.createElement("option", { key: route(item), value: route(item) }, route(item))))), model && account && !account.enabled && /* @__PURE__ */ import_react64.default.createElement("aside", { className: "bp-blocked" }, /* @__PURE__ */ import_react64.default.createElement("strong", null, "资金范围尚未启用"), /* @__PURE__ */ import_react64.default.createElement("p", null, account.provider, " 需要本地预算上限;它不是厂商余额。"), /* @__PURE__ */ import_react64.default.createElement("label", null, "账户每日上限(USD)", /* @__PURE__ */ import_react64.default.createElement("input", { type: "number", min: "0", step: "0.01", value: form.accountDaily, onChange: (event) => change("accountDaily", event.target.value) })), /* @__PURE__ */ import_react64.default.createElement("label", null, "账户每月上限(USD)", /* @__PURE__ */ import_react64.default.createElement("input", { type: "number", min: "0", step: "0.01", value: form.accountMonthly, onChange: (event) => change("accountMonthly", event.target.value) })), /* @__PURE__ */ import_react64.default.createElement("button", { type: "button", disabled: busy, onClick: enableAccount }, "启用 ", account.provider, " 资金范围")), /* @__PURE__ */ import_react64.default.createElement("label", null, "工作区", /* @__PURE__ */ import_react64.default.createElement("select", { "aria-label": `${bot.name} 的绑定工作区`, value: form.workspace, onChange: (event) => change("workspace", event.target.value), required: !0 }, /* @__PURE__ */ import_react64.default.createElement("option", { value: "", disabled: !0 }, "请选择"), record3.catalog.machines.flatMap((machine) => machine.roots.map((root) => /* @__PURE__ */ import_react64.default.createElement("option", { key: `${machine.machineId}/${root.rootId}`, value: `${machine.machineId}/${root.rootId}` }, machine.label, " / ", root.label))))), /* @__PURE__ */ import_react64.default.createElement("label", null, "工作区权限", /* @__PURE__ */ import_react64.default.createElement("select", { value: form.workspaceMode, onChange: (event) => change("workspaceMode", event.target.value) }, /* @__PURE__ */ import_react64.default.createElement("option", { value: "read-only" }, "只读"), /* @__PURE__ */ import_react64.default.createElement("option", { value: "workspace-write" }, "允许写入"))), /* @__PURE__ */ import_react64.default.createElement("fieldset", null, /* @__PURE__ */ import_react64.default.createElement("legend", null, "Bot 路由策略"), /* @__PURE__ */ import_react64.default.createElement("p", { className: "bp-muted" }, "这个 Bot 派活给别人时用哪套取舍;留空表示沿用全局预设。"), /* @__PURE__ */ import_react64.default.createElement("label", null, "预设", /* @__PURE__ */ import_react64.default.createElement("select", { "aria-label": `${bot.name} 的路由预设`, value: routing.preset, onChange: (event) => change("routing", { ...routing, preset: event.target.value }) }, /* @__PURE__ */ import_react64.default.createElement("option", { value: "" }, "沿用全局"), /* @__PURE__ */ import_react64.default.createElement("option", { value: "economy" }, "省钱优先"), /* @__PURE__ */ import_react64.default.createElement("option", { value: "balanced" }, "均衡"), /* @__PURE__ */ import_react64.default.createElement("option", { value: "quality" }, "效果优先"))), /* @__PURE__ */ import_react64.default.createElement("label", null, "每日预算(USD)", /* @__PURE__ */ import_react64.default.createElement("input", { type: "number", min: "0", step: "0.01", value: routing.dailyBudgetUsd, onChange: (event) => change("routing", { ...routing, dailyBudgetUsd: event.target.value }), placeholder: "留空表示不单独限制" })), /* @__PURE__ */ import_react64.default.createElement("label", null, "每月预算(USD)", /* @__PURE__ */ import_react64.default.createElement("input", { type: "number", min: "0", step: "0.01", value: routing.monthlyBudgetUsd, onChange: (event) => change("routing", { ...routing, monthlyBudgetUsd: event.target.value }), placeholder: "留空表示不单独限制" }))), /* @__PURE__ */ import_react64.default.createElement("fieldset", null, /* @__PURE__ */ import_react64.default.createElement("legend", null, "路由与任务能力"), record3.catalog.capabilities.map((capability) => /* @__PURE__ */ import_react64.default.createElement("label", { key: capability.id }, /* @__PURE__ */ import_react64.default.createElement("input", { type: "checkbox", checked: form.capabilities.includes(capability.id), onChange: (event) => change("capabilities", event.target.checked ? [...form.capabilities, capability.id] : form.capabilities.filter((id2) => id2 !== capability.id)) }), capability.label))), cliMappings.length > 0 && /* @__PURE__ */ import_react64.default.createElement("fieldset", null, /* @__PURE__ */ import_react64.default.createElement("legend", null, "已核验官方 CLI"), cliMappings.map((mapping) => {
|
|
33550
33704
|
let selected = form.officialTools.some((tool) => tool.toolId === mapping.toolId && tool.cliModel === mapping.model);
|
|
33551
|
-
return /* @__PURE__ */
|
|
33552
|
-
})), /* @__PURE__ */
|
|
33553
|
-
}
|
|
33554
|
-
|
|
33555
|
-
// apps/integration-client/library-panel.jsx
|
|
33556
|
-
var import_react64 = __toESM(require("react"), 1);
|
|
33557
|
-
|
|
33558
|
-
// apps/integration-client/ui-icons.jsx
|
|
33559
|
-
var import_react63 = __toESM(require("react"), 1), paths = {
|
|
33560
|
-
bot: ["M8 4h8l4 4v8l-4 4H8l-4-4V8Z", "M9 10v3m6-3v3"],
|
|
33561
|
-
team: ["M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2m20 0v-2a4 4 0 0 0-3-3.87", "M9 11a4 4 0 1 0 0-8 4 4 0 0 0 0 8m8-7.87a4 4 0 0 1 0 7.75"],
|
|
33562
|
-
tasks: ["M9 5H6a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7a2 2 0 0 0-2-2h-3", "M9 3h6v4H9Zm-1 10 2 2 5-5m-7 8h8"],
|
|
33563
|
-
computer: ["M4 4h16a1 1 0 0 1 1 1v11a1 1 0 0 1-1 1H4a1 1 0 0 1-1-1V5a1 1 0 0 1 1-1Z", "M8 21h8m-4-4v4"],
|
|
33564
|
-
folder: ["M3 7V5a2 2 0 0 1 2-2h5l2 3h7a2 2 0 0 1 2 2v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2Zm0 1h18"],
|
|
33565
|
-
repeat: ["m17 2 4 4-4 4M3 11V8a2 2 0 0 1 2-2h16M7 22l-4-4 4-4m14-1v3a2 2 0 0 1-2 2H3"],
|
|
33566
|
-
chart: ["M4 3v17h17M9 15V9m5 6V5m5 10v-4"],
|
|
33567
|
-
settings: ["M4 7h7m4 0h5M4 17h3m4 0h9", "M11 4v6m-4 4v6m8-16v6m-4 4v6"],
|
|
33568
|
-
refresh: ["M20 7v5h-5M4 17v-5h5", "M6.1 6.1A8 8 0 0 1 19.5 9M4.5 15a8 8 0 0 0 13.4 2.9"],
|
|
33569
|
-
search: ["M11 18a7 7 0 1 0 0-14 7 7 0 0 0 0 14m5-2 5 5"],
|
|
33570
|
-
upload: ["M12 16V3m-5 5 5-5 5 5M4 15v4a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2v-4"],
|
|
33571
|
-
plus: ["M12 5v14M5 12h14"],
|
|
33572
|
-
file: ["M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8Zm0 0v6h6", "M8 13h8m-8 4h5"],
|
|
33573
|
-
arrow: ["M7 17 17 7M7 7h10v10"],
|
|
33574
|
-
chevron: ["m9 5 7 7-7 7"],
|
|
33575
|
-
back: ["m12 5-7 7 7 7m-7-7h14"],
|
|
33576
|
-
expand: ["M8 3H3v5m13-5h5v5M3 16v5h5m13-5v5h-5"],
|
|
33577
|
-
check: ["m5 12 4 4L19 6"],
|
|
33578
|
-
play: ["m8 4 12 8-12 8Z"],
|
|
33579
|
-
lock: ["M5 10h14v11H5Zm3 0V7a4 4 0 0 1 8 0v3m-4 4v3"]
|
|
33580
|
-
};
|
|
33581
|
-
function UiIcon({ name, size = 18, className = "", ...props }) {
|
|
33582
|
-
return /* @__PURE__ */ import_react63.default.createElement(
|
|
33583
|
-
"svg",
|
|
33584
|
-
{
|
|
33585
|
-
className: `bp-icon ${className}`,
|
|
33586
|
-
width: size,
|
|
33587
|
-
height: size,
|
|
33588
|
-
viewBox: "0 0 24 24",
|
|
33589
|
-
fill: "none",
|
|
33590
|
-
stroke: "currentColor",
|
|
33591
|
-
strokeWidth: "1.65",
|
|
33592
|
-
strokeLinecap: "round",
|
|
33593
|
-
strokeLinejoin: "round",
|
|
33594
|
-
"aria-hidden": "true",
|
|
33595
|
-
focusable: "false",
|
|
33596
|
-
...props
|
|
33597
|
-
},
|
|
33598
|
-
(paths[name] ?? paths.bot).map((d, index) => /* @__PURE__ */ import_react63.default.createElement("path", { key: index, d }))
|
|
33599
|
-
);
|
|
33705
|
+
return /* @__PURE__ */ import_react64.default.createElement("label", { key: `${mapping.toolId}/${mapping.model}` }, /* @__PURE__ */ import_react64.default.createElement("input", { type: "checkbox", checked: selected, onChange: (event) => change("officialTools", event.target.checked ? [...form.officialTools, { toolId: mapping.toolId, cliModel: mapping.model, mode: "read-only" }] : form.officialTools.filter((tool) => !(tool.toolId === mapping.toolId && tool.cliModel === mapping.model))) }), mapping.toolId, " / ", mapping.model, "(只读)");
|
|
33706
|
+
})), /* @__PURE__ */ import_react64.default.createElement("label", null, "资金渠道", /* @__PURE__ */ import_react64.default.createElement("select", { value: form.fundingMode, onChange: (event) => change("fundingMode", event.target.value) }, /* @__PURE__ */ import_react64.default.createElement("option", { value: "api" }, "API(金额)"), /* @__PURE__ */ import_react64.default.createElement("option", { value: "subscription" }, "订阅(调用次数)"))), form.fundingMode === "api" ? /* @__PURE__ */ import_react64.default.createElement(import_react64.default.Fragment, null, /* @__PURE__ */ import_react64.default.createElement("label", null, "输入价格(USD / 百万 Token)", /* @__PURE__ */ import_react64.default.createElement("input", { type: "number", min: "0", step: "0.000001", value: form.input, onChange: (event) => change("input", event.target.value), required: !0 })), /* @__PURE__ */ import_react64.default.createElement("label", null, "输出价格(USD / 百万 Token)", /* @__PURE__ */ import_react64.default.createElement("input", { type: "number", min: "0", step: "0.000001", value: form.output, onChange: (event) => change("output", event.target.value), required: !0 })), /* @__PURE__ */ import_react64.default.createElement("label", null, "最大输入 Token", /* @__PURE__ */ import_react64.default.createElement("input", { type: "number", min: "1", step: "1", value: form.maxInputTokens, onChange: (event) => change("maxInputTokens", event.target.value), required: !0 })), /* @__PURE__ */ import_react64.default.createElement("label", null, "最大输出 Token", /* @__PURE__ */ import_react64.default.createElement("input", { type: "number", min: "1", step: "1", value: form.maxOutputTokens, onChange: (event) => change("maxOutputTokens", event.target.value), required: !0 })), /* @__PURE__ */ import_react64.default.createElement("label", null, "Bot 每日预算(USD)", /* @__PURE__ */ import_react64.default.createElement("input", { type: "number", min: "0", step: "0.01", value: form.daily, onChange: (event) => change("daily", event.target.value), required: !0 })), /* @__PURE__ */ import_react64.default.createElement("label", null, "Bot 每月预算(USD)", /* @__PURE__ */ import_react64.default.createElement("input", { type: "number", min: "0", step: "0.01", value: form.monthly, onChange: (event) => change("monthly", event.target.value), required: !0 }))) : /* @__PURE__ */ import_react64.default.createElement(import_react64.default.Fragment, null, /* @__PURE__ */ import_react64.default.createElement("label", null, "每日订阅调用次数", /* @__PURE__ */ import_react64.default.createElement("input", { type: "number", min: "0", step: "1", value: form.dailyCalls, onChange: (event) => change("dailyCalls", event.target.value), required: !0 })), /* @__PURE__ */ import_react64.default.createElement("label", null, "每月订阅调用次数", /* @__PURE__ */ import_react64.default.createElement("input", { type: "number", min: "0", step: "1", value: form.monthlyCalls, onChange: (event) => change("monthlyCalls", event.target.value), required: !0 }))), /* @__PURE__ */ import_react64.default.createElement("label", null, "最大并发任务", /* @__PURE__ */ import_react64.default.createElement("input", { type: "number", min: "1", max: "32", step: "1", value: form.maxConcurrentTasks, onChange: (event) => change("maxConcurrentTasks", event.target.value), required: !0 })), /* @__PURE__ */ import_react64.default.createElement("label", null, /* @__PURE__ */ import_react64.default.createElement("input", { type: "checkbox", checked: form.enabled, onChange: (event) => change("enabled", event.target.checked) }), "启用此绑定(模型、工作区和资金范围必须完整)"), /* @__PURE__ */ import_react64.default.createElement("button", { type: "submit", disabled: busy || form.enabled && (!model || !account?.enabled || !selectedMachine || !selectedRoot) }, "保存绑定"), record3.blockedReason && /* @__PURE__ */ import_react64.default.createElement(Blocked, { value: record3 })));
|
|
33600
33707
|
}
|
|
33601
33708
|
|
|
33602
33709
|
// apps/integration-client/library-panel.jsx
|
|
33710
|
+
var import_react65 = __toESM(require("react"), 1);
|
|
33603
33711
|
var MAX_UPLOAD_BYTES = 16 * 1024 * 1024, textFile = (name) => /\.(?:txt|md|markdown|csv|tsv|json|ya?ml|xml|html|log|m?js|ts|py)$/iu.test(name) || !name.includes("."), bytesLabel = (size) => size >= 1024 * 1024 ? `${(size / 1024 / 1024).toFixed(1)} MB` : `${Math.ceil(size / 1024)} KB`, fileBase64 = (file) => new Promise((resolve2, reject) => {
|
|
33604
33712
|
let reader = new FileReader();
|
|
33605
33713
|
reader.onerror = () => reject(new Error("文件读取失败。")), reader.onload = () => resolve2(String(reader.result).split(",")[1] ?? ""), reader.readAsDataURL(file);
|
|
33606
33714
|
});
|
|
33607
33715
|
function LibraryPanel({ snapshot, dispatch, busy }) {
|
|
33608
|
-
let bots = snapshot.bots ?? [], [botId, setBotId] = (0,
|
|
33716
|
+
let bots = snapshot.bots ?? [], [botId, setBotId] = (0, import_react65.useState)(bots[0]?.id ?? ""), [path, setPath] = (0, import_react65.useState)(""), [entries2, setEntries] = (0, import_react65.useState)([]), [editor, setEditor] = (0, import_react65.useState)(null), [newName, setNewName] = (0, import_react65.useState)(""), [filter, setFilter] = (0, import_react65.useState)(""), [query, setQuery] = (0, import_react65.useState)(""), [searchResults, setSearchResults] = (0, import_react65.useState)(null), [searchedQuery, setSearchedQuery] = (0, import_react65.useState)(""), [error, setError] = (0, import_react65.useState)(""), [status, setStatus] = (0, import_react65.useState)(""), [working, setWorking] = (0, import_react65.useState)(!1), [deleteName, setDeleteName] = (0, import_react65.useState)(null), sequence = (0, import_react65.useRef)(0), editorRef = (0, import_react65.useRef)(null), createMenuRef = (0, import_react65.useRef)(null), dispatchRef = (0, import_react65.useRef)(dispatch);
|
|
33609
33717
|
dispatchRef.current = dispatch;
|
|
33610
|
-
let call2 = (0,
|
|
33718
|
+
let call2 = (0, import_react65.useCallback)(async (action, payload) => {
|
|
33611
33719
|
let value = await dispatchRef.current(action, payload);
|
|
33612
33720
|
if (value === void 0 || value?.ok === !1) throw new Error(value?.error?.message ?? "宿主尚未确认这次操作,请刷新后重试。");
|
|
33613
33721
|
return value;
|
|
33614
|
-
}, []), fullPath = (name) => path ? `${path}/${name}` : name, load = (0,
|
|
33722
|
+
}, []), fullPath = (name) => path ? `${path}/${name}` : name, load = (0, import_react65.useCallback)(async () => {
|
|
33615
33723
|
let generation = ++sequence.current;
|
|
33616
33724
|
if (!(!botId || typeof dispatchRef.current != "function"))
|
|
33617
33725
|
try {
|
|
@@ -33621,11 +33729,11 @@ function LibraryPanel({ snapshot, dispatch, busy }) {
|
|
|
33621
33729
|
generation === sequence.current && setError(String(failure?.message ?? failure));
|
|
33622
33730
|
}
|
|
33623
33731
|
}, [botId, path, call2]);
|
|
33624
|
-
(0,
|
|
33732
|
+
(0, import_react65.useEffect)(() => (setEditor(null), setDeleteName(null), setEntries([]), setSearchResults(null), load(), () => {
|
|
33625
33733
|
sequence.current++;
|
|
33626
|
-
}), [load]), (0,
|
|
33734
|
+
}), [load]), (0, import_react65.useEffect)(() => {
|
|
33627
33735
|
!botId && bots[0] && setBotId(bots[0].id);
|
|
33628
|
-
}, [botId, bots]), (0,
|
|
33736
|
+
}, [botId, bots]), (0, import_react65.useEffect)(() => {
|
|
33629
33737
|
if (!editor?.line || !editorRef.current) return;
|
|
33630
33738
|
let textarea = editorRef.current, lines = textarea.value.split(`
|
|
33631
33739
|
`), index = Math.min(lines.length - 1, Math.max(0, editor.line - 1)), start = lines.slice(0, index).reduce((sum, line) => sum + line.length + 1, 0);
|
|
@@ -33673,35 +33781,35 @@ function LibraryPanel({ snapshot, dispatch, busy }) {
|
|
|
33673
33781
|
}
|
|
33674
33782
|
openText(fullPath(entry.name), entry.name);
|
|
33675
33783
|
}, disabled = busy || working || !botId;
|
|
33676
|
-
return bots.length ? /* @__PURE__ */
|
|
33784
|
+
return bots.length ? /* @__PURE__ */ import_react65.default.createElement("article", { className: "bp-card bp-library" }, /* @__PURE__ */ import_react65.default.createElement("div", { className: "bp-card-title" }, /* @__PURE__ */ import_react65.default.createElement("h2", null, "资料库"), /* @__PURE__ */ import_react65.default.createElement("select", { "aria-label": "资料库 Bot", value: botId, disabled: working, onChange: (event) => {
|
|
33677
33785
|
setBotId(event.target.value), setPath(""), setStatus("");
|
|
33678
|
-
} }, bots.map((bot) => /* @__PURE__ */
|
|
33786
|
+
} }, bots.map((bot) => /* @__PURE__ */ import_react65.default.createElement("option", { key: bot.id, value: bot.id }, bot.name ?? bot.id)))), /* @__PURE__ */ import_react65.default.createElement("p", { className: "bp-muted" }, "按 Bot 保存文档、图片和工作资料。单文件最大 16 MB,文本可直接编辑。"), /* @__PURE__ */ import_react65.default.createElement("nav", { className: "bp-actions bp-library-breadcrumb", "aria-label": "资料库目录" }, /* @__PURE__ */ import_react65.default.createElement(UiIcon, { name: "folder", size: 15 }), /* @__PURE__ */ import_react65.default.createElement("button", { disabled, onClick: () => setPath("") }, "根目录"), path && /* @__PURE__ */ import_react65.default.createElement(import_react65.default.Fragment, null, /* @__PURE__ */ import_react65.default.createElement("span", null, "/ ", path), /* @__PURE__ */ import_react65.default.createElement("button", { disabled, onClick: () => setPath(path.split("/").slice(0, -1).join("/")) }, "上一级")), /* @__PURE__ */ import_react65.default.createElement("button", { disabled, onClick: () => {
|
|
33679
33787
|
load();
|
|
33680
|
-
} }, "列出目录")), /* @__PURE__ */
|
|
33788
|
+
} }, "列出目录")), /* @__PURE__ */ import_react65.default.createElement("div", { className: "bp-library-toolbar" }, /* @__PURE__ */ import_react65.default.createElement("label", { className: "bp-search-field" }, /* @__PURE__ */ import_react65.default.createElement(UiIcon, { name: "search", size: 15 }), /* @__PURE__ */ import_react65.default.createElement("input", { "aria-label": "筛选资料", placeholder: "按文件名查找…", value: filter, onChange: (event) => setFilter(event.target.value) })), /* @__PURE__ */ import_react65.default.createElement("details", { className: "bp-create-menu", ref: createMenuRef }, /* @__PURE__ */ import_react65.default.createElement("summary", null, /* @__PURE__ */ import_react65.default.createElement(UiIcon, { name: "plus", size: 15 }), "新建"), /* @__PURE__ */ import_react65.default.createElement("div", { className: "bp-create-popover" }, /* @__PURE__ */ import_react65.default.createElement("input", { "aria-label": "新建名称", value: newName, onChange: (event) => setNewName(event.target.value), placeholder: "文件或文件夹名称" }), /* @__PURE__ */ import_react65.default.createElement("div", { className: "bp-actions" }, /* @__PURE__ */ import_react65.default.createElement("button", { disabled: disabled || !newName.trim(), onClick: () => {
|
|
33681
33789
|
setEditor({ name: newName.trim(), content: "", fresh: !0 }), setNewName(""), createMenuRef.current.open = !1;
|
|
33682
|
-
} }, "新建文本"), /* @__PURE__ */
|
|
33790
|
+
} }, "新建文本"), /* @__PURE__ */ import_react65.default.createElement("button", { disabled: disabled || !newName.trim(), onClick: () => {
|
|
33683
33791
|
perform(async () => {
|
|
33684
33792
|
await call2("library.mkdir", { botId, relativePath: fullPath(newName.trim()) }), setNewName(""), createMenuRef.current.open = !1, await load();
|
|
33685
33793
|
});
|
|
33686
|
-
} }, "新建文件夹")))), /* @__PURE__ */
|
|
33794
|
+
} }, "新建文件夹")))), /* @__PURE__ */ import_react65.default.createElement("label", { className: "bp-upload" }, /* @__PURE__ */ import_react65.default.createElement(UiIcon, { name: "upload", size: 15 }), "上传文件", /* @__PURE__ */ import_react65.default.createElement("input", { "aria-label": "上传资料", type: "file", multiple: !0, disabled, onChange: upload }))), /* @__PURE__ */ import_react65.default.createElement("div", { className: "bp-library-search" }, /* @__PURE__ */ import_react65.default.createElement("input", { "aria-label": "资料库文本查询", maxLength: 256, value: query, onChange: (event) => setQuery(event.target.value), placeholder: "搜索这个 Bot 的文本内容" }), /* @__PURE__ */ import_react65.default.createElement("button", { disabled: disabled || !query.trim(), onClick: () => {
|
|
33687
33795
|
search();
|
|
33688
|
-
} }, "搜索文本"), searchResults !== null && /* @__PURE__ */
|
|
33796
|
+
} }, "搜索文本"), searchResults !== null && /* @__PURE__ */ import_react65.default.createElement("button", { disabled: working, onClick: () => setSearchResults(null) }, "清除搜索")), error && /* @__PURE__ */ import_react65.default.createElement("p", { className: "bp-error", role: "alert" }, error), status && /* @__PURE__ */ import_react65.default.createElement("p", { role: "status" }, status), searchResults !== null && /* @__PURE__ */ import_react65.default.createElement("section", { "aria-label": "资料库搜索结果" }, /* @__PURE__ */ import_react65.default.createElement("p", { role: "status" }, "“", searchedQuery, "” · ", searchResults.length, " 条结果(最多 50 条,扫描最多 500 个条目 / 8 层目录,仅限不超过 1 MiB 的文本文件)"), searchResults.length ? /* @__PURE__ */ import_react65.default.createElement("div", { className: "bp-table-wrap" }, /* @__PURE__ */ import_react65.default.createElement("table", null, /* @__PURE__ */ import_react65.default.createElement("thead", null, /* @__PURE__ */ import_react65.default.createElement("tr", null, /* @__PURE__ */ import_react65.default.createElement("th", null, "文件 / 行号"), /* @__PURE__ */ import_react65.default.createElement("th", null, "匹配文本"))), /* @__PURE__ */ import_react65.default.createElement("tbody", null, searchResults.map((row, index) => /* @__PURE__ */ import_react65.default.createElement("tr", { key: `${row.path}:${row.line}:${index}` }, /* @__PURE__ */ import_react65.default.createElement("td", null, /* @__PURE__ */ import_react65.default.createElement("button", { disabled, className: "bp-text-button", onClick: () => {
|
|
33689
33797
|
openText(row.path, row.path.split("/").at(-1), row.line);
|
|
33690
|
-
} }, row.path, ":", row.line)), /* @__PURE__ */
|
|
33798
|
+
} }, row.path, ":", row.line)), /* @__PURE__ */ import_react65.default.createElement("td", null, /* @__PURE__ */ import_react65.default.createElement("code", null, row.text))))))) : /* @__PURE__ */ import_react65.default.createElement("p", { className: "bp-muted" }, "没有匹配的文本内容。")), entries2.length ? /* @__PURE__ */ import_react65.default.createElement("div", { className: "bp-table-wrap" }, /* @__PURE__ */ import_react65.default.createElement("table", null, /* @__PURE__ */ import_react65.default.createElement("thead", null, /* @__PURE__ */ import_react65.default.createElement("tr", null, /* @__PURE__ */ import_react65.default.createElement("th", null, "名称"), /* @__PURE__ */ import_react65.default.createElement("th", null, "大小"), /* @__PURE__ */ import_react65.default.createElement("th", null, "操作"))), /* @__PURE__ */ import_react65.default.createElement("tbody", null, entries2.filter((entry) => entry.name.toLocaleLowerCase().includes(filter.toLocaleLowerCase())).map((entry) => /* @__PURE__ */ import_react65.default.createElement("tr", { key: entry.name }, /* @__PURE__ */ import_react65.default.createElement("td", null, /* @__PURE__ */ import_react65.default.createElement("button", { className: "bp-text-button bp-file-name", disabled: disabled || entry.kind === "other", onClick: () => open(entry) }, /* @__PURE__ */ import_react65.default.createElement(UiIcon, { name: entry.kind === "directory" ? "folder" : "file", size: 18 }), entry.name)), /* @__PURE__ */ import_react65.default.createElement("td", { className: "bp-file-meta" }, entry.kind === "file" ? bytesLabel(entry.size ?? 0) : "文件夹"), /* @__PURE__ */ import_react65.default.createElement("td", null, /* @__PURE__ */ import_react65.default.createElement("div", { className: "bp-row-actions" }, entry.kind === "file" && /* @__PURE__ */ import_react65.default.createElement(import_react65.default.Fragment, null, textFile(entry.name) && /* @__PURE__ */ import_react65.default.createElement("button", { disabled, onClick: () => open(entry) }, "查看"), /* @__PURE__ */ import_react65.default.createElement("button", { disabled, onClick: () => {
|
|
33691
33799
|
download2(entry.name);
|
|
33692
|
-
} }, "下载"), /* @__PURE__ */
|
|
33800
|
+
} }, "下载"), /* @__PURE__ */ import_react65.default.createElement("button", { disabled, onClick: () => setDeleteName(entry.name) }, "删除")), deleteName === entry.name && /* @__PURE__ */ import_react65.default.createElement("span", null, "删除此文件? ", /* @__PURE__ */ import_react65.default.createElement("button", { className: "bp-button-danger", disabled, onClick: () => {
|
|
33693
33801
|
perform(async () => {
|
|
33694
33802
|
await call2("library.remove", { botId, relativePath: fullPath(entry.name) }), setDeleteName(null), editor?.name === entry.name && setEditor(null), await load();
|
|
33695
33803
|
});
|
|
33696
|
-
} }, "确认删除"), /* @__PURE__ */
|
|
33804
|
+
} }, "确认删除"), /* @__PURE__ */ import_react65.default.createElement("button", { onClick: () => setDeleteName(null) }, "取消"))))))))) : /* @__PURE__ */ import_react65.default.createElement("div", { className: "bp-empty-state" }, /* @__PURE__ */ import_react65.default.createElement("span", { className: "bp-empty-icon" }, /* @__PURE__ */ import_react65.default.createElement(UiIcon, { name: "folder", size: 28 })), /* @__PURE__ */ import_react65.default.createElement("strong", null, "给这位伙伴一份资料"), /* @__PURE__ */ import_react65.default.createElement("p", null, "这个目录是空的。上传文件或新建文本开始。")), editor && /* @__PURE__ */ import_react65.default.createElement("section", { className: "bp-form" }, /* @__PURE__ */ import_react65.default.createElement("strong", null, editor.relativePath ?? editor.name, editor.line ? `:${editor.line}` : ""), /* @__PURE__ */ import_react65.default.createElement("textarea", { ref: editorRef, autoFocus: !0, rows: 12, "aria-label": "资料内容", value: editor.content, onChange: (event) => setEditor({ ...editor, content: event.target.value }) }), /* @__PURE__ */ import_react65.default.createElement("div", { className: "bp-actions" }, /* @__PURE__ */ import_react65.default.createElement("button", { className: "bp-button-primary", disabled, onClick: () => {
|
|
33697
33805
|
perform(async () => {
|
|
33698
33806
|
editor.fresh ? await call2("library.upload", { botId, relativePath: fullPath(editor.name), contentBase64: await fileBase64(new File([editor.content], editor.name, { type: "text/plain" })) }) : await call2("library.write", { botId, relativePath: editor.relativePath ?? fullPath(editor.name), content: editor.content }), setEditor({ ...editor, fresh: !1 }), await load(), setStatus(`已保存 ${editor.name}`);
|
|
33699
33807
|
});
|
|
33700
|
-
} }, "保存"), /* @__PURE__ */
|
|
33808
|
+
} }, "保存"), /* @__PURE__ */ import_react65.default.createElement("button", { disabled: working, onClick: () => setEditor(null) }, "关闭")))) : /* @__PURE__ */ import_react65.default.createElement("p", { className: "bp-empty" }, "还没有 Bot。");
|
|
33701
33809
|
}
|
|
33702
33810
|
|
|
33703
33811
|
// apps/integration-client/desktop-pane.jsx
|
|
33704
|
-
var
|
|
33812
|
+
var import_react67 = __toESM(require("react"), 1);
|
|
33705
33813
|
|
|
33706
33814
|
// apps/integration-client/desktop-stream.mjs
|
|
33707
33815
|
function connectDesktopStream({
|
|
@@ -33992,11 +34100,11 @@ function createAcknowledgedRoutineRecorder({ now = Date.now, onChange } = {}) {
|
|
|
33992
34100
|
}
|
|
33993
34101
|
|
|
33994
34102
|
// apps/integration-client/routines-panel.jsx
|
|
33995
|
-
var
|
|
34103
|
+
var import_react66 = __toESM(require("react"), 1);
|
|
33996
34104
|
var message = (failure) => String(failure?.message ?? failure), rootOf = (machine) => typeof machine?.roots?.[0] == "string" ? machine.roots[0] : machine?.rootId ?? machine?.roots?.[0]?.rootId ?? machine?.roots?.[0]?.id ?? "", STATUS = { running: "正在执行", succeeded: "全部动作已确认", failed: "执行失败,已停止", cancelled: "已取消", unknown: "结果未知,需要检查电脑", cancel_pending: "正在请求停止" };
|
|
33997
34105
|
function RoutineCaptureControls({ recorder, sessionId, metadata, mode, connected, drainInputs, releaseInput, saveRoutine }) {
|
|
33998
|
-
let [capture, setCapture] = (0,
|
|
33999
|
-
(0,
|
|
34106
|
+
let [capture, setCapture] = (0, import_react66.useState)(recorder.snapshot), [name, setName] = (0, import_react66.useState)(""), [busy, setBusy] = (0, import_react66.useState)(!1), [error, setError] = (0, import_react66.useState)(""), [saved, setSaved] = (0, import_react66.useState)(null), [draft2, setDraft] = (0, import_react66.useState)(null);
|
|
34107
|
+
(0, import_react66.useEffect)(() => (setCapture(recorder.snapshot), recorder.subscribe(setCapture)), [recorder]);
|
|
34000
34108
|
let start = () => {
|
|
34001
34109
|
try {
|
|
34002
34110
|
setError(""), setSaved(null), setDraft(null), recorder.start({ sessionId, metadata, mode });
|
|
@@ -34026,17 +34134,17 @@ function RoutineCaptureControls({ recorder, sessionId, metadata, mode, connected
|
|
|
34026
34134
|
setBusy(!1);
|
|
34027
34135
|
}
|
|
34028
34136
|
};
|
|
34029
|
-
return /* @__PURE__ */
|
|
34137
|
+
return /* @__PURE__ */ import_react66.default.createElement("section", { className: "bp-card bp-routine-capture", "aria-label": "录制例行任务" }, /* @__PURE__ */ import_react66.default.createElement("h4", null, "演示并保存例行任务"), /* @__PURE__ */ import_react66.default.createElement("p", { className: "bp-muted" }, "取得控制权后开始录制,像平常一样操作这台电脑。仅保存远端已确认的鼠标、键盘和文字输入;输入文字也会保存在这个 Bot 的私有例行任务中。"), /* @__PURE__ */ import_react66.default.createElement("p", { className: "bp-muted" }, "这是固定显示器和分辨率的动作回放,最多 200 个步骤,单次停顿最多 60 秒。鼠标轨迹按 200 毫秒采样,保留点击和拖动结束位置;不适合精细绘图。开始前把应用恢复到相同界面;页面或布局改变时需要重新演示。"), /* @__PURE__ */ import_react66.default.createElement("div", { className: "bp-actions" }, /* @__PURE__ */ import_react66.default.createElement("input", { "aria-label": "例行任务名称", maxLength: 120, value: name, onChange: (event) => setName(event.target.value), placeholder: "例如:打开日报并填写日期" }), /* @__PURE__ */ import_react66.default.createElement("button", { disabled: busy || !connected || mode !== "control" || capture.status === "recording", onClick: start }, "开始录制"), /* @__PURE__ */ import_react66.default.createElement("button", { disabled: busy || !name.trim() || !(draft2 || capture.status === "recording" && capture.length > 0), onClick: () => {
|
|
34030
34138
|
finish();
|
|
34031
|
-
} }, draft2 ? "重试保存" : "结束并保存"), /* @__PURE__ */
|
|
34139
|
+
} }, draft2 ? "重试保存" : "结束并保存"), /* @__PURE__ */ import_react66.default.createElement("button", { disabled: busy || capture.status === "idle", onClick: () => {
|
|
34032
34140
|
recorder.reset(), setDraft(null), setError("");
|
|
34033
|
-
} }, "丢弃录制")), /* @__PURE__ */
|
|
34141
|
+
} }, "丢弃录制")), /* @__PURE__ */ import_react66.default.createElement("p", { role: "status" }, capture.status === "recording" ? `正在录制:${capture.length} 个回放步骤,${capture.observedInputs} 个输入已确认,${capture.pending} 个等待确认` : capture.status === "invalid" ? `录制已中止:${capture.error},请丢弃后重新演示。` : saved ? "例行任务已保存。" : "尚未录制。"), error && /* @__PURE__ */ import_react66.default.createElement("p", { className: "bp-error", role: "alert" }, error));
|
|
34034
34142
|
}
|
|
34035
34143
|
function RoutinesPanel({ snapshot, dispatch, busy = !1, onOpenMachines }) {
|
|
34036
|
-
let bots = snapshot.bots ?? [], machines = (snapshot.machines?.items ?? []).filter((row) => row.status !== "revoked"), [botId, setBotId] = (0,
|
|
34037
|
-
(0,
|
|
34144
|
+
let bots = snapshot.bots ?? [], machines = (snapshot.machines?.items ?? []).filter((row) => row.status !== "revoked"), [botId, setBotId] = (0, import_react66.useState)(bots[0]?.id ?? ""), [machineId, setMachineId] = (0, import_react66.useState)(machines[0]?.id ?? machines[0]?.machineId ?? ""), [rows2, setRows] = (0, import_react66.useState)([]), [runs, setRuns] = (0, import_react66.useState)([]), [result, setResult] = (0, import_react66.useState)(null), [error, setError] = (0, import_react66.useState)(""), [running, setRunning] = (0, import_react66.useState)(!1), [notes, setNotes] = (0, import_react66.useState)({});
|
|
34145
|
+
(0, import_react66.useEffect)(() => {
|
|
34038
34146
|
!botId && bots[0] && setBotId(bots[0].id);
|
|
34039
|
-
}, [botId, bots[0]?.id]), (0,
|
|
34147
|
+
}, [botId, bots[0]?.id]), (0, import_react66.useEffect)(() => {
|
|
34040
34148
|
!machineId && machines[0] && setMachineId(machines[0].id ?? machines[0].machineId);
|
|
34041
34149
|
}, [machineId, machines[0]?.id, machines[0]?.machineId]);
|
|
34042
34150
|
let call2 = async (action, payload) => {
|
|
@@ -34053,9 +34161,9 @@ function RoutinesPanel({ snapshot, dispatch, busy = !1, onOpenMachines }) {
|
|
|
34053
34161
|
setError(message(failure));
|
|
34054
34162
|
}
|
|
34055
34163
|
};
|
|
34056
|
-
(0,
|
|
34164
|
+
(0, import_react66.useEffect)(() => {
|
|
34057
34165
|
refresh();
|
|
34058
|
-
}, [botId, dispatch]), (0,
|
|
34166
|
+
}, [botId, dispatch]), (0, import_react66.useEffect)(() => {
|
|
34059
34167
|
if (!running && !runs.some((row) => row.status === "running")) return;
|
|
34060
34168
|
let timer = setInterval(() => {
|
|
34061
34169
|
refresh();
|
|
@@ -34085,32 +34193,32 @@ function RoutinesPanel({ snapshot, dispatch, busy = !1, onOpenMachines }) {
|
|
|
34085
34193
|
setError(message(failure));
|
|
34086
34194
|
}
|
|
34087
34195
|
};
|
|
34088
|
-
return bots.length ? /* @__PURE__ */
|
|
34196
|
+
return bots.length ? /* @__PURE__ */ import_react66.default.createElement("article", { className: "bp-card" }, /* @__PURE__ */ import_react66.default.createElement("h2", null, "例行任务"), /* @__PURE__ */ import_react66.default.createElement("p", { className: "bp-muted" }, "在远程电脑中演示并保存动作,再选择电脑回放。每一步都等待确认;失败会停止,结果未知时需检查电脑后再运行。"), /* @__PURE__ */ import_react66.default.createElement("div", { className: "bp-actions" }, /* @__PURE__ */ import_react66.default.createElement("label", null, "Bot", /* @__PURE__ */ import_react66.default.createElement("select", { disabled: running, value: botId, onChange: (event) => {
|
|
34089
34197
|
setBotId(event.target.value), setResult(null), setError("");
|
|
34090
|
-
} }, bots.map((bot) => /* @__PURE__ */
|
|
34198
|
+
} }, bots.map((bot) => /* @__PURE__ */ import_react66.default.createElement("option", { key: bot.id, value: bot.id }, bot.name ?? bot.id)))), /* @__PURE__ */ import_react66.default.createElement("label", null, "电脑", /* @__PURE__ */ import_react66.default.createElement("select", { disabled: running, value: machineId, onChange: (event) => setMachineId(event.target.value) }, machines.map((machine) => /* @__PURE__ */ import_react66.default.createElement("option", { key: machine.id ?? machine.machineId, value: machine.id ?? machine.machineId }, machine.name ?? machine.label ?? machine.id ?? machine.machineId)))), /* @__PURE__ */ import_react66.default.createElement("button", { disabled: busy, onClick: () => {
|
|
34091
34199
|
refresh();
|
|
34092
|
-
} }, "刷新")), error && /* @__PURE__ */
|
|
34200
|
+
} }, "刷新")), error && /* @__PURE__ */ import_react66.default.createElement("p", { className: "bp-error", role: "alert" }, error), rows2.length ? /* @__PURE__ */ import_react66.default.createElement("div", { className: "bp-table-wrap" }, /* @__PURE__ */ import_react66.default.createElement("table", null, /* @__PURE__ */ import_react66.default.createElement("thead", null, /* @__PURE__ */ import_react66.default.createElement("tr", null, /* @__PURE__ */ import_react66.default.createElement("th", null, "名称"), /* @__PURE__ */ import_react66.default.createElement("th", null, "来源 / 步数"), /* @__PURE__ */ import_react66.default.createElement("th", null, "操作"))), /* @__PURE__ */ import_react66.default.createElement("tbody", null, rows2.map((row) => /* @__PURE__ */ import_react66.default.createElement("tr", { key: row.id }, /* @__PURE__ */ import_react66.default.createElement("td", null, row.name, row.display && /* @__PURE__ */ import_react66.default.createElement("small", null, row.display.width, " × ", row.display.height, " · ", row.display.displayId)), /* @__PURE__ */ import_react66.default.createElement("td", null, row.demonstrated ? "桌面演示" : "手工步骤", " / ", row.steps), /* @__PURE__ */ import_react66.default.createElement("td", null, /* @__PURE__ */ import_react66.default.createElement("button", { disabled: busy || running || !machineId || runs.some((run3) => run3.machineId === machineId && (run3.status === "running" || run3.status === "unknown" && !run3.resolvedAt)), onClick: () => {
|
|
34093
34201
|
run2(row.id);
|
|
34094
|
-
} }, "在这台电脑运行"))))))) : /* @__PURE__ */
|
|
34202
|
+
} }, "在这台电脑运行"))))))) : /* @__PURE__ */ import_react66.default.createElement("div", { className: "bp-empty-state" }, /* @__PURE__ */ import_react66.default.createElement("span", { className: "bp-empty-icon" }, /* @__PURE__ */ import_react66.default.createElement(UiIcon, { name: "repeat", size: 27 })), /* @__PURE__ */ import_react66.default.createElement("strong", null, "把重复的事,交给 Bot"), /* @__PURE__ */ import_react66.default.createElement("p", null, "这个 Bot 还没有保存例行任务。在远程电脑中演示并保存,之后就能在这里运行。"), onOpenMachines && /* @__PURE__ */ import_react66.default.createElement("button", { className: "bp-button-primary", onClick: onOpenMachines }, /* @__PURE__ */ import_react66.default.createElement(UiIcon, { name: "computer", size: 15 }), "去电脑中演示")), result && /* @__PURE__ */ import_react66.default.createElement("p", { role: "status" }, STATUS[result.status] ?? result.status, result.stoppedAt != null ? ` · 停在第 ${result.stoppedAt + 1} 步` : "", result.error ? ` · ${result.error}` : ""), /* @__PURE__ */ import_react66.default.createElement("h3", null, "执行记录"), runs.slice().reverse().slice(0, 20).map((row) => /* @__PURE__ */ import_react66.default.createElement("section", { className: "bp-blocked", key: row.runId }, /* @__PURE__ */ import_react66.default.createElement("strong", null, STATUS[row.status] ?? row.status), /* @__PURE__ */ import_react66.default.createElement("small", null, row.runId), /* @__PURE__ */ import_react66.default.createElement("p", null, row.steps.length, " 步完成 · ", row.evidence.filter((item) => item.status === "acknowledged").length, " 个输入已确认", row.stoppedAt != null ? ` · 停在第 ${row.stoppedAt + 1} 步` : ""), row.error && /* @__PURE__ */ import_react66.default.createElement("p", { className: "bp-error" }, row.error), row.status === "running" && /* @__PURE__ */ import_react66.default.createElement("button", { onClick: () => {
|
|
34095
34203
|
stop(row.runId);
|
|
34096
|
-
} }, "请求停止"), row.status === "unknown" && !row.resolvedAt && /* @__PURE__ */
|
|
34204
|
+
} }, "请求停止"), row.status === "unknown" && !row.resolvedAt && /* @__PURE__ */ import_react66.default.createElement("div", null, /* @__PURE__ */ import_react66.default.createElement("p", null, "检查远程电脑,确认任务已经做到哪里,并手动恢复到适合下一次运行的界面。"), /* @__PURE__ */ import_react66.default.createElement("input", { "aria-label": "检查结果", value: notes[row.runId] ?? "", onChange: (event) => setNotes((before) => ({ ...before, [row.runId]: event.target.value })), placeholder: "记录你检查到的结果和恢复操作" }), /* @__PURE__ */ import_react66.default.createElement("button", { disabled: !(notes[row.runId] ?? "").trim(), onClick: () => {
|
|
34097
34205
|
resolve2(row.runId);
|
|
34098
|
-
} }, "已检查实际结果,解除运行阻塞")), row.resolvedAt && /* @__PURE__ */
|
|
34206
|
+
} }, "已检查实际结果,解除运行阻塞")), row.resolvedAt && /* @__PURE__ */ import_react66.default.createElement("p", null, "已由你检查:", row.resolution?.note)))) : /* @__PURE__ */ import_react66.default.createElement("p", { className: "bp-empty" }, "还没有 Bot。");
|
|
34099
34207
|
}
|
|
34100
34208
|
|
|
34101
34209
|
// apps/integration-client/desktop-pane.jsx
|
|
34102
34210
|
var rootOf2 = (machine) => typeof machine?.roots?.[0] == "string" ? machine.roots[0] : machine?.rootId ?? machine?.roots?.[0]?.id ?? "", STATUS2 = { idle: "未连接", connecting: "连接中", authenticating: "验证中", connected: "已连接", releasing: "归还控制中", disconnected: "已断开", error: "连接异常" };
|
|
34103
34211
|
function DesktopViewer({ botId, machines, openSession, renewSession, closeSession, saveRoutine }) {
|
|
34104
|
-
let [machineId, setMachineId] = (0,
|
|
34212
|
+
let [machineId, setMachineId] = (0, import_react67.useState)(machines[0]?.machineId ?? machines[0]?.id ?? ""), [displayId, setDisplayId] = (0, import_react67.useState)(""), [displays, setDisplays] = (0, import_react67.useState)([]), [state, setState] = (0, import_react67.useState)({ status: "idle", mode: "watch" }), [expanded, setExpanded] = (0, import_react67.useState)(!1), [stats, setStats] = (0, import_react67.useState)({ fps: 0, width: 0, height: 0 }), [text7, setText] = (0, import_react67.useState)(""), [metadata, setMetadata] = (0, import_react67.useState)({}), recorderRef = (0, import_react67.useRef)(null);
|
|
34105
34213
|
recorderRef.current || (recorderRef.current = createAcknowledgedRoutineRecorder());
|
|
34106
|
-
let recorder = recorderRef.current, canvasRef = (0,
|
|
34107
|
-
closeRef.current = closeSession, (0,
|
|
34214
|
+
let recorder = recorderRef.current, canvasRef = (0, import_react67.useRef)(null), largeRef = (0, import_react67.useRef)(null), streamRef = (0, import_react67.useRef)(null), ticketRef = (0, import_react67.useRef)(null), generation = (0, import_react67.useRef)(0), pendingFrame = (0, import_react67.useRef)(null), drawing = (0, import_react67.useRef)(!1), surface = (0, import_react67.useRef)(null), size = (0, import_react67.useRef)({ width: 0, height: 0 }), rate = (0, import_react67.useRef)({ at: performance.now(), count: 0 }), renewTimer = (0, import_react67.useRef)(null), moveTimer = (0, import_react67.useRef)(null), pendingMove = (0, import_react67.useRef)(null), [canControl, setCanControl] = (0, import_react67.useState)(!1), closeRef = (0, import_react67.useRef)(closeSession);
|
|
34215
|
+
closeRef.current = closeSession, (0, import_react67.useEffect)(() => {
|
|
34108
34216
|
!machineId && machines[0] && setMachineId(machines[0].machineId ?? machines[0].id);
|
|
34109
34217
|
}, [machines, machineId]);
|
|
34110
|
-
let release = (0,
|
|
34218
|
+
let release = (0, import_react67.useCallback)(() => {
|
|
34111
34219
|
pendingMove.current = null, streamRef.current?.releaseInput()?.catch(() => {
|
|
34112
34220
|
});
|
|
34113
|
-
}, []), stop = (0,
|
|
34221
|
+
}, []), stop = (0, import_react67.useCallback)(async () => {
|
|
34114
34222
|
recorder.invalidate("ROUTINE_DESKTOP_DISCONNECTED"), generation.current++, clearTimeout(renewTimer.current), renewTimer.current = null, moveTimer.current !== null && cancelAnimationFrame(moveTimer.current), moveTimer.current = null, pendingMove.current = null, pendingFrame.current = null, size.current = { width: 0, height: 0 }, streamRef.current?.close(), streamRef.current = null;
|
|
34115
34223
|
let ticket = ticketRef.current;
|
|
34116
34224
|
if (ticketRef.current = null, ticket)
|
|
@@ -34120,7 +34228,7 @@ function DesktopViewer({ botId, machines, openSession, renewSession, closeSessio
|
|
|
34120
34228
|
return { stopConfirmed: !1 };
|
|
34121
34229
|
}
|
|
34122
34230
|
return { stopConfirmed: !0 };
|
|
34123
|
-
}, [botId]), draw = (0,
|
|
34231
|
+
}, [botId]), draw = (0, import_react67.useCallback)(async (bytes, info) => {
|
|
34124
34232
|
let queue = pendingFrame.current ?? [];
|
|
34125
34233
|
if (info?.keyframe === !0 && (queue.length = 0), queue.push({ bytes, info }), pendingFrame.current = queue, queue.length > 16) {
|
|
34126
34234
|
streamRef.current?.close(), setState({ status: "error", mode: "watch", error: "画面解码跟不上,请重新连接。" });
|
|
@@ -34128,12 +34236,12 @@ function DesktopViewer({ botId, machines, openSession, renewSession, closeSessio
|
|
|
34128
34236
|
}
|
|
34129
34237
|
if (drawing.current) return;
|
|
34130
34238
|
drawing.current = !0;
|
|
34131
|
-
let
|
|
34239
|
+
let active2 = generation.current;
|
|
34132
34240
|
try {
|
|
34133
|
-
for (; pendingFrame.current?.length &&
|
|
34241
|
+
for (; pendingFrame.current?.length && active2 === generation.current; ) {
|
|
34134
34242
|
let frame = pendingFrame.current.shift(), bitmap = await createImageBitmap(new Blob([frame.bytes], { type: "image/jpeg" }));
|
|
34135
34243
|
try {
|
|
34136
|
-
if (
|
|
34244
|
+
if (active2 !== generation.current) break;
|
|
34137
34245
|
(!size.current.width || !size.current.height) && (size.current = { width: bitmap.width, height: bitmap.height });
|
|
34138
34246
|
let width = frame.info?.frameWidth ?? bitmap.width, height = frame.info?.frameHeight ?? bitmap.height, region = frame.info?.region;
|
|
34139
34247
|
surface.current || (surface.current = document.createElement("canvas"));
|
|
@@ -34162,13 +34270,13 @@ function DesktopViewer({ botId, machines, openSession, renewSession, closeSessio
|
|
|
34162
34270
|
} finally {
|
|
34163
34271
|
drawing.current = !1;
|
|
34164
34272
|
}
|
|
34165
|
-
}, []), connect = (0,
|
|
34273
|
+
}, []), connect = (0, import_react67.useCallback)(async () => {
|
|
34166
34274
|
await stop();
|
|
34167
|
-
let
|
|
34275
|
+
let active2 = generation.current;
|
|
34168
34276
|
setState({ status: "connecting", mode: "watch" }), setStats({ fps: 0, width: 0, height: 0 });
|
|
34169
34277
|
try {
|
|
34170
34278
|
let ticket = await openSession(botId, machineId, { ...displayId ? { displayId } : {}, mode: "watch", fps: 15 });
|
|
34171
|
-
if (
|
|
34279
|
+
if (active2 !== generation.current) {
|
|
34172
34280
|
await closeSession(botId, ticket.sessionId);
|
|
34173
34281
|
return;
|
|
34174
34282
|
}
|
|
@@ -34179,18 +34287,18 @@ function DesktopViewer({ botId, machines, openSession, renewSession, closeSessio
|
|
|
34179
34287
|
onInputAcknowledged: (event, meta) => recorder.inputAcknowledged(event, meta),
|
|
34180
34288
|
onInputFailure: (event, meta) => recorder.inputFailed(event, meta),
|
|
34181
34289
|
onMetadata: (value) => {
|
|
34182
|
-
|
|
34290
|
+
active2 === generation.current && (value.displays && setDisplays(value.displays), value.width && value.height && (size.current = { width: value.width, height: value.height }), setMetadata((before) => {
|
|
34183
34291
|
let next = { ...before, ...value };
|
|
34184
34292
|
return recorder.metadataChanged(next), next;
|
|
34185
34293
|
}));
|
|
34186
34294
|
},
|
|
34187
34295
|
onState: (value) => {
|
|
34188
|
-
|
|
34296
|
+
active2 === generation.current && (["error", "disconnected"].includes(value.status) && recorder.invalidate("ROUTINE_DESKTOP_DISCONNECTED"), setState((before) => ({ ...before, error: "", ...value })));
|
|
34189
34297
|
}
|
|
34190
34298
|
});
|
|
34191
34299
|
let renew = () => {
|
|
34192
34300
|
renewTimer.current = setTimeout(async () => {
|
|
34193
|
-
if (!(
|
|
34301
|
+
if (!(active2 !== generation.current || !ticketRef.current))
|
|
34194
34302
|
try {
|
|
34195
34303
|
ticketRef.current = await renewSession(botId, ticket.sessionId), renew();
|
|
34196
34304
|
} catch (failure) {
|
|
@@ -34200,12 +34308,12 @@ function DesktopViewer({ botId, machines, openSession, renewSession, closeSessio
|
|
|
34200
34308
|
};
|
|
34201
34309
|
renew();
|
|
34202
34310
|
} catch (failure) {
|
|
34203
|
-
|
|
34311
|
+
active2 === generation.current && setState({ status: "error", mode: "watch", error: String(failure?.message ?? failure) });
|
|
34204
34312
|
}
|
|
34205
34313
|
}, [stop, botId, machineId, displayId, openSession, closeSession, renewSession, draw]);
|
|
34206
|
-
(0,
|
|
34314
|
+
(0, import_react67.useEffect)(() => () => {
|
|
34207
34315
|
stop();
|
|
34208
|
-
}, [stop]), (0,
|
|
34316
|
+
}, [stop]), (0, import_react67.useEffect)(() => {
|
|
34209
34317
|
let lost = () => release();
|
|
34210
34318
|
return window.addEventListener("blur", lost), document.addEventListener("visibilitychange", lost), () => {
|
|
34211
34319
|
window.removeEventListener("blur", lost), document.removeEventListener("visibilitychange", lost);
|
|
@@ -34232,7 +34340,7 @@ function DesktopViewer({ botId, machines, openSession, renewSession, closeSessio
|
|
|
34232
34340
|
event.preventDefault(), event.stopPropagation();
|
|
34233
34341
|
let input = desktopKeyboardInput(event, action);
|
|
34234
34342
|
input && streamRef.current?.input(input);
|
|
34235
|
-
}, screen = (ref, big = !1) => /* @__PURE__ */
|
|
34343
|
+
}, screen = (ref, big = !1) => /* @__PURE__ */ import_react67.default.createElement(
|
|
34236
34344
|
"canvas",
|
|
34237
34345
|
{
|
|
34238
34346
|
ref,
|
|
@@ -34257,22 +34365,22 @@ function DesktopViewer({ botId, machines, openSession, renewSession, closeSessio
|
|
|
34257
34365
|
state.mode === "control" && (event.preventDefault(), streamRef.current?.input({ type: "wheel", deltaX: Math.round(event.deltaX), deltaY: Math.round(event.deltaY) }));
|
|
34258
34366
|
}
|
|
34259
34367
|
}
|
|
34260
|
-
), controls = /* @__PURE__ */
|
|
34368
|
+
), controls = /* @__PURE__ */ import_react67.default.createElement("div", { className: "bp-actions" }, /* @__PURE__ */ import_react67.default.createElement("button", { disabled: state.status !== "connected" || state.mode === "watch", onClick: () => {
|
|
34261
34369
|
release(), streamRef.current?.setMode("watch");
|
|
34262
|
-
} }, "仅观看"), /* @__PURE__ */
|
|
34263
|
-
return /* @__PURE__ */
|
|
34370
|
+
} }, "仅观看"), /* @__PURE__ */ import_react67.default.createElement("button", { disabled: state.status !== "connected" || state.mode === "control" || !canControl, onClick: () => streamRef.current?.setMode("control") }, "取得控制权"), /* @__PURE__ */ import_react67.default.createElement("span", { role: "status" }, state.mode === "control" ? "你正在控制这台电脑" : "仅观看"));
|
|
34371
|
+
return /* @__PURE__ */ import_react67.default.createElement("section", { className: "bp-desktop-viewer" }, /* @__PURE__ */ import_react67.default.createElement("div", { className: "bp-card-title" }, /* @__PURE__ */ import_react67.default.createElement("h3", null, /* @__PURE__ */ import_react67.default.createElement(UiIcon, { name: "computer", size: 16 }), " 远程桌面"), /* @__PURE__ */ import_react67.default.createElement("span", { className: "bp-desktop-status", "data-connected": state.status === "connected" }, STATUS2[state.status] ?? state.status)), /* @__PURE__ */ import_react67.default.createElement("div", { className: "bp-actions" }, /* @__PURE__ */ import_react67.default.createElement("select", { "aria-label": "远程桌面电脑", value: machineId, onChange: (event) => {
|
|
34264
34372
|
stop(), setMachineId(event.target.value), setDisplayId(""), setState({ status: "idle", mode: "watch" });
|
|
34265
|
-
} }, machines.map((item) => /* @__PURE__ */
|
|
34373
|
+
} }, machines.map((item) => /* @__PURE__ */ import_react67.default.createElement("option", { key: item.machineId ?? item.id, value: item.machineId ?? item.id }, item.label ?? item.name ?? item.machineId ?? item.id))), displays.length > 1 && /* @__PURE__ */ import_react67.default.createElement("select", { "aria-label": "远程显示器", value: displayId, onChange: (event) => {
|
|
34266
34374
|
stop(), setDisplayId(event.target.value), setState({ status: "idle", mode: "watch" });
|
|
34267
|
-
} }, /* @__PURE__ */
|
|
34375
|
+
} }, /* @__PURE__ */ import_react67.default.createElement("option", { value: "" }, "主显示器"), displays.map((display) => /* @__PURE__ */ import_react67.default.createElement("option", { key: display.id ?? display.displayId, value: display.id ?? display.displayId }, display.name ?? display.id ?? display.displayId))), /* @__PURE__ */ import_react67.default.createElement("button", { className: "bp-button-primary", disabled: !machineId || !botId || ["connecting", "authenticating"].includes(state.status), onClick: () => {
|
|
34268
34376
|
connect();
|
|
34269
|
-
} }, state.status === "connected" ? "重新连接" : "连接桌面"), /* @__PURE__ */
|
|
34377
|
+
} }, state.status === "connected" ? "重新连接" : "连接桌面"), /* @__PURE__ */ import_react67.default.createElement("button", { disabled: !ticketRef.current, onClick: () => {
|
|
34270
34378
|
stop().then((result) => setState(result?.stopConfirmed === !0 ? { status: "idle", mode: "watch" } : { status: "error", mode: "watch", error: "画面连接已关闭,但远端尚未确认释放输入,请检查远程电脑。" }));
|
|
34271
|
-
} }, "断开")), state.error && /* @__PURE__ */
|
|
34379
|
+
} }, "断开")), state.error && /* @__PURE__ */ import_react67.default.createElement("p", { className: "bp-error", role: "alert" }, state.error), controls, /* @__PURE__ */ import_react67.default.createElement("div", { className: "bp-stream-screen", "data-connected": state.status === "connected", onDoubleClick: () => {
|
|
34272
34380
|
state.mode === "watch" && setExpanded(!0);
|
|
34273
|
-
} }, screen(canvasRef), state.status !== "connected" && /* @__PURE__ */
|
|
34381
|
+
} }, screen(canvasRef), state.status !== "connected" && /* @__PURE__ */ import_react67.default.createElement("div", { className: "bp-desktop-idle" }, /* @__PURE__ */ import_react67.default.createElement(UiIcon, { name: "computer", size: 34 }), /* @__PURE__ */ import_react67.default.createElement("strong", null, ["connecting", "authenticating"].includes(state.status) ? "正在连接你的电脑…" : "你的电脑,就在这里"), /* @__PURE__ */ import_react67.default.createElement("span", null, "连接后查看实时桌面,或取得鼠标键盘控制权"))), /* @__PURE__ */ import_react67.default.createElement("div", { className: "bp-actions" }, /* @__PURE__ */ import_react67.default.createElement("small", null, stats.width ? `${stats.width} × ${stats.height} · ${stats.fps} 帧/秒${stats.frameWidth && stats.frameWidth !== stats.width ? ` · 传输 ${stats.frameWidth} × ${stats.frameHeight}` : ""}` : "连接后显示整台电脑的桌面。"), /* @__PURE__ */ import_react67.default.createElement("button", { onClick: () => setExpanded(!0) }, "放大")), state.mode === "control" && /* @__PURE__ */ import_react67.default.createElement("div", { className: "bp-actions" }, /* @__PURE__ */ import_react67.default.createElement("input", { "aria-label": "发送到远程电脑的文字", value: text7, onChange: (event) => setText(event.target.value), placeholder: "中文或多行文字" }), /* @__PURE__ */ import_react67.default.createElement("button", { disabled: !text7, onClick: () => {
|
|
34274
34382
|
streamRef.current?.input({ type: "text", text: text7 }) && setText("");
|
|
34275
|
-
} }, "发送文字")), typeof saveRoutine == "function" && /* @__PURE__ */
|
|
34383
|
+
} }, "发送文字")), typeof saveRoutine == "function" && /* @__PURE__ */ import_react67.default.createElement(
|
|
34276
34384
|
RoutineCaptureControls,
|
|
34277
34385
|
{
|
|
34278
34386
|
recorder,
|
|
@@ -34284,43 +34392,95 @@ function DesktopViewer({ botId, machines, openSession, renewSession, closeSessio
|
|
|
34284
34392
|
releaseInput: () => streamRef.current?.releaseInput(),
|
|
34285
34393
|
saveRoutine: (routine) => saveRoutine(botId, routine)
|
|
34286
34394
|
}
|
|
34287
|
-
), expanded && /* @__PURE__ */
|
|
34395
|
+
), expanded && /* @__PURE__ */ import_react67.default.createElement("div", { className: "bp-stream-overlay", role: "dialog", "aria-modal": "true", "aria-label": "远程桌面放大" }, /* @__PURE__ */ import_react67.default.createElement("div", { className: "bp-stream-dialog" }, /* @__PURE__ */ import_react67.default.createElement("div", { className: "bp-actions" }, controls, /* @__PURE__ */ import_react67.default.createElement("button", { onClick: () => {
|
|
34288
34396
|
release(), setExpanded(!1);
|
|
34289
34397
|
} }, "关闭放大")), screen(largeRef, !0))));
|
|
34290
34398
|
}
|
|
34291
34399
|
function DesktopPane2({ bot }) {
|
|
34292
|
-
let api = globalThis.__dshDesktop, [machines, setMachines] = (0,
|
|
34293
|
-
return (0,
|
|
34294
|
-
let
|
|
34400
|
+
let api = globalThis.__dshDesktop, [machines, setMachines] = (0, import_react67.useState)([]), [error, setError] = (0, import_react67.useState)("");
|
|
34401
|
+
return (0, import_react67.useEffect)(() => {
|
|
34402
|
+
let active2 = !0;
|
|
34295
34403
|
return Promise.resolve(api?.machines?.(bot.id)).then((rows2) => {
|
|
34296
|
-
|
|
34404
|
+
active2 && setMachines(rows2 ?? []);
|
|
34297
34405
|
}, (failure) => {
|
|
34298
|
-
|
|
34406
|
+
active2 && setError(failure.message);
|
|
34299
34407
|
}), () => {
|
|
34300
|
-
|
|
34408
|
+
active2 = !1;
|
|
34301
34409
|
};
|
|
34302
|
-
}, [api, bot.id]), api?.open ? error ? /* @__PURE__ */
|
|
34410
|
+
}, [api, bot.id]), api?.open ? error ? /* @__PURE__ */ import_react67.default.createElement("p", { role: "alert" }, error) : machines.length ? /* @__PURE__ */ import_react67.default.createElement(DesktopViewer, { key: bot.id, botId: bot.id, machines, openSession: api.open, renewSession: api.renew, closeSession: api.close, saveRoutine: api.saveRoutine }) : /* @__PURE__ */ import_react67.default.createElement("p", { className: "bp-muted" }, "在“远程电脑”中配对电脑并为这个 Bot 授权。") : /* @__PURE__ */ import_react67.default.createElement("p", { className: "bp-muted" }, "桌面通道尚未就绪。");
|
|
34303
34411
|
}
|
|
34304
34412
|
function DesktopWorkbench({ snapshot, dispatch }) {
|
|
34305
|
-
let bots = snapshot.bots ?? [], [botId, setBotId] = (0,
|
|
34413
|
+
let bots = snapshot.bots ?? [], [botId, setBotId] = (0, import_react67.useState)(bots[0]?.id ?? ""), machines = (snapshot.machines?.items ?? []).filter((item) => item.status !== "revoked"), current = (0, import_react67.useRef)({ dispatch, machines });
|
|
34306
34414
|
current.current = { dispatch, machines };
|
|
34307
|
-
let openSession = (0,
|
|
34308
|
-
return machines.length ? /* @__PURE__ */
|
|
34415
|
+
let openSession = (0, import_react67.useCallback)((id2, machineId, options) => current.current.dispatch("machine.desktop.open", { botId: id2, machineId, rootId: rootOf2(current.current.machines.find((item) => item.id === machineId)), ...options }), []), renewSession = (0, import_react67.useCallback)((id2, sessionId) => current.current.dispatch("machine.desktop.renew", { botId: id2, sessionId }), []), closeSession = (0, import_react67.useCallback)((id2, sessionId) => current.current.dispatch("machine.desktop.close", { botId: id2, sessionId }), []), saveRoutine = (0, import_react67.useCallback)((id2, routine) => current.current.dispatch("routine.save", { botId: id2, routine }), []);
|
|
34416
|
+
return machines.length ? /* @__PURE__ */ import_react67.default.createElement("section", { className: "bp-card" }, /* @__PURE__ */ import_react67.default.createElement("div", { className: "bp-actions", style: { marginBottom: 20 } }, /* @__PURE__ */ import_react67.default.createElement("label", null, "连接身份", /* @__PURE__ */ import_react67.default.createElement("select", { value: botId, onChange: (event) => setBotId(event.target.value) }, bots.map((bot) => /* @__PURE__ */ import_react67.default.createElement("option", { key: bot.id, value: bot.id }, bot.name ?? bot.id))))), /* @__PURE__ */ import_react67.default.createElement(DesktopViewer, { key: botId, botId, machines, openSession, renewSession, closeSession, saveRoutine })) : /* @__PURE__ */ import_react67.default.createElement("section", { className: "bp-card" }, /* @__PURE__ */ import_react67.default.createElement("div", { className: "bp-empty-state" }, /* @__PURE__ */ import_react67.default.createElement("span", { className: "bp-empty-icon" }, /* @__PURE__ */ import_react67.default.createElement(UiIcon, { name: "computer", size: 29 })), /* @__PURE__ */ import_react67.default.createElement("strong", null, "连接你的第一台电脑"), /* @__PURE__ */ import_react67.default.createElement("p", null, "在自己的 Windows 或云电脑上运行 Agent,再导入配对文件,就能在这里查看和接管桌面。"), /* @__PURE__ */ import_react67.default.createElement("div", { className: "bp-actions" }, /* @__PURE__ */ import_react67.default.createElement("a", { className: "bp-download-link", href: "https://github.com/Alice-Marx/dsh-model-router/releases/download/v0.63.0/dsh-remote-agent-0.1.0-windows-x64.zip", target: "_blank", rel: "noopener noreferrer" }, /* @__PURE__ */ import_react67.default.createElement(UiIcon, { name: "arrow", size: 15 }), "下载 Windows Agent"), /* @__PURE__ */ import_react67.default.createElement("button", { className: "bp-button-primary", onClick: () => {
|
|
34309
34417
|
let setup = document.querySelector(".bp-machine-setup");
|
|
34310
34418
|
setup && (setup.open = !0, setup.scrollIntoView({ block: "start", behavior: "smooth" }));
|
|
34311
34419
|
} }, "导入配对文件"))));
|
|
34312
34420
|
}
|
|
34313
34421
|
|
|
34422
|
+
// apps/integration-client/routing-submissions.mjs
|
|
34423
|
+
var scopes = /* @__PURE__ */ new WeakMap(), same = (left, right) => left?.requestKey === right?.requestKey && left?.requesterBotId === right?.requesterBotId, reference = (value) => {
|
|
34424
|
+
for (let field2 of ["requestKey", "requesterBotId"])
|
|
34425
|
+
if (typeof value?.[field2] != "string" || !/^[A-Za-z0-9_-]{1,128}$/.test(value[field2])) throw new TypeError("INVALID_ROUTING_SUBMISSION_REFERENCE");
|
|
34426
|
+
return { requestKey: value.requestKey, requesterBotId: value.requesterBotId };
|
|
34427
|
+
};
|
|
34428
|
+
function submissionCode(input) {
|
|
34429
|
+
let value = reference(input);
|
|
34430
|
+
return `dsh-route-v1:${value.requesterBotId}:${value.requestKey}`;
|
|
34431
|
+
}
|
|
34432
|
+
function parseCode(code) {
|
|
34433
|
+
if (typeof code != "string" || code.length > 1024) throw new TypeError("INVALID_ROUTING_SUBMISSION_CODE");
|
|
34434
|
+
let match = /^dsh-route-v1:([A-Za-z0-9_-]{1,128}):([A-Za-z0-9_-]{1,128})$/.exec(code.trim());
|
|
34435
|
+
if (!match) throw new TypeError("INVALID_ROUTING_SUBMISSION_CODE");
|
|
34436
|
+
return { requesterBotId: match[1], requestKey: match[2] };
|
|
34437
|
+
}
|
|
34438
|
+
function routingSubmissions(scope) {
|
|
34439
|
+
if (!scope || !["object", "function"].includes(typeof scope)) throw new TypeError("ROUTING_SUBMISSION_SCOPE_REQUIRED");
|
|
34440
|
+
if (scopes.has(scope)) return scopes.get(scope);
|
|
34441
|
+
let value = null, listeners2 = /* @__PURE__ */ new Set(), publish2 = (next) => {
|
|
34442
|
+
value = next === null ? null : Object.freeze(next);
|
|
34443
|
+
for (let listener of [...listeners2]) listener();
|
|
34444
|
+
}, store = Object.freeze({
|
|
34445
|
+
getSnapshot: () => value,
|
|
34446
|
+
subscribe: (listener) => (listeners2.add(listener), () => listeners2.delete(listener)),
|
|
34447
|
+
start(input) {
|
|
34448
|
+
let identity2 = reference(input);
|
|
34449
|
+
return value ? !1 : (publish2({ ...identity2, state: "submitting", planId: null, planState: null }), !0);
|
|
34450
|
+
},
|
|
34451
|
+
restore(code) {
|
|
34452
|
+
return value ? !1 : (publish2({ ...parseCode(code), state: "unknown", planId: null, planState: null }), !0);
|
|
34453
|
+
},
|
|
34454
|
+
update(input, result) {
|
|
34455
|
+
if (!same(value, input)) return !1;
|
|
34456
|
+
if (!["unknown", "not-found", "confirmed"].includes(result.state)) throw new TypeError("INVALID_ROUTING_SUBMISSION_STATE");
|
|
34457
|
+
return value.state === "confirmed" && result.state !== "confirmed" ? !1 : (publish2({
|
|
34458
|
+
...reference(input),
|
|
34459
|
+
state: result.state,
|
|
34460
|
+
planId: result.state === "confirmed" ? result.planId : null,
|
|
34461
|
+
planState: result.state === "confirmed" ? result.planState ?? (value.state === "confirmed" ? value.planState : null) : null
|
|
34462
|
+
}), !0);
|
|
34463
|
+
},
|
|
34464
|
+
clear(input) {
|
|
34465
|
+
return !same(value, input) || value.state !== "confirmed" ? !1 : (publish2(null), !0);
|
|
34466
|
+
},
|
|
34467
|
+
dismissUnconfirmed(input) {
|
|
34468
|
+
return !same(value, input) || value.state !== "not-found" ? !1 : (publish2(null), !0);
|
|
34469
|
+
}
|
|
34470
|
+
});
|
|
34471
|
+
return scopes.set(scope, store), store;
|
|
34472
|
+
}
|
|
34473
|
+
|
|
34314
34474
|
// apps/integration-client/panels.jsx
|
|
34315
34475
|
var NAV_EVENT = "bot-product:navigation", activePanel = null, announcePanel = (id2, clear = !1) => {
|
|
34316
34476
|
clear ? activePanel === id2 && (activePanel = null) : activePanel = id2, document.dispatchEvent(new document.defaultView.CustomEvent(NAV_EVENT, { detail: { id: activePanel } }));
|
|
34317
34477
|
};
|
|
34318
34478
|
function ProductNavigation({ openPanel, panels, compact: compact2 = !1 }) {
|
|
34319
|
-
let [
|
|
34320
|
-
return (0,
|
|
34479
|
+
let [active2, setActive] = (0, import_react68.useState)(() => activePanel);
|
|
34480
|
+
return (0, import_react68.useEffect)(() => {
|
|
34321
34481
|
let change = (event) => setActive(event.detail.id);
|
|
34322
34482
|
return document.addEventListener(NAV_EVENT, change), setActive(activePanel), () => document.removeEventListener(NAV_EVENT, change);
|
|
34323
|
-
}, []), /* @__PURE__ */
|
|
34483
|
+
}, []), /* @__PURE__ */ import_react68.default.createElement("nav", { className: `bp-nav${compact2 ? " bp-nav-compact" : ""}`, "aria-label": "Bot 工作系统" }, /* @__PURE__ */ import_react68.default.createElement("p", { className: "bp-nav-label" }, "工作空间"), [
|
|
34324
34484
|
[panels.bindings, "Bot 绑定", "team", "绑定"],
|
|
34325
34485
|
[panels.tasks, "任务", "tasks", "任务"],
|
|
34326
34486
|
[panels.machines, "远程电脑", "computer", "电脑"],
|
|
@@ -34328,29 +34488,29 @@ function ProductNavigation({ openPanel, panels, compact: compact2 = !1 }) {
|
|
|
34328
34488
|
[panels.routine, "例行任务", "repeat", "例行"],
|
|
34329
34489
|
[panels.usage, "费用与用量", "chart", "费用"],
|
|
34330
34490
|
["model-router-galgame", "高级工作台", "settings", "工作台"]
|
|
34331
|
-
].map(([id2, label, icon2, caption]) => /* @__PURE__ */
|
|
34491
|
+
].map(([id2, label, icon2, caption]) => /* @__PURE__ */ import_react68.default.createElement(
|
|
34332
34492
|
"button",
|
|
34333
34493
|
{
|
|
34334
34494
|
key: id2,
|
|
34335
34495
|
type: "button",
|
|
34336
|
-
"aria-current":
|
|
34496
|
+
"aria-current": active2 === id2 ? "page" : void 0,
|
|
34337
34497
|
onClick: () => {
|
|
34338
34498
|
announcePanel(id2), openPanel(id2);
|
|
34339
34499
|
},
|
|
34340
34500
|
title: label,
|
|
34341
34501
|
"aria-label": label
|
|
34342
34502
|
},
|
|
34343
|
-
/* @__PURE__ */
|
|
34344
|
-
/* @__PURE__ */
|
|
34345
|
-
/* @__PURE__ */
|
|
34503
|
+
/* @__PURE__ */ import_react68.default.createElement(UiIcon, { name: icon2, size: 17 }),
|
|
34504
|
+
/* @__PURE__ */ import_react68.default.createElement("span", { className: "bp-nav-name" }, label),
|
|
34505
|
+
/* @__PURE__ */ import_react68.default.createElement("span", { className: "bp-nav-caption" }, caption)
|
|
34346
34506
|
)));
|
|
34347
34507
|
}
|
|
34348
34508
|
function Blocked({ value }) {
|
|
34349
|
-
return /* @__PURE__ */
|
|
34509
|
+
return /* @__PURE__ */ import_react68.default.createElement("aside", { className: "bp-blocked", role: "status" }, /* @__PURE__ */ import_react68.default.createElement("strong", null, "暂不可用"), /* @__PURE__ */ import_react68.default.createElement("p", null, value?.reason ?? "尚未取得宿主状态。"), value?.nextAction && /* @__PURE__ */ import_react68.default.createElement("p", { className: "bp-muted" }, "下一步:", value.nextAction));
|
|
34350
34510
|
}
|
|
34351
|
-
var
|
|
34511
|
+
var Value2 = ({ label, children }) => /* @__PURE__ */ import_react68.default.createElement("div", { className: "bp-value" }, /* @__PURE__ */ import_react68.default.createElement("dt", null, label), /* @__PURE__ */ import_react68.default.createElement("dd", null, children ?? "未配置")), Tag3 = ({ children }) => /* @__PURE__ */ import_react68.default.createElement("span", { className: "bp-tag" }, children), subscriptionText = (value) => value && typeof value == "object" ? `今日 ${value.callsToday ?? "未知"} 次 · 本月 ${value.callsMonth ?? "未知"} 次` : value ?? "见逐来源收据";
|
|
34352
34512
|
function BotRuntimeRow({ botId, dispatch, busy }) {
|
|
34353
|
-
let [state, setState] =
|
|
34513
|
+
let [state, setState] = import_react68.default.useState(null), [error, setError] = import_react68.default.useState(""), [working, setWorking] = import_react68.default.useState(!1), load = import_react68.default.useCallback(async () => {
|
|
34354
34514
|
if (typeof dispatch == "function")
|
|
34355
34515
|
try {
|
|
34356
34516
|
let rows2 = await dispatch("botRuntimeStatus", {}), row = Array.isArray(rows2) ? rows2.find((item) => item.botId === botId) : null;
|
|
@@ -34364,7 +34524,7 @@ function BotRuntimeRow({ botId, dispatch, busy }) {
|
|
|
34364
34524
|
} catch (failure) {
|
|
34365
34525
|
setState(null), setError(String(failure?.message ?? failure));
|
|
34366
34526
|
}
|
|
34367
|
-
}, [botId, dispatch]), [history, setHistory] =
|
|
34527
|
+
}, [botId, dispatch]), [history, setHistory] = import_react68.default.useState([]), [historyError, setHistoryError] = import_react68.default.useState(""), loadHistory = import_react68.default.useCallback(async () => {
|
|
34368
34528
|
if (typeof dispatch == "function")
|
|
34369
34529
|
try {
|
|
34370
34530
|
let rows2 = await dispatch("botRuntimeHistory", { botId, limit: 20 });
|
|
@@ -34372,7 +34532,7 @@ function BotRuntimeRow({ botId, dispatch, busy }) {
|
|
|
34372
34532
|
} catch (failure) {
|
|
34373
34533
|
setHistory([]), setHistoryError(String(failure?.message ?? failure));
|
|
34374
34534
|
}
|
|
34375
|
-
}, [botId, dispatch]), [full2, setFull] =
|
|
34535
|
+
}, [botId, dispatch]), [full2, setFull] = import_react68.default.useState(null), openFull = import_react68.default.useCallback(async (index) => {
|
|
34376
34536
|
try {
|
|
34377
34537
|
let message2 = await dispatch("botRuntimeMessage", { botId, index });
|
|
34378
34538
|
setFull({ index, ...message2 }), setHistoryError("");
|
|
@@ -34380,7 +34540,7 @@ function BotRuntimeRow({ botId, dispatch, busy }) {
|
|
|
34380
34540
|
setHistoryError(String(failure?.message ?? failure)), setFull(null);
|
|
34381
34541
|
}
|
|
34382
34542
|
}, [botId, dispatch]);
|
|
34383
|
-
if (
|
|
34543
|
+
if (import_react68.default.useEffect(() => {
|
|
34384
34544
|
load();
|
|
34385
34545
|
}, [load]), !state && !error) return null;
|
|
34386
34546
|
let target = state?.runtime === "independent" ? "integration" : "independent", move = async () => {
|
|
@@ -34393,16 +34553,16 @@ function BotRuntimeRow({ botId, dispatch, busy }) {
|
|
|
34393
34553
|
setWorking(!1);
|
|
34394
34554
|
}
|
|
34395
34555
|
};
|
|
34396
|
-
return /* @__PURE__ */
|
|
34556
|
+
return /* @__PURE__ */ import_react68.default.createElement("div", { className: "bp-runtime" }, /* @__PURE__ */ import_react68.default.createElement("dl", { className: "bp-facts" }, /* @__PURE__ */ import_react68.default.createElement(Value2, { label: "运行时" }, state?.runtime === "independent" ? "独立循环 + 独立会话库" : "Harness 会话集成"), /* @__PURE__ */ import_react68.default.createElement(Value2, { label: "切换时间" }, state?.changedAt ? new Date(state.changedAt).toLocaleString("zh-CN") : "从未切换")), /* @__PURE__ */ import_react68.default.createElement("div", { className: "bp-actions" }, /* @__PURE__ */ import_react68.default.createElement("button", { disabled: busy || working, onClick: () => {
|
|
34397
34557
|
move();
|
|
34398
|
-
} }, working ? "切换中…" : target === "independent" ? "迁移到独立运行时" : "迁回 Harness 会话")), /* @__PURE__ */
|
|
34558
|
+
} }, working ? "切换中…" : target === "independent" ? "迁移到独立运行时" : "迁回 Harness 会话")), /* @__PURE__ */ import_react68.default.createElement("p", { className: "bp-muted" }, "迁移是原子的:Bot 正在对话时会被拒绝。搬过去后该 Bot 的会话写进独立会话库,界面与工具沿用现有授权。"), error && /* @__PURE__ */ import_react68.default.createElement("p", { className: "bp-error", role: "alert" }, error), state ? /* @__PURE__ */ import_react68.default.createElement("details", { className: "bp-log" }, /* @__PURE__ */ import_react68.default.createElement("summary", null, "最近会话(仅预览)"), /* @__PURE__ */ import_react68.default.createElement("button", { type: "button", disabled: working, onClick: () => {
|
|
34399
34559
|
loadHistory();
|
|
34400
|
-
} }, "读取预览"), historyError && /* @__PURE__ */
|
|
34560
|
+
} }, "读取预览"), historyError && /* @__PURE__ */ import_react68.default.createElement("p", { className: "bp-error", role: "alert" }, historyError), history.length === 0 ? /* @__PURE__ */ import_react68.default.createElement("p", { className: "bp-muted" }, "点“读取预览”加载最近 20 条。") : /* @__PURE__ */ import_react68.default.createElement("ul", { className: "bp-checklist" }, history.map((row, index) => /* @__PURE__ */ import_react68.default.createElement("li", { key: index }, /* @__PURE__ */ import_react68.default.createElement("strong", null, row.role), row.name ? ` · ${row.name}` : "", " · ", row.chars, " 字", row.at ? ` · ${new Date(row.at).toLocaleTimeString("zh-CN")}` : "", /* @__PURE__ */ import_react68.default.createElement("small", null, row.preview, String(row.preview ?? "").length < row.chars ? "…" : ""), /* @__PURE__ */ import_react68.default.createElement("button", { type: "button", onClick: () => {
|
|
34401
34561
|
openFull(index);
|
|
34402
|
-
} }, "查看全文")))), full2 ? /* @__PURE__ */
|
|
34562
|
+
} }, "查看全文")))), full2 ? /* @__PURE__ */ import_react68.default.createElement("div", { className: "bp-fulltext" }, /* @__PURE__ */ import_react68.default.createElement("p", { className: "bp-muted" }, "第 ", full2.index + 1, " 条(从最新往前数)· ", full2.role, " · ", full2.chars, " 字"), /* @__PURE__ */ import_react68.default.createElement("pre", null, full2.content)) : null) : null);
|
|
34403
34563
|
}
|
|
34404
34564
|
function BotBindings({ snapshot, openSession, dispatch, busy }) {
|
|
34405
|
-
let bots = snapshot.bots ?? [], [selected, setSelected] = (0,
|
|
34565
|
+
let bots = snapshot.bots ?? [], [selected, setSelected] = (0, import_react68.useState)(bots[0]?.id ?? ""), bot = bots.find((row) => row.id === selected) ?? bots[0], section = snapshot.botBindings ?? snapshot.bindings, binding = section?.items?.find((row) => row.botId === bot?.id), capabilities = binding?.tools ?? binding?.capabilities ?? [], permissionGroups = [
|
|
34406
34566
|
["模型调用", /^model\//],
|
|
34407
34567
|
["模型工作台", /^(?:command\/router|tool\/model_router_)/],
|
|
34408
34568
|
["任务管理", /^task\//],
|
|
@@ -34411,130 +34571,221 @@ function BotBindings({ snapshot, openSession, dispatch, busy }) {
|
|
|
34411
34571
|
["例行任务", /^tool\/bot_routine_/],
|
|
34412
34572
|
["远程工具", /^remote\//]
|
|
34413
34573
|
].filter(([, pattern]) => capabilities.some((value) => pattern.test(value))).map(([label]) => label);
|
|
34414
|
-
return bots.length ? /* @__PURE__ */
|
|
34415
|
-
}
|
|
34416
|
-
function BotAttention({ snapshot, dispatch, busy, openTask }) {
|
|
34417
|
-
let rows2 = deriveBotAttention(snapshot);
|
|
34418
|
-
if (rows2.length === 0) return null;
|
|
34419
|
-
let actions = snapshot?.availableActions ?? [], run2 = (row, action, payload) => {
|
|
34420
|
-
!dispatch || busy || !actions.includes(action) || dispatch(action, { botId: row.botId, taskId: row.taskId, requestKey: crypto.randomUUID(), ...payload });
|
|
34421
|
-
};
|
|
34422
|
-
return /* @__PURE__ */ import_react67.default.createElement("section", { className: "bp-card bp-attention", "aria-label": "需要你处理" }, /* @__PURE__ */ import_react67.default.createElement("div", { className: "bp-card-title" }, /* @__PURE__ */ import_react67.default.createElement("h2", null, "需要你处理"), /* @__PURE__ */ import_react67.default.createElement(Tag2, null, botAttentionSummary(rows2))), /* @__PURE__ */ import_react67.default.createElement("ul", { className: "bp-attention-list" }, rows2.map((row) => /* @__PURE__ */ import_react67.default.createElement("li", { key: row.key, className: `bp-attention-row bp-attention-${row.stage}` }, /* @__PURE__ */ import_react67.default.createElement("div", null, /* @__PURE__ */ import_react67.default.createElement("strong", null, row.title), /* @__PURE__ */ import_react67.default.createElement("p", { className: "bp-muted" }, row.detail)), row.action === "reconcile" && actions.includes("task.reconcile") && /* @__PURE__ */ import_react67.default.createElement("button", { disabled: busy, onClick: () => run2(row, "task.reconcile") }, "核对原收据"), row.action === "retry" && actions.includes("task.retry") && /* @__PURE__ */ import_react67.default.createElement("button", { disabled: busy, onClick: () => run2(row, "task.retry") }, "重试"), row.action !== "reconcile" && row.action !== "retry" && /* @__PURE__ */ import_react67.default.createElement("button", { disabled: busy, onClick: () => openTask(row.taskId) }, "打开任务")))));
|
|
34574
|
+
return bots.length ? /* @__PURE__ */ import_react68.default.createElement("div", { className: "bp-columns" }, /* @__PURE__ */ import_react68.default.createElement("div", { className: "bp-bot-list", "aria-label": "Bot 列表" }, bots.map((item) => /* @__PURE__ */ import_react68.default.createElement("button", { key: item.id, "aria-current": item.id === bot?.id ? "true" : void 0, onClick: () => setSelected(item.id) }, /* @__PURE__ */ import_react68.default.createElement("span", { className: "bp-person-avatar" }, /* @__PURE__ */ import_react68.default.createElement(UiIcon, { name: "bot", size: 23 })), /* @__PURE__ */ import_react68.default.createElement("span", { className: "bp-person-copy" }, /* @__PURE__ */ import_react68.default.createElement("strong", null, item.name), item.main && /* @__PURE__ */ import_react68.default.createElement(Tag3, null, "Main"), /* @__PURE__ */ import_react68.default.createElement("small", null, item.role || "尚未填写职责"))))), /* @__PURE__ */ import_react68.default.createElement("article", { className: "bp-card" }, /* @__PURE__ */ import_react68.default.createElement("div", { className: "bp-card-title" }, /* @__PURE__ */ import_react68.default.createElement("div", { className: "bp-person-heading" }, /* @__PURE__ */ import_react68.default.createElement("span", { className: "bp-person-avatar bp-person-avatar-large" }, /* @__PURE__ */ import_react68.default.createElement(UiIcon, { name: "bot", size: 27 })), /* @__PURE__ */ import_react68.default.createElement("div", null, /* @__PURE__ */ import_react68.default.createElement("h2", null, bot.name), /* @__PURE__ */ import_react68.default.createElement("p", { className: "bp-muted" }, bot.main ? "团队协调 Bot" : "团队成员"))), /* @__PURE__ */ import_react68.default.createElement("button", { className: "bp-button-primary", onClick: () => openSession(bot.sessionId) }, "打开私聊", /* @__PURE__ */ import_react68.default.createElement(UiIcon, { name: "arrow", size: 15 }))), /* @__PURE__ */ import_react68.default.createElement("dl", { className: "bp-facts" }, /* @__PURE__ */ import_react68.default.createElement(Value2, { label: "职责" }, bot.role || "未填写"), /* @__PURE__ */ import_react68.default.createElement(Value2, { label: "准确模型" }, modelName(bot.model)), /* @__PURE__ */ import_react68.default.createElement(Value2, { label: "模型策略" }, "精确绑定;不可用时暂停并说明原因"), /* @__PURE__ */ import_react68.default.createElement(Value2, { label: "工作区" }, binding?.workspace?.root ?? binding?.workspaceRef?.rootId ?? bot.workDir ?? "未指定,请在 Bot 详情选择文件夹"), /* @__PURE__ */ import_react68.default.createElement(Value2, { label: "执行位置" }, binding?.machineId ?? binding?.workspaceRef?.machineId ?? "尚未取得宿主绑定"), /* @__PURE__ */ import_react68.default.createElement(Value2, { label: "最大并发" }, binding?.maxConcurrentTasks)), section?.status === "blocked" ? /* @__PURE__ */ import_react68.default.createElement(Blocked, { value: section }) : binding ? /* @__PURE__ */ import_react68.default.createElement(import_react68.default.Fragment, null, /* @__PURE__ */ import_react68.default.createElement("h3", null, "官方工具"), binding.officialTools?.length ? /* @__PURE__ */ import_react68.default.createElement("ul", null, binding.officialTools.map((tool) => /* @__PURE__ */ import_react68.default.createElement("li", { key: tool.toolId }, tool.toolId, " · ", tool.cliModel ?? "未核验模型", " · ", tool.identityStatus ?? tool.identityPolicy ?? "未知"))) : /* @__PURE__ */ import_react68.default.createElement("p", { className: "bp-muted" }, "此 Bot 没有官方工具绑定。"), /* @__PURE__ */ import_react68.default.createElement("h3", null, "有效权限 ", /* @__PURE__ */ import_react68.default.createElement("span", { className: "bp-inline-count" }, capabilities.length, " 项")), /* @__PURE__ */ import_react68.default.createElement("div", { className: "bp-permission-chips" }, permissionGroups.map((label) => /* @__PURE__ */ import_react68.default.createElement("span", { key: label }, /* @__PURE__ */ import_react68.default.createElement(UiIcon, { name: "check", size: 13 }), label)), !capabilities.length && /* @__PURE__ */ import_react68.default.createElement("p", { className: "bp-muted" }, "无额外能力")), binding.blockedReason && /* @__PURE__ */ import_react68.default.createElement(Blocked, { value: { reason: binding.blockedReason, nextAction: binding.nextAction } })) : /* @__PURE__ */ import_react68.default.createElement(Blocked, { value: { reason: "此 Bot 尚未取得有效绑定。", nextAction: "在宿主 Bot 绑定配置中授予明确工具、机器与工作区。" } }), /* @__PURE__ */ import_react68.default.createElement("p", { className: "bp-muted" }, "角色文本不会授予工具或机器权限。职责、模型、记忆及会话设置沿用私聊右侧的 Bot 详情。"), dispatch && /* @__PURE__ */ import_react68.default.createElement("details", { className: "bp-edit-section" }, /* @__PURE__ */ import_react68.default.createElement("summary", null, /* @__PURE__ */ import_react68.default.createElement(UiIcon, { name: "settings", size: 16 }), "编辑权限与预算"), /* @__PURE__ */ import_react68.default.createElement(BotBindingEditor, { bot, record: binding, accounts: snapshot.fundingAccounts, dispatch, busy })), /* @__PURE__ */ import_react68.default.createElement("details", { className: "bp-technical" }, /* @__PURE__ */ import_react68.default.createElement("summary", null, "连接与运行详情"), /* @__PURE__ */ import_react68.default.createElement("dl", { className: "bp-facts" }, /* @__PURE__ */ import_react68.default.createElement(Value2, { label: "稳定 Bot ID" }, bot.id), /* @__PURE__ */ import_react68.default.createElement(Value2, { label: "预算范围" }, binding?.budgetScope)), /* @__PURE__ */ import_react68.default.createElement("h3", null, "完整权限标识"), /* @__PURE__ */ import_react68.default.createElement("p", { className: "bp-code" }, capabilities.join("、") || "无额外能力"), snapshot.availableActions?.includes("botRuntimeStatus") && /* @__PURE__ */ import_react68.default.createElement(BotRuntimeRow, { botId: bot.id, dispatch, busy })))) : /* @__PURE__ */ import_react68.default.createElement("p", null, "还没有 Bot。返回 Main 完成首次设置,或从侧栏新建 Bot。");
|
|
34423
34575
|
}
|
|
34424
|
-
|
|
34425
|
-
let
|
|
34426
|
-
|
|
34427
|
-
|
|
34428
|
-
|
|
34429
|
-
|
|
34576
|
+
var routingPresetLabel = (preset) => ({ economy: "省钱优先", balanced: "均衡", quality: "效果优先" })[preset] ?? "当前策略", routingRefusalMessage = (reason) => {
|
|
34577
|
+
let code = String(reason ?? "").split(":")[0];
|
|
34578
|
+
return {
|
|
34579
|
+
INVALID_CANDIDATE: "候选信息不完整",
|
|
34580
|
+
BOT_DISABLED: "已停用",
|
|
34581
|
+
MISSING_BOT_ID: "缺少 Bot 标识",
|
|
34582
|
+
BOT_MODEL_UNBOUND: "尚未绑定模型",
|
|
34583
|
+
BOT_MACHINE_OFFLINE: "所需电脑未在线",
|
|
34584
|
+
BOT_BUSY: "正在处理其他任务",
|
|
34585
|
+
BOT_MISSING_TOOL: "缺少任务所需工具",
|
|
34586
|
+
BOT_MISSING_CAPABILITY: "缺少任务所需能力",
|
|
34587
|
+
BOT_ROUTING_WORKER_CEILING_INSUFFICIENT: "保存的电脑权限不足"
|
|
34588
|
+
}[code] ?? "不满足本次执行条件";
|
|
34589
|
+
}, validRoutingView = (value) => value && typeof value.enabled == "boolean" && ["economy", "balanced", "quality"].includes(value.preset) && Array.isArray(value.candidates) && value.candidates.every((row) => row && typeof row.botId == "string" && row.botId !== ""), submissionFailureMessage = (failure) => {
|
|
34590
|
+
let code = failure?.code;
|
|
34591
|
+
return code === "REMOTE_OWNER_REQUIRED" ? "请重新登录宿主拥有者账号后核对原提交;请保留核对码,不要重新创建任务。" : ["BOT_ROUTING_STATUS_UNAVAILABLE", "PRODUCT_ACTION_UNAVAILABLE"].includes(code) ? "当前宿主尚不支持原提交核对,请更新宿主或在任务记录中核对;请保留核对码。" : ["BOT_ROUTING_SUBMISSION_IDENTITY_MISMATCH", "INVALID_ROUTING_SUBMISSION_STATUS"].includes(code) ? "返回记录与原提交身份不一致,尚不能确认结果。请在原宿主核对任务记录并保留核对码。" : code === "PRODUCT_READ_ONLY" ? "宿主目前处于只读状态,请恢复宿主后核对原提交;请保留核对码,不要重新创建任务。" : "原提交核对尚未完成,请恢复宿主连接后再次核对;请保留核对码,不会重新提交任务。";
|
|
34592
|
+
};
|
|
34593
|
+
function BotRoutingCard({ snapshot, dispatch, busy, submissionScope = dispatch }) {
|
|
34594
|
+
let submissions = (0, import_react68.useMemo)(() => routingSubmissions(submissionScope), [submissionScope]), submission = (0, import_react68.useSyncExternalStore)(submissions.subscribe, submissions.getSnapshot, submissions.getSnapshot), [view, setView] = import_react68.default.useState(null), [error, setError] = import_react68.default.useState(""), [text7, setText] = import_react68.default.useState(""), [pin, setPin] = import_react68.default.useState(""), [machine, setMachine] = import_react68.default.useState(""), [root, setRoot] = import_react68.default.useState(""), [effect, setEffect] = import_react68.default.useState("read"), [decision, setDecision] = import_react68.default.useState(null), [working, setWorking] = import_react68.default.useState(""), [savedCode, setSavedCode] = (0, import_react68.useState)(""), [copyStatus, setCopyStatus] = (0, import_react68.useState)(""), codeInput = (0, import_react68.useRef)(null), [viewReady, setViewReady] = import_react68.default.useState(!1), control = (0, import_react68.useRef)({ live: !1, epoch: 0, draft: 0, active: null, prepared: null, ready: !1 }), form = (0, import_react68.useRef)({ text: "", pin: "", machine: "", root: "", effect: "read" }), busyRef = (0, import_react68.useRef)(busy);
|
|
34595
|
+
busyRef.current = busy;
|
|
34596
|
+
let call2 = (0, import_react68.useCallback)(async (action, payload) => {
|
|
34597
|
+
if (typeof dispatch != "function") throw new Error("宿主接口尚未就绪。");
|
|
34598
|
+
let value = await dispatch(action, payload, { errorResult: !0 });
|
|
34599
|
+
if (value === void 0 || value?.ok === !1) throw Object.assign(new Error(value?.error?.message ?? "宿主尚未确认这次请求,请刷新后重试。"), { code: value?.error?.code });
|
|
34430
34600
|
return value;
|
|
34431
|
-
}, []),
|
|
34432
|
-
|
|
34601
|
+
}, [dispatch]), invalidate = (0, import_react68.useCallback)(() => {
|
|
34602
|
+
control.current.draft++, control.current.prepared = null, setDecision(null);
|
|
34603
|
+
}, []), editDraft = (changes) => {
|
|
34604
|
+
let next = { ...form.current, ...changes };
|
|
34605
|
+
form.current = next, setText(next.text), setPin(next.pin), setMachine(next.machine), setRoot(next.root), setEffect(next.effect);
|
|
34606
|
+
let previous = submissions.getSnapshot();
|
|
34607
|
+
previous?.state === "confirmed" && submissions.clear(previous), invalidate();
|
|
34608
|
+
}, begin = (0, import_react68.useCallback)((kind) => {
|
|
34609
|
+
let state = control.current;
|
|
34610
|
+
if (!state.live || state.active || busyRef.current) return null;
|
|
34611
|
+
let token = { epoch: state.epoch };
|
|
34612
|
+
return state.active = token, setWorking(kind), setError(""), token;
|
|
34613
|
+
}, []), current = (token) => control.current.live && control.current.epoch === token.epoch && control.current.active === token, finish = (token) => {
|
|
34614
|
+
current(token) && (control.current.active = null, setWorking(""));
|
|
34615
|
+
}, staleView = () => {
|
|
34616
|
+
control.current.ready = !1, setViewReady(!1);
|
|
34617
|
+
}, load = import_react68.default.useCallback(async () => {
|
|
34618
|
+
let token = begin("inspect");
|
|
34619
|
+
if (token) {
|
|
34620
|
+
invalidate(), staleView();
|
|
34433
34621
|
try {
|
|
34434
34622
|
let next = await call2("botRoutingInspect", {});
|
|
34435
|
-
|
|
34623
|
+
if (!current(token)) return;
|
|
34624
|
+
if (!validRoutingView(next)) throw new Error("宿主未返回完整候选信息,请刷新后重试。");
|
|
34625
|
+
setView(next), control.current.ready = !0, setViewReady(!0);
|
|
34436
34626
|
} catch (failure) {
|
|
34437
|
-
setError(String(failure?.message ?? failure));
|
|
34627
|
+
current(token) && setError(String(failure?.message ?? failure));
|
|
34628
|
+
} finally {
|
|
34629
|
+
finish(token);
|
|
34438
34630
|
}
|
|
34439
|
-
|
|
34440
|
-
|
|
34441
|
-
|
|
34442
|
-
|
|
34631
|
+
}
|
|
34632
|
+
}, [call2, begin, invalidate]);
|
|
34633
|
+
(0, import_react68.useEffect)(() => {
|
|
34634
|
+
let state = control.current;
|
|
34635
|
+
return state.live = !0, state.epoch++, state.active = null, state.ready = !1, setView(null), setViewReady(!1), setWorking(""), setSavedCode(""), setCopyStatus(""), setError(""), invalidate(), load(), () => {
|
|
34636
|
+
state.live = !1, state.epoch++, state.draft++, state.active = null, state.prepared = null, state.ready = !1;
|
|
34637
|
+
};
|
|
34638
|
+
}, [load, invalidate]), (0, import_react68.useEffect)(() => {
|
|
34639
|
+
setCopyStatus("");
|
|
34640
|
+
}, [submissions, submission?.requestKey]), (0, import_react68.useEffect)(() => {
|
|
34641
|
+
!busy && !view && control.current.live && !control.current.active && load();
|
|
34642
|
+
}, [busy, view, load]);
|
|
34443
34643
|
let saveSettings = async (settings) => {
|
|
34444
|
-
|
|
34644
|
+
if (!control.current.ready) return;
|
|
34645
|
+
let token = begin("settings");
|
|
34646
|
+
if (token) {
|
|
34647
|
+
invalidate(), staleView();
|
|
34648
|
+
try {
|
|
34649
|
+
let value = await call2("botRouting.save", { expectedRevision: view.settingsRevision ?? 0, settings });
|
|
34650
|
+
if (!current(token)) return;
|
|
34651
|
+
if (!validRoutingView(value)) throw new Error("设置保存结果尚未确认,请刷新候选核对。");
|
|
34652
|
+
setView(value), control.current.ready = !0, setViewReady(!0);
|
|
34653
|
+
} catch (failure) {
|
|
34654
|
+
current(token) && setError(String(failure?.message ?? failure));
|
|
34655
|
+
} finally {
|
|
34656
|
+
finish(token);
|
|
34657
|
+
}
|
|
34658
|
+
}
|
|
34659
|
+
}, routeRequest = () => {
|
|
34660
|
+
let input = form.current;
|
|
34661
|
+
return {
|
|
34662
|
+
text: input.text.trim(),
|
|
34663
|
+
requiresMachine: input.machine !== "",
|
|
34664
|
+
requesterBotId: view.requesterBotId ?? snapshot.mainBotId ?? snapshot.bots?.find((bot) => bot.main)?.id ?? "",
|
|
34665
|
+
...input.pin ? { pinnedBotId: input.pin } : {},
|
|
34666
|
+
...input.machine ? { machineId: input.machine, rootId: input.root || snapshot.machines?.items?.find((item) => item.id === input.machine)?.roots?.[0] || "" } : {},
|
|
34667
|
+
needs: { write: input.effect === "write", desktop: input.effect === "desktop", browser: input.effect === "browser" }
|
|
34668
|
+
};
|
|
34669
|
+
}, submitRouted = async () => {
|
|
34670
|
+
let state = control.current, prepared = state.prepared;
|
|
34671
|
+
if (!state.ready || submissions.getSnapshot() || !prepared || prepared.draft !== state.draft || prepared.epoch !== state.epoch) return;
|
|
34672
|
+
let token = begin("dispatch");
|
|
34673
|
+
if (!token) return;
|
|
34674
|
+
let reference2;
|
|
34445
34675
|
try {
|
|
34446
|
-
|
|
34447
|
-
|
|
34676
|
+
prepared.requestKey ??= crypto.randomUUID();
|
|
34677
|
+
let request = { ...prepared.request, requestKey: prepared.requestKey };
|
|
34678
|
+
if (!request.requesterBotId) throw new Error("尚未取得提交任务的主 Bot,请刷新候选后重试。");
|
|
34679
|
+
if (reference2 = { requestKey: request.requestKey, requesterBotId: request.requesterBotId }, !submissions.start(reference2)) return;
|
|
34680
|
+
let next = await call2("botRouting.dispatch", request), planId = next?.planId ?? next?.taskId;
|
|
34681
|
+
if (next?.accepted !== !0 || typeof planId != "string" || !planId.trim()) throw new Error("未取得有效的任务计划编号。");
|
|
34682
|
+
submissions.update(reference2, { state: "confirmed", planId, planState: next.planState }), current(token) && (state.prepared = null);
|
|
34448
34683
|
} catch (failure) {
|
|
34449
|
-
setError(String(failure?.message ?? failure));
|
|
34684
|
+
reference2 && submissions.update(reference2, { state: "unknown" }), current(token) && (invalidate(), staleView(), setError(reference2 ? "提交结果尚未确认,请刷新任务列表或核对原提交,避免重复创建。" : String(failure?.message ?? failure)));
|
|
34450
34685
|
} finally {
|
|
34451
|
-
|
|
34686
|
+
finish(token);
|
|
34452
34687
|
}
|
|
34453
|
-
},
|
|
34454
|
-
|
|
34455
|
-
|
|
34456
|
-
|
|
34457
|
-
|
|
34458
|
-
needs: { write: effect === "write", desktop: effect === "desktop", browser: effect === "browser" }
|
|
34459
|
-
}), submitRouted = async () => {
|
|
34460
|
-
if (!(!decision?.chosen || working)) {
|
|
34461
|
-
setWorking(!0), setError("");
|
|
34688
|
+
}, checkSubmission = async () => {
|
|
34689
|
+
let reference2 = submissions.getSnapshot();
|
|
34690
|
+
if (!reference2 || !snapshot.availableActions?.includes("botRouting.status")) return;
|
|
34691
|
+
let token = begin("status");
|
|
34692
|
+
if (token)
|
|
34462
34693
|
try {
|
|
34463
|
-
let
|
|
34464
|
-
if (next && next.
|
|
34465
|
-
|
|
34694
|
+
let next = await call2("botRouting.status", { requestKey: reference2.requestKey, requesterBotId: reference2.requesterBotId });
|
|
34695
|
+
if (typeof next?.found != "boolean" || next.originBotId !== reference2.requesterBotId || next.found && (next.accepted !== !0 || typeof next.planId != "string" || !next.planId.trim())) throw Object.assign(new Error("宿主未返回有效的原提交记录。"), { code: "INVALID_ROUTING_SUBMISSION_STATUS" });
|
|
34696
|
+
submissions.update(reference2, next.found ? { state: "confirmed", planId: next.planId, planState: next.planState } : { state: "not-found" });
|
|
34466
34697
|
} catch (failure) {
|
|
34467
|
-
setError(
|
|
34698
|
+
current(token) && setError(submissionFailureMessage(failure));
|
|
34468
34699
|
} finally {
|
|
34469
|
-
|
|
34700
|
+
finish(token);
|
|
34470
34701
|
}
|
|
34471
|
-
|
|
34472
|
-
|
|
34473
|
-
if (!(!text7.trim() || working)) {
|
|
34474
|
-
setWorking(!0), setError("");
|
|
34702
|
+
}, restoreSubmission = (event) => {
|
|
34703
|
+
if (event.preventDefault(), !(busyRef.current || control.current.active || !control.current.live || submissions.getSnapshot()))
|
|
34475
34704
|
try {
|
|
34476
|
-
|
|
34477
|
-
|
|
34478
|
-
|
|
34479
|
-
|
|
34480
|
-
setDecision(null), setError(String(failure?.message ?? failure));
|
|
34481
|
-
} finally {
|
|
34482
|
-
setWorking(!1);
|
|
34705
|
+
if (!submissions.restore(savedCode)) return;
|
|
34706
|
+
setSavedCode(""), invalidate(), checkSubmission();
|
|
34707
|
+
} catch {
|
|
34708
|
+
setError("核对码格式无效或版本不支持,请粘贴完整的提交核对码。");
|
|
34483
34709
|
}
|
|
34710
|
+
}, copySubmission = async () => {
|
|
34711
|
+
let reference2 = submissions.getSnapshot(), epoch = control.current.epoch;
|
|
34712
|
+
if (!reference2) return;
|
|
34713
|
+
let code = submissionCode(reference2), stillCurrent = () => control.current.live && control.current.epoch === epoch && submissions.getSnapshot()?.requestKey === reference2.requestKey && submissions.getSnapshot()?.requesterBotId === reference2.requesterBotId;
|
|
34714
|
+
codeInput.current?.focus(), codeInput.current?.select();
|
|
34715
|
+
try {
|
|
34716
|
+
if (typeof globalThis.navigator?.clipboard?.writeText != "function") throw new Error("CLIPBOARD_UNAVAILABLE");
|
|
34717
|
+
await globalThis.navigator.clipboard.writeText(code), stillCurrent() && setCopyStatus("已复制核对码,请保存后用于原宿主查询。");
|
|
34718
|
+
} catch {
|
|
34719
|
+
stillCurrent() && setCopyStatus("请选中核对码后手动复制,并保存用于原宿主查询。");
|
|
34484
34720
|
}
|
|
34485
|
-
}
|
|
34721
|
+
}, decide = async () => {
|
|
34722
|
+
let state = control.current;
|
|
34723
|
+
if (!state.ready || submissions.getSnapshot() || !view.enabled || !form.current.text.trim()) return;
|
|
34724
|
+
let token = begin("preview");
|
|
34725
|
+
if (!token) return;
|
|
34726
|
+
invalidate();
|
|
34727
|
+
let draft2 = state.draft, request = routeRequest();
|
|
34728
|
+
try {
|
|
34729
|
+
let next = await call2("botRoutingDecide", request);
|
|
34730
|
+
if (!current(token) || state.draft !== draft2) return;
|
|
34731
|
+
if (!next || !Object.hasOwn(next, "chosen") || !Array.isArray(next.ranked) || !Array.isArray(next.rejected) || next.chosen !== null && typeof next.chosen?.botId != "string") throw new Error("宿主未返回完整预览,请刷新后重试。");
|
|
34732
|
+
state.prepared = next.chosen ? { request, draft: draft2, epoch: token.epoch, requestKey: null } : null, setDecision(next);
|
|
34733
|
+
} catch (failure) {
|
|
34734
|
+
current(token) && state.draft === draft2 && (invalidate(), staleView(), setError(String(failure?.message ?? failure)));
|
|
34735
|
+
} finally {
|
|
34736
|
+
finish(token);
|
|
34737
|
+
}
|
|
34738
|
+
}, submissionNotice = submission && /* @__PURE__ */ import_react68.default.createElement("section", { className: "bp-blocked", role: "region", "aria-label": "原提交核对" }, submission.state === "confirmed" ? /* @__PURE__ */ import_react68.default.createElement("p", { role: "status" }, "已提交:", submission.planId, "。", TASK_STATES[submission.planState] ?? "请在任务记录中跟踪执行结果。") : submission.state === "not-found" ? /* @__PURE__ */ import_react68.default.createElement("p", { role: "status" }, "当前尚未查到原提交,原请求仍可能完成,请稍后再次核对。") : /* @__PURE__ */ import_react68.default.createElement("p", { role: "status" }, submission.state === "submitting" && working === "dispatch" ? "正在提交任务…" : "提交结果尚未确认,请核对原提交。"), /* @__PURE__ */ import_react68.default.createElement("p", null, "核对只读取原任务记录,不会再次提交或授予权限。"), /* @__PURE__ */ import_react68.default.createElement("details", { className: "bp-technical" }, /* @__PURE__ */ import_react68.default.createElement("summary", null, "保存提交核对码"), /* @__PURE__ */ import_react68.default.createElement("p", null, "重载应用前可保存核对码,之后在原宿主粘贴查询。核对码只包含提交编号,不包含任务正文或登录凭据。"), /* @__PURE__ */ import_react68.default.createElement("label", null, "当前提交核对码", /* @__PURE__ */ import_react68.default.createElement("input", { ref: codeInput, "aria-label": "当前提交核对码", className: "bp-submission-code", readOnly: !0, value: submissionCode(submission), onFocus: (event) => event.target.select() })), /* @__PURE__ */ import_react68.default.createElement("div", { className: "bp-actions" }, /* @__PURE__ */ import_react68.default.createElement("button", { type: "button", onClick: () => {
|
|
34739
|
+
copySubmission();
|
|
34740
|
+
} }, "复制核对码"), copyStatus && /* @__PURE__ */ import_react68.default.createElement("small", { role: "status" }, copyStatus))), /* @__PURE__ */ import_react68.default.createElement("div", { className: "bp-actions" }, snapshot.availableActions?.includes("botRouting.status") ? /* @__PURE__ */ import_react68.default.createElement("button", { type: "button", disabled: busy || !!working, onClick: () => {
|
|
34741
|
+
checkSubmission();
|
|
34742
|
+
} }, "核对原提交") : /* @__PURE__ */ import_react68.default.createElement("small", null, "当前宿主尚未提供原提交核对,请先在任务记录中核对。"), submission.state === "confirmed" && /* @__PURE__ */ import_react68.default.createElement("button", { type: "button", disabled: busy || !!working, onClick: () => {
|
|
34743
|
+
submissions.clear(submission), invalidate();
|
|
34744
|
+
} }, "新建另一项任务")), submission.state === "not-found" && /* @__PURE__ */ import_react68.default.createElement("details", { className: "bp-technical" }, /* @__PURE__ */ import_react68.default.createElement("summary", null, "已自行核对记录"), /* @__PURE__ */ import_react68.default.createElement("p", null, "原请求仍可能完成。清除提醒不会停止原任务,再次创建可能重复;只有自行核对后才清除。"), /* @__PURE__ */ import_react68.default.createElement("button", { type: "button", disabled: busy || !!working, onClick: () => {
|
|
34745
|
+
submissions.dismissUnconfirmed(submission), invalidate();
|
|
34746
|
+
} }, "清除本窗口提醒"))), savedSubmissionForm = !submission && snapshot.availableActions?.includes("botRouting.status") && /* @__PURE__ */ import_react68.default.createElement("details", { className: "bp-technical" }, /* @__PURE__ */ import_react68.default.createElement("summary", null, "核对已保存的提交"), /* @__PURE__ */ import_react68.default.createElement("p", null, "请连接原宿主并粘贴之前保存的核对码。此操作只查询原记录,不会创建任务。"), /* @__PURE__ */ import_react68.default.createElement("form", { className: "bp-submission-restore", onSubmit: restoreSubmission }, /* @__PURE__ */ import_react68.default.createElement("label", null, "已保存的提交核对码", /* @__PURE__ */ import_react68.default.createElement("input", { "aria-label": "已保存的提交核对码", className: "bp-submission-code", value: savedCode, maxLength: 1024, autoComplete: "off", spellCheck: !1, disabled: busy || !!working, onChange: (event) => setSavedCode(event.target.value), placeholder: "dsh-route-v1:…" })), /* @__PURE__ */ import_react68.default.createElement("button", { type: "submit", disabled: busy || !!working || !savedCode.trim() }, "核对已保存的提交")));
|
|
34486
34747
|
if (!view)
|
|
34487
|
-
return /* @__PURE__ */
|
|
34748
|
+
return /* @__PURE__ */ import_react68.default.createElement("article", { className: "bp-card" }, /* @__PURE__ */ import_react68.default.createElement("div", { className: "bp-card-title" }, /* @__PURE__ */ import_react68.default.createElement("h2", null, "Bot 路由")), /* @__PURE__ */ import_react68.default.createElement("p", { className: "bp-muted" }, error || "正在读取候选…"), /* @__PURE__ */ import_react68.default.createElement("button", { type: "button", disabled: busy || working, onClick: () => {
|
|
34488
34749
|
load();
|
|
34489
|
-
} }, "读取候选"));
|
|
34490
|
-
let machines = (snapshot.machines?.items ?? []).filter((item) => item.status !== "revoked");
|
|
34491
|
-
return /* @__PURE__ */
|
|
34750
|
+
} }, "读取候选"), submissionNotice, savedSubmissionForm);
|
|
34751
|
+
let machines = (snapshot.machines?.items ?? []).filter((item) => item.status !== "revoked"), inputDisabled = busy || !viewReady || working === "dispatch" || working === "settings", nameOf = (botId) => view.candidates.find((row) => row.botId === botId)?.name ?? botId;
|
|
34752
|
+
return /* @__PURE__ */ import_react68.default.createElement("article", { className: "bp-card" }, /* @__PURE__ */ import_react68.default.createElement("div", { className: "bp-card-title" }, /* @__PURE__ */ import_react68.default.createElement("h2", null, "Bot 路由"), /* @__PURE__ */ import_react68.default.createElement(Tag3, null, view.enabled ? `已开启 · ${routingPresetLabel(view.preset)}` : "未开启"), /* @__PURE__ */ import_react68.default.createElement("button", { type: "button", disabled: busy || !!working, onClick: () => {
|
|
34492
34753
|
load();
|
|
34493
|
-
} },
|
|
34754
|
+
} }, "刷新候选")), /* @__PURE__ */ import_react68.default.createElement("div", { className: "bp-actions" }, /* @__PURE__ */ import_react68.default.createElement("label", { className: "bp-check" }, /* @__PURE__ */ import_react68.default.createElement("input", { type: "checkbox", checked: view.enabled, disabled: busy || !!working || !viewReady, onChange: (event) => {
|
|
34494
34755
|
saveSettings({ enabled: event.target.checked, preset: view.preset, autoGrant: view.autoGrant });
|
|
34495
|
-
} }), "开启 Bot 路由"), /* @__PURE__ */
|
|
34756
|
+
} }), "开启 Bot 路由"), /* @__PURE__ */ import_react68.default.createElement("label", null, "策略", /* @__PURE__ */ import_react68.default.createElement("select", { value: view.preset, disabled: busy || !!working || !viewReady, onChange: (event) => {
|
|
34496
34757
|
saveSettings({ enabled: view.enabled, preset: event.target.value, autoGrant: view.autoGrant });
|
|
34497
|
-
} }, /* @__PURE__ */
|
|
34758
|
+
} }, /* @__PURE__ */ import_react68.default.createElement("option", { value: "economy" }, "省钱优先"), /* @__PURE__ */ import_react68.default.createElement("option", { value: "balanced" }, "均衡"), /* @__PURE__ */ import_react68.default.createElement("option", { value: "quality" }, "效果优先"))), /* @__PURE__ */ import_react68.default.createElement("label", { className: "bp-check" }, /* @__PURE__ */ import_react68.default.createElement("input", { type: "checkbox", checked: view.autoGrant?.machineTools === !0, disabled: busy || !!working || !viewReady, onChange: (event) => {
|
|
34498
34759
|
saveSettings({ enabled: view.enabled, preset: view.preset, autoGrant: { ...view.autoGrant, machineTools: event.target.checked } });
|
|
34499
|
-
} }), "自动授予任务所需电脑权限")), !view.enabled && /* @__PURE__ */
|
|
34500
|
-
setText(event.target.value), setDecision(null);
|
|
34501
|
-
}, placeholder: "例如:整理上周的发布记录" })), /* @__PURE__ */ import_react67.default.createElement("label", null, "路由方式", /* @__PURE__ */ import_react67.default.createElement("select", { value: pin, onChange: (event) => {
|
|
34502
|
-
setPin(event.target.value), setDecision(null);
|
|
34503
|
-
} }, /* @__PURE__ */ import_react67.default.createElement("option", { value: "" }, "自动路由(按预设打分)"), view.candidates.map((row) => /* @__PURE__ */ import_react67.default.createElement("option", { key: row.botId, value: row.botId }, "指定:", row.name)))), /* @__PURE__ */ import_react67.default.createElement("label", null, "需要远程电脑", /* @__PURE__ */ import_react67.default.createElement("select", { value: machine, onChange: (event) => {
|
|
34504
|
-
setMachine(event.target.value), setRoot(""), setEffect("read"), setDecision(null);
|
|
34505
|
-
} }, /* @__PURE__ */ import_react67.default.createElement("option", { value: "" }, "不需要"), machines.map((item) => /* @__PURE__ */ import_react67.default.createElement("option", { key: item.id, value: item.id }, item.name ?? item.id)))), machine && /* @__PURE__ */ import_react67.default.createElement("label", null, "共享目录", /* @__PURE__ */ import_react67.default.createElement("select", { value: root || machines.find((item) => item.id === machine)?.roots?.[0] || "", onChange: (event) => {
|
|
34506
|
-
setRoot(event.target.value), setDecision(null);
|
|
34507
|
-
} }, (machines.find((item) => item.id === machine)?.roots ?? []).map((id2) => /* @__PURE__ */ import_react67.default.createElement("option", { key: id2, value: id2 }, id2)))), /* @__PURE__ */ import_react67.default.createElement("label", null, "任务需要的操作", /* @__PURE__ */ import_react67.default.createElement("select", { value: effect, onChange: (event) => {
|
|
34508
|
-
setEffect(event.target.value), setDecision(null);
|
|
34509
|
-
} }, /* @__PURE__ */ import_react67.default.createElement("option", { value: "read" }, "只读 / 分析"), /* @__PURE__ */ import_react67.default.createElement("option", { value: "write" }, "写入文件"), machine && /* @__PURE__ */ import_react67.default.createElement(import_react67.default.Fragment, null, /* @__PURE__ */ import_react67.default.createElement("option", { value: "desktop" }, "操作 Windows 桌面"), /* @__PURE__ */ import_react67.default.createElement("option", { value: "browser" }, "操作远程浏览器")))), /* @__PURE__ */ import_react67.default.createElement("button", { type: "button", disabled: busy || working || !text7.trim(), onClick: () => {
|
|
34760
|
+
} }), "自动授予任务所需电脑权限")), !view.enabled && /* @__PURE__ */ import_react68.default.createElement("p", { className: "bp-muted" }, "开启后,主 Bot 可根据各 Bot 已配置的模型、工具与电脑权限分配任务。手动指定也会检查是否具备执行条件。"), error && /* @__PURE__ */ import_react68.default.createElement("p", { className: "bp-error", role: "alert" }, error), submissionNotice, savedSubmissionForm, !viewReady && !working && /* @__PURE__ */ import_react68.default.createElement("p", { className: "bp-muted" }, "候选尚未更新,请刷新候选后再预览。"), view.enabled ? /* @__PURE__ */ import_react68.default.createElement("div", { className: "bp-table-wrap" }, /* @__PURE__ */ import_react68.default.createElement("table", { className: "bp-routing-candidates" }, /* @__PURE__ */ import_react68.default.createElement("thead", null, /* @__PURE__ */ import_react68.default.createElement("tr", null, /* @__PURE__ */ import_react68.default.createElement("th", null, "Bot"), /* @__PURE__ */ import_react68.default.createElement("th", null, "模型"), /* @__PURE__ */ import_react68.default.createElement("th", null, "机器"), /* @__PURE__ */ import_react68.default.createElement("th", null, "价格/百万"), /* @__PURE__ */ import_react68.default.createElement("th", null, "质量"), /* @__PURE__ */ import_react68.default.createElement("th", null, "状态"))), /* @__PURE__ */ import_react68.default.createElement("tbody", null, view.candidates.map((row) => /* @__PURE__ */ import_react68.default.createElement("tr", { key: row.botId }, /* @__PURE__ */ import_react68.default.createElement("td", null, row.name, row.main ? /* @__PURE__ */ import_react68.default.createElement(Tag3, null, "Main") : null, /* @__PURE__ */ import_react68.default.createElement("small", null, row.botId)), /* @__PURE__ */ import_react68.default.createElement("td", null, row.model ? `${row.model.provider}/${row.model.model}` : /* @__PURE__ */ import_react68.default.createElement("em", null, "未绑定")), /* @__PURE__ */ import_react68.default.createElement("td", null, row.machineId ? row.machineOnline ? "在线" : "未在线" : "无"), /* @__PURE__ */ import_react68.default.createElement("td", null, row.pricePerMTokUsd === null ? "未知" : `$${row.pricePerMTokUsd}`), /* @__PURE__ */ import_react68.default.createElement("td", null, row.quality === null ? "未知" : row.quality), /* @__PURE__ */ import_react68.default.createElement("td", null, row.busy ? "正忙" : "空闲")))))) : null, view.enabled ? /* @__PURE__ */ import_react68.default.createElement("div", { className: "bp-form" }, /* @__PURE__ */ import_react68.default.createElement("label", null, "任务描述", /* @__PURE__ */ import_react68.default.createElement("textarea", { rows: 2, value: text7, disabled: inputDisabled, onChange: (event) => editDraft({ text: event.target.value }), placeholder: "例如:整理上周的发布记录" })), /* @__PURE__ */ import_react68.default.createElement("label", null, "路由方式", /* @__PURE__ */ import_react68.default.createElement("select", { value: pin, disabled: inputDisabled, onChange: (event) => editDraft({ pin: event.target.value }) }, /* @__PURE__ */ import_react68.default.createElement("option", { value: "" }, "自动路由(按预设打分)"), view.candidates.map((row) => /* @__PURE__ */ import_react68.default.createElement("option", { key: row.botId, value: row.botId }, "指定:", row.name)))), /* @__PURE__ */ import_react68.default.createElement("label", null, "需要远程电脑", /* @__PURE__ */ import_react68.default.createElement("select", { value: machine, disabled: inputDisabled, onChange: (event) => editDraft({ machine: event.target.value, root: "", effect: "read" }) }, /* @__PURE__ */ import_react68.default.createElement("option", { value: "" }, "不需要"), machines.map((item) => /* @__PURE__ */ import_react68.default.createElement("option", { key: item.id, value: item.id }, item.name ?? item.id)))), machine && /* @__PURE__ */ import_react68.default.createElement("label", null, "共享目录", /* @__PURE__ */ import_react68.default.createElement("select", { value: root || machines.find((item) => item.id === machine)?.roots?.[0] || "", disabled: inputDisabled, onChange: (event) => editDraft({ root: event.target.value }) }, (machines.find((item) => item.id === machine)?.roots ?? []).map((id2) => /* @__PURE__ */ import_react68.default.createElement("option", { key: id2, value: id2 }, id2)))), /* @__PURE__ */ import_react68.default.createElement("label", null, "任务需要的操作", /* @__PURE__ */ import_react68.default.createElement("select", { value: effect, disabled: inputDisabled, onChange: (event) => editDraft({ effect: event.target.value }) }, /* @__PURE__ */ import_react68.default.createElement("option", { value: "read" }, "只读 / 分析"), /* @__PURE__ */ import_react68.default.createElement("option", { value: "write" }, "写入文件"), machine && /* @__PURE__ */ import_react68.default.createElement(import_react68.default.Fragment, null, /* @__PURE__ */ import_react68.default.createElement("option", { value: "desktop" }, "操作 Windows 桌面"), /* @__PURE__ */ import_react68.default.createElement("option", { value: "browser" }, "操作远程浏览器")))), /* @__PURE__ */ import_react68.default.createElement("button", { type: "button", disabled: busy || !!working || !!submission || !viewReady || !text7.trim(), onClick: () => {
|
|
34510
34761
|
decide();
|
|
34511
|
-
} }, working ? "计算中…" : "预览路由"),
|
|
34762
|
+
} }, working === "preview" ? "计算中…" : "预览路由")) : null, decision ? /* @__PURE__ */ import_react68.default.createElement("div", { className: "bp-blocked", role: "region", "aria-label": "路由预览结果" }, /* @__PURE__ */ import_react68.default.createElement("strong", null, "选中:", decision.chosen ? `${decision.chosen.name ?? decision.chosen.botId}${decision.pinned ? "(手动指定)" : ""}` : "没有可用的 Bot"), /* @__PURE__ */ import_react68.default.createElement("p", null, decision.pinned ? "手动指定的 Bot 已通过本次执行条件检查,未与其他 Bot 比较评分。" : `按${routingPresetLabel(decision.preset)}策略比较,综合评分越低越靠前。`), decision.binding ? /* @__PURE__ */ import_react68.default.createElement(import_react68.default.Fragment, null, /* @__PURE__ */ import_react68.default.createElement("p", null, "所需电脑权限:", decision.binding.mode === "read-only" ? "只读" : "读写", " · ", decision.binding.tools.length, " 项工具。"), /* @__PURE__ */ import_react68.default.createElement("p", null, decision.grant?.autoGrant === !1 ? "自动授权已关闭,创建任务时会核对已有授权;权限不足时需先配置。" : "创建任务时才会按已保存的权限上限核对和授权。")) : null, decision.rejected?.length ? /* @__PURE__ */ import_react68.default.createElement("p", null, "未满足条件:", decision.rejected.map((row) => `${nameOf(row.botId)}(${routingRefusalMessage(row.reason)})`).join(";")) : null, !decision.pinned && decision.ranked?.length > 0 && /* @__PURE__ */ import_react68.default.createElement("details", { className: "bp-technical" }, /* @__PURE__ */ import_react68.default.createElement("summary", null, "查看比较依据"), /* @__PURE__ */ import_react68.default.createElement("p", null, "评分只用于本次候选排序,不代表成功率。未知价格按保守值计算,未知质量按中间值参与比较。"), /* @__PURE__ */ import_react68.default.createElement("div", { className: "bp-table-wrap" }, /* @__PURE__ */ import_react68.default.createElement("table", { className: "bp-routing-comparison", "aria-label": "候选比较" }, /* @__PURE__ */ import_react68.default.createElement("thead", null, /* @__PURE__ */ import_react68.default.createElement("tr", null, /* @__PURE__ */ import_react68.default.createElement("th", null, "Bot"), /* @__PURE__ */ import_react68.default.createElement("th", null, "综合评分"), /* @__PURE__ */ import_react68.default.createElement("th", null, "价格/百万"), /* @__PURE__ */ import_react68.default.createElement("th", null, "参考质量"))), /* @__PURE__ */ import_react68.default.createElement("tbody", null, decision.ranked.map((row) => /* @__PURE__ */ import_react68.default.createElement("tr", { key: row.botId }, /* @__PURE__ */ import_react68.default.createElement("td", null, nameOf(row.botId)), /* @__PURE__ */ import_react68.default.createElement("td", null, Number.isFinite(row.score) ? row.score.toFixed(6) : "未知"), /* @__PURE__ */ import_react68.default.createElement("td", null, Number.isFinite(row.pricePerMTokUsd) ? `$${row.pricePerMTokUsd}` : "未知"), /* @__PURE__ */ import_react68.default.createElement("td", null, Number.isFinite(row.quality) ? row.quality : "未知"))))))), (decision.binding || decision.rejected?.length > 0) && /* @__PURE__ */ import_react68.default.createElement("details", { className: "bp-technical" }, /* @__PURE__ */ import_react68.default.createElement("summary", null, "执行条件详情"), decision.binding && /* @__PURE__ */ import_react68.default.createElement("p", null, "所需工具:", decision.binding.tools.join("、")), decision.rejected?.map((row) => /* @__PURE__ */ import_react68.default.createElement("p", { key: row.botId }, row.botId, ":", row.reason))), decision.chosen ? /* @__PURE__ */ import_react68.default.createElement("div", { className: "bp-actions" }, /* @__PURE__ */ import_react68.default.createElement("button", { type: "button", disabled: busy || !!working || !viewReady || !!submission, onClick: () => {
|
|
34512
34763
|
submitRouted();
|
|
34513
|
-
} }, "按此路由创建任务")
|
|
34514
|
-
}
|
|
34515
|
-
function Tasks({ snapshot, dispatch, busy }) {
|
|
34516
|
-
|
|
34517
|
-
|
|
34518
|
-
|
|
34519
|
-
|
|
34520
|
-
|
|
34521
|
-
|
|
34522
|
-
|
|
34523
|
-
|
|
34524
|
-
|
|
34525
|
-
|
|
34526
|
-
}
|
|
34527
|
-
|
|
34764
|
+
} }, "按此路由创建任务")) : null) : null);
|
|
34765
|
+
}
|
|
34766
|
+
function Tasks({ snapshot, dispatch, busy, submissionScope = dispatch, inspect, openSession }) {
|
|
34767
|
+
return snapshot.tasks?.status !== "available" ? /* @__PURE__ */ import_react68.default.createElement(Blocked, { value: snapshot.tasks }) : /* @__PURE__ */ import_react68.default.createElement(
|
|
34768
|
+
TaskWorkspace,
|
|
34769
|
+
{
|
|
34770
|
+
snapshot,
|
|
34771
|
+
dispatch,
|
|
34772
|
+
busy,
|
|
34773
|
+
scope: submissionScope,
|
|
34774
|
+
inspect,
|
|
34775
|
+
openSession,
|
|
34776
|
+
routingCard: snapshot.availableActions?.includes("botRoutingInspect") ? /* @__PURE__ */ import_react68.default.createElement(BotRoutingCard, { snapshot, dispatch, busy, submissionScope }) : null
|
|
34777
|
+
}
|
|
34778
|
+
);
|
|
34528
34779
|
}
|
|
34529
34780
|
function DesktopControl({ snapshot, dispatch, busy }) {
|
|
34530
|
-
let machines = (snapshot.machines?.items ?? []).filter((item) => item.status !== "revoked"), bots = snapshot.bots ?? [], [machineId, setMachineId] =
|
|
34781
|
+
let machines = (snapshot.machines?.items ?? []).filter((item) => item.status !== "revoked"), bots = snapshot.bots ?? [], [machineId, setMachineId] = import_react68.default.useState(machines[0]?.id ?? ""), [botId, setBotId] = import_react68.default.useState(bots[0]?.id ?? ""), [frame, setFrame] = import_react68.default.useState(null), [status, setStatus] = import_react68.default.useState("idle"), [error, setError] = import_react68.default.useState(""), [live, setLive] = import_react68.default.useState(!1), [text7, setText] = import_react68.default.useState(""), imageRef = import_react68.default.useRef(null), firstRoot = machines.find((item) => item.id === machineId)?.roots?.[0], rootId = typeof firstRoot == "string" ? firstRoot : firstRoot?.id ?? firstRoot?.rootId ?? "", canView = typeof dispatch == "function" && !!(machineId && rootId && botId), call2 = async (action, payload) => {
|
|
34531
34782
|
setError("");
|
|
34532
34783
|
try {
|
|
34533
34784
|
return await dispatch(action, payload);
|
|
34534
34785
|
} catch (failure) {
|
|
34535
34786
|
return setError(String(failure?.message ?? failure)), null;
|
|
34536
34787
|
}
|
|
34537
|
-
}, capture =
|
|
34788
|
+
}, capture = import_react68.default.useCallback(async () => {
|
|
34538
34789
|
if (!canView) return;
|
|
34539
34790
|
setStatus("capturing");
|
|
34540
34791
|
let value = await call2("machine.desktop.view", { botId, machineId, rootId });
|
|
@@ -34548,7 +34799,7 @@ function DesktopControl({ snapshot, dispatch, busy }) {
|
|
|
34548
34799
|
}
|
|
34549
34800
|
setFrame({ ...value, takenAtMs: Date.now() }), setStatus("ready");
|
|
34550
34801
|
}, [botId, machineId, rootId, canView]);
|
|
34551
|
-
|
|
34802
|
+
import_react68.default.useEffect(() => {
|
|
34552
34803
|
if (!live || !canView) return;
|
|
34553
34804
|
capture();
|
|
34554
34805
|
let timer = setInterval(() => {
|
|
@@ -34573,26 +34824,26 @@ function DesktopControl({ snapshot, dispatch, busy }) {
|
|
|
34573
34824
|
setError(String(failure?.message ?? failure));
|
|
34574
34825
|
}
|
|
34575
34826
|
}, keys = ["Enter", "Tab", "Escape", "Backspace", "ArrowUp", "ArrowDown", "ArrowLeft", "ArrowRight"];
|
|
34576
|
-
return /* @__PURE__ */
|
|
34827
|
+
return /* @__PURE__ */ import_react68.default.createElement("section", { className: "bp-card", "aria-label": "电脑操作" }, /* @__PURE__ */ import_react68.default.createElement("div", { className: "bp-card-title" }, /* @__PURE__ */ import_react68.default.createElement("h2", null, "电脑操作"), /* @__PURE__ */ import_react68.default.createElement("span", { className: "bp-tag" }, `${status}${frame?.screenshotId ? " · 帧 " + frame.screenshotId.slice(-6) : ""}`)), /* @__PURE__ */ import_react68.default.createElement("p", { className: "bp-muted" }, "画面来自已配对电脑的桌面;每个操作只对它下面那一帧生效,帧过期请重新截取。"), /* @__PURE__ */ import_react68.default.createElement("div", { className: "bp-form" }, /* @__PURE__ */ import_react68.default.createElement("label", null, "电脑", /* @__PURE__ */ import_react68.default.createElement("select", { value: machineId, onChange: (event) => {
|
|
34577
34828
|
setMachineId(event.target.value), setFrame(null);
|
|
34578
|
-
} }, machines.map((item) => /* @__PURE__ */
|
|
34829
|
+
} }, machines.map((item) => /* @__PURE__ */ import_react68.default.createElement("option", { key: item.id, value: item.id }, item.name ?? item.id)))), /* @__PURE__ */ import_react68.default.createElement("label", null, "以哪个 Bot 执行", /* @__PURE__ */ import_react68.default.createElement("select", { value: botId, onChange: (event) => setBotId(event.target.value) }, bots.map((item) => /* @__PURE__ */ import_react68.default.createElement("option", { key: item.id, value: item.id }, item.name ?? item.id)))), /* @__PURE__ */ import_react68.default.createElement("div", { className: "bp-actions" }, /* @__PURE__ */ import_react68.default.createElement("button", { disabled: busy || !canView || status === "capturing", onClick: () => {
|
|
34579
34830
|
capture();
|
|
34580
|
-
} }, status === "capturing" ? "截取中…" : "截取当前画面"), /* @__PURE__ */
|
|
34831
|
+
} }, status === "capturing" ? "截取中…" : "截取当前画面"), /* @__PURE__ */ import_react68.default.createElement("label", { className: "bp-check" }, /* @__PURE__ */ import_react68.default.createElement("input", { type: "checkbox", checked: live, disabled: !canView, onChange: (event) => setLive(event.target.checked) }), "实时(1.5 秒)"))), error && /* @__PURE__ */ import_react68.default.createElement("p", { className: "bp-error", role: "alert" }, error), frame?.base64 ? /* @__PURE__ */ import_react68.default.createElement("img", { ref: imageRef, className: "bp-desktop-frame", alt: "远程桌面画面", src: `data:${frame.mediaType};base64,${frame.base64}`, onClick: clickImage }) : /* @__PURE__ */ import_react68.default.createElement("p", { className: "bp-empty" }, canView ? "还没有画面。点“截取当前画面”。" : "先配对一台电脑,并选择一个 Bot。"), frame?.base64 && /* @__PURE__ */ import_react68.default.createElement("div", { className: "bp-actions bp-desktop-keys" }, keys.map((key) => /* @__PURE__ */ import_react68.default.createElement("button", { key, disabled: busy, onClick: () => {
|
|
34581
34832
|
act({ tool: "key", key });
|
|
34582
|
-
} }, key)), /* @__PURE__ */
|
|
34833
|
+
} }, key)), /* @__PURE__ */ import_react68.default.createElement("button", { disabled: busy, onClick: () => {
|
|
34583
34834
|
act({ tool: "scroll", delta: 120 });
|
|
34584
|
-
} }, "滚轮上"), /* @__PURE__ */
|
|
34835
|
+
} }, "滚轮上"), /* @__PURE__ */ import_react68.default.createElement("button", { disabled: busy, onClick: () => {
|
|
34585
34836
|
act({ tool: "scroll", delta: -120 });
|
|
34586
|
-
} }, "滚轮下")), frame?.base64 && /* @__PURE__ */
|
|
34837
|
+
} }, "滚轮下")), frame?.base64 && /* @__PURE__ */ import_react68.default.createElement("div", { className: "bp-actions" }, /* @__PURE__ */ import_react68.default.createElement("input", { className: "bp-desktop-text", "aria-label": "要输入的文本", value: text7, placeholder: "输入文字后发送(发送的是按键,不是剪贴板)", onChange: (event) => setText(event.target.value) }), /* @__PURE__ */ import_react68.default.createElement("button", { disabled: busy || !text7, onClick: () => {
|
|
34587
34838
|
act({ type: "type", tool: "type", text: text7 });
|
|
34588
34839
|
} }, "发送文本")));
|
|
34589
34840
|
}
|
|
34590
34841
|
function MachineSetup({ snapshot, dispatch, busy }) {
|
|
34591
|
-
let available = snapshot.availableActions ?? [], [paste, setPaste] =
|
|
34592
|
-
|
|
34842
|
+
let available = snapshot.availableActions ?? [], [paste, setPaste] = import_react68.default.useState(""), [address, setAddress] = import_react68.default.useState(""), [tunnel, setTunnel] = import_react68.default.useState(!1), [status, setStatus] = import_react68.default.useState(""), [error, setError] = import_react68.default.useState(""), [working, setWorking] = import_react68.default.useState(!1), parsed = import_react68.default.useMemo(() => parsePairingPaste(paste), [paste]);
|
|
34843
|
+
import_react68.default.useEffect(() => {
|
|
34593
34844
|
parsed.endpoint && setAddress(parsed.endpoint), typeof parsed.protectedTunnel == "boolean" && setTunnel(parsed.protectedTunnel);
|
|
34594
34845
|
}, [parsed.endpoint, parsed.protectedTunnel]);
|
|
34595
|
-
let endpoint =
|
|
34846
|
+
let endpoint = import_react68.default.useMemo(() => normalizeEndpoint(address, {}), [address]), ready = parsed.problems.length === 0 && endpoint.problem === "", secretName = import_react68.default.useMemo(() => secretNameFor({ clientId: parsed.clientId, machineId: parsed.machineId }), [parsed]), importFile = async (event) => {
|
|
34596
34847
|
let file = event.target.files?.[0];
|
|
34597
34848
|
if (file)
|
|
34598
34849
|
try {
|
|
@@ -34628,11 +34879,11 @@ function MachineSetup({ snapshot, dispatch, busy }) {
|
|
|
34628
34879
|
}
|
|
34629
34880
|
}
|
|
34630
34881
|
};
|
|
34631
|
-
return /* @__PURE__ */
|
|
34882
|
+
return /* @__PURE__ */ import_react68.default.createElement("details", { className: "bp-card bp-machine-setup" }, /* @__PURE__ */ import_react68.default.createElement("summary", null, "添加电脑(导入配对文件)"), /* @__PURE__ */ import_react68.default.createElement("p", { className: "bp-muted" }, "在你自己的 Windows 电脑或云电脑上解压 Agent 包,双击 ", /* @__PURE__ */ import_react68.default.createElement("code", null, "start.cmd"), ",按向导选共享文件夹和连接地址。回到这里导入向导生成的 ", /* @__PURE__ */ import_react68.default.createElement("code", null, "pairing.private.json"), ",地址、目录和权限会自动填好。"), available.includes("machine.secret") && available.includes("machine.pair") ? /* @__PURE__ */ import_react68.default.createElement("div", { className: "bp-form" }, /* @__PURE__ */ import_react68.default.createElement("label", null, "配对文件", /* @__PURE__ */ import_react68.default.createElement("input", { type: "file", accept: ".json,application/json", onChange: (event) => {
|
|
34632
34883
|
importFile(event);
|
|
34633
|
-
} })), /* @__PURE__ */
|
|
34884
|
+
} })), /* @__PURE__ */ import_react68.default.createElement("label", null, "或粘贴文件内容", /* @__PURE__ */ import_react68.default.createElement("textarea", { rows: 3, value: paste, onChange: (event) => setPaste(event.target.value), placeholder: '{"clientId":"host-office","token":"...","machineId":"machine-..."}' })), /* @__PURE__ */ import_react68.default.createElement("label", null, "Agent 地址", /* @__PURE__ */ import_react68.default.createElement("input", { value: address, onChange: (event) => setAddress(event.target.value), placeholder: "10.0.0.2 或 http://10.0.0.2:9701", autoComplete: "off", spellCheck: !1 })), /* @__PURE__ */ import_react68.default.createElement("label", null, /* @__PURE__ */ import_react68.default.createElement("input", { type: "checkbox", checked: tunnel, onChange: (event) => setTunnel(event.target.checked) }), "地址位于已配置的 WireGuard / Tailscale 受保护隧道"), paste !== "" && parsed.problems.length > 0 && /* @__PURE__ */ import_react68.default.createElement("p", { className: "bp-error", role: "alert" }, parsed.problems.join(" ")), address !== "" && endpoint.problem !== "" && /* @__PURE__ */ import_react68.default.createElement("p", { className: "bp-error", role: "alert" }, endpoint.problem), ready && /* @__PURE__ */ import_react68.default.createElement("p", { className: "bp-muted" }, "将保存凭据 ", /* @__PURE__ */ import_react68.default.createElement("code", null, "ds-secret/", secretName), " 并配对 ", parsed.machineId, "。"), ready && parsed.rootIds.length > 0 && /* @__PURE__ */ import_react68.default.createElement("p", { className: "bp-muted" }, "共享目录:", parsed.rootIds.join("、"), "。", parsed.hostManagedBots === !0 ? "此电脑允许本宿主管理团队 Bot,后续分配无需重新复制 Bot ID。" : parsed.botIds.length > 0 ? `此电脑只允许这些 Bot:${parsed.botIds.join("、")}。` : ""), /* @__PURE__ */ import_react68.default.createElement("button", { type: "button", disabled: !ready || busy || working, onClick: () => {
|
|
34634
34885
|
submit();
|
|
34635
|
-
} }, working ? "添加中…" : "导入并添加"), status !== "" && /* @__PURE__ */
|
|
34886
|
+
} }, working ? "添加中…" : "导入并添加"), status !== "" && /* @__PURE__ */ import_react68.default.createElement("p", { className: "bp-muted", role: "status" }, status), error !== "" && /* @__PURE__ */ import_react68.default.createElement("p", { className: "bp-error", role: "alert" }, error)) : /* @__PURE__ */ import_react68.default.createElement("p", { className: "bp-muted" }, "宿主尚未提供配对操作。"));
|
|
34636
34887
|
}
|
|
34637
34888
|
function MachineControls({ machine, snapshot, dispatch, busy }) {
|
|
34638
34889
|
let groups = [
|
|
@@ -34642,8 +34893,8 @@ function MachineControls({ machine, snapshot, dispatch, busy }) {
|
|
|
34642
34893
|
["browser", "远程浏览器", ["browser_open", "browser_snapshot", "browser_click", "browser_type", "browser_script", "browser_upload", "browser_download", "browser_close"]],
|
|
34643
34894
|
["desktop", "Windows 桌面", ["desktop_screenshot", "desktop_click", "desktop_type", "desktop_key", "desktop_scroll"]],
|
|
34644
34895
|
["cli", "远程 Codex", ["cli_probe_v1", "cli_task_v1"]]
|
|
34645
|
-
], [botId, setBotId] = (0,
|
|
34646
|
-
(0,
|
|
34896
|
+
], [botId, setBotId] = (0, import_react68.useState)(snapshot.bots?.[0]?.id ?? ""), [rootId, setRootId] = (0, import_react68.useState)(machine.roots?.[0] ?? ""), [relativePath, setRelativePath] = (0, import_react68.useState)(""), [mode, setMode] = (0, import_react68.useState)("read-only"), [selected, setSelected] = (0, import_react68.useState)(["read"]), available = snapshot.availableActions ?? [], savedBinding = machine.bindings?.find((item) => item.botId === botId), binding = savedBinding && !savedBinding.revoked ? savedBinding : null;
|
|
34897
|
+
(0, import_react68.useEffect)(() => {
|
|
34647
34898
|
let tools = savedBinding?.tools ?? [];
|
|
34648
34899
|
setMode(savedBinding?.mode ?? "read-only"), setSelected(groups.filter(([, , names]) => names.some((name) => tools.includes(name))).map(([id2]) => id2));
|
|
34649
34900
|
}, [botId, savedBinding?.revision]);
|
|
@@ -34652,28 +34903,28 @@ function MachineControls({ machine, snapshot, dispatch, busy }) {
|
|
|
34652
34903
|
for (let [id2, , names] of groups) if (selected.includes(id2)) for (let name of names) tools.add(name);
|
|
34653
34904
|
run2("machine.bind", { botId, roots: [rootId], tools: [...tools].filter((tool) => machine.tools.includes(tool)), mode, expectedRevision: savedBinding?.revision ?? 0 });
|
|
34654
34905
|
};
|
|
34655
|
-
return /* @__PURE__ */
|
|
34906
|
+
return /* @__PURE__ */ import_react68.default.createElement("div", { className: "bp-form" }, /* @__PURE__ */ import_react68.default.createElement("label", null, "Bot", /* @__PURE__ */ import_react68.default.createElement("select", { "aria-label": `机器 ${machine.id} 的 Bot`, value: botId, onChange: (event) => setBotId(event.target.value) }, snapshot.bots.map((bot) => /* @__PURE__ */ import_react68.default.createElement("option", { key: bot.id, value: bot.id }, bot.name ?? bot.id)))), /* @__PURE__ */ import_react68.default.createElement("label", null, "根目录", /* @__PURE__ */ import_react68.default.createElement("select", { "aria-label": `机器 ${machine.id} 的根目录`, value: rootId, onChange: (event) => setRootId(event.target.value) }, (machine.roots ?? []).map((id2) => /* @__PURE__ */ import_react68.default.createElement("option", { key: id2 }, id2)))), /* @__PURE__ */ import_react68.default.createElement("fieldset", null, /* @__PURE__ */ import_react68.default.createElement("legend", null, "授予此 Bot 的能力"), groups.map(([id2, label, names]) => /* @__PURE__ */ import_react68.default.createElement("label", { key: id2 }, /* @__PURE__ */ import_react68.default.createElement("input", { type: "checkbox", disabled: !names.some((name) => machine.tools.includes(name)), checked: selected.includes(id2), onChange: (event) => {
|
|
34656
34907
|
let next = event.target.checked ? [...selected, id2] : selected.filter((value) => value !== id2);
|
|
34657
34908
|
setSelected(next), id2 !== "read" && event.target.checked && setMode("workspace-write");
|
|
34658
|
-
} }), label, /* @__PURE__ */
|
|
34909
|
+
} }), label, /* @__PURE__ */ import_react68.default.createElement("small", null, names.filter((name) => machine.tools.includes(name)).join("、") || "此 Agent 未提供")))), /* @__PURE__ */ import_react68.default.createElement("label", null, "权限模式", /* @__PURE__ */ import_react68.default.createElement("select", { value: mode, onChange: (event) => setMode(event.target.value) }, /* @__PURE__ */ import_react68.default.createElement("option", { value: "read-only" }, "只读"), /* @__PURE__ */ import_react68.default.createElement("option", { value: "workspace-write" }, "允许写入及已勾选的控制操作"))), available.includes("machine.bind") && /* @__PURE__ */ import_react68.default.createElement("button", { type: "button", disabled: busy || !botId || !rootId || selected.length === 0, onClick: save }, "保存此 Bot 的机器授权"), available.includes("machine.probe") && /* @__PURE__ */ import_react68.default.createElement(import_react68.default.Fragment, null, /* @__PURE__ */ import_react68.default.createElement("button", { type: "button", disabled: busy || !binding, onClick: () => run2("machine.probe", { botId, rootId }) }, "检查 Agent 在线状态"), /* @__PURE__ */ import_react68.default.createElement("label", null, "受控读测试的相对路径", /* @__PURE__ */ import_react68.default.createElement("input", { "aria-label": `机器 ${machine.id} 的测试路径`, value: relativePath, onChange: (event) => setRelativePath(event.target.value), placeholder: "README.md" })), /* @__PURE__ */ import_react68.default.createElement("button", { type: "button", disabled: busy || !binding || !relativePath, onClick: () => run2("machine.probe", { botId, rootId, relativePath }) }, "验证可读(不显示文件内容)")), available.includes("machine.revoke") && /* @__PURE__ */ import_react68.default.createElement(import_react68.default.Fragment, null, /* @__PURE__ */ import_react68.default.createElement("button", { type: "button", disabled: busy || !binding, onClick: () => run2("machine.revoke", { botId, expectedRevision: binding.revision }) }, "撤销此 Bot 的机器访问"), /* @__PURE__ */ import_react68.default.createElement("button", { type: "button", disabled: busy, onClick: () => run2("machine.revoke", { expectedRevision: machine.revision }) }, "撤销电脑配对")), /* @__PURE__ */ import_react68.default.createElement("p", { className: "bp-muted" }, "每次保存都会先撤销旧票据再按新范围授权。桌面截图也需要 artifact 权限;撤销离线时会保留“停止未确认”。"));
|
|
34659
34910
|
}
|
|
34660
34911
|
function ArtifactDownload({ machine, snapshot, dispatch, busy }) {
|
|
34661
|
-
let [form, setForm] = (0,
|
|
34662
|
-
return /* @__PURE__ */
|
|
34912
|
+
let [form, setForm] = (0, import_react68.useState)({ botId: snapshot.bots?.[0]?.id ?? "", taskId: "", attemptId: "", operationId: "", artifactId: "" }), [result, setResult] = (0, import_react68.useState)(null), [error, setError] = (0, import_react68.useState)(null), change = (key, value) => setForm((current) => ({ ...current, [key]: value }));
|
|
34913
|
+
return /* @__PURE__ */ import_react68.default.createElement("details", { className: "bp-form" }, /* @__PURE__ */ import_react68.default.createElement("summary", null, "下载 artifact"), /* @__PURE__ */ import_react68.default.createElement("p", { className: "bp-muted" }, "仅下载原任务已授权的 artifact;先核对元数据,再校验完整字节和 SHA-256。内容不会显示在页面中。"), /* @__PURE__ */ import_react68.default.createElement("form", { onSubmit: async (event) => {
|
|
34663
34914
|
event.preventDefault(), setError(null), setResult(null);
|
|
34664
34915
|
try {
|
|
34665
34916
|
setResult(await dispatch("machine.artifact", { machineId: machine.id, ...form }));
|
|
34666
34917
|
} catch (error2) {
|
|
34667
34918
|
setError(error2);
|
|
34668
34919
|
}
|
|
34669
|
-
} }, /* @__PURE__ */
|
|
34920
|
+
} }, /* @__PURE__ */ import_react68.default.createElement("label", null, "Bot", /* @__PURE__ */ import_react68.default.createElement("select", { "aria-label": `机器 ${machine.id} 的 artifact Bot`, value: form.botId, onChange: (event) => change("botId", event.target.value) }, snapshot.bots.map((bot) => /* @__PURE__ */ import_react68.default.createElement("option", { key: bot.id, value: bot.id }, bot.name ?? bot.id)))), [["taskId", "Task"], ["attemptId", "Attempt"], ["operationId", "Operation"], ["artifactId", "Artifact"]].map(([key, label]) => /* @__PURE__ */ import_react68.default.createElement("label", { key }, label, /* @__PURE__ */ import_react68.default.createElement("input", { "aria-label": `机器 ${machine.id} 的 artifact ${label}`, value: form[key], onInput: (event) => change(key, event.target.value), required: !0, autoComplete: "off" }))), /* @__PURE__ */ import_react68.default.createElement("button", { type: "submit", disabled: busy || Object.values(form).some((value) => !value) }, "核验并下载")), error && /* @__PURE__ */ import_react68.default.createElement("p", { className: "bp-blocked", role: "status" }, "下载失败:", error.code ?? "ARTIFACT_DOWNLOAD_FAILED", "。artifact 不存在、已过期或未获授权。"), result && /* @__PURE__ */ import_react68.default.createElement("a", { download: `${form.artifactId}.bin`, href: `data:${result.mediaType ?? "application/octet-stream"};base64,${result.content}` }, "下载已核验 artifact(", result.size, " 字节,SHA-256 已匹配)"));
|
|
34670
34921
|
}
|
|
34671
34922
|
function Machines({ snapshot, dispatch, busy }) {
|
|
34672
34923
|
let section = snapshot.machines;
|
|
34673
|
-
return section?.status !== "available" ? /* @__PURE__ */
|
|
34924
|
+
return section?.status !== "available" ? /* @__PURE__ */ import_react68.default.createElement(Blocked, { value: section }) : /* @__PURE__ */ import_react68.default.createElement(import_react68.default.Fragment, null, dispatch && /* @__PURE__ */ import_react68.default.createElement(import_react68.default.Fragment, null, /* @__PURE__ */ import_react68.default.createElement(DesktopWorkbench, { snapshot, dispatch }), /* @__PURE__ */ import_react68.default.createElement("details", null, /* @__PURE__ */ import_react68.default.createElement("summary", null, "兼容截图操作"), /* @__PURE__ */ import_react68.default.createElement(DesktopControl, { snapshot, dispatch, busy })), /* @__PURE__ */ import_react68.default.createElement(MachineSetup, { snapshot, dispatch, busy })), section.items.length ? /* @__PURE__ */ import_react68.default.createElement("div", { className: "bp-grid" }, section.items.map((machine) => /* @__PURE__ */ import_react68.default.createElement("article", { className: "bp-card", key: machine.id ?? machine.machineId }, /* @__PURE__ */ import_react68.default.createElement("div", { className: "bp-card-title" }, /* @__PURE__ */ import_react68.default.createElement("h2", null, machine.name ?? machine.id ?? machine.machineId), /* @__PURE__ */ import_react68.default.createElement(Tag3, null, machine.status ?? "未知")), /* @__PURE__ */ import_react68.default.createElement("dl", { className: "bp-facts" }, /* @__PURE__ */ import_react68.default.createElement(Value2, { label: "平台" }, machine.platform), /* @__PURE__ */ import_react68.default.createElement(Value2, { label: "Agent 版本" }, machine.version), /* @__PURE__ */ import_react68.default.createElement(Value2, { label: "最后在线" }, machine.lastSeenAt ? new Date(machine.lastSeenAt).toLocaleString("zh-CN") : "从未取得心跳"), /* @__PURE__ */ import_react68.default.createElement(Value2, { label: "能力" }, machine.capabilities?.join("、")), /* @__PURE__ */ import_react68.default.createElement(Value2, { label: "桌面会话" }, machine.desktop?.status ?? "未报告")), (machine.blockedReason || machine.status !== "online") && /* @__PURE__ */ import_react68.default.createElement(Blocked, { value: { reason: machine.blockedReason ?? "机器未在线,任务不会派到此机器。", nextAction: machine.nextAction ?? "启动 Agent 并检查配对、网络及登录桌面。" } }), machine.revocations?.some((item) => item.status !== "revoked") && /* @__PURE__ */ import_react68.default.createElement("aside", { className: "bp-blocked", role: "status" }, /* @__PURE__ */ import_react68.default.createElement("strong", null, "远程停止尚未确认"), /* @__PURE__ */ import_react68.default.createElement("p", null, "本机授权已经撤销。目标电脑恢复连接后,可重新确认远程票据撤销;此操作不会恢复任何权限。"), dispatch && snapshot.availableActions?.includes("machine.reconcile") && /* @__PURE__ */ import_react68.default.createElement("button", { type: "button", disabled: busy, onClick: () => dispatch("machine.reconcile", { machineId: machine.id }) }, "重试确认远程撤销")), dispatch && machine.status !== "revoked" && /* @__PURE__ */ import_react68.default.createElement(import_react68.default.Fragment, null, /* @__PURE__ */ import_react68.default.createElement(MachineControls, { machine, snapshot, dispatch, busy }), /* @__PURE__ */ import_react68.default.createElement(ArtifactDownload, { machine, snapshot, dispatch, busy }))))) : !dispatch && /* @__PURE__ */ import_react68.default.createElement("p", { className: "bp-empty" }, "尚未配对远程电脑。安装 Agent,核验指纹并授予所需根目录后,机器会显示在这里。"));
|
|
34674
34925
|
}
|
|
34675
34926
|
function UnknownReview({ item, dispatch, busy }) {
|
|
34676
|
-
let [note, setNote] = (0,
|
|
34927
|
+
let [note, setNote] = (0, import_react68.useState)(""), [amount, setAmount] = (0, import_react68.useState)(""), attestable = note.trim().length > 0 && amount.trim() !== "" && Number.isFinite(Number(amount)) && Number(amount) >= 0, submit = (kind) => dispatch("usage.resolve", {
|
|
34677
34928
|
botId: item.botId,
|
|
34678
34929
|
runId: item.runId,
|
|
34679
34930
|
packageId: item.packageId,
|
|
@@ -34681,18 +34932,18 @@ function UnknownReview({ item, dispatch, busy }) {
|
|
|
34681
34932
|
...kind === "attest" ? { costUsd: Number(amount) } : {},
|
|
34682
34933
|
note: note.trim()
|
|
34683
34934
|
});
|
|
34684
|
-
return /* @__PURE__ */
|
|
34935
|
+
return /* @__PURE__ */ import_react68.default.createElement("article", { className: "bp-card" }, /* @__PURE__ */ import_react68.default.createElement("div", { className: "bp-card-title" }, /* @__PURE__ */ import_react68.default.createElement("h2", null, item.botId), /* @__PURE__ */ import_react68.default.createElement(Tag3, null, item.billing === "subscription" ? "订阅" : "API")), /* @__PURE__ */ import_react68.default.createElement("dl", { className: "bp-facts" }, /* @__PURE__ */ import_react68.default.createElement(Value2, { label: "运行" }, item.runId), /* @__PURE__ */ import_react68.default.createElement(Value2, { label: "工作包" }, item.packageId), /* @__PURE__ */ import_react68.default.createElement(Value2, { label: "模型" }, modelName(item.model ?? (item.provider ? { provider: item.provider, model: item.model } : null))), /* @__PURE__ */ import_react68.default.createElement(Value2, { label: "用量" }, item.usage ? `${item.usage.inputTokens ?? "未报告"} / ${item.usage.outputTokens ?? "未报告"}` : "未报告"), /* @__PURE__ */ import_react68.default.createElement(Value2, { label: "结束于" }, item.finishedAt ? new Date(item.finishedAt).toLocaleString("zh-CN") : "未取得")), /* @__PURE__ */ import_react68.default.createElement("label", null, "核对说明(必填,留痕于运行记录)", /* @__PURE__ */ import_react68.default.createElement("input", { "aria-label": `核对说明 ${item.runId}`, value: note, onChange: (event) => setNote(event.target.value), maxLength: 2e3, required: !0, autoComplete: "off" })), /* @__PURE__ */ import_react68.default.createElement("label", null, "厂商确认金额(美元;留空并按零费用放行)", /* @__PURE__ */ import_react68.default.createElement("input", { "aria-label": `核对金额 ${item.runId}`, value: amount, onChange: (event) => setAmount(event.target.value), inputMode: "decimal", placeholder: "0.00", autoComplete: "off" })), /* @__PURE__ */ import_react68.default.createElement("div", { className: "bp-actions" }, /* @__PURE__ */ import_react68.default.createElement("button", { type: "button", disabled: busy || !attestable, onClick: () => submit("attest") }, "按厂商账单确认"), /* @__PURE__ */ import_react68.default.createElement("button", { type: "button", disabled: busy || !note.trim(), onClick: () => submit("waive") }, "按零费用放行")));
|
|
34685
34936
|
}
|
|
34686
34937
|
function Usage({ snapshot, dispatch, busy, openAdvanced }) {
|
|
34687
34938
|
let section = snapshot.usage;
|
|
34688
|
-
if (section?.status !== "available") return /* @__PURE__ */
|
|
34939
|
+
if (section?.status !== "available") return /* @__PURE__ */ import_react68.default.createElement(import_react68.default.Fragment, null, /* @__PURE__ */ import_react68.default.createElement(Blocked, { value: section }), /* @__PURE__ */ import_react68.default.createElement("button", { onClick: openAdvanced }, "打开已有 MR 费用与订阅面板"));
|
|
34689
34940
|
let unresolved = section.unresolved ?? [];
|
|
34690
|
-
return /* @__PURE__ */
|
|
34941
|
+
return /* @__PURE__ */ import_react68.default.createElement(import_react68.default.Fragment, null, /* @__PURE__ */ import_react68.default.createElement("p", { className: "bp-muted" }, "以宿主唯一资金库的收据和预占为准。未知费用保留未知;Token 统计与实际计费分开呈现。"), section.summary && /* @__PURE__ */ import_react68.default.createElement("dl", { className: "bp-facts bp-card" }, /* @__PURE__ */ import_react68.default.createElement(Value2, { label: "已知 API 费用" }, money3(section.summary.apiUsd)), /* @__PURE__ */ import_react68.default.createElement(Value2, { label: "当前预占" }, money3(section.summary.reservedUsd)), /* @__PURE__ */ import_react68.default.createElement(Value2, { label: "未知费用记录" }, section.summary.unknownCount ?? "未报告"), /* @__PURE__ */ import_react68.default.createElement(Value2, { label: "订阅用量" }, subscriptionText(section.summary.subscriptionSummary))), unresolved.length ? /* @__PURE__ */ import_react68.default.createElement("section", { className: "bp-card", "aria-label": "待人工核对的未确认费用" }, /* @__PURE__ */ import_react68.default.createElement("h2", null, "待人工核对的未确认费用"), /* @__PURE__ */ import_react68.default.createElement("p", { className: "bp-muted" }, "以下执行已经分派,但没有取得可核验的厂商账单;在核对完成前,其 Bot 与资金范围不会放行新的付费调用。核对说明会记录在运行记录中。"), /* @__PURE__ */ import_react68.default.createElement("div", { className: "bp-grid" }, unresolved.map((item) => /* @__PURE__ */ import_react68.default.createElement(UnknownReview, { key: `${item.runId}/${item.packageId}`, item, dispatch, busy })))) : null, section.items.length ? /* @__PURE__ */ import_react68.default.createElement("div", { className: "bp-table-wrap" }, /* @__PURE__ */ import_react68.default.createElement("table", null, /* @__PURE__ */ import_react68.default.createElement("thead", null, /* @__PURE__ */ import_react68.default.createElement("tr", null, /* @__PURE__ */ import_react68.default.createElement("th", null, "Bot / 任务"), /* @__PURE__ */ import_react68.default.createElement("th", null, "来源"), /* @__PURE__ */ import_react68.default.createElement("th", null, "准确模型"), /* @__PURE__ */ import_react68.default.createElement("th", null, "金额"), /* @__PURE__ */ import_react68.default.createElement("th", null, "状态"))), /* @__PURE__ */ import_react68.default.createElement("tbody", null, section.items.map((row, i) => /* @__PURE__ */ import_react68.default.createElement("tr", { key: row.id ?? row.receiptId ?? i }, /* @__PURE__ */ import_react68.default.createElement("td", null, row.botName ?? row.botId ?? "未归属", /* @__PURE__ */ import_react68.default.createElement("small", null, row.taskId ?? row.runId)), /* @__PURE__ */ import_react68.default.createElement("td", null, { bot: "Bot 对话", aux: "Bot 辅助调用", "mr-api": "MR API", cli: "官方 CLI", review: "评审" }[row.source] ?? row.source ?? "未报告"), /* @__PURE__ */ import_react68.default.createElement("td", null, modelName(row.model ?? (row.provider ? { provider: row.provider, model: row.modelId } : null))), /* @__PURE__ */ import_react68.default.createElement("td", null, row.billing === "subscription" ? "订阅" : money3(row.amountUsd ?? row.costUsd)), /* @__PURE__ */ import_react68.default.createElement("td", null, row.status ?? "未知", row.resolution && /* @__PURE__ */ import_react68.default.createElement(Tag3, null, row.resolution.kind === "waive" ? "已按零费用放行" : `已确认 ${money3(row.resolution.costUsd)}`))))))) : /* @__PURE__ */ import_react68.default.createElement("p", { className: "bp-empty" }, "尚无费用收据。"), /* @__PURE__ */ import_react68.default.createElement("button", { onClick: openAdvanced }, "打开高级费用、订阅与历史能力"));
|
|
34691
34942
|
}
|
|
34692
34943
|
var Library = LibraryPanel;
|
|
34693
34944
|
function RoleCatalog({ dispatch, busy }) {
|
|
34694
|
-
let [roles, setRoles] =
|
|
34695
|
-
|
|
34945
|
+
let [roles, setRoles] = import_react68.default.useState(null), [copied, setCopied] = import_react68.default.useState(""), [error, setError] = import_react68.default.useState("");
|
|
34946
|
+
import_react68.default.useEffect(() => {
|
|
34696
34947
|
let live = !0;
|
|
34697
34948
|
if (typeof dispatch == "function")
|
|
34698
34949
|
return dispatch("roles.list", {}).then((value) => {
|
|
@@ -34710,18 +34961,18 @@ function RoleCatalog({ dispatch, busy }) {
|
|
|
34710
34961
|
setError(String(failure?.message ?? failure));
|
|
34711
34962
|
}
|
|
34712
34963
|
};
|
|
34713
|
-
return error ? /* @__PURE__ */
|
|
34964
|
+
return error ? /* @__PURE__ */ import_react68.default.createElement("article", { className: "bp-card" }, /* @__PURE__ */ import_react68.default.createElement("div", { className: "bp-card-title" }, /* @__PURE__ */ import_react68.default.createElement("h2", null, "岗位")), /* @__PURE__ */ import_react68.default.createElement("p", { className: "bp-error", role: "alert" }, error)) : roles ? /* @__PURE__ */ import_react68.default.createElement("article", { className: "bp-card" }, /* @__PURE__ */ import_react68.default.createElement("div", { className: "bp-card-title" }, /* @__PURE__ */ import_react68.default.createElement("h2", null, "岗位"), /* @__PURE__ */ import_react68.default.createElement(Tag3, null, roles.length)), /* @__PURE__ */ import_react68.default.createElement("p", { className: "bp-muted" }, "这些是给 Bot 的岗位简述。新建 Bot 时把简述粘进描述即可;岗位文本不会授予任何工具或机器权限。"), /* @__PURE__ */ import_react68.default.createElement("div", { className: "bp-table-wrap" }, /* @__PURE__ */ import_react68.default.createElement("table", null, /* @__PURE__ */ import_react68.default.createElement("thead", null, /* @__PURE__ */ import_react68.default.createElement("tr", null, /* @__PURE__ */ import_react68.default.createElement("th", null, "岗位"), /* @__PURE__ */ import_react68.default.createElement("th", null, "简述"), /* @__PURE__ */ import_react68.default.createElement("th", null, "需要的能力"), /* @__PURE__ */ import_react68.default.createElement("th", null, "操作"))), /* @__PURE__ */ import_react68.default.createElement("tbody", null, roles.map((role) => /* @__PURE__ */ import_react68.default.createElement("tr", { key: role.id }, /* @__PURE__ */ import_react68.default.createElement("td", null, role.name, /* @__PURE__ */ import_react68.default.createElement("small", null, role.id)), /* @__PURE__ */ import_react68.default.createElement("td", null, role.brief), /* @__PURE__ */ import_react68.default.createElement("td", { className: "bp-code" }, role.tools.join("、")), /* @__PURE__ */ import_react68.default.createElement("td", null, /* @__PURE__ */ import_react68.default.createElement("button", { type: "button", disabled: busy, onClick: () => {
|
|
34714
34965
|
copy2(role);
|
|
34715
34966
|
} }, copied === role.id ? "已复制" : "复制简述")))))))) : null;
|
|
34716
34967
|
}
|
|
34717
34968
|
function ProductPage({ section, productApi, openSession, openPanel }) {
|
|
34718
|
-
(0,
|
|
34969
|
+
(0, import_react68.useEffect)(() => {
|
|
34719
34970
|
let id2 = PRODUCT_PANELS[section];
|
|
34720
34971
|
return announcePanel(id2), () => announcePanel(id2, !0);
|
|
34721
34972
|
}, [section]);
|
|
34722
|
-
let [snapshot, setSnapshot] = (0,
|
|
34973
|
+
let [snapshot, setSnapshot] = (0, import_react68.useState)(null), [error, setError] = (0, import_react68.useState)(""), [busy, setBusy] = (0, import_react68.useState)(!1), [snapshotStale, setSnapshotStale] = (0, import_react68.useState)(!1), pendingActions = (0, import_react68.useRef)(0), lifecycle = (0, import_react68.useRef)({ live: !1, epoch: 0, request: 0 }), snapshotApi = (0, import_react68.useRef)(null), dispatchState = (0, import_react68.useRef)(null);
|
|
34723
34974
|
dispatchState.current = { snapshotStale, readOnly: snapshot?.readOnly };
|
|
34724
|
-
let refresh = (0,
|
|
34975
|
+
let refresh = (0, import_react68.useCallback)(async (signal) => {
|
|
34725
34976
|
let state = lifecycle.current;
|
|
34726
34977
|
if (!state.live) return;
|
|
34727
34978
|
let epoch = state.epoch, request = ++state.request, current = () => state.live && state.epoch === epoch && state.request === request && !signal?.aborted;
|
|
@@ -34734,7 +34985,7 @@ function ProductPage({ section, productApi, openSession, openPanel }) {
|
|
|
34734
34985
|
current() && (setSnapshotStale(!0), setError(cause.message));
|
|
34735
34986
|
}
|
|
34736
34987
|
}, [productApi]);
|
|
34737
|
-
(0,
|
|
34988
|
+
(0, import_react68.useEffect)(() => {
|
|
34738
34989
|
let controller = new AbortController(), state = lifecycle.current;
|
|
34739
34990
|
state.live = !0, state.epoch++, setSnapshotStale(!0), pendingActions.current = 0, setBusy(!1);
|
|
34740
34991
|
let timer, stopped = !1, loop = async () => {
|
|
@@ -34744,7 +34995,7 @@ function ProductPage({ section, productApi, openSession, openPanel }) {
|
|
|
34744
34995
|
stopped = !0, state.live = !1, state.epoch++, state.request++, controller.abort(), clearTimeout(timer);
|
|
34745
34996
|
};
|
|
34746
34997
|
}, [refresh]);
|
|
34747
|
-
let dispatch = (0,
|
|
34998
|
+
let dispatch = (0, import_react68.useCallback)(async (action, payload, { errorResult = !1 } = {}) => {
|
|
34748
34999
|
if (dispatchState.current.snapshotStale || dispatchState.current.readOnly || snapshotApi.current !== productApi || !lifecycle.current.live) return;
|
|
34749
35000
|
let state = lifecycle.current, epoch = state.epoch, current = () => state.live && state.epoch === epoch;
|
|
34750
35001
|
pendingActions.current++, setBusy(!0);
|
|
@@ -34752,11 +35003,11 @@ function ProductPage({ section, productApi, openSession, openPanel }) {
|
|
|
34752
35003
|
let result = await productApi.dispatch(action, payload);
|
|
34753
35004
|
return current() && (await refresh(), current() && result?.warning && setError("宿主已撤销授权,但远程停止尚未确认;请恢复连接并检查 Agent。")), result;
|
|
34754
35005
|
} catch (cause) {
|
|
34755
|
-
current() && (state.request++, setSnapshotStale(!0), setError(cause.message));
|
|
35006
|
+
if (current() && (state.request++, setSnapshotStale(!0), setError(errorResult ? "宿主请求未完成,请查看操作区域的提示并刷新记录。" : cause.message)), errorResult) return { ok: !1, error: { code: cause?.code ?? "PRODUCT_REQUEST_FAILED", message: String(cause?.message ?? cause) } };
|
|
34756
35007
|
} finally {
|
|
34757
35008
|
current() && (pendingActions.current = Math.max(0, pendingActions.current - 1), setBusy(pendingActions.current > 0));
|
|
34758
35009
|
}
|
|
34759
|
-
}, [productApi, refresh]), disabled = busy || snapshotStale || snapshotApi.current !== productApi || !!snapshot?.readOnly, title = { bindings: "Bot 绑定与权限", tasks: "任务", machines: "远程电脑", library: "资料库", routine: "例行任务", usage: "费用与用量" }[section], meta = {
|
|
35010
|
+
}, [productApi, refresh]), inspectTask = (0, import_react68.useCallback)((payload, signal) => productApi.dispatch("task.inspect", payload, signal), [productApi]), disabled = busy || snapshotStale || snapshotApi.current !== productApi || !!snapshot?.readOnly, title = { bindings: "Bot 绑定与权限", tasks: "任务", machines: "远程电脑", library: "资料库", routine: "例行任务", usage: "费用与用量" }[section], meta = {
|
|
34760
35011
|
bindings: ["team", "让每位伙伴各司其职。管理模型、工具和工作空间。"],
|
|
34761
35012
|
tasks: ["tasks", "把工作交给合适的 Bot,在这里关注进展与结果。"],
|
|
34762
35013
|
machines: ["computer", "连接你自己的电脑,随时查看桌面或接过控制权。"],
|
|
@@ -34764,7 +35015,7 @@ function ProductPage({ section, productApi, openSession, openPanel }) {
|
|
|
34764
35015
|
routine: ["repeat", "演示一次,保存步骤,把重复的工作交给 Bot。"],
|
|
34765
35016
|
usage: ["chart", "查看真实使用记录,清楚掌握每一笔费用。"]
|
|
34766
35017
|
}[section] ?? ["bot", ""];
|
|
34767
|
-
return /* @__PURE__ */
|
|
35018
|
+
return /* @__PURE__ */ import_react68.default.createElement("main", { className: "bp-page", "data-section": section }, /* @__PURE__ */ import_react68.default.createElement("div", { className: "bp-page-inner" }, /* @__PURE__ */ import_react68.default.createElement("header", { className: "bp-page-header" }, /* @__PURE__ */ import_react68.default.createElement("div", { className: "bp-page-heading" }, /* @__PURE__ */ import_react68.default.createElement("p", { className: "bp-eyebrow" }, /* @__PURE__ */ import_react68.default.createElement(UiIcon, { name: meta[0], size: 14 }), "工作空间", /* @__PURE__ */ import_react68.default.createElement(UiIcon, { name: "chevron", size: 12 }), /* @__PURE__ */ import_react68.default.createElement("span", null, title)), /* @__PURE__ */ import_react68.default.createElement("h1", null, title), /* @__PURE__ */ import_react68.default.createElement("p", { className: "bp-page-description" }, meta[1])), /* @__PURE__ */ import_react68.default.createElement("div", { className: "bp-page-tools" }, /* @__PURE__ */ import_react68.default.createElement("span", { className: "bp-sync", "data-state": snapshotStale ? "stale" : snapshot ? "ready" : "loading" }, snapshotStale ? "等待同步" : snapshot ? "已同步" : "正在连接"), /* @__PURE__ */ import_react68.default.createElement("button", { className: "bp-refresh", disabled: busy, onClick: () => refresh(), title: "刷新当前页面" }, /* @__PURE__ */ import_react68.default.createElement(UiIcon, { name: "refresh", size: 16, className: busy ? "bp-spinning" : "" }), /* @__PURE__ */ import_react68.default.createElement("span", null, "刷新")))), /* @__PURE__ */ import_react68.default.createElement("div", { className: "bp-page-body" }, error && /* @__PURE__ */ import_react68.default.createElement("div", { role: "alert", className: "bp-blocked" }, /* @__PURE__ */ import_react68.default.createElement("strong", null, "无法取得最新宿主状态"), /* @__PURE__ */ import_react68.default.createElement("p", null, error), snapshot && /* @__PURE__ */ import_react68.default.createElement("p", null, snapshotStale ? "下面保留上次读取结果;状态未更新时,操作暂不可用。" : "下面保留上次读取结果,操作以宿主当前授权为准。")), snapshot?.readOnly && /* @__PURE__ */ import_react68.default.createElement(Blocked, { value: { reason: snapshot.readOnly, nextAction: "关闭持有写锁的另一宿主后重新加载。" } }), !snapshot && !error && /* @__PURE__ */ import_react68.default.createElement("div", { className: "bp-loading", role: "status" }, /* @__PURE__ */ import_react68.default.createElement("span", { className: "bp-loading-line", "aria-hidden": "true" }), /* @__PURE__ */ import_react68.default.createElement("span", { className: "bp-loading-line", "aria-hidden": "true" }), /* @__PURE__ */ import_react68.default.createElement("p", null, "正在读取宿主状态…")), snapshot && /* @__PURE__ */ import_react68.default.createElement(import_react68.default.Fragment, null, section === "bindings" && /* @__PURE__ */ import_react68.default.createElement(import_react68.default.Fragment, null, /* @__PURE__ */ import_react68.default.createElement(BotBindings, { snapshot, openSession, dispatch, busy: disabled }), snapshot.availableActions?.includes("roles.list") && /* @__PURE__ */ import_react68.default.createElement(RoleCatalog, { dispatch, busy: disabled })), section === "tasks" && /* @__PURE__ */ import_react68.default.createElement(Tasks, { snapshot, dispatch, busy: disabled, submissionScope: productApi, inspect: !snapshotStale && snapshotApi.current === productApi && !snapshot.readOnly ? inspectTask : void 0, openSession }), section === "machines" && /* @__PURE__ */ import_react68.default.createElement(Machines, { snapshot, dispatch, busy: disabled }), section === "routine" && /* @__PURE__ */ import_react68.default.createElement(RoutinesPanel, { snapshot, dispatch, busy: disabled, onOpenMachines: () => openPanel(PRODUCT_PANELS.machines) }), section === "library" && /* @__PURE__ */ import_react68.default.createElement(Library, { snapshot, dispatch, busy: disabled }), section === "usage" && /* @__PURE__ */ import_react68.default.createElement(Usage, { snapshot, dispatch, busy: disabled, openAdvanced: () => openPanel("model-router-galgame") }), /* @__PURE__ */ import_react68.default.createElement("footer", { className: "bp-page-footer bp-muted" }, "上次同步 ", new Date(snapshot.observedAt).toLocaleString("zh-CN"))))));
|
|
34768
35019
|
}
|
|
34769
35020
|
|
|
34770
35021
|
// apps/integration-client/product.css
|
|
@@ -34867,6 +35118,35 @@ html body[data-bot-product-ui][data-ds-dark-theme] {
|
|
|
34867
35118
|
.bp-person-copy { min-width: 0; }
|
|
34868
35119
|
.bp-person-copy strong { font-size: 13px; font-weight: 550; }
|
|
34869
35120
|
.bp-plan-list { list-style: none; display: grid; gap: 0; margin: 12px 0 0; padding: 0; }
|
|
35121
|
+
.bp-task-counts { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 10px; margin: 18px 0; }
|
|
35122
|
+
.bp-task-overview .bp-card-title > .bp-tag { flex-shrink: 0; white-space: nowrap; }
|
|
35123
|
+
.bp-task-counts button { display: grid; justify-items: start; gap: 2px; padding: 14px 16px; text-align: left; background: var(--bp-subtle); border-color: transparent; }
|
|
35124
|
+
.bp-task-counts strong { font-size: 25px; font-weight: 600; line-height: 1.3; }
|
|
35125
|
+
.bp-task-counts span { color: var(--bp-muted); font-size: 12px; }
|
|
35126
|
+
.bp-task-counts button[aria-pressed=true], .bp-task-bots button[aria-pressed=true] { border-color: var(--bp-focus); background: var(--bp-surface); }
|
|
35127
|
+
.bp-task-bots { display: flex; flex-wrap: wrap; gap: 8px; }
|
|
35128
|
+
.bp-task-bots button { text-align: left; max-width: 100%; overflow-wrap: anywhere; }
|
|
35129
|
+
.bp-task-bots small { margin: 1px 0 0; font-size: 10px; }
|
|
35130
|
+
.bp-task-search { display: flex; align-items: flex-end; gap: 12px; margin: 10px 0 18px; }
|
|
35131
|
+
.bp-task-search label { display: grid; gap: 6px; width: min(100%, 520px); color: var(--bp-muted); font-size: 12px; }
|
|
35132
|
+
.bp-task-search input { width: 100%; color: var(--bp-ink); }
|
|
35133
|
+
.bp-task-detail { scroll-margin-top: 16px; }
|
|
35134
|
+
.bp-task-detail .bp-card-title p { overflow-wrap: anywhere; }
|
|
35135
|
+
.bp-task-detail .bp-actions { flex-wrap: wrap; }
|
|
35136
|
+
.bp-task-timeline { list-style: none; margin: 20px 0; padding: 0; }
|
|
35137
|
+
.bp-task-timeline li { position: relative; display: flex; gap: 15px; padding: 0 0 20px; }
|
|
35138
|
+
.bp-task-timeline li::before { content: ''; position: absolute; top: 12px; bottom: 0; left: 4px; width: 1px; background: var(--bp-border); }
|
|
35139
|
+
.bp-task-timeline li:last-child::before { display: none; }
|
|
35140
|
+
.bp-timeline-dot { width: 9px; height: 9px; margin-top: 7px; border: 2px solid var(--bp-focus); background: var(--bp-surface); border-radius: 50%; flex-shrink: 0; }
|
|
35141
|
+
.bp-task-timeline strong { font-size: 13px; font-weight: 550; }
|
|
35142
|
+
.bp-task-plans > button { margin: 0 0 16px; }
|
|
35143
|
+
@container (max-width: 600px) {
|
|
35144
|
+
.bp-task-counts { gap: 6px; }
|
|
35145
|
+
.bp-task-counts button { padding: 12px 9px; }
|
|
35146
|
+
.bp-task-counts strong { font-size: 21px; }
|
|
35147
|
+
.bp-task-search { flex-wrap: wrap; }
|
|
35148
|
+
.bp-attention-row > .bp-actions { flex-wrap: wrap; }
|
|
35149
|
+
}
|
|
34870
35150
|
.bp-plan-list li { display: flex; align-items: flex-start; gap: 12px; padding: 13px 0; border-top: 1px solid var(--bp-border); }
|
|
34871
35151
|
.bp-plan-step { display: inline-flex; align-items: center; justify-content: center; width: 24px; height: 24px; flex: none; margin-top: 1px; border: 1px solid var(--bp-border); border-radius: 7px; color: var(--bp-muted); background: var(--bp-subtle); font-size: 11px; }
|
|
34872
35152
|
.bp-plan-copy { flex: 1; min-width: 0; overflow-wrap: anywhere; }
|
|
@@ -34907,6 +35187,10 @@ html body[data-bot-product-ui][data-ds-dark-theme] {
|
|
|
34907
35187
|
.bp-page tbody tr:last-child td { border-bottom: 0; }
|
|
34908
35188
|
.bp-page tbody tr:hover { background: var(--bp-subtle); }
|
|
34909
35189
|
.bp-page td:first-child { max-width: 360px; overflow-wrap: anywhere; }
|
|
35190
|
+
.bp-page .bp-routing-candidates { min-width: 680px; }
|
|
35191
|
+
.bp-page .bp-routing-comparison { min-width: 480px; }
|
|
35192
|
+
.bp-page :is(.bp-routing-candidates, .bp-routing-comparison) :is(th,td):first-child { min-width: 128px; }
|
|
35193
|
+
.bp-page .bp-routing-comparison td:nth-child(2) { white-space: nowrap; font-variant-numeric: tabular-nums; }
|
|
34910
35194
|
.bp-page .bp-text-button { background: transparent; border: 0; padding: 0; min-height: 24px; text-align: left; justify-content: flex-start; font-weight: 500; }
|
|
34911
35195
|
.bp-page pre { overflow: auto; max-height: 400px; margin: 14px 0; padding: 15px; border: 1px solid var(--bp-border); border-radius: 9px; background: var(--bp-subtle); font: 11px/1.7 ui-monospace,SFMono-Regular,Consolas,monospace; }
|
|
34912
35196
|
.bp-code { overflow-wrap: anywhere; font: 11px/1.8 ui-monospace,SFMono-Regular,Consolas,monospace; color: var(--bp-muted); }
|
|
@@ -35032,6 +35316,9 @@ body[data-bot-product-ui] .mr-workspace { background: var(--bp-bg); color: var(-
|
|
|
35032
35316
|
@media (prefers-reduced-motion: reduce) {
|
|
35033
35317
|
.bp-page *, .bp-nav *, .bp-desktop-viewer * { animation: none !important; transition: none !important; }
|
|
35034
35318
|
}
|
|
35319
|
+
.bp-submission-code { width: 100%; min-width: 0; box-sizing: border-box; font-family: var(--bp-mono, monospace); }
|
|
35320
|
+
.bp-submission-restore { display: grid; gap: 10px; margin-top: 10px; }
|
|
35321
|
+
.bp-submission-restore > button { justify-self: start; }
|
|
35035
35322
|
/* Sidebar width belongs to the Bot surface, independently of the Harness rail. */
|
|
35036
35323
|
.bp-nav { container-name: workspace-navigation; container-type: inline-size; }
|
|
35037
35324
|
.bp-nav-compact { padding: 14px 11px 10px; gap: 2px; }
|
|
@@ -35088,8 +35375,8 @@ function productSlots(slots, openPanel) {
|
|
|
35088
35375
|
if (key === "register") return (options, component) => {
|
|
35089
35376
|
if (component !== TeamSidebar) return target.register(options, component);
|
|
35090
35377
|
let Sidebar = (props) => {
|
|
35091
|
-
let sidebarAddon = () => /* @__PURE__ */
|
|
35092
|
-
return /* @__PURE__ */
|
|
35378
|
+
let sidebarAddon = () => /* @__PURE__ */ import_react69.default.createElement(ProductNavigation, { panels: PRODUCT_PANELS, openPanel, compact: !props.wide });
|
|
35379
|
+
return /* @__PURE__ */ import_react69.default.createElement(TeamSidebar, { ...props, actions: { ...props.actions, sidebarAddon } });
|
|
35093
35380
|
};
|
|
35094
35381
|
return Sidebar.dsBotTeamSidebar = TeamSidebar, target.register(options, Sidebar);
|
|
35095
35382
|
};
|
|
@@ -35099,7 +35386,7 @@ function productSlots(slots, openPanel) {
|
|
|
35099
35386
|
}
|
|
35100
35387
|
async function apply3(ctx) {
|
|
35101
35388
|
let api = createProductApi();
|
|
35102
|
-
ctx.effect(() => installDesktopBridge(api, (props) => /* @__PURE__ */
|
|
35389
|
+
ctx.effect(() => installDesktopBridge(api, (props) => /* @__PURE__ */ import_react69.default.createElement(DesktopPane2, { ...props })), "bot-product: desktop bridge");
|
|
35103
35390
|
let openPanel = (id2) => ctx.layout.selectPanel(id2), slots = productSlots(ctx.slots, openPanel), dsContext = new Proxy(ctx, { get: (target, key) => key === "slots" ? slots : Reflect.get(target, key, target) });
|
|
35104
35391
|
ctx.effect(() => {
|
|
35105
35392
|
let previous = document.body.getAttribute("data-bot-product-ui");
|