@tyr1105/dsh-buddy 0.1.0 → 0.1.1
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.
- dsh-buddy/LICENSE +21 -0
- {package → dsh-buddy}/README.md +5 -4
- dsh-buddy/lib/client.js +15431 -0
- {package → dsh-buddy}/lib/index.js +7984 -997
- {package → dsh-buddy}/package.json +1 -1
- package/lib/client.js +0 -2561
- {package → dsh-buddy}/cordis.patch.yml +0 -0
package/lib/client.js
DELETED
|
@@ -1,2561 +0,0 @@
|
|
|
1
|
-
window.__ModuleLoader__.load({ id: '@tyr1105/dsh-buddy', factory: function (require) { var module = { exports: {} }; var exports = module.exports;
|
|
2
|
-
"use strict";
|
|
3
|
-
var __defProp = Object.defineProperty;
|
|
4
|
-
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
-
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
-
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
7
|
-
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
8
|
-
var __export = (target, all) => {
|
|
9
|
-
for (var name in all)
|
|
10
|
-
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
-
};
|
|
12
|
-
var __copyProps = (to, from, except, desc) => {
|
|
13
|
-
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
-
for (let key of __getOwnPropNames(from))
|
|
15
|
-
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
-
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
-
}
|
|
18
|
-
return to;
|
|
19
|
-
};
|
|
20
|
-
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
21
|
-
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
22
|
-
|
|
23
|
-
// src/client/index.tsx
|
|
24
|
-
var index_exports = {};
|
|
25
|
-
__export(index_exports, {
|
|
26
|
-
HubEntryIcon: () => HubEntryIcon,
|
|
27
|
-
apply: () => apply,
|
|
28
|
-
inject: () => inject
|
|
29
|
-
});
|
|
30
|
-
module.exports = __toCommonJS(index_exports);
|
|
31
|
-
|
|
32
|
-
// src/client/styles.css
|
|
33
|
-
var styles_default = "/*\n * \u961F\u53CB\u9875\u9762\u6837\u5F0F\u3002\u7EA6\u675F\uFF08docs/prd/sections/16-ui.md 16.0 \u4E0E\u4EFB\u52A1\u5361\uFF09\uFF1A\n * - \u989C\u8272\u53EA\u7528 var(--dsw-alias-*) \u4E0E --dsw-radius-* / --dsw-shadow-* \u7B49\u4E3B\u9898 token\uFF0C\n * \u4E0D\u51FA\u73B0\u5341\u516D\u8FDB\u5236\u3001rgb\u3001hsl\uFF08transparent / currentColor \u9664\u5916\uFF09\uFF0C\u4EAE\u6697\u81EA\u52A8\u8DDF\u968F\u3002\n * - \u4E2D\u680F 720\u20131600px \u53EF\u7528\uFF1B\u7A84\u4E8E 900px \u65F6\u53F3\u680F\u6539\u4E3A\u62BD\u5C49\u3002\n * - macOS \u6807\u9898\u533A\u53EA\u5728 [data-platform=darwin] \u4E0B\u7559\u51FA\u5218\u6D77\u7A7A\u95F4\u3002\n */\n\n/*\n * \u4E3B\u9898\u53D8\u91CF\u522B\u540D\u5C42\uFF08\u89C6\u89C9\u4FEE\u590D\uFF09\uFF1A\u672C\u6837\u5F0F\u8868\u5386\u53F2\u4E0A\u4F7F\u7528\u7684\u5206\u9694\u7EBF/\u5E95\u8272/\u5F3A\u8C03\u8272\u7B49\u53D8\u91CF\u540D\n * \u4E0E\u5BBF\u4E3B\u5B9E\u9645\u63D0\u4F9B\u7684\u4E3B\u9898 token \u540D\u4E0D\u4E00\u81F4\uFF08\u5BBF\u4E3B\u53EA\u6709 border-l1/l2\u3001bg-layer-1/2\u3001\n * brand-primary\u3001label-primary/secondary\u3001state-* \u7B49\uFF09\u3002\u5BF9\u4E0D\u4E0A\u7684\u53D8\u91CF\u5728\u8BA1\u7B97\u65F6\n * \u6574\u6761\u58F0\u660E\u5931\u6548\uFF0C\u4E8E\u662F\u51FA\u73B0\u300C\u6309\u94AE\u6CA1\u6709\u8FB9\u6846\u3001\u6CA1\u6709\u80CC\u666F\u3001hover \u6CA1\u6709\u53CD\u9988\u300D\u3002\n * \u8FD9\u91CC\u5728 .ah-page \u4E0A\u628A\u65E7\u540D\u4E00\u4E00\u6620\u5C04\u5230\u771F\u5B9E token\uFF08\u627E\u4E0D\u5230\u7684\u4E2D\u95F4\u8C03\u7528 color-mix\n * \u4ECE\u54C1\u724C\u8272\u6D3E\u751F\uFF0C\u4E0D\u5199\u6B7B\u4EFB\u4F55\u5341\u516D\u8FDB\u5236\uFF09\uFF0C\u4E0B\u65B9\u6837\u5F0F\u65E0\u9700\u9010\u884C\u4FEE\u6539\u3002\n * .ah-toast-layer \u6302\u5728 shell.overlay \u63D2\u69FD\u3001\u4E0D\u5728\u9875\u9762\u5B50\u6811\u91CC\uFF0C\u6240\u4EE5\u4E00\u5E76\u58F0\u660E\u3002\n */\n.ah-page,\n.ah-toast-layer {\n /* \u5206\u9694\u7EBF\uFF1A\u65E7 separator / separator-strong \u2192 \u5BBF\u4E3B border-l1 / border-l2 */\n --dsw-alias-separator: var(--dsw-alias-border-l1, var(--dsw-alias-border-l2));\n --dsw-alias-separator-strong: var(--dsw-alias-border-l2, var(--dsw-alias-border-l1));\n /* \u5E95\u8272\uFF1A\u65E7 inset / elevated \u2192 \u5BBF\u4E3B bg-layer-1 / bg-layer-2 */\n --dsw-alias-bg-inset: var(--dsw-alias-bg-layer-1, var(--dsw-alias-bg-base));\n --dsw-alias-bg-elevated: var(--dsw-alias-bg-layer-2, var(--dsw-alias-bg-layer-1));\n /* \u5F3A\u8C03\u8272\uFF1A\u65E7 accent \u2192 \u5BBF\u4E3B brand-primary\uFF1B\u6DE1\u5F3A\u8C03\u5E95\u7528\u5B83\u6D3E\u751F */\n --dsw-alias-accent: var(--dsw-alias-brand-primary);\n --dsw-alias-accent-muted: color-mix(in srgb, var(--dsw-alias-brand-primary) 14%, transparent);\n /* \u6587\u5B57\uFF1A\u65E7 text-primary/secondary \u2192 \u5BBF\u4E3B label-primary/secondary */\n --dsw-alias-text-primary: var(--dsw-alias-label-primary);\n --dsw-alias-text-secondary: var(--dsw-alias-label-secondary);\n --dsw-alias-text-danger: var(--dsw-alias-state-error-primary);\n /* \u72B6\u6001\u8272 */\n --dsw-alias-danger: var(--dsw-alias-state-error-primary);\n --dsw-alias-success: var(--dsw-alias-state-success-primary);\n --dsw-alias-warning: var(--dsw-alias-state-warn-primary);\n --dsw-alias-warning-muted: color-mix(in srgb, var(--dsw-alias-state-warn-primary) 14%, transparent);\n /* \u60AC\u505C / \u9009\u4E2D\u5E95\u8272\uFF1A\u5BBF\u4E3B\u672A\u63D0\u4F9B\uFF0C\u4ECE\u6587\u5B57\u8272\u4F4E\u6BD4\u4F8B\u6D3E\u751F\uFF08\u4EAE\u6697\u4E3B\u9898\u90FD\u6210\u7ACB\uFF09 */\n --dsw-alias-fill-hover: color-mix(in srgb, var(--dsw-alias-label-primary) 8%, transparent);\n --dsw-alias-fill-selected: color-mix(in srgb, var(--dsw-alias-label-primary) 12%, transparent);\n /* \u5F3A\u8C03\u5E95\u4E0A\u7684\u6587\u5B57\uFF1A\u7528\u57FA\u7840\u5E95\u8272\uFF08\u6697\u8272\u4E3B\u9898=\u6D45\u5B57\u3001\u4EAE\u8272\u4E3B\u9898=\u6DF1\u5B57\uFF0C\u5728\u54C1\u724C\u8272\u4E0A\u90FD\u53EF\u8BFB\uFF09 */\n --dsw-alias-text-on-accent: var(--dsw-alias-bg-base);\n /* \u906E\u7F69\u4E0E\u6D6E\u5C42 */\n --dsw-alias-scrim: color-mix(in srgb, var(--dsw-alias-label-primary) 32%, transparent);\n --dsw-alias-toast-bg: var(--dsw-alias-bg-overlay, var(--dsw-alias-bg-layer-2));\n --dsw-alias-toast-label: var(--dsw-alias-label-primary);\n /* \u9634\u5F71\uFF1A\u5BBF\u4E3B\u672A\u66B4\u9732 shadow token\uFF0C\u7528\u6587\u5B57\u8272\u6D3E\u751F\u7684\u8F6F\u6295\u5F71\uFF0C\u8DDF\u968F\u4E3B\u9898\u6DF1\u6D45 */\n --dsw-shadow-lv2: 0 4px 16px color-mix(in srgb, var(--dsw-alias-label-primary) 18%, transparent);\n --dsw-shadow-lv3: 0 8px 28px color-mix(in srgb, var(--dsw-alias-label-primary) 26%, transparent);\n}\n\n.ah-page {\n display: flex;\n flex-direction: column;\n height: 100%;\n min-height: 0;\n background: var(--dsw-alias-bg-base);\n color: var(--dsw-alias-text-primary);\n}\n\n/* \u6574\u9875\u4E0D\u53EF\u7528\u63D0\u793A */\n.ah-page-down { align-items: center; justify-content: center; }\n.ah-down { text-align: center; display: grid; gap: 12px; justify-items: center; }\n\n/* ---------- \u9876\u680F ---------- */\n.ah-topbar {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 12px;\n padding: 12px 20px;\n border-bottom: 1px solid var(--dsw-alias-separator);\n}\n.ah-topbar h1 { font-size: 20px; font-weight: 500; margin: 0; }\n.ah-topbar-title { display: flex; align-items: baseline; gap: 10px; padding-top: calc(0px + var(--dsh-frame-top-clearance, 0px)); }\n.ah-topbar-now { font-size: 13px; color: var(--dsw-alias-text-secondary); }\n.ah-topbar-status { display: flex; align-items: center; gap: 10px; }\n\n/* macOS\uFF1A\u6807\u9898\u7ED9\u5218\u6D77/\u6807\u9898\u533A\u7559\u7A7A\u95F4 */\n[data-platform='darwin'] .ah-topbar-title { padding-top: calc(28px + var(--dsh-frame-top-clearance, 0px)); }\n\n/* ---------- \u4E09\u680F\u9AA8\u67B6 ---------- */\n.ah-body { display: flex; flex: 1; min-height: 0; }\n.ah-botlist { width: 260px; flex-shrink: 0; display: flex; flex-direction: column; border-right: 1px solid var(--dsw-alias-separator); overflow-y: auto; }\n.ah-thread { flex: 1; min-width: 0; display: flex; flex-direction: column; }\n.ah-right { width: 320px; flex-shrink: 0; border-left: 1px solid var(--dsw-alias-separator); display: flex; flex-direction: column; min-height: 0; }\n.ah-right-scroll { overflow-y: auto; flex: 1; padding: 0 16px; }\n\n/* \u4E2D\u680F\u6700\u5C0F\u53EF\u7528\u5BBD\u5EA6 */\n.ah-thread { min-width: 400px; }\n@media (max-width: 900px) {\n /* \u7A84\u5C4F\uFF1A\u53F3\u680F\u6539\u6210\u62BD\u5C49\uFF08\u76D6\u5728\u7EBF\u7A0B\u4E0A\uFF0C\u53EF\u6536\u8D77\uFF09 */\n .ah-right {\n position: absolute;\n top: 0; right: 0; bottom: 0;\n z-index: 30;\n box-shadow: var(--dsw-shadow-lv2);\n background: var(--dsw-alias-bg-base);\n width: min(320px, 85vw);\n }\n .ah-botlist { width: 200px; }\n}\n\n/* ---------- \u5DE6\u680F\u5217\u8868 ---------- */\n.ah-bot-row {\n display: flex; align-items: center; gap: 10px;\n width: 100%; padding: 10px 12px;\n background: transparent; border: none; cursor: pointer;\n color: inherit; text-align: left; font: inherit;\n}\n.ah-bot-row:hover { background: var(--dsw-alias-fill-hover, var(--dsw-alias-bg-inset)); }\n.ah-bot-row.ah-selected { background: var(--dsw-alias-fill-selected, var(--dsw-alias-bg-inset)); }\n.ah-bot-row-main { flex: 1; min-width: 0; display: grid; gap: 2px; }\n.ah-bot-row-name { font-weight: 500; display: flex; align-items: center; gap: 6px; }\n.ah-bot-row-role { font-size: 12px; color: var(--dsw-alias-text-secondary); }\n.ah-bot-row-activity {\n font-size: 12px; color: var(--dsw-alias-text-secondary);\n white-space: nowrap; overflow: hidden; text-overflow: ellipsis;\n}\n.ah-botlist-footer { margin-top: auto; padding: 10px 12px; border-top: 1px solid var(--dsw-alias-separator); }\n.ah-inbox-entry { width: 100%; padding: 8px; }\n\n/* \u5934\u50CF\u4E0E\u672A\u8BFB */\n.ah-avatar {\n display: inline-flex; align-items: center; justify-content: center;\n border-radius: 999px; flex-shrink: 0;\n font-size: 13px; font-weight: 500;\n}\n.ah-avatar-team { background: var(--dsw-alias-accent-muted); color: var(--dsw-alias-text-primary); }\n.ah-unread {\n background: var(--dsw-alias-danger); color: var(--dsw-alias-text-on-accent, var(--dsw-alias-text-primary));\n border-radius: 999px; font-size: 11px; padding: 1px 6px; flex-shrink: 0;\n}\n\n/* \u6807\u7B7E */\n.ah-tag { font-size: 11px; border-radius: var(--dsw-radius-sm, 4px); padding: 1px 6px; }\n.ah-tag-wait { background: var(--dsw-alias-warning-muted, var(--dsw-alias-bg-inset)); color: var(--dsw-alias-warning, var(--dsw-alias-text-primary)); }\n\n/* ---------- \u4E2D\u680F\u7EBF\u7A0B ---------- */\n.ah-thread-header { display: flex; align-items: center; justify-content: space-between; padding: 10px 20px; border-bottom: 1px solid var(--dsw-alias-separator); }\n.ah-thread-header h2 { margin: 0; font-size: 15px; font-weight: 500; }\n.ah-thread-messages { flex: 1; overflow-y: auto; padding: 16px 20px; display: flex; flex-direction: column; gap: 12px; }\n.ah-msg { display: flex; gap: 8px; align-items: flex-start; }\n.ah-msg-mine { flex-direction: row-reverse; }\n.ah-msg-body { max-width: min(70%, 620px); display: grid; gap: 3px; }\n.ah-msg-mine .ah-msg-body { justify-items: end; }\n.ah-msg-meta { font-size: 11px; color: var(--dsw-alias-text-secondary); }\n.ah-msg-bubble {\n padding: 8px 12px; border-radius: var(--dsw-radius-lg, 10px);\n background: var(--dsw-alias-bg-inset); word-break: break-word;\n}\n.ah-msg-mine .ah-msg-bubble { background: var(--dsw-alias-accent-muted); }\n.ah-msg-center { justify-content: center; text-align: center; }\n.ah-msg-bubble-center { font-size: 12px; color: var(--dsw-alias-text-secondary); background: transparent; padding: 2px 8px; }\n.ah-msg-center .ah-msg-time { font-size: 11px; color: var(--dsw-alias-text-secondary); }\n\n/* \u8F93\u5165\u533A */\n.ah-thread-input { display: flex; gap: 8px; padding: 12px 20px; border-top: 1px solid var(--dsw-alias-separator); }\n.ah-thread-input input {\n flex: 1; padding: 8px 12px;\n border-radius: var(--dsw-radius-md, 8px);\n border: 1px solid var(--dsw-alias-separator-strong, var(--dsw-alias-separator));\n background: var(--dsw-alias-bg-inset); color: inherit;\n}\n/* \u53D1\u9001\u5931\u8D25\u63D0\u793A\uFF08\u4EA4\u4E92\u5BA1\u67E5\u7B2C 4 \u6761\uFF09\uFF1A\u8D34\u5728\u8F93\u5165\u6846\u4E0B\u65B9\uFF0C\u4E00\u53E5\u8BDD\u539F\u56E0 + \u91CD\u8BD5\uFF0C\u4E0D\u6253\u65AD\u8F93\u5165\u3002 */\n.ah-thread-senderror {\n display: flex; align-items: center; gap: 8px;\n padding: 6px 20px 10px; font-size: 12px;\n color: var(--dsw-alias-text-danger, var(--dsw-alias-text-secondary));\n}\n\n/* ---------- \u5361\u7247 ---------- */\n.ah-card {\n margin-top: 6px; padding: 10px 12px;\n border: 1px solid var(--dsw-alias-separator-strong, var(--dsw-alias-separator));\n border-radius: var(--dsw-radius-lg, 10px);\n background: var(--dsw-alias-bg-elevated, var(--dsw-alias-bg-base));\n display: grid; gap: 6px; text-align: left;\n}\n.ah-card-done { opacity: 0.7; }\n.ah-card-head { display: flex; align-items: center; gap: 8px; }\n.ah-card-type { font-size: 11px; color: var(--dsw-alias-text-secondary); border: 1px solid var(--dsw-alias-separator); border-radius: var(--dsw-radius-sm, 4px); padding: 0 6px; }\n.ah-card-title { font-weight: 500; }\n.ah-card-body { margin: 0; font-size: 13px; }\n.ah-card-expire { margin: 0; font-size: 12px; color: var(--dsw-alias-text-secondary); }\n.ah-card-answer { margin: 0; font-size: 12px; color: var(--dsw-alias-text-secondary); }\n.ah-card-error { margin: 4px 0 0; font-size: 12px; color: var(--dsw-alias-danger, var(--dsw-alias-text-secondary)); }\n.ah-card-options { display: flex; flex-wrap: wrap; gap: 8px; }\n\n/* ---------- \u6536\u4EF6\u7BB1 ---------- */\n.ah-inbox { flex: 1; overflow-y: auto; padding: 16px 20px; display: grid; gap: 12px; align-content: start; }\n.ah-inbox-row {\n padding: 12px 14px; border: 1px solid var(--dsw-alias-separator);\n border-radius: var(--dsw-radius-lg, 10px);\n background: var(--dsw-alias-bg-elevated, var(--dsw-alias-bg-base));\n display: grid; gap: 8px;\n}\n.ah-inbox-row header { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }\n.ah-inbox-row p { margin: 0; font-size: 13px; }\n.ah-inbox-time { font-size: 12px; color: var(--dsw-alias-text-secondary); margin-left: auto; }\n.ah-inbox-p0 { border-color: var(--dsw-alias-danger); }\n.ah-inbox-p1 { border-color: var(--dsw-alias-warning, var(--dsw-alias-separator-strong, var(--dsw-alias-separator))); }\n\n/* ---------- \u53F3\u680F ---------- */\n.ah-right-head { display: flex; align-items: center; justify-content: space-between; padding: 10px 16px; border-bottom: 1px solid var(--dsw-alias-separator); }\n.ah-right-head h2 { margin: 0; font-size: 15px; font-weight: 500; display: flex; align-items: center; gap: 8px; }\n.ah-right-section { padding: 10px 0; border-bottom: 1px solid var(--dsw-alias-separator); }\n.ah-right-section h3 { margin: 0 0 6px; font-size: 12px; color: var(--dsw-alias-text-secondary); font-weight: 500; }\n.ah-right-section p, .ah-right-section li { margin: 0; font-size: 13px; }\n.ah-right-section ul { margin: 0; padding-left: 18px; display: grid; gap: 6px; }\n.ah-right-kv { color: var(--dsw-alias-text-secondary); }\n.ah-right-actions { display: flex; gap: 8px; flex-wrap: wrap; padding: 12px 16px; border-top: 1px solid var(--dsw-alias-separator); align-items: center; }\n.ah-right-notice { width: 100%; margin: 0; font-size: 12px; color: var(--dsw-alias-text-secondary); }\n.ah-appraisals { list-style: none; padding: 0; display: grid; gap: 5px; font-size: 12px; }\n.ah-appraisal-decision { color: var(--dsw-alias-text-secondary); margin-right: 4px; }\n.ah-appraisal-woke { color: var(--dsw-alias-success, var(--dsw-alias-text-primary)); }\n\n/* ---------- \u901A\u7528\u4EF6 ---------- */\n.ah-btn {\n padding: 5px 12px; border-radius: var(--dsw-radius-md, 8px);\n border: 1px solid var(--dsw-alias-separator-strong, var(--dsw-alias-separator));\n background: var(--dsw-alias-bg-inset); color: inherit;\n cursor: pointer; font: inherit; font-size: 13px;\n}\n.ah-btn:hover { background: var(--dsw-alias-fill-hover, var(--dsw-alias-bg-inset)); }\n.ah-btn:disabled { opacity: 0.5; cursor: default; }\n.ah-btn-primary { border-color: var(--dsw-alias-accent); color: var(--dsw-alias-text-on-accent, var(--dsw-alias-text-primary)); background: var(--dsw-alias-accent-muted); }\n.ah-btn-ghost { border-color: transparent; background: transparent; }\n\n.ah-dot { display: inline-flex; align-items: center; gap: 5px; font-size: 12px; }\n.ah-dot-circle { width: 8px; height: 8px; border-radius: 999px; display: inline-block; }\n.ah-dot-ok .ah-dot-circle { background: var(--dsw-alias-success, var(--dsw-alias-accent)); }\n.ah-dot-warn .ah-dot-circle { background: var(--dsw-alias-warning, var(--dsw-alias-accent)); }\n.ah-dot-busy .ah-dot-circle { background: var(--dsw-alias-accent); }\n.ah-dot-idle .ah-dot-circle { background: var(--dsw-alias-text-secondary); }\n.ah-dot-danger .ah-dot-circle { background: var(--dsw-alias-danger); }\n\n.ah-skeleton { display: grid; gap: 8px; padding: 16px; }\n.ah-skeleton-row { height: 14px; border-radius: var(--dsw-radius-sm, 4px); background: var(--dsw-alias-bg-inset); }\n.ah-retry { display: flex; align-items: center; gap: 10px; padding: 16px 20px; color: var(--dsw-alias-text-secondary); }\n.ah-empty { padding: 16px 20px; font-size: 13px; color: var(--dsw-alias-text-secondary); }\n\n/* \u5360\u4F4D\u5BF9\u8BDD\u6846 */\n.ah-dialog-mask { position: fixed; inset: 0; background: var(--dsw-alias-scrim, transparent); display: flex; align-items: center; justify-content: center; z-index: 100; }\n.ah-dialog {\n background: var(--dsw-alias-bg-elevated, var(--dsw-alias-bg-base));\n border-radius: var(--dsw-radius-lg, 10px); box-shadow: var(--dsw-shadow-lv3);\n padding: 20px 24px; display: grid; gap: 12px; justify-items: center; text-align: center;\n}\n\n/* ================= D03\uFF1A\u6C14\u6CE1\u3001\u7EBF\u7A0B\u5934\u90E8\u3001\u5411\u5BFC\u3001\u6536\u4EF6\u7BB1\u3001\u6D3B\u52A8\u6D41\u3001\u8BBE\u7F6E\u3001\u63D0\u793A ================= */\n\n/* \u7EBF\u7A0B\u5934\u90E8\uFF1A\u540D\u5B57/\u89D2\u8272 + \u72B6\u6001\u53E5 + \u4E0B\u6B21\u81EA\u67E5 + \u53F3\u4FA7\u64CD\u4F5C */\n.ah-thread-header { flex-wrap: wrap; gap: 6px 12px; }\n.ah-thread-header-main { display: grid; gap: 2px; min-width: 0; }\n.ah-thread-header-main h2 { display: flex; align-items: center; gap: 8px; }\n.ah-thread-status { margin: 0; font-size: 12px; color: var(--dsw-alias-text-secondary); }\n.ah-thread-next { margin: 0; font-size: 12px; color: var(--dsw-alias-text-secondary); }\n.ah-thread-header-actions { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; }\n\n/* \u6C14\u6CE1\uFF1A\u4E3B\u4EBA\u53F3\u4E3B\u8272\u6DE1\u5E95\u3001\u673A\u5668\u4EBA\u5DE6\u4E2D\u6027\u5E95\uFF1B\u6C47\u62A5\u5DE6\u4FA7\u7EC6\u8272\u6761 */\n.ah-msg-bubble {\n border-radius: var(--dsw-radius-lg, 10px);\n background: var(--dsw-alias-bg-inset);\n padding: 8px 12px;\n border-top-left-radius: var(--dsw-radius-sm, 4px);\n}\n.ah-msg-mine .ah-msg-bubble {\n background: var(--dsw-alias-accent-muted);\n border-top-left-radius: var(--dsw-radius-lg, 10px);\n border-top-right-radius: var(--dsw-radius-sm, 4px);\n}\n.ah-msg-report .ah-msg-bubble { border-left: 3px solid var(--dsw-alias-accent); }\n\n/* \u6309\u94AE\uFF1A\u60AC\u505C\u4E0E\u6309\u4E0B\u53CD\u9988 */\n.ah-btn { transition: background 0.12s ease, border-color 0.12s ease, transform 0.06s ease; }\n.ah-btn:hover:not(:disabled) { filter: brightness(1.05); background: var(--dsw-alias-fill-hover, var(--dsw-alias-bg-inset)); }\n.ah-btn:active:not(:disabled) { transform: translateY(1px); }\n/* \u952E\u76D8\u7126\u70B9\u73AF\uFF08\u89C6\u89C9\u4FEE\u590D\uFF1A\u539F\u6765\u6CA1\u6709\u7126\u70B9\u6837\u5F0F\uFF0CTab \u5BFC\u822A\u5B8C\u5168\u770B\u4E0D\u51FA\u7126\u70B9\u5728\u54EA\uFF09 */\n.ah-btn:focus-visible, .ah-bot-row:focus-visible, .ah-inbox-entry:focus-visible,\n.ah-thread-input input:focus-visible, .ah-card-freetext input:focus-visible, .ah-card-note:focus-visible {\n outline: 2px solid var(--dsw-alias-accent);\n outline-offset: 1px;\n}\n.ah-btn-primary {\n border-color: var(--dsw-alias-accent);\n background: var(--dsw-alias-accent);\n color: var(--dsw-alias-text-on-accent, var(--dsw-alias-text-primary));\n}\n.ah-btn-primary:hover:not(:disabled) {\n background: color-mix(in srgb, var(--dsw-alias-accent) 88%, var(--dsw-alias-label-primary));\n border-color: color-mix(in srgb, var(--dsw-alias-accent) 88%, var(--dsw-alias-label-primary));\n}\n.ah-btn-danger { border-color: var(--dsw-alias-danger); color: var(--dsw-alias-danger); }\n.ah-btn-icon { display: inline-flex; align-items: center; gap: 4px; }\n\n/* \u5361\u7247\u91CC\u7684\u81EA\u7531\u6587\u672C\u4E0E\u9644\u8A00 */\n.ah-card-freetext { display: flex; gap: 8px; }\n.ah-card-freetext input, .ah-card-note {\n flex: 1; padding: 6px 10px; font: inherit; color: inherit;\n border-radius: var(--dsw-radius-md, 8px);\n border: 1px solid var(--dsw-alias-separator);\n background: var(--dsw-alias-bg-inset);\n}\n.ah-card-note { width: 100%; }\n\n/* \u6536\u4EF6\u7BB1\u5206\u7EC4 */\n.ah-inbox-group { display: grid; gap: 8px; }\n.ah-inbox-group h3 { margin: 8px 0 0; font-size: 12px; color: var(--dsw-alias-text-secondary); font-weight: 500; }\n.ah-inbox-bot { font-weight: 500; }\n.ah-inbox-row { border: 1px solid var(--dsw-alias-separator); border-radius: var(--dsw-radius-lg, 10px); padding: 10px 12px; display: grid; gap: 8px; background: var(--dsw-alias-bg-elevated, var(--dsw-alias-bg-base)); }\n.ah-inbox-row header { display: flex; align-items: center; gap: 8px; }\n.ah-inbox-row .ah-card { border: none; margin: 0; padding: 0; background: transparent; }\n.ah-inbox-p0 .ah-inbox-row { border-color: var(--dsw-alias-danger); }\n\n/* \u6D3B\u52A8\u6D41 */\n.ah-activity { flex: 1; overflow-y: auto; padding: 16px 20px; display: grid; gap: 12px; align-content: start; }\n.ah-activity-filters { display: flex; gap: 12px; align-items: center; flex-wrap: wrap; font-size: 13px; }\n.ah-activity-filters label { display: flex; align-items: center; gap: 6px; color: var(--dsw-alias-text-secondary); }\n.ah-activity-filters select {\n font: inherit; color: inherit; padding: 4px 8px;\n border-radius: var(--dsw-radius-md, 8px);\n border: 1px solid var(--dsw-alias-separator);\n background: var(--dsw-alias-bg-inset);\n}\n.ah-activity-list { list-style: none; margin: 0; padding: 0; display: grid; gap: 10px; }\n.ah-activity-row { display: flex; align-items: flex-start; gap: 8px; font-size: 13px; }\n.ah-activity-time { color: var(--dsw-alias-text-secondary); font-size: 12px; flex-shrink: 0; min-width: 72px; }\n.ah-activity-text { flex: 1; min-width: 0; }\n.ah-activity-kind {\n font-size: 11px; color: var(--dsw-alias-text-secondary);\n border: 1px solid var(--dsw-alias-separator);\n border-radius: var(--dsw-radius-sm, 4px);\n padding: 0 6px; margin-right: 6px;\n}\n.ah-activity-alert .ah-activity-kind { color: var(--dsw-alias-danger); border-color: var(--dsw-alias-danger); }\n.ah-activity-approval .ah-activity-kind { color: var(--dsw-alias-warning, var(--dsw-alias-text-secondary)); }\n.ah-activity-more { display: flex; justify-content: center; }\n\n/* \u8BBE\u7F6E\u9875 */\n.ah-settings { flex: 1; overflow-y: auto; padding: 16px 20px; display: grid; gap: 10px; align-content: start; }\n.ah-settings h3 { margin: 8px 0 0; font-size: 13px; font-weight: 500; color: var(--dsw-alias-text-secondary); }\n.ah-settings-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); gap: 10px; }\n.ah-settings-grid label, .ah-wizard-field label, .ah-edit-box label, .ah-wizard-grid label {\n display: grid; gap: 4px; font-size: 13px;\n}\n.ah-settings-grid input, .ah-settings-grid select,\n.ah-wizard-field input, .ah-wizard-field textarea, .ah-wizard-field select,\n.ah-edit-box input, .ah-edit-box textarea, .ah-edit-add input, .ah-edit-list input {\n font: inherit; color: inherit; padding: 6px 10px;\n border-radius: var(--dsw-radius-md, 8px);\n border: 1px solid var(--dsw-alias-separator);\n background: var(--dsw-alias-bg-inset);\n}\n.ah-settings-grid input:disabled { opacity: 0.7; }\n.ah-settings-error { margin: 0; font-size: 13px; color: var(--dsw-alias-danger); }\n.ah-settings-actions { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; }\n.ah-settings-health { margin: 0; padding-left: 18px; display: grid; gap: 4px; font-size: 13px; }\n\n/* \u5411\u5BFC */\n.ah-dialog-wide { max-width: min(680px, calc(100vw - 48px)); text-align: left; justify-items: stretch; }\n.ah-wizard-head { display: flex; align-items: center; justify-content: space-between; }\n.ah-wizard-head h3 { margin: 0; }\n.ah-wizard-steps { list-style: none; display: flex; gap: 6px; margin: 0; padding: 0; flex-wrap: wrap; font-size: 12px; }\n.ah-wizard-steps li { color: var(--dsw-alias-text-secondary); padding: 2px 8px; border-radius: var(--dsw-radius-sm, 4px); border: 1px solid var(--dsw-alias-separator); }\n.ah-wizard-steps .ah-wizard-step-current { color: var(--dsw-alias-text-on-accent, var(--dsw-alias-text-primary)); background: var(--dsw-alias-accent); border-color: var(--dsw-alias-accent); }\n.ah-wizard-steps .ah-wizard-step-done { color: var(--dsw-alias-accent); border-color: var(--dsw-alias-accent); }\n.ah-wizard-body { display: grid; gap: 12px; }\n.ah-wizard-roles { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 8px; }\n.ah-wizard-role {\n display: grid; gap: 4px; padding: 10px; text-align: left; font: inherit; color: inherit; cursor: pointer;\n border: 1px solid var(--dsw-alias-separator); border-radius: var(--dsw-radius-lg, 10px);\n background: var(--dsw-alias-bg-inset); font-size: 13px;\n}\n.ah-wizard-role span { color: var(--dsw-alias-text-secondary); }\n.ah-wizard-role-picked { border-color: var(--dsw-alias-accent); background: var(--dsw-alias-accent-muted); }\n.ah-wizard-role-disabled { opacity: 0.5; cursor: not-allowed; }\n.ah-wizard-colors { display: flex; gap: 8px; flex-wrap: wrap; }\n.ah-wizard-colors button { width: 26px; height: 26px; border-radius: 999px; border: 2px solid transparent; cursor: pointer; }\n.ah-wizard-colors .ah-wizard-color-picked { border-color: var(--dsw-alias-text-primary); }\n.ah-wizard-examples { display: grid; gap: 6px; }\n.ah-wizard-examples .ah-btn { text-align: left; font-size: 12px; }\n.ah-wizard-optional { font-size: 13px; display: grid; gap: 8px; }\n.ah-wizard-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 10px; }\n.ah-wizard-confirm .ah-wizard-restatement { margin: 0; font-size: 14px; }\n.ah-wizard-label { font-size: 13px; color: var(--dsw-alias-text-secondary); }\n\n/* \u6559\u5B66\u5F39\u7A97 */\n.ah-teach-search, .ah-teach-note { font: inherit; color: inherit; padding: 6px 10px; border-radius: var(--dsw-radius-md, 8px); border: 1px solid var(--dsw-alias-separator); background: var(--dsw-alias-bg-inset); }\n.ah-teach-list { list-style: none; margin: 0; padding: 0; display: grid; gap: 6px; max-height: 240px; overflow-y: auto; }\n.ah-teach-list label { display: flex; align-items: center; gap: 8px; padding: 6px 8px; border-radius: var(--dsw-radius-md, 8px); font-size: 13px; cursor: pointer; }\n.ah-teach-picked { background: var(--dsw-alias-accent-muted); }\n.ah-teach-title { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n.ah-dialog-actions { display: flex; gap: 8px; justify-content: flex-end; }\n\n/* \u53F3\u680F\u7F16\u8F91 */\n.ah-edit-list { list-style: none; margin: 0; padding: 0; display: grid; gap: 8px; font-size: 13px; }\n.ah-edit-list li { display: grid; gap: 4px; }\n.ah-edit-ops { display: flex; gap: 6px; align-items: center; flex-wrap: wrap; }\n.ah-edit-ops input { font-size: 12px; padding: 3px 8px; max-width: 200px; }\n.ah-edit-add { display: flex; gap: 6px; align-items: center; flex-wrap: wrap; }\n.ah-edit-box { display: grid; gap: 8px; font-size: 13px; }\n.ah-routine-steps { margin: 4px 0; padding-left: 18px; display: grid; gap: 2px; font-size: 12px; color: var(--dsw-alias-text-secondary); }\n\n/* \u5E94\u7528\u5185\u63D0\u793A\uFF08\u5B98\u65B9 toast \u6837\u5F0F\uFF0Cverified-T5 Q4-2\uFF1B\u53EA\u7528\u4E3B\u9898\u53D8\u91CF\uFF09 */\n.ah-toast-layer {\n position: fixed; top: 40px; left: 50%; transform: translateX(-50%);\n z-index: 1100; pointer-events: none;\n display: grid; gap: 8px; justify-items: center;\n max-width: min(640px, calc(100vw - 48px));\n}\n.ah-toast {\n padding: 12px 16px; border-radius: var(--dsw-radius-lg, 10px);\n background: var(--dsw-alias-toast-bg, var(--dsw-alias-bg-elevated, var(--dsw-alias-bg-base)));\n color: var(--dsw-alias-toast-label, var(--dsw-alias-text-primary));\n font-size: 14px; line-height: 22px;\n box-shadow: var(--dsw-shadow-lv3);\n pointer-events: auto;\n animation: ah-toast-in 0.16s ease;\n}\n.ah-toast-btn { all: unset; cursor: pointer; }\n.ah-toast-btn:hover { text-decoration: underline; }\n@keyframes ah-toast-in { from { opacity: 0; } to { opacity: 1; } }\n\n/* \u9875\u9762\u5E95\u90E8\u7684\u884C\u5185\u901A\u77E5\uFF08\u8BD5\u8DD1\u63D0\u793A\u7B49\uFF09\u2014\u2014D04 3c-3 \u8D77\u6539\u7528\u7EBF\u7A0B\u9876\u90E8\u63D0\u793A\u6761\uFF0C\u6B64\u6837\u5F0F\u4FDD\u7559\u517C\u5BB9 */\n.ah-toast-inline {\n position: absolute; bottom: 16px; left: 50%; transform: translateX(-50%);\n display: flex; gap: 10px; align-items: center;\n padding: 10px 16px; border-radius: var(--dsw-radius-lg, 10px);\n background: var(--dsw-alias-bg-elevated, var(--dsw-alias-bg-inset));\n box-shadow: var(--dsw-shadow-lv2); font-size: 13px; z-index: 40;\n}\n\n/* ================= D04\uFF1A\u5411\u5BFC\u9009\u4E2D\u6001\u3001\u4E09\u9009\u4E00\u7248\u5F0F\u3001\u7EBF\u7A0B\u9876\u90E8\u63D0\u793A\u6761\u3001\u6C14\u6CE1\u53EF\u8FA8\u6027 ================= */\n\n/* \u5411\u5BFC\u7B2C 1 \u6B65\uFF1A\u89D2\u8272\u5361\u9009\u4E2D = \u4E3B\u8272\u63CF\u8FB9 + \u6D45\u5E95 + \u53F3\u4E0A\u89D2\u300C\u5DF2\u9009\u300D\u89D2\u6807\uFF08D04 3c-1\uFF09 */\n.ah-wizard-role { position: relative; }\n.ah-wizard-role-picked {\n border-color: var(--dsw-alias-accent);\n background: var(--dsw-alias-accent-muted);\n box-shadow: inset 0 0 0 1px var(--dsw-alias-accent);\n}\n.ah-wizard-role-check {\n position: absolute; top: 6px; right: 6px;\n font-size: 11px; padding: 1px 6px; border-radius: var(--dsw-radius-sm, 4px);\n color: var(--dsw-alias-text-on-accent, var(--dsw-alias-text-primary));\n background: var(--dsw-alias-accent);\n}\n/* \u8272\u5757\u9009\u4E2D\u63CF\u8FB9\u7528\u4E3B\u8272\uFF08\u539F text-primary \u5728\u6697\u8272\u4E0B\u4E0D\u663E\u773C\uFF09 */\n.ah-wizard-colors .ah-wizard-color-picked { border-color: var(--dsw-alias-accent); }\n\n/* \u5411\u5BFC\u7B2C 4 \u6B65\uFF1A\u4E09\u4E2A\u9009\u62E9\u6846\u540C\u9AD8\u540C\u5BBD\u4E00\u884C\u5BF9\u9F50\uFF1B\u8BF4\u660E\u653E\u4E0B\u65B9\u3001\u6B21\u8981\u8272\u3001\u6B63\u5E38\u5B57\u53F7\uFF08D04 3c-2\uFF09 */\n.ah-wizard-trio {\n display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 10px;\n}\n.ah-wizard-trio label { display: grid; gap: 4px; font-size: 13px; }\n.ah-wizard-trio select { width: 100%; height: 34px; }\n.ah-wizard-note { margin: 0; font-size: 13px; color: var(--dsw-alias-text-secondary); }\n\n/* \u7EBF\u7A0B\u9876\u90E8\u63D0\u793A\u6761\uFF08\u8BD5\u8DD1\u63D0\u793A\u7B49\uFF09\uFF1A\u5934\u90E8\u4E0B\u65B9\u3001\u4E0D\u906E\u6321\u8F93\u5165\u6846\uFF08D04 3c-3\uFF09 */\n.ah-thread-banner {\n display: flex; gap: 10px; align-items: center; justify-content: space-between;\n margin: 8px 20px 0; padding: 8px 12px;\n border: 1px solid var(--dsw-alias-separator);\n border-radius: var(--dsw-radius-md, 8px);\n background: var(--dsw-alias-accent-muted);\n font-size: 13px;\n}\n\n/* \u6C14\u6CE1\u53EF\u8FA8\u6027\uFF08D04 3c-4\uFF09\uFF1A\u4E3B\u4EBA\u4E3B\u8272\u6D45\u5E95 + \u4E3B\u8272\u63CF\u8FB9\uFF1B\u673A\u5668\u4EBA\u4E2D\u6027\u5E95 + \u5206\u9694\u7EBF\u63CF\u8FB9 */\n.ah-msg-bubble { border: 1px solid var(--dsw-alias-separator); }\n.ah-msg-mine .ah-msg-bubble {\n background: var(--dsw-alias-accent-muted);\n border: 1px solid var(--dsw-alias-accent);\n}\n\n/* \u53F3\u680F\u5FD7\u5411\u884C\uFF1A\u6587\u5B57\u4E0E\u64CD\u4F5C\u540C\u4E00\u884C\uFF0C\u53EA\u5728\u7F16\u8F91\u65F6\u51FA\u73B0\u8F93\u5165\u6846\uFF08D04 3c-5\uFF09 */\n.ah-edit-row { display: flex; gap: 8px; align-items: center; justify-content: space-between; min-width: 0; }\n";
|
|
34
|
-
|
|
35
|
-
// src/client/api.ts
|
|
36
|
-
var BASE = "api/agent-hub";
|
|
37
|
-
async function getJson(path) {
|
|
38
|
-
let response;
|
|
39
|
-
try {
|
|
40
|
-
response = await fetch(`${BASE}/${path}`, { credentials: "same-origin" });
|
|
41
|
-
} catch {
|
|
42
|
-
throw new Error("\u8FDE\u4E0D\u4E0A Agent \u4E2D\u5FC3\uFF08\u7F51\u7EDC\u9519\u8BEF\uFF09");
|
|
43
|
-
}
|
|
44
|
-
if (!response.ok) {
|
|
45
|
-
let message = `\u8BF7\u6C42\u5931\u8D25\uFF08${response.status}\uFF09`;
|
|
46
|
-
try {
|
|
47
|
-
const body = await response.json();
|
|
48
|
-
if (body?.error) message = body.error;
|
|
49
|
-
} catch {
|
|
50
|
-
}
|
|
51
|
-
throw new Error(message);
|
|
52
|
-
}
|
|
53
|
-
return await response.json();
|
|
54
|
-
}
|
|
55
|
-
async function postCommand(name, input) {
|
|
56
|
-
let response;
|
|
57
|
-
try {
|
|
58
|
-
response = await fetch(`${BASE}/command`, {
|
|
59
|
-
method: "POST",
|
|
60
|
-
credentials: "same-origin",
|
|
61
|
-
headers: { "Content-Type": "application/json; charset=utf-8" },
|
|
62
|
-
body: JSON.stringify({ name, input })
|
|
63
|
-
});
|
|
64
|
-
} catch {
|
|
65
|
-
return { ok: false, error: "\u8FDE\u4E0D\u4E0A Agent \u4E2D\u5FC3\uFF08\u7F51\u7EDC\u9519\u8BEF\uFF09" };
|
|
66
|
-
}
|
|
67
|
-
if (!response.ok) {
|
|
68
|
-
let message = `\u8BF7\u6C42\u5931\u8D25\uFF08${response.status}\uFF09`;
|
|
69
|
-
try {
|
|
70
|
-
const body = await response.json();
|
|
71
|
-
if (body?.error) message = body.error;
|
|
72
|
-
} catch {
|
|
73
|
-
}
|
|
74
|
-
return { ok: false, error: message };
|
|
75
|
-
}
|
|
76
|
-
return await response.json();
|
|
77
|
-
}
|
|
78
|
-
var api = {
|
|
79
|
-
overview: () => getJson("overview"),
|
|
80
|
-
bot: (id) => getJson(`bot?id=${encodeURIComponent(id)}`),
|
|
81
|
-
thread: (id, opts) => {
|
|
82
|
-
const params = new URLSearchParams({ id });
|
|
83
|
-
if (opts?.before) params.set("before", opts.before);
|
|
84
|
-
if (opts?.limit) params.set("limit", String(opts.limit));
|
|
85
|
-
return getJson(`thread?${params.toString()}`);
|
|
86
|
-
},
|
|
87
|
-
inbox: () => getJson("inbox"),
|
|
88
|
-
activity: (opts) => {
|
|
89
|
-
const params = new URLSearchParams();
|
|
90
|
-
if (opts?.before) params.set("before", opts.before);
|
|
91
|
-
if (opts?.limit) params.set("limit", String(opts.limit));
|
|
92
|
-
const qs = params.toString();
|
|
93
|
-
return getJson(qs ? `activity?${qs}` : "activity");
|
|
94
|
-
},
|
|
95
|
-
settings: () => getJson("settings"),
|
|
96
|
-
recentSessions: () => getJson("recent-sessions"),
|
|
97
|
-
command: postCommand
|
|
98
|
-
};
|
|
99
|
-
|
|
100
|
-
// src/client/store.ts
|
|
101
|
-
var import_react = require("react");
|
|
102
|
-
function createStore(initial) {
|
|
103
|
-
let snapshot = initial;
|
|
104
|
-
const listeners = /* @__PURE__ */ new Set();
|
|
105
|
-
return {
|
|
106
|
-
getSnapshot: () => snapshot,
|
|
107
|
-
subscribe(fn) {
|
|
108
|
-
listeners.add(fn);
|
|
109
|
-
return () => {
|
|
110
|
-
listeners.delete(fn);
|
|
111
|
-
};
|
|
112
|
-
},
|
|
113
|
-
set(next) {
|
|
114
|
-
if (next === snapshot) return;
|
|
115
|
-
snapshot = next;
|
|
116
|
-
for (const fn of [...listeners]) {
|
|
117
|
-
try {
|
|
118
|
-
fn();
|
|
119
|
-
} catch (error) {
|
|
120
|
-
console.error("[agent-hub] store \u901A\u77E5\u51FA\u9519:", error);
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
},
|
|
124
|
-
update(fn) {
|
|
125
|
-
this.set(fn(snapshot));
|
|
126
|
-
}
|
|
127
|
-
};
|
|
128
|
-
}
|
|
129
|
-
function useStore(store) {
|
|
130
|
-
return (0, import_react.useSyncExternalStore)(store.subscribe, store.getSnapshot, store.getSnapshot);
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
// src/client/logic/feeds.ts
|
|
134
|
-
var PRIORITY_ORDER = ["P0", "P1", "P2"];
|
|
135
|
-
var PRIORITY_LABEL = {
|
|
136
|
-
P0: "P0 \u9A6C\u4E0A\u8981\u4F60\u5904\u7406",
|
|
137
|
-
P1: "P1 \u7B49\u4F60\u62CD\u677F",
|
|
138
|
-
P2: "P2 \u6709\u7A7A\u518D\u770B"
|
|
139
|
-
};
|
|
140
|
-
function groupInbox(items) {
|
|
141
|
-
const groups = [];
|
|
142
|
-
for (const priority of PRIORITY_ORDER) {
|
|
143
|
-
const list = items.filter((item) => item.priority === priority).sort((a, b) => b.createdAt - a.createdAt || a.id.localeCompare(b.id));
|
|
144
|
-
if (list.length > 0) groups.push({ priority, label: PRIORITY_LABEL[priority], items: list });
|
|
145
|
-
}
|
|
146
|
-
return groups;
|
|
147
|
-
}
|
|
148
|
-
var ACTIVITY_KIND_LABELS = {
|
|
149
|
-
wake: "\u5524\u9192",
|
|
150
|
-
commit: "\u4EA4\u8D26",
|
|
151
|
-
approval: "\u5BA1\u6279",
|
|
152
|
-
alert: "\u544A\u8B66",
|
|
153
|
-
handoff: "\u4EA4\u63A5",
|
|
154
|
-
peer: "\u540C\u4F34\u6D88\u606F",
|
|
155
|
-
lifecycle: "\u751F\u547D\u5468\u671F",
|
|
156
|
-
system: "\u4E2D\u5FC3"
|
|
157
|
-
};
|
|
158
|
-
function filterActivity(rows, filter) {
|
|
159
|
-
return rows.filter(
|
|
160
|
-
(row) => (filter.botId == null || filter.botId === "" || row.botId === filter.botId) && (filter.kind == null || row.kind === filter.kind)
|
|
161
|
-
);
|
|
162
|
-
}
|
|
163
|
-
function entryLabel(inboxTotal) {
|
|
164
|
-
return inboxTotal > 0 ? `\u961F\u53CB \xB7 ${inboxTotal > 99 ? "99+" : inboxTotal}` : "\u961F\u53CB";
|
|
165
|
-
}
|
|
166
|
-
function newUrgentInbox(prev, next) {
|
|
167
|
-
const seen = new Set(prev.map((item) => item.id));
|
|
168
|
-
return next.filter((item) => !seen.has(item.id) && (item.priority === "P0" || item.priority === "P1"));
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
// src/client/logic/scopes.ts
|
|
172
|
-
var HUB_SCOPES = {
|
|
173
|
-
overview: "overview",
|
|
174
|
-
bot: "bot",
|
|
175
|
-
thread: "thread",
|
|
176
|
-
inbox: "inbox",
|
|
177
|
-
activity: "activity",
|
|
178
|
-
settings: "settings"
|
|
179
|
-
};
|
|
180
|
-
var emptyPlan = () => ({ overview: false, bots: [], threads: [], inbox: false, activity: false, settings: false });
|
|
181
|
-
function refreshPlan(scope, botId) {
|
|
182
|
-
const plan = emptyPlan();
|
|
183
|
-
const id = typeof botId === "string" && botId !== "" ? botId : null;
|
|
184
|
-
switch (scope) {
|
|
185
|
-
case HUB_SCOPES.overview:
|
|
186
|
-
plan.overview = true;
|
|
187
|
-
if (id !== null) plan.bots.push(id);
|
|
188
|
-
return plan;
|
|
189
|
-
case HUB_SCOPES.bot:
|
|
190
|
-
plan.overview = true;
|
|
191
|
-
if (id !== null) plan.bots.push(id);
|
|
192
|
-
return plan;
|
|
193
|
-
case HUB_SCOPES.thread:
|
|
194
|
-
plan.overview = true;
|
|
195
|
-
plan.threads.push(id ?? "team");
|
|
196
|
-
return plan;
|
|
197
|
-
case HUB_SCOPES.inbox:
|
|
198
|
-
plan.inbox = true;
|
|
199
|
-
plan.overview = true;
|
|
200
|
-
return plan;
|
|
201
|
-
case HUB_SCOPES.activity:
|
|
202
|
-
plan.activity = true;
|
|
203
|
-
return plan;
|
|
204
|
-
case HUB_SCOPES.settings:
|
|
205
|
-
plan.settings = true;
|
|
206
|
-
return plan;
|
|
207
|
-
default:
|
|
208
|
-
plan.overview = true;
|
|
209
|
-
plan.activity = true;
|
|
210
|
-
return plan;
|
|
211
|
-
}
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
// src/client/hub-state.ts
|
|
215
|
-
var TOAST_MS = 4e3;
|
|
216
|
-
function mergeThreadMessages(base, fresh) {
|
|
217
|
-
const index = new Map(base.map((m, i) => [m.id, i]));
|
|
218
|
-
const out = [...base];
|
|
219
|
-
for (const message of fresh) {
|
|
220
|
-
const at = index.get(message.id);
|
|
221
|
-
if (at === void 0) {
|
|
222
|
-
index.set(message.id, out.length);
|
|
223
|
-
out.push(message);
|
|
224
|
-
} else out[at] = message;
|
|
225
|
-
}
|
|
226
|
-
return out;
|
|
227
|
-
}
|
|
228
|
-
function emptyState() {
|
|
229
|
-
return {
|
|
230
|
-
overview: null,
|
|
231
|
-
inbox: null,
|
|
232
|
-
activity: null,
|
|
233
|
-
settings: null,
|
|
234
|
-
recentSessions: [],
|
|
235
|
-
bots: {},
|
|
236
|
-
threads: {},
|
|
237
|
-
connectionDown: false,
|
|
238
|
-
downReason: null,
|
|
239
|
-
downMessage: null,
|
|
240
|
-
settingsError: null,
|
|
241
|
-
view: "main",
|
|
242
|
-
selectedThread: "team",
|
|
243
|
-
toasts: []
|
|
244
|
-
};
|
|
245
|
-
}
|
|
246
|
-
function reasonOfError(message) {
|
|
247
|
-
if (message.includes("\u5DF2\u505C\u7528")) return "disabled";
|
|
248
|
-
if (message.includes("\u5C1A\u672A\u5C31\u7EEA")) return "starting";
|
|
249
|
-
if (message.includes("\u542F\u52A8\u5931\u8D25")) return "failed";
|
|
250
|
-
return null;
|
|
251
|
-
}
|
|
252
|
-
function isNetworkError(message) {
|
|
253
|
-
return message.includes("\u7F51\u7EDC\u9519\u8BEF");
|
|
254
|
-
}
|
|
255
|
-
function createHubStore() {
|
|
256
|
-
const store = createStore(emptyState());
|
|
257
|
-
const patch = (partial) => store.update((prev) => ({ ...prev, ...partial }));
|
|
258
|
-
const guard = async (fn) => {
|
|
259
|
-
try {
|
|
260
|
-
patch(await fn());
|
|
261
|
-
if (store.getSnapshot().connectionDown) patch({ connectionDown: false, downReason: null, downMessage: null });
|
|
262
|
-
} catch (error) {
|
|
263
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
264
|
-
console.error("[agent-hub] \u62C9\u53D6\u6570\u636E\u5931\u8D25:", error);
|
|
265
|
-
patch({ connectionDown: true, downReason: reasonOfError(message), downMessage: reasonOfError(message) === "failed" ? message : null });
|
|
266
|
-
}
|
|
267
|
-
};
|
|
268
|
-
const applyInbox = (next, prevItems) => {
|
|
269
|
-
const fresh = prevItems === null ? [] : newUrgentInbox(prevItems, next.items);
|
|
270
|
-
for (const item of fresh) {
|
|
271
|
-
const toast = { id: `toast-${item.id}`, text: `${item.botName ?? "\u4E2D\u5FC3"}\uFF1A${item.title}`, inboxItemId: item.id };
|
|
272
|
-
store.update((prev) => ({ ...prev, toasts: [...prev.toasts.filter((t) => t.id !== toast.id), toast] }));
|
|
273
|
-
try {
|
|
274
|
-
setTimeout(() => {
|
|
275
|
-
try {
|
|
276
|
-
store.update((prev) => ({ ...prev, toasts: prev.toasts.filter((t) => t.id !== toast.id) }));
|
|
277
|
-
} catch {
|
|
278
|
-
}
|
|
279
|
-
}, TOAST_MS);
|
|
280
|
-
} catch {
|
|
281
|
-
}
|
|
282
|
-
}
|
|
283
|
-
return { inbox: next };
|
|
284
|
-
};
|
|
285
|
-
const hub = {
|
|
286
|
-
...store,
|
|
287
|
-
async refreshOverview() {
|
|
288
|
-
await guard(async () => ({ overview: await api.overview() }));
|
|
289
|
-
},
|
|
290
|
-
async refreshInbox() {
|
|
291
|
-
const prevItems = store.getSnapshot().inbox?.items ?? null;
|
|
292
|
-
await guard(async () => applyInbox(await api.inbox(), prevItems));
|
|
293
|
-
},
|
|
294
|
-
async refreshActivity(before) {
|
|
295
|
-
try {
|
|
296
|
-
const next = await api.activity(before ? { before } : void 0);
|
|
297
|
-
if (!before) patch({ activity: next });
|
|
298
|
-
else store.update((prev) => ({
|
|
299
|
-
...prev,
|
|
300
|
-
activity: prev.activity === null ? next : { rows: [...prev.activity.rows, ...next.rows], hasMore: next.hasMore }
|
|
301
|
-
}));
|
|
302
|
-
if (store.getSnapshot().connectionDown) patch({ connectionDown: false, downReason: null, downMessage: null });
|
|
303
|
-
} catch (error) {
|
|
304
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
305
|
-
console.error("[agent-hub] \u62C9\u53D6\u6D3B\u52A8\u6D41\u5931\u8D25:", error);
|
|
306
|
-
patch({ connectionDown: true, downReason: reasonOfError(message), downMessage: reasonOfError(message) === "failed" ? message : null });
|
|
307
|
-
}
|
|
308
|
-
},
|
|
309
|
-
/**
|
|
310
|
-
* 设置拉取(D07 第 2 条):不走会标 connectionDown 的通用 guard——设置读不到
|
|
311
|
-
* 不等于连不上。只有网络错误、「尚未就绪」「已停用」「启动失败」才整页提示;
|
|
312
|
-
* 其余(例如宿主模型目录坏了)把中文原因存进 settingsError,设置页与各模型
|
|
313
|
-
* 下拉处显示原因和「重试」;旧的 settings 保持原值。
|
|
314
|
-
*/
|
|
315
|
-
async refreshSettings() {
|
|
316
|
-
try {
|
|
317
|
-
const settings = await api.settings();
|
|
318
|
-
patch({ settings, settingsError: null });
|
|
319
|
-
if (store.getSnapshot().connectionDown) patch({ connectionDown: false, downReason: null, downMessage: null });
|
|
320
|
-
} catch (error) {
|
|
321
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
322
|
-
console.error("[agent-hub] \u62C9\u53D6\u8BBE\u7F6E\u5931\u8D25:", error);
|
|
323
|
-
const reason = reasonOfError(message);
|
|
324
|
-
if (reason !== null) patch({ connectionDown: true, downReason: reason, downMessage: reason === "failed" ? message : null });
|
|
325
|
-
else if (isNetworkError(message)) patch({ connectionDown: true, downReason: null, downMessage: null });
|
|
326
|
-
else patch({ settingsError: message });
|
|
327
|
-
}
|
|
328
|
-
},
|
|
329
|
-
async refreshRecentSessions() {
|
|
330
|
-
await guard(async () => ({ recentSessions: await api.recentSessions() }));
|
|
331
|
-
},
|
|
332
|
-
/**
|
|
333
|
-
* 机器人详情(D07 第 9 条):先拿到详情,再在 updater 里合并进**最新**状态——
|
|
334
|
-
* 两条 bot 推送挨着到时,后返回的请求不能把另一台刚拉到的新详情改回旧值。
|
|
335
|
-
*/
|
|
336
|
-
async refreshBot(botId) {
|
|
337
|
-
try {
|
|
338
|
-
const view = await api.bot(botId);
|
|
339
|
-
store.update((prev) => ({ ...prev, bots: { ...prev.bots, [botId]: view } }));
|
|
340
|
-
if (store.getSnapshot().connectionDown) patch({ connectionDown: false, downReason: null, downMessage: null });
|
|
341
|
-
} catch (error) {
|
|
342
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
343
|
-
console.error("[agent-hub] \u62C9\u53D6\u673A\u5668\u4EBA\u8BE6\u60C5\u5931\u8D25:", error);
|
|
344
|
-
patch({ connectionDown: true, downReason: reasonOfError(message), downMessage: reasonOfError(message) === "failed" ? message : null });
|
|
345
|
-
}
|
|
346
|
-
},
|
|
347
|
-
/**
|
|
348
|
-
* 线程(D07 第 14/9 条):带 before 是「加载更早」,把旧一页拼在已有列表前面;
|
|
349
|
-
* 不带 before 是最新一页,**按消息 id 合并**进已加载的列表——更新已有消息与
|
|
350
|
-
* 卡片状态、追加新消息,保留主人翻出来的更早历史(只在切换线程时才重置,
|
|
351
|
-
* 见 selectThread)。合并一律在 updater 里做,避免并发覆盖。
|
|
352
|
-
*/
|
|
353
|
-
async refreshThread(threadId, before) {
|
|
354
|
-
try {
|
|
355
|
-
const thread = await api.thread(threadId, before ? { before } : void 0);
|
|
356
|
-
store.update((prev) => {
|
|
357
|
-
const loaded = prev.threads[threadId];
|
|
358
|
-
if (loaded === void 0) return { ...prev, threads: { ...prev.threads, [threadId]: thread } };
|
|
359
|
-
const messages = before ? mergeThreadMessages(thread.messages, loaded.messages) : mergeThreadMessages(loaded.messages, thread.messages);
|
|
360
|
-
const oldest = messages[0]?.id ?? null;
|
|
361
|
-
return { ...prev, threads: { ...prev.threads, [threadId]: { ...thread, messages, hasMore: thread.hasMore || loaded.hasMore, oldestId: oldest } } };
|
|
362
|
-
});
|
|
363
|
-
if (store.getSnapshot().connectionDown) patch({ connectionDown: false, downReason: null, downMessage: null });
|
|
364
|
-
} catch (error) {
|
|
365
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
366
|
-
console.error("[agent-hub] \u62C9\u53D6\u7EBF\u7A0B\u5931\u8D25:", error);
|
|
367
|
-
patch({ connectionDown: true, downReason: reasonOfError(message), downMessage: reasonOfError(message) === "failed" ? message : null });
|
|
368
|
-
}
|
|
369
|
-
},
|
|
370
|
-
async refreshAll() {
|
|
371
|
-
await Promise.all([hub.refreshOverview(), hub.refreshInbox(), hub.refreshActivity()]);
|
|
372
|
-
},
|
|
373
|
-
onChanged(event) {
|
|
374
|
-
void (async () => {
|
|
375
|
-
try {
|
|
376
|
-
const plan = refreshPlan(event.scope, event.botId);
|
|
377
|
-
const jobs = [];
|
|
378
|
-
if (plan.overview) jobs.push(hub.refreshOverview());
|
|
379
|
-
for (const botId of plan.bots) jobs.push(hub.refreshBot(botId));
|
|
380
|
-
for (const threadId of plan.threads) jobs.push(hub.refreshThread(threadId));
|
|
381
|
-
if (plan.inbox) jobs.push(hub.refreshInbox());
|
|
382
|
-
if (plan.activity) jobs.push(hub.refreshActivity());
|
|
383
|
-
if (plan.settings) jobs.push(hub.refreshSettings());
|
|
384
|
-
await Promise.all(jobs);
|
|
385
|
-
} catch (error) {
|
|
386
|
-
console.error("[agent-hub] \u5904\u7406\u53D8\u5316\u4E8B\u4EF6\u51FA\u9519:", error);
|
|
387
|
-
}
|
|
388
|
-
})();
|
|
389
|
-
},
|
|
390
|
-
markDown(reason = null, message = null) {
|
|
391
|
-
patch({ connectionDown: true, downReason: reason, downMessage: reason === "failed" ? message : null });
|
|
392
|
-
},
|
|
393
|
-
onReconnected() {
|
|
394
|
-
if (store.getSnapshot().connectionDown) patch({ connectionDown: false, downReason: null, downMessage: null });
|
|
395
|
-
const selected = store.getSnapshot().selectedThread;
|
|
396
|
-
store.update((prev) => ({ ...prev, bots: {} }));
|
|
397
|
-
void hub.refreshAll();
|
|
398
|
-
void hub.refreshSettings();
|
|
399
|
-
void hub.refreshThread(selected);
|
|
400
|
-
if (selected !== "team") void hub.refreshBot(selected);
|
|
401
|
-
},
|
|
402
|
-
async send(threadId, text) {
|
|
403
|
-
const result = await api.command("sendMessage", { threadId, text });
|
|
404
|
-
if (!result.ok) throw new Error(result.error);
|
|
405
|
-
await hub.refreshThread(threadId);
|
|
406
|
-
},
|
|
407
|
-
command(name, input) {
|
|
408
|
-
return api.command(name, input);
|
|
409
|
-
},
|
|
410
|
-
selectThread(threadId) {
|
|
411
|
-
store.update((prev) => {
|
|
412
|
-
if (prev.selectedThread === threadId) return { ...prev, view: "main" };
|
|
413
|
-
const threads = { ...prev.threads };
|
|
414
|
-
delete threads[threadId];
|
|
415
|
-
return { ...prev, selectedThread: threadId, view: "main", threads };
|
|
416
|
-
});
|
|
417
|
-
void api.command("markThreadRead", { threadId }).then(() => hub.refreshOverview()).catch(() => void 0);
|
|
418
|
-
},
|
|
419
|
-
setView(view) {
|
|
420
|
-
patch({ view });
|
|
421
|
-
},
|
|
422
|
-
dismissToast(id) {
|
|
423
|
-
store.update((prev) => ({ ...prev, toasts: prev.toasts.filter((t) => t.id !== id) }));
|
|
424
|
-
}
|
|
425
|
-
};
|
|
426
|
-
return hub;
|
|
427
|
-
}
|
|
428
|
-
var RECONNECT_BACKOFF_MS = [1e3, 2e3, 5e3, 1e4];
|
|
429
|
-
var DOWN_AFTER_MS = 3e4;
|
|
430
|
-
function connectEvents(hub) {
|
|
431
|
-
let closed = false;
|
|
432
|
-
let source = null;
|
|
433
|
-
let retryTimer = null;
|
|
434
|
-
let attempt = 0;
|
|
435
|
-
let downTimer = null;
|
|
436
|
-
const clearDownTimer = () => {
|
|
437
|
-
if (downTimer !== null) {
|
|
438
|
-
clearTimeout(downTimer);
|
|
439
|
-
downTimer = null;
|
|
440
|
-
}
|
|
441
|
-
};
|
|
442
|
-
const scheduleReconnect = () => {
|
|
443
|
-
if (closed) return;
|
|
444
|
-
const wait = RECONNECT_BACKOFF_MS[Math.min(attempt, RECONNECT_BACKOFF_MS.length - 1)];
|
|
445
|
-
attempt += 1;
|
|
446
|
-
retryTimer = setTimeout(open, wait);
|
|
447
|
-
};
|
|
448
|
-
const open = () => {
|
|
449
|
-
if (closed) return;
|
|
450
|
-
try {
|
|
451
|
-
source = new EventSource("agent-hub/events");
|
|
452
|
-
} catch (error) {
|
|
453
|
-
console.error("[agent-hub] \u5EFA\u7ACB SSE \u8FDE\u63A5\u5931\u8D25:", error);
|
|
454
|
-
scheduleReconnect();
|
|
455
|
-
return;
|
|
456
|
-
}
|
|
457
|
-
source.onopen = () => {
|
|
458
|
-
attempt = 0;
|
|
459
|
-
clearDownTimer();
|
|
460
|
-
hub.onReconnected();
|
|
461
|
-
};
|
|
462
|
-
source.addEventListener("changed", (event) => {
|
|
463
|
-
try {
|
|
464
|
-
hub.onChanged(JSON.parse(event.data));
|
|
465
|
-
} catch (error) {
|
|
466
|
-
console.error("[agent-hub] \u89E3\u6790 changed \u4E8B\u4EF6\u5931\u8D25:", error);
|
|
467
|
-
}
|
|
468
|
-
});
|
|
469
|
-
source.onerror = () => {
|
|
470
|
-
try {
|
|
471
|
-
source?.close();
|
|
472
|
-
} catch {
|
|
473
|
-
}
|
|
474
|
-
source = null;
|
|
475
|
-
if (downTimer === null && !closed) downTimer = setTimeout(() => {
|
|
476
|
-
if (!closed) hub.markDown(null);
|
|
477
|
-
}, DOWN_AFTER_MS);
|
|
478
|
-
scheduleReconnect();
|
|
479
|
-
};
|
|
480
|
-
};
|
|
481
|
-
open();
|
|
482
|
-
return () => {
|
|
483
|
-
closed = true;
|
|
484
|
-
clearDownTimer();
|
|
485
|
-
if (retryTimer !== null) clearTimeout(retryTimer);
|
|
486
|
-
try {
|
|
487
|
-
source?.close();
|
|
488
|
-
} catch {
|
|
489
|
-
}
|
|
490
|
-
};
|
|
491
|
-
}
|
|
492
|
-
|
|
493
|
-
// src/client/pages/HubPage.tsx
|
|
494
|
-
var import_react11 = require("react");
|
|
495
|
-
|
|
496
|
-
// src/client/components/TopBar.tsx
|
|
497
|
-
var import_jsx_runtime = require("react/jsx-runtime");
|
|
498
|
-
function GearIcon() {
|
|
499
|
-
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("svg", { viewBox: "0 0 16 16", width: "14", height: "14", "aria-hidden": "true", className: "ah-gear-icon", children: [
|
|
500
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { fill: "currentColor", d: "M8 5.2A2.8 2.8 0 1 0 8 10.8 2.8 2.8 0 0 0 8 5.2zm0 1.5a1.3 1.3 0 1 1 0 2.6 1.3 1.3 0 0 1 0-2.6z" }),
|
|
501
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { fill: "currentColor", d: "M7.1 1h1.8l.3 1.6c.5.1 1 .3 1.4.6l1.5-.7 1.3 1.3-.7 1.5c.3.4.5.9.6 1.4l1.6.3v1.8l-1.6.3c-.1.5-.3 1-.6 1.4l.7 1.5-1.3 1.3-1.5-.7c-.4.3-.9.5-1.4.6L8.9 15H7.1l-.3-1.6c-.5-.1-1-.3-1.4-.6l-1.5.7-1.3-1.3.7-1.5c-.3-.4-.5-.9-.6-1.4L1.1 8.6V6.8l1.6-.3c.1-.5.3-1 .6-1.4l-.7-1.5 1.3-1.3 1.5.7c.4-.3.9-.5 1.4-.6L7.1 1z", opacity: "0.55" })
|
|
502
|
-
] });
|
|
503
|
-
}
|
|
504
|
-
function TopBar(props) {
|
|
505
|
-
const o = props.overview;
|
|
506
|
-
const back = props.view === "main" ? null : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { type: "button", className: "ah-btn", onClick: props.onBack, children: "\u8FD4\u56DE" });
|
|
507
|
-
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("header", { className: "ah-topbar", children: [
|
|
508
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "ah-topbar-title", children: [
|
|
509
|
-
back,
|
|
510
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("h1", { children: "\u961F\u53CB" }),
|
|
511
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { className: "ah-topbar-now", children: [
|
|
512
|
-
o.nowText,
|
|
513
|
-
o.quietNow ? " \xB7 \u514D\u6253\u6270\u4E2D" : ""
|
|
514
|
-
] })
|
|
515
|
-
] }),
|
|
516
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "ah-topbar-status", children: [
|
|
517
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { className: `ah-dot ah-dot-${o.quota.light === "green" ? "ok" : o.quota.light === "yellow" ? "warn" : "danger"}`, children: [
|
|
518
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "ah-dot-circle", "aria-hidden": "true" }),
|
|
519
|
-
o.quota.lightLabel,
|
|
520
|
-
" \xB7 ",
|
|
521
|
-
o.quota.usedText
|
|
522
|
-
] }),
|
|
523
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { type: "button", className: "ah-btn", onClick: props.onOpenActivity, children: "\u6D3B\u52A8\u6D41" }),
|
|
524
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("button", { type: "button", className: "ah-btn ah-btn-icon", "aria-label": "\u8BBE\u7F6E", title: "\u8BBE\u7F6E", onClick: props.onOpenSettings, children: [
|
|
525
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(GearIcon, {}),
|
|
526
|
-
"\u8BBE\u7F6E"
|
|
527
|
-
] }),
|
|
528
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("button", { type: "button", className: "ah-btn", onClick: props.onOpenInbox, children: [
|
|
529
|
-
"\u6536\u4EF6\u7BB1",
|
|
530
|
-
o.inbox.total > 0 ? `\uFF08${o.inbox.total}\uFF09` : ""
|
|
531
|
-
] }),
|
|
532
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { type: "button", className: "ah-btn ah-btn-primary", onClick: props.onNewBot, children: "\u65B0\u5EFA\u961F\u53CB" })
|
|
533
|
-
] })
|
|
534
|
-
] });
|
|
535
|
-
}
|
|
536
|
-
|
|
537
|
-
// src/client/components/Ui.tsx
|
|
538
|
-
var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
539
|
-
function Avatar(props) {
|
|
540
|
-
const style = {
|
|
541
|
-
width: `${props.size ?? 32}px`,
|
|
542
|
-
height: `${props.size ?? 32}px`,
|
|
543
|
-
background: props.color || "var(--dsw-alias-accent-muted)",
|
|
544
|
-
color: "var(--dsw-alias-text-on-accent, currentColor)"
|
|
545
|
-
};
|
|
546
|
-
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "ah-avatar", style, "aria-hidden": "true", children: props.initials });
|
|
547
|
-
}
|
|
548
|
-
function Skeleton(props) {
|
|
549
|
-
const rows = props.rows ?? 3;
|
|
550
|
-
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "ah-skeleton", "aria-busy": "true", "aria-label": "\u52A0\u8F7D\u4E2D", children: Array.from({ length: rows }, (_, i) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "ah-skeleton-row" }, i)) });
|
|
551
|
-
}
|
|
552
|
-
function RetryBox(props) {
|
|
553
|
-
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "ah-retry", role: "alert", children: [
|
|
554
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { children: props.message }),
|
|
555
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("button", { type: "button", className: "ah-btn", onClick: props.onRetry, children: "\u91CD\u8BD5" })
|
|
556
|
-
] });
|
|
557
|
-
}
|
|
558
|
-
function EmptyHint(props) {
|
|
559
|
-
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "ah-empty", children: props.text });
|
|
560
|
-
}
|
|
561
|
-
function UnreadBadge(props) {
|
|
562
|
-
if (props.count <= 0) return null;
|
|
563
|
-
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "ah-unread", "aria-label": `${props.count} \u6761\u672A\u8BFB`, children: props.count > 99 ? "99+" : props.count });
|
|
564
|
-
}
|
|
565
|
-
|
|
566
|
-
// src/client/components/BotList.tsx
|
|
567
|
-
var import_jsx_runtime3 = require("react/jsx-runtime");
|
|
568
|
-
function BotRow(props) {
|
|
569
|
-
const b = props.bot;
|
|
570
|
-
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("button", { type: "button", className: `ah-bot-row${props.selected ? " ah-selected" : ""}`, onClick: () => props.onSelect(b.id), children: [
|
|
571
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Avatar, { color: b.color, initials: b.initials }),
|
|
572
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("span", { className: "ah-bot-row-main", children: [
|
|
573
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("span", { className: "ah-bot-row-name", children: [
|
|
574
|
-
b.name,
|
|
575
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "ah-bot-row-role", children: b.roleLabel }),
|
|
576
|
-
b.waitingOwner ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "ah-tag ah-tag-wait", children: "\u7B49\u4F60" }) : null
|
|
577
|
-
] }),
|
|
578
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "ah-bot-row-activity", title: b.activityText, children: b.activityText })
|
|
579
|
-
] }),
|
|
580
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(UnreadBadge, { count: b.unread })
|
|
581
|
-
] });
|
|
582
|
-
}
|
|
583
|
-
function BotList(props) {
|
|
584
|
-
const threadOf = (botId) => botId;
|
|
585
|
-
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("nav", { className: "ah-botlist", "aria-label": "\u961F\u53CB\u5217\u8868", children: [
|
|
586
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
|
|
587
|
-
"button",
|
|
588
|
-
{
|
|
589
|
-
type: "button",
|
|
590
|
-
className: `ah-bot-row${props.selected === "team" ? " ah-selected" : ""}`,
|
|
591
|
-
onClick: () => props.onSelect("team"),
|
|
592
|
-
children: [
|
|
593
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "ah-avatar ah-avatar-team", "aria-hidden": "true", children: "\u961F" }),
|
|
594
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("span", { className: "ah-bot-row-main", children: [
|
|
595
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "ah-bot-row-name", children: "\u56E2\u961F" }),
|
|
596
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "ah-bot-row-activity", children: props.overview.team.lastMessageText ?? "\u673A\u5668\u4EBA\u7684\u4EA4\u63A5\u548C\u6C47\u62A5\u4F1A\u6284\u9001\u5230\u8FD9\u91CC" })
|
|
597
|
-
] }),
|
|
598
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(UnreadBadge, { count: props.overview.team.unread })
|
|
599
|
-
]
|
|
600
|
-
}
|
|
601
|
-
),
|
|
602
|
-
props.overview.bots.map((bot) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(BotRow, { bot, selected: props.selected === threadOf(bot.id), onSelect: (id) => props.onSelect(threadOf(id)) }, bot.id)),
|
|
603
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "ah-botlist-footer", children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("button", { type: "button", className: "ah-inbox-entry", onClick: props.onOpenInbox, children: [
|
|
604
|
-
"\u6536\u4EF6\u7BB1",
|
|
605
|
-
props.overview.inbox.total > 0 ? `\uFF08${props.overview.inbox.total}\uFF09` : ""
|
|
606
|
-
] }) })
|
|
607
|
-
] });
|
|
608
|
-
}
|
|
609
|
-
|
|
610
|
-
// src/client/components/ThreadPane.tsx
|
|
611
|
-
var import_react3 = require("react");
|
|
612
|
-
|
|
613
|
-
// src/client/components/Cards.tsx
|
|
614
|
-
var import_react2 = require("react");
|
|
615
|
-
|
|
616
|
-
// src/client/logic/cards.ts
|
|
617
|
-
function isApproveOption(option) {
|
|
618
|
-
return option === "\u6279\u51C6";
|
|
619
|
-
}
|
|
620
|
-
function expiryMeaningOf(card) {
|
|
621
|
-
if (card.expiresText === null || card.expiresText === "") return null;
|
|
622
|
-
const at = card.expiresText.endsWith("\u540E") ? card.expiresText.slice(0, -1) : card.expiresText;
|
|
623
|
-
if (card.type === "question") {
|
|
624
|
-
const fallback = card.defaultOption ?? "\u9ED8\u8BA4\u9009\u9879";
|
|
625
|
-
return `${at}\u524D\u672A\u7B54\u590D\u6309\u9ED8\u8BA4\u300C${fallback}\u300D\u5904\u7406`;
|
|
626
|
-
}
|
|
627
|
-
if (card.type === "approval") return `${at}\u524D\u6709\u6548\uFF0C\u8FC7\u671F\u89C6\u4E3A\u62D2\u7EDD`;
|
|
628
|
-
if (card.type === "proposal") return `${at}\u524D\u672A\u7B54\u590D\u81EA\u52A8\u64A4\u56DE`;
|
|
629
|
-
return card.expiresText;
|
|
630
|
-
}
|
|
631
|
-
function cardResultText(card) {
|
|
632
|
-
if (card.status === "answered") return `\u4F60\u9009\u4E86\uFF1A${card.answer ?? "\u5DF2\u5904\u7406"}`;
|
|
633
|
-
if (card.status === "expired") return `\u5DF2\u8FC7\u671F\uFF0C\u5DF2\u6309\u9ED8\u8BA4\uFF1A${card.answer ?? "\u9ED8\u8BA4\u9009\u9879"}`;
|
|
634
|
-
if (card.status === "withdrawn") return "\u5DF2\u64A4\u56DE";
|
|
635
|
-
if (card.status === "closed") return "\u5DF2\u5173\u95ED";
|
|
636
|
-
return null;
|
|
637
|
-
}
|
|
638
|
-
function cardSubmission(card, option, note) {
|
|
639
|
-
const picked = option.trim();
|
|
640
|
-
if (picked === "") return { error: "\u56DE\u7B54\uFF1A\u4E0D\u80FD\u4E3A\u7A7A" };
|
|
641
|
-
if (card.type === "approval") {
|
|
642
|
-
if (card.approvalId === null) {
|
|
643
|
-
return { name: "answerInbox", input: { id: card.inboxId, answer: picked } };
|
|
644
|
-
}
|
|
645
|
-
return { name: "decideApproval", input: { id: card.approvalId, approve: isApproveOption(picked), ...note !== void 0 && note !== "" ? { note } : {} } };
|
|
646
|
-
}
|
|
647
|
-
return { name: "answerInbox", input: { id: card.inboxId, answer: picked } };
|
|
648
|
-
}
|
|
649
|
-
|
|
650
|
-
// src/client/logic/thread.ts
|
|
651
|
-
function isCenterMessage(m) {
|
|
652
|
-
return m.kind === "system" || m.kind === "digest";
|
|
653
|
-
}
|
|
654
|
-
function sameGroup(a, b) {
|
|
655
|
-
if (isCenterMessage(a) || isCenterMessage(b)) return false;
|
|
656
|
-
return a.from === b.from;
|
|
657
|
-
}
|
|
658
|
-
function groupMessages(messages) {
|
|
659
|
-
const out = [];
|
|
660
|
-
for (let i = 0; i < messages.length; i += 1) {
|
|
661
|
-
const message = messages[i];
|
|
662
|
-
const prev = i > 0 ? messages[i - 1] : null;
|
|
663
|
-
out.push({ message, showHeader: prev === null || !sameGroup(prev, message) });
|
|
664
|
-
}
|
|
665
|
-
return out;
|
|
666
|
-
}
|
|
667
|
-
function shouldStickToBottom(input) {
|
|
668
|
-
if (input.prevLastId === null) return true;
|
|
669
|
-
if (input.lastId === input.prevLastId) return false;
|
|
670
|
-
return input.nearBottom;
|
|
671
|
-
}
|
|
672
|
-
function isSendEnter(event) {
|
|
673
|
-
if (event.key !== "Enter") return false;
|
|
674
|
-
if (event.isComposing === true) return false;
|
|
675
|
-
if (event.keyCode === 229) return false;
|
|
676
|
-
return true;
|
|
677
|
-
}
|
|
678
|
-
function openBotSessionWith(ctx, sessionId) {
|
|
679
|
-
const c = ctx;
|
|
680
|
-
const get = c?.get?.bind(c);
|
|
681
|
-
if (typeof get !== "function") return "unavailable";
|
|
682
|
-
const ws = get("uiWorkspace");
|
|
683
|
-
const sessions = get("sessions");
|
|
684
|
-
const workspaces = get("workspaces");
|
|
685
|
-
if (!ws || !sessions || !workspaces) return "unavailable";
|
|
686
|
-
let list, wsList;
|
|
687
|
-
try {
|
|
688
|
-
list = sessions.list?.getSnapshot?.();
|
|
689
|
-
wsList = workspaces.list?.getSnapshot?.();
|
|
690
|
-
} catch {
|
|
691
|
-
return "unavailable";
|
|
692
|
-
}
|
|
693
|
-
if (wsList?.state === "error") return "unavailable";
|
|
694
|
-
if (list?.phase === "pending" || wsList?.phase === "pending") return "loading";
|
|
695
|
-
if (wsList?.archivedSessionIds?.includes(sessionId)) return "archived";
|
|
696
|
-
if (list?.ids && !list.ids.includes(sessionId)) return "unavailable";
|
|
697
|
-
try {
|
|
698
|
-
ws.openSession(sessionId);
|
|
699
|
-
} catch {
|
|
700
|
-
return "unavailable";
|
|
701
|
-
}
|
|
702
|
-
return "opened";
|
|
703
|
-
}
|
|
704
|
-
var OPEN_SESSION_HINTS = {
|
|
705
|
-
opened: null,
|
|
706
|
-
loading: "\u4F1A\u8BDD\u5217\u8868\u8FD8\u5728\u52A0\u8F7D\uFF0C\u7A0D\u7B49\u4E00\u4E0B\u518D\u8BD5\u3002",
|
|
707
|
-
archived: "\u5B83\u7684\u5DE5\u4F5C\u4F1A\u8BDD\u88AB\u5F52\u6863\u4E86\uFF0C\u5148\u5728\u4F1A\u8BDD\u5217\u8868\u91CC\u6062\u590D\u5B83\u3002",
|
|
708
|
-
unavailable: "\u73B0\u5728\u6253\u4E0D\u5F00\u5B83\u7684\u5DE5\u4F5C\u4F1A\u8BDD\uFF1A\u53EF\u4EE5\u5728\u5DE6\u4FA7\u680F\u7684\u9879\u76EE\u91CC\u627E\u5B83\u7684\u4F1A\u8BDD\u3002"
|
|
709
|
-
};
|
|
710
|
-
|
|
711
|
-
// src/client/components/Cards.tsx
|
|
712
|
-
var import_jsx_runtime4 = require("react/jsx-runtime");
|
|
713
|
-
var CARD_TYPE_LABELS = {
|
|
714
|
-
question: "\u63D0\u95EE",
|
|
715
|
-
approval: "\u5BA1\u6279",
|
|
716
|
-
proposal: "\u63D0\u8BAE",
|
|
717
|
-
alert: "\u544A\u8B66"
|
|
718
|
-
};
|
|
719
|
-
function InboxCard(props) {
|
|
720
|
-
const c = props.card;
|
|
721
|
-
const [picked, setPicked] = (0, import_react2.useState)(null);
|
|
722
|
-
const [error, setError] = (0, import_react2.useState)(null);
|
|
723
|
-
const [freeText, setFreeText] = (0, import_react2.useState)("");
|
|
724
|
-
const [note, setNote] = (0, import_react2.useState)("");
|
|
725
|
-
const resultText = cardResultText(c);
|
|
726
|
-
const answered = resultText !== null;
|
|
727
|
-
const busy = props.busy || picked !== null;
|
|
728
|
-
const pick = (option) => {
|
|
729
|
-
setPicked(option);
|
|
730
|
-
setError(null);
|
|
731
|
-
void props.actions.onPick(c, option, c.type === "approval" ? note : void 0).then((failure) => {
|
|
732
|
-
if (failure !== null) {
|
|
733
|
-
setPicked(null);
|
|
734
|
-
setError(failure);
|
|
735
|
-
}
|
|
736
|
-
}).catch((e) => {
|
|
737
|
-
setPicked(null);
|
|
738
|
-
setError(e instanceof Error ? e.message : String(e));
|
|
739
|
-
});
|
|
740
|
-
};
|
|
741
|
-
return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: `ah-card ah-card-${c.type}${answered ? " ah-card-done" : ""}`, "data-answered": answered ? "true" : "false", children: [
|
|
742
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "ah-card-head", children: [
|
|
743
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "ah-card-type", children: CARD_TYPE_LABELS[c.type] }),
|
|
744
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "ah-card-title", children: c.title })
|
|
745
|
-
] }),
|
|
746
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("p", { className: "ah-card-body", children: c.body }),
|
|
747
|
-
expiryMeaningOf(c) ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("p", { className: "ah-card-expire", children: expiryMeaningOf(c) }) : null,
|
|
748
|
-
answered ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("p", { className: "ah-card-answer", children: resultText }) : /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_jsx_runtime4.Fragment, { children: [
|
|
749
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "ah-card-options", children: c.options.map((option) => /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
|
|
750
|
-
"button",
|
|
751
|
-
{
|
|
752
|
-
type: "button",
|
|
753
|
-
className: c.type === "approval" ? isApproveOption(option) ? "ah-btn ah-btn-primary" : "ah-btn ah-btn-danger" : option === c.defaultOption ? "ah-btn ah-btn-primary" : "ah-btn",
|
|
754
|
-
disabled: busy,
|
|
755
|
-
onClick: () => pick(option),
|
|
756
|
-
children: [
|
|
757
|
-
option,
|
|
758
|
-
option === c.defaultOption && c.type !== "approval" ? "\uFF08\u9ED8\u8BA4\uFF09" : ""
|
|
759
|
-
]
|
|
760
|
-
},
|
|
761
|
-
option
|
|
762
|
-
)) }),
|
|
763
|
-
c.type === "approval" && picked === null ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
764
|
-
"input",
|
|
765
|
-
{
|
|
766
|
-
className: "ah-card-note",
|
|
767
|
-
value: note,
|
|
768
|
-
placeholder: "\u9644\u4E00\u53E5\u8BDD\uFF08\u53EF\u4E0D\u586B\uFF09",
|
|
769
|
-
disabled: busy,
|
|
770
|
-
onChange: (e) => setNote(e.target.value)
|
|
771
|
-
}
|
|
772
|
-
) : null,
|
|
773
|
-
c.type === "question" && picked === null ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "ah-card-freetext", children: [
|
|
774
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
775
|
-
"input",
|
|
776
|
-
{
|
|
777
|
-
value: freeText,
|
|
778
|
-
placeholder: "\u6216\u8005\u5199\u4E00\u53E5\u4F60\u7684\u56DE\u7B54",
|
|
779
|
-
disabled: busy,
|
|
780
|
-
onChange: (e) => setFreeText(e.target.value),
|
|
781
|
-
onKeyDown: (e) => {
|
|
782
|
-
if (isSendEnter(e.nativeEvent) && freeText.trim() !== "") pick(freeText.trim());
|
|
783
|
-
}
|
|
784
|
-
}
|
|
785
|
-
),
|
|
786
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
787
|
-
"button",
|
|
788
|
-
{
|
|
789
|
-
type: "button",
|
|
790
|
-
className: "ah-btn",
|
|
791
|
-
disabled: busy || freeText.trim() === "",
|
|
792
|
-
onClick: () => pick(freeText.trim()),
|
|
793
|
-
children: "\u53D1\u9001"
|
|
794
|
-
}
|
|
795
|
-
)
|
|
796
|
-
] }) : null,
|
|
797
|
-
error ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("p", { className: "ah-card-error", role: "alert", children: error }) : null
|
|
798
|
-
] })
|
|
799
|
-
] });
|
|
800
|
-
}
|
|
801
|
-
|
|
802
|
-
// src/client/logic/lifecycle.ts
|
|
803
|
-
function lifecycleButtons(lifecycle) {
|
|
804
|
-
const buttons = [];
|
|
805
|
-
if (lifecycle === "active" || lifecycle === "probation") buttons.push({ action: "pause", label: "\u6682\u505C" });
|
|
806
|
-
if (lifecycle === "paused") buttons.push({ action: "resume", label: "\u6062\u590D" });
|
|
807
|
-
if (lifecycle === "quarantined") buttons.push({ action: "release_quarantine", label: "\u89E3\u9664\u505C\u7528" });
|
|
808
|
-
if (lifecycle === "probation") buttons.push({ action: "promote", label: "\u63D0\u524D\u8F6C\u6B63" });
|
|
809
|
-
if (lifecycle !== "retired") buttons.push({ action: "retire", label: "\u9000\u5F79" });
|
|
810
|
-
return buttons;
|
|
811
|
-
}
|
|
812
|
-
function pauseResumeAction(lifecycle) {
|
|
813
|
-
if (lifecycle === "active" || lifecycle === "probation") return "pause";
|
|
814
|
-
if (lifecycle === "paused") return "resume";
|
|
815
|
-
return null;
|
|
816
|
-
}
|
|
817
|
-
function lifecycleAllTargets(bots, target) {
|
|
818
|
-
const wanted = target === "paused" ? ["active", "probation"] : ["paused"];
|
|
819
|
-
return bots.filter((bot) => wanted.includes(bot.lifecycle)).map((bot) => bot.id);
|
|
820
|
-
}
|
|
821
|
-
|
|
822
|
-
// src/client/components/ThreadPane.tsx
|
|
823
|
-
var import_jsx_runtime5 = require("react/jsx-runtime");
|
|
824
|
-
function Message(props) {
|
|
825
|
-
const { m, showHeader } = props;
|
|
826
|
-
if (isCenterMessage(m)) {
|
|
827
|
-
return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "ah-msg ah-msg-center", children: [
|
|
828
|
-
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "ah-msg-time", children: m.timeText }),
|
|
829
|
-
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "ah-msg-bubble-center", children: m.text })
|
|
830
|
-
] });
|
|
831
|
-
}
|
|
832
|
-
if (m.card) {
|
|
833
|
-
return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: `ah-msg${m.from === "owner" ? " ah-msg-mine" : ""}`, children: [
|
|
834
|
-
m.from === "owner" || !showHeader ? null : /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Avatar, { color: m.fromColor, initials: m.fromName.slice(0, 1), size: 28 }),
|
|
835
|
-
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "ah-msg-body", children: [
|
|
836
|
-
m.from === "owner" || !showHeader ? null : /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("span", { className: "ah-msg-meta", children: [
|
|
837
|
-
m.fromName,
|
|
838
|
-
" \xB7 ",
|
|
839
|
-
m.timeText
|
|
840
|
-
] }),
|
|
841
|
-
m.from === "owner" && showHeader ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "ah-msg-meta", children: m.timeText }) : null,
|
|
842
|
-
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(InboxCard, { card: m.card, actions: props.actions, busy: props.busyInboxId === m.card.inboxId })
|
|
843
|
-
] })
|
|
844
|
-
] });
|
|
845
|
-
}
|
|
846
|
-
const mine = m.from === "owner";
|
|
847
|
-
return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: `ah-msg${mine ? " ah-msg-mine" : ""}${m.kind === "report" ? " ah-msg-report" : ""}`, children: [
|
|
848
|
-
mine || !showHeader ? null : /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Avatar, { color: m.fromColor, initials: m.fromName.slice(0, 1), size: 28 }),
|
|
849
|
-
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "ah-msg-body", children: [
|
|
850
|
-
mine || !showHeader ? null : /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("span", { className: "ah-msg-meta", children: [
|
|
851
|
-
m.fromName,
|
|
852
|
-
" \xB7 ",
|
|
853
|
-
m.timeText
|
|
854
|
-
] }),
|
|
855
|
-
mine && showHeader ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "ah-msg-meta", children: m.timeText }) : null,
|
|
856
|
-
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "ah-msg-bubble", children: m.text })
|
|
857
|
-
] })
|
|
858
|
-
] });
|
|
859
|
-
}
|
|
860
|
-
var NEAR_BOTTOM_PX = 120;
|
|
861
|
-
var threadDrafts = /* @__PURE__ */ new Map();
|
|
862
|
-
function readDraft(threadId) {
|
|
863
|
-
return threadDrafts.get(threadId) ?? "";
|
|
864
|
-
}
|
|
865
|
-
function saveDraft(threadId, text) {
|
|
866
|
-
if (text === "") threadDrafts.delete(threadId);
|
|
867
|
-
else threadDrafts.set(threadId, text);
|
|
868
|
-
}
|
|
869
|
-
function ThreadPane(props) {
|
|
870
|
-
const [draft, setDraft] = (0, import_react3.useState)(() => readDraft(props.thread?.threadId ?? ""));
|
|
871
|
-
const [sending, setSending] = (0, import_react3.useState)(false);
|
|
872
|
-
const [sendError, setSendError] = (0, import_react3.useState)(null);
|
|
873
|
-
const [confirmInterrupt, setConfirmInterrupt] = (0, import_react3.useState)(false);
|
|
874
|
-
const bottomRef = (0, import_react3.useRef)(null);
|
|
875
|
-
const listRef = (0, import_react3.useRef)(null);
|
|
876
|
-
const prevLastIdRef = (0, import_react3.useRef)(null);
|
|
877
|
-
const prevHeightRef = (0, import_react3.useRef)(null);
|
|
878
|
-
const messageCount = props.thread?.messages.length ?? 0;
|
|
879
|
-
(0, import_react3.useLayoutEffect)(() => {
|
|
880
|
-
const list = listRef.current;
|
|
881
|
-
if (list !== null) prevHeightRef.current = list.scrollHeight;
|
|
882
|
-
}, [messageCount]);
|
|
883
|
-
const lastId = props.thread?.messages.at(-1)?.id ?? null;
|
|
884
|
-
(0, import_react3.useEffect)(() => {
|
|
885
|
-
const list = listRef.current;
|
|
886
|
-
const prevLastId = prevLastIdRef.current;
|
|
887
|
-
prevLastIdRef.current = lastId;
|
|
888
|
-
if (list === null) return;
|
|
889
|
-
if (lastId !== null && prevLastId !== null && lastId === prevLastId) {
|
|
890
|
-
const prevHeight = prevHeightRef.current;
|
|
891
|
-
prevHeightRef.current = list.scrollHeight;
|
|
892
|
-
if (prevHeight !== null && list.scrollHeight > prevHeight) list.scrollTop += list.scrollHeight - prevHeight;
|
|
893
|
-
return;
|
|
894
|
-
}
|
|
895
|
-
const nearBottom = list.scrollHeight - list.scrollTop - list.clientHeight < NEAR_BOTTOM_PX;
|
|
896
|
-
if (shouldStickToBottom({ prevLastId, lastId, nearBottom })) {
|
|
897
|
-
bottomRef.current?.scrollIntoView({ block: "end" });
|
|
898
|
-
}
|
|
899
|
-
}, [lastId, messageCount]);
|
|
900
|
-
const send = async () => {
|
|
901
|
-
const text = draft.trim();
|
|
902
|
-
if (!text || sending) return;
|
|
903
|
-
setSending(true);
|
|
904
|
-
setSendError(null);
|
|
905
|
-
try {
|
|
906
|
-
await props.onSend(text);
|
|
907
|
-
saveDraft(props.thread?.threadId ?? "", "");
|
|
908
|
-
setDraft("");
|
|
909
|
-
} catch (error) {
|
|
910
|
-
setSendError(error instanceof Error ? error.message : String(error) || "\u53D1\u9001\u5931\u8D25\uFF0C\u8BF7\u91CD\u8BD5");
|
|
911
|
-
} finally {
|
|
912
|
-
setSending(false);
|
|
913
|
-
}
|
|
914
|
-
};
|
|
915
|
-
const h = props.header;
|
|
916
|
-
if (props.error) {
|
|
917
|
-
return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "ah-thread", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "ah-retry", role: "alert", children: [
|
|
918
|
-
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { children: props.error }),
|
|
919
|
-
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("button", { type: "button", className: "ah-btn", onClick: props.onRetry, children: "\u91CD\u8BD5" })
|
|
920
|
-
] }) });
|
|
921
|
-
}
|
|
922
|
-
if (!props.thread) {
|
|
923
|
-
return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "ah-thread", children: props.loading ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Skeleton, { rows: 5 }) : /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(EmptyHint, { text: "\u4ECE\u5DE6\u8FB9\u9009\u4E00\u4E2A\u961F\u53CB\u5F00\u59CB\u804A\uFF1B\u5B83\u4EEC\u7684\u6C47\u62A5\u548C\u63D0\u95EE\u90FD\u4F1A\u51FA\u73B0\u5728\u5BF9\u5E94\u7EBF\u7A0B\u91CC\u3002" }) });
|
|
924
|
-
}
|
|
925
|
-
return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("section", { className: "ah-thread", "aria-label": `\u4E0E ${h?.name ?? props.thread.title} \u7684\u5BF9\u8BDD`, children: [
|
|
926
|
-
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("header", { className: "ah-thread-header", children: [
|
|
927
|
-
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "ah-thread-header-main", children: [
|
|
928
|
-
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("h2", { children: [
|
|
929
|
-
h?.name ?? props.thread.title,
|
|
930
|
-
h?.roleLabel ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "ah-bot-row-role", children: h.roleLabel }) : null
|
|
931
|
-
] }),
|
|
932
|
-
h?.activityText ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { className: "ah-thread-status", title: h.activityText, children: h.activityText }) : null,
|
|
933
|
-
h?.nextThinkText ? /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("p", { className: "ah-thread-next", children: [
|
|
934
|
-
"\u4E0B\u6B21\u81EA\u67E5\uFF1A",
|
|
935
|
-
h.nextThinkText
|
|
936
|
-
] }) : null
|
|
937
|
-
] }),
|
|
938
|
-
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "ah-thread-header-actions", children: [
|
|
939
|
-
props.thread.hasMore ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("button", { type: "button", className: "ah-btn ah-btn-ghost", onClick: props.onLoadEarlier, children: "\u52A0\u8F7D\u66F4\u65E9" }) : null,
|
|
940
|
-
h?.thinking ? confirmInterrupt ? /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_jsx_runtime5.Fragment, { children: [
|
|
941
|
-
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("button", { type: "button", className: "ah-btn ah-btn-danger", onClick: () => {
|
|
942
|
-
setConfirmInterrupt(false);
|
|
943
|
-
props.onInterrupt();
|
|
944
|
-
}, children: "\u786E\u8BA4\u6253\u65AD" }),
|
|
945
|
-
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("button", { type: "button", className: "ah-btn ah-btn-ghost", onClick: () => setConfirmInterrupt(false), children: "\u518D\u60F3\u60F3" })
|
|
946
|
-
] }) : /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("button", { type: "button", className: "ah-btn ah-btn-danger", onClick: () => setConfirmInterrupt(true), children: "\u6253\u65AD" }) : null,
|
|
947
|
-
h && h.lifecycle !== null ? /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_jsx_runtime5.Fragment, { children: [
|
|
948
|
-
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("button", { type: "button", className: "ah-btn", onClick: props.onTeach, children: "\u6559\u5B83\u4E00\u62DB" }),
|
|
949
|
-
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("button", { type: "button", className: "ah-btn", onClick: props.onOpenSession, children: "\u6253\u5F00\u5DE5\u4F5C\u4F1A\u8BDD" }),
|
|
950
|
-
props.rightCollapsed && props.onExpandRight ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("button", { type: "button", className: "ah-btn", onClick: props.onExpandRight, children: "\u8BE6\u60C5" }) : null,
|
|
951
|
-
pauseResumeAction(h.lifecycle) !== null ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("button", { type: "button", className: "ah-btn", onClick: props.onTogglePause, children: pauseResumeAction(h.lifecycle) === "pause" ? "\u6682\u505C" : "\u6062\u590D" }) : null
|
|
952
|
-
] }) : null
|
|
953
|
-
] })
|
|
954
|
-
] }),
|
|
955
|
-
props.banner ? /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "ah-thread-banner", role: "status", children: [
|
|
956
|
-
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { children: props.banner }),
|
|
957
|
-
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("button", { type: "button", className: "ah-btn ah-btn-ghost", onClick: props.onBannerDismiss, children: "\u77E5\u9053\u4E86" })
|
|
958
|
-
] }) : null,
|
|
959
|
-
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "ah-thread-messages", ref: listRef, children: [
|
|
960
|
-
groupMessages(props.thread.messages).map((slot) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
961
|
-
Message,
|
|
962
|
-
{
|
|
963
|
-
m: slot.message,
|
|
964
|
-
showHeader: slot.showHeader,
|
|
965
|
-
actions: props.actions,
|
|
966
|
-
busyInboxId: props.busyInboxId
|
|
967
|
-
},
|
|
968
|
-
slot.message.id
|
|
969
|
-
)),
|
|
970
|
-
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { ref: bottomRef })
|
|
971
|
-
] }),
|
|
972
|
-
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("footer", { className: "ah-thread-input", children: [
|
|
973
|
-
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
974
|
-
"input",
|
|
975
|
-
{
|
|
976
|
-
value: draft,
|
|
977
|
-
placeholder: `\u7ED9 ${props.inputPlaceholderName} \u53D1\u6D88\u606F\u2026`,
|
|
978
|
-
disabled: sending,
|
|
979
|
-
onChange: (e) => {
|
|
980
|
-
setDraft(e.target.value);
|
|
981
|
-
saveDraft(props.thread?.threadId ?? "", e.target.value);
|
|
982
|
-
},
|
|
983
|
-
onKeyDown: (e) => {
|
|
984
|
-
if (isSendEnter(e.nativeEvent)) void send();
|
|
985
|
-
}
|
|
986
|
-
}
|
|
987
|
-
),
|
|
988
|
-
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("button", { type: "button", className: "ah-btn ah-btn-primary", disabled: sending || draft.trim() === "", onClick: () => void send(), children: sending ? "\u53D1\u9001\u4E2D\u2026" : "\u53D1\u9001" })
|
|
989
|
-
] }),
|
|
990
|
-
sendError ? /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "ah-thread-senderror", role: "alert", children: [
|
|
991
|
-
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("span", { children: [
|
|
992
|
-
"\u6CA1\u53D1\u51FA\u53BB\uFF1A",
|
|
993
|
-
sendError
|
|
994
|
-
] }),
|
|
995
|
-
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("button", { type: "button", className: "ah-btn", onClick: () => void send(), children: "\u91CD\u8BD5" })
|
|
996
|
-
] }) : null
|
|
997
|
-
] });
|
|
998
|
-
}
|
|
999
|
-
|
|
1000
|
-
// src/client/components/RightPanel.tsx
|
|
1001
|
-
var import_react4 = require("react");
|
|
1002
|
-
|
|
1003
|
-
// src/client/logic/settings.ts
|
|
1004
|
-
function validateClockTime(value, field) {
|
|
1005
|
-
if (!/^([01]\d|2[0-3]):[0-5]\d$/.test(value.trim())) return `${field}\uFF1A\u8981\u5199\u6210 HH:mm\uFF08\u4F8B\u5982 23:00\uFF09`;
|
|
1006
|
-
return null;
|
|
1007
|
-
}
|
|
1008
|
-
function draftFromSettings(settings) {
|
|
1009
|
-
return {
|
|
1010
|
-
quietStart: settings.quietHours.start,
|
|
1011
|
-
quietEnd: settings.quietHours.end,
|
|
1012
|
-
digestAt: settings.digestAt,
|
|
1013
|
-
pushChannel: settings.pushChannel,
|
|
1014
|
-
dailyPushCap: String(settings.dailyPushCap),
|
|
1015
|
-
botDailyPushCap: String(settings.botDailyPushCap),
|
|
1016
|
-
defaultModel: settings.defaultModel === null ? "" : JSON.stringify(settings.defaultModel)
|
|
1017
|
-
};
|
|
1018
|
-
}
|
|
1019
|
-
function validateSettingsDraft(draft) {
|
|
1020
|
-
const start = validateClockTime(draft.quietStart, "\u514D\u6253\u6270\u5F00\u59CB");
|
|
1021
|
-
if (start !== null) return start;
|
|
1022
|
-
const end = validateClockTime(draft.quietEnd, "\u514D\u6253\u6270\u7ED3\u675F");
|
|
1023
|
-
if (end !== null) return end;
|
|
1024
|
-
const digest = validateClockTime(draft.digestAt, "\u65E5\u62A5\u65F6\u95F4");
|
|
1025
|
-
if (digest !== null) return digest;
|
|
1026
|
-
if (!["dsh", "macos", "none"].includes(draft.pushChannel)) return "\u63A8\u9001\u6E20\u9053\uFF1A\u53EA\u80FD\u9009 macOS \u901A\u77E5 / \u4E0D\u63A8 / \u5BBF\u4E3B";
|
|
1027
|
-
const whole = Number(draft.dailyPushCap);
|
|
1028
|
-
if (!Number.isInteger(whole) || whole < 0 || whole > 10) return "\u6BCF\u65E5\u5355\u63A8\u4E0A\u9650\uFF08\u5168\u4F53\uFF09\uFF1A0 \u5230 10 \u7684\u6574\u6570";
|
|
1029
|
-
const perBot = Number(draft.botDailyPushCap);
|
|
1030
|
-
if (!Number.isInteger(perBot) || perBot < 0 || perBot > 3) return "\u6BCF\u65E5\u5355\u63A8\u4E0A\u9650\uFF08\u6BCF\u4E2A\u961F\u53CB\uFF09\uFF1A0 \u5230 3 \u7684\u6574\u6570";
|
|
1031
|
-
if (perBot > whole) return "\u6BCF\u4E2A\u961F\u53CB\u7684\u5355\u63A8\u4E0A\u9650\u4E0D\u80FD\u8D85\u8FC7\u5168\u4F53\u4E0A\u9650";
|
|
1032
|
-
return null;
|
|
1033
|
-
}
|
|
1034
|
-
function modelSelectOptions(current, options) {
|
|
1035
|
-
const list = [...options];
|
|
1036
|
-
if (current == null) return list;
|
|
1037
|
-
const present = list.some((option) => JSON.stringify(option.value) === JSON.stringify(current));
|
|
1038
|
-
if (!present) {
|
|
1039
|
-
list.push({ value: current, label: `${current.provider} / ${current.model}\uFF08\u5DF2\u4E0D\u5728\u5BBF\u4E3B\u76EE\u5F55\uFF0C\u8BF7\u6362\u4E00\u4E2A\uFF09` });
|
|
1040
|
-
}
|
|
1041
|
-
return list;
|
|
1042
|
-
}
|
|
1043
|
-
function buildSettingsPatch(draft, loaded) {
|
|
1044
|
-
const patch = {
|
|
1045
|
-
quietHours: { start: draft.quietStart.trim(), end: draft.quietEnd.trim() },
|
|
1046
|
-
digestAt: draft.digestAt.trim(),
|
|
1047
|
-
pushChannel: draft.pushChannel,
|
|
1048
|
-
dailyPushCap: Number(draft.dailyPushCap),
|
|
1049
|
-
botDailyPushCap: Number(draft.botDailyPushCap)
|
|
1050
|
-
};
|
|
1051
|
-
if (loaded === void 0 || loaded.defaultModel !== draft.defaultModel) {
|
|
1052
|
-
if (draft.defaultModel === "") patch.defaultModel = null;
|
|
1053
|
-
else {
|
|
1054
|
-
try {
|
|
1055
|
-
patch.defaultModel = JSON.parse(draft.defaultModel);
|
|
1056
|
-
} catch {
|
|
1057
|
-
}
|
|
1058
|
-
}
|
|
1059
|
-
}
|
|
1060
|
-
return patch;
|
|
1061
|
-
}
|
|
1062
|
-
|
|
1063
|
-
// src/client/components/RightPanel.tsx
|
|
1064
|
-
var import_jsx_runtime6 = require("react/jsx-runtime");
|
|
1065
|
-
var AUTONOMY_CHOICES = [
|
|
1066
|
-
{ value: "L0", label: "L0 \u53EA\u89C2\u5BDF" },
|
|
1067
|
-
{ value: "L1", label: "L1 \u5EFA\u8BAE" },
|
|
1068
|
-
{ value: "L2", label: "L2 \u6267\u884C" },
|
|
1069
|
-
{ value: "L3", label: "L3 \u6388\u6743\u6267\u884C" }
|
|
1070
|
-
];
|
|
1071
|
-
var PACE_CHOICES = [
|
|
1072
|
-
{ value: "active", label: "\u79EF\u6781" },
|
|
1073
|
-
{ value: "normal", label: "\u9002\u4E2D" },
|
|
1074
|
-
{ value: "quiet", label: "\u5B89\u9759" }
|
|
1075
|
-
];
|
|
1076
|
-
var LIFECYCLE_OK_TEXT = {
|
|
1077
|
-
pause: "\u5DF2\u6682\u505C\uFF08\u671F\u95F4\u7684\u53D8\u5316\u90FD\u5B58\u7740\uFF09",
|
|
1078
|
-
resume: "\u5DF2\u6062\u590D",
|
|
1079
|
-
promote: "\u5DF2\u63D0\u524D\u8F6C\u6B63",
|
|
1080
|
-
release_quarantine: "\u5DF2\u89E3\u9664\u505C\u7528",
|
|
1081
|
-
retire: "\u5DF2\u9000\u5F79\uFF08\u6570\u636E\u4FDD\u7559\uFF09"
|
|
1082
|
-
};
|
|
1083
|
-
function watchStatusInput(botId, w, status) {
|
|
1084
|
-
return { id: w.id, botId, kind: w.kind, target: w.target, why: w.why ?? "", status };
|
|
1085
|
-
}
|
|
1086
|
-
function Section(props) {
|
|
1087
|
-
return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("section", { className: "ah-right-section", children: [
|
|
1088
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("h3", { children: props.title }),
|
|
1089
|
-
props.children
|
|
1090
|
-
] });
|
|
1091
|
-
}
|
|
1092
|
-
function useRunner(run) {
|
|
1093
|
-
const [busy, setBusy] = (0, import_react4.useState)(false);
|
|
1094
|
-
const [message, setMessage] = (0, import_react4.useState)(null);
|
|
1095
|
-
const exec = async (name, input, okText) => {
|
|
1096
|
-
if (busy) return false;
|
|
1097
|
-
setBusy(true);
|
|
1098
|
-
try {
|
|
1099
|
-
const result = await run(name, input);
|
|
1100
|
-
setMessage(result.ok ? okText : result.error);
|
|
1101
|
-
return result.ok;
|
|
1102
|
-
} catch (e) {
|
|
1103
|
-
setMessage(e instanceof Error ? e.message : String(e));
|
|
1104
|
-
return false;
|
|
1105
|
-
} finally {
|
|
1106
|
-
setBusy(false);
|
|
1107
|
-
}
|
|
1108
|
-
};
|
|
1109
|
-
return { busy, message, exec, setMessage };
|
|
1110
|
-
}
|
|
1111
|
-
function RightPanel(props) {
|
|
1112
|
-
const runner = useRunner(props.run);
|
|
1113
|
-
const [editingProfile, setEditingProfile] = (0, import_react4.useState)(false);
|
|
1114
|
-
const [editingAspiration, setEditingAspiration] = (0, import_react4.useState)(null);
|
|
1115
|
-
const [persona, setPersona] = (0, import_react4.useState)("");
|
|
1116
|
-
const [newAspiration, setNewAspiration] = (0, import_react4.useState)("");
|
|
1117
|
-
const [newRule, setNewRule] = (0, import_react4.useState)("");
|
|
1118
|
-
const [newRuleRedLine, setNewRuleRedLine] = (0, import_react4.useState)(false);
|
|
1119
|
-
const [editingRoutine, setEditingRoutine] = (0, import_react4.useState)(null);
|
|
1120
|
-
const [routineSteps, setRoutineSteps] = (0, import_react4.useState)("");
|
|
1121
|
-
const [confirmRetire, setConfirmRetire] = (0, import_react4.useState)(false);
|
|
1122
|
-
const [notice, setNotice] = (0, import_react4.useState)(null);
|
|
1123
|
-
if (!props.bot) {
|
|
1124
|
-
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("aside", { className: "ah-right", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "ah-empty", children: "\u4ECE\u5DE6\u8FB9\u9009\u4E00\u4E2A\u961F\u53CB\uFF0C\u8FD9\u91CC\u663E\u793A\u5B83\u7684\u6863\u6848\u3001\u76EE\u6807\u3001\u8BAE\u7A0B\u548C\u300C\u4E3A\u4EC0\u4E48\u9192 / \u4E3A\u4EC0\u4E48\u6CA1\u9192\u300D\u3002" }) });
|
|
1125
|
-
}
|
|
1126
|
-
const b = props.bot;
|
|
1127
|
-
const doExec = async (name, input, okText) => {
|
|
1128
|
-
const ok = await runner.exec(name, input, okText);
|
|
1129
|
-
if (ok) props.onRefresh();
|
|
1130
|
-
};
|
|
1131
|
-
const openSession = () => {
|
|
1132
|
-
if (!b.profile.sessionId) {
|
|
1133
|
-
setNotice("\u5B83\u8FD8\u6CA1\u6709\u5DE5\u4F5C\u4F1A\u8BDD\u3002");
|
|
1134
|
-
return;
|
|
1135
|
-
}
|
|
1136
|
-
const result = openBotSessionWith(props.clientCtx, b.profile.sessionId);
|
|
1137
|
-
setNotice(OPEN_SESSION_HINTS[result]);
|
|
1138
|
-
};
|
|
1139
|
-
return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("aside", { className: "ah-right", "aria-label": `${b.card.name} \u7684\u8BE6\u60C5`, children: [
|
|
1140
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "ah-right-head", children: [
|
|
1141
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("h2", { children: [
|
|
1142
|
-
b.card.name,
|
|
1143
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "ah-bot-row-role", children: b.card.roleLabel })
|
|
1144
|
-
] }),
|
|
1145
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("button", { type: "button", className: "ah-btn ah-btn-ghost", onClick: props.onCollapse, "aria-label": "\u6536\u8D77\u53F3\u680F", children: "\u6536\u8D77" })
|
|
1146
|
-
] }),
|
|
1147
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "ah-right-scroll", children: [
|
|
1148
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Section, { title: "\u6863\u6848", children: editingProfile ? /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "ah-edit-box", children: [
|
|
1149
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("label", { children: [
|
|
1150
|
-
"\u6027\u683C\u4E0E\u8BF4\u8BDD\u98CE\u683C",
|
|
1151
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("textarea", { rows: 3, value: persona, onChange: (e) => setPersona(e.target.value) })
|
|
1152
|
-
] }),
|
|
1153
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("label", { children: [
|
|
1154
|
-
"\u81EA\u4E3B\u7B49\u7EA7",
|
|
1155
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("select", { value: b.profile.autonomy, onChange: (e) => {
|
|
1156
|
-
void doExec("updateBot", { botId: b.card.id, patch: { autonomy: e.target.value } }, "\u5DF2\u6539\u81EA\u4E3B\u7B49\u7EA7\uFF08\u4E0B\u4E00\u6B21\u601D\u8003\u751F\u6548\uFF09");
|
|
1157
|
-
}, children: AUTONOMY_CHOICES.map((a) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("option", { value: a.value, children: a.label }, a.value)) })
|
|
1158
|
-
] }),
|
|
1159
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("label", { children: [
|
|
1160
|
-
"\u8282\u594F",
|
|
1161
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("select", { value: b.profile.pace, onChange: (e) => {
|
|
1162
|
-
void doExec("updateBot", { botId: b.card.id, patch: { pace: e.target.value } }, "\u5DF2\u6539\u8282\u594F");
|
|
1163
|
-
}, children: PACE_CHOICES.map((p) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("option", { value: p.value, children: p.label }, p.value)) })
|
|
1164
|
-
] }),
|
|
1165
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("label", { children: [
|
|
1166
|
-
"\u6A21\u578B",
|
|
1167
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
|
|
1168
|
-
"select",
|
|
1169
|
-
{
|
|
1170
|
-
value: b.profile.model === null ? "" : JSON.stringify(b.profile.model),
|
|
1171
|
-
onChange: (e) => {
|
|
1172
|
-
void doExec("updateBot", { botId: b.card.id, patch: { model: e.target.value === "" ? null : JSON.parse(e.target.value) } }, "\u5DF2\u6539\u6A21\u578B");
|
|
1173
|
-
},
|
|
1174
|
-
children: [
|
|
1175
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("option", { value: "", children: "\u8DDF\u968F DSH \u9ED8\u8BA4" }),
|
|
1176
|
-
modelSelectOptions(b.profile.model ?? void 0, props.modelOptions.filter((option) => option.value !== null)).map((option, i) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("option", { value: JSON.stringify(option.value) ?? "", children: option.label }, i))
|
|
1177
|
-
]
|
|
1178
|
-
}
|
|
1179
|
-
),
|
|
1180
|
-
props.modelOptionsError ? /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("span", { className: "ah-right-kv ah-card-error", children: [
|
|
1181
|
-
props.modelOptionsError,
|
|
1182
|
-
props.onRetrySettings ? /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
|
|
1183
|
-
"\u3000",
|
|
1184
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("button", { type: "button", className: "ah-btn ah-btn-ghost", onClick: props.onRetrySettings, children: "\u91CD\u8BD5" })
|
|
1185
|
-
] }) : null
|
|
1186
|
-
] }) : null
|
|
1187
|
-
] }),
|
|
1188
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "ah-settings-actions", children: [
|
|
1189
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
1190
|
-
"button",
|
|
1191
|
-
{
|
|
1192
|
-
type: "button",
|
|
1193
|
-
className: "ah-btn ah-btn-primary",
|
|
1194
|
-
disabled: runner.busy,
|
|
1195
|
-
onClick: () => {
|
|
1196
|
-
void doExec("updateBot", { botId: b.card.id, patch: { persona } }, "\u5DF2\u4FDD\u5B58\u6027\u683C");
|
|
1197
|
-
setEditingProfile(false);
|
|
1198
|
-
},
|
|
1199
|
-
children: "\u4FDD\u5B58"
|
|
1200
|
-
}
|
|
1201
|
-
),
|
|
1202
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("button", { type: "button", className: "ah-btn", onClick: () => setEditingProfile(false), children: "\u53D6\u6D88" })
|
|
1203
|
-
] })
|
|
1204
|
-
] }) : /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
|
|
1205
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { children: b.profile.persona === "" ? "\uFF08\u8FD8\u6CA1\u5199\u8FC7\u6027\u683C\u8BF4\u660E\uFF09" : b.profile.persona }),
|
|
1206
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("p", { className: "ah-right-kv", children: [
|
|
1207
|
-
"\u81EA\u4E3B\u7B49\u7EA7\uFF1A",
|
|
1208
|
-
b.profile.autonomyLabel,
|
|
1209
|
-
" \xB7 \u8282\u594F\uFF1A",
|
|
1210
|
-
b.profile.paceLabel,
|
|
1211
|
-
" \xB7 \u6A21\u578B\uFF1A",
|
|
1212
|
-
b.profile.modelText
|
|
1213
|
-
] }),
|
|
1214
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("p", { className: "ah-right-kv", children: [
|
|
1215
|
-
b.profile.createdText,
|
|
1216
|
-
" \u4E0A\u5C97",
|
|
1217
|
-
b.profile.probationText ? ` \xB7 ${b.profile.probationText}` : ""
|
|
1218
|
-
] }),
|
|
1219
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("button", { type: "button", className: "ah-btn ah-btn-ghost", onClick: () => {
|
|
1220
|
-
setPersona(b.profile.persona);
|
|
1221
|
-
setEditingProfile(true);
|
|
1222
|
-
}, children: "\u7F16\u8F91\u6863\u6848" })
|
|
1223
|
-
] }) }),
|
|
1224
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(Section, { title: "\u5FD7\u5411", children: [
|
|
1225
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("ul", { className: "ah-edit-list", children: b.aspirations.map((a) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("li", { children: editingAspiration === a.id ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "ah-edit-ops", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
1226
|
-
"input",
|
|
1227
|
-
{
|
|
1228
|
-
"aria-label": "\u6539\u5FD7\u5411",
|
|
1229
|
-
defaultValue: a.text,
|
|
1230
|
-
autoFocus: true,
|
|
1231
|
-
onBlur: (e) => {
|
|
1232
|
-
const text = e.target.value.trim();
|
|
1233
|
-
if (text !== "" && text !== a.text) void doExec("upsertAspiration", { id: a.id, botId: b.card.id, text }, "\u5DF2\u6539\u5FD7\u5411");
|
|
1234
|
-
setEditingAspiration(null);
|
|
1235
|
-
}
|
|
1236
|
-
}
|
|
1237
|
-
) }) : /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("span", { className: "ah-edit-row", children: [
|
|
1238
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { children: a.text }),
|
|
1239
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("span", { className: "ah-edit-ops", children: [
|
|
1240
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("button", { type: "button", className: "ah-btn ah-btn-ghost", onClick: () => setEditingAspiration(a.id), children: "\u6539" }),
|
|
1241
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("button", { type: "button", className: "ah-btn ah-btn-ghost", onClick: () => void doExec("upsertAspiration", { id: a.id, botId: b.card.id, text: a.text, status: "archived" }, "\u5DF2\u6536\u8D77\u5FD7\u5411"), children: "\u6536\u8D77" })
|
|
1242
|
-
] })
|
|
1243
|
-
] }) }, a.id)) }),
|
|
1244
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "ah-edit-add", children: [
|
|
1245
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
1246
|
-
"input",
|
|
1247
|
-
{
|
|
1248
|
-
value: newAspiration,
|
|
1249
|
-
placeholder: "\u52A0\u4E00\u6761\u5FD7\u5411",
|
|
1250
|
-
onChange: (e) => setNewAspiration(e.target.value),
|
|
1251
|
-
onKeyDown: (e) => {
|
|
1252
|
-
if (e.key === "Enter" && newAspiration.trim() !== "") {
|
|
1253
|
-
void doExec("upsertAspiration", { botId: b.card.id, text: newAspiration.trim() }, "\u5DF2\u52A0\u5FD7\u5411");
|
|
1254
|
-
setNewAspiration("");
|
|
1255
|
-
}
|
|
1256
|
-
}
|
|
1257
|
-
}
|
|
1258
|
-
),
|
|
1259
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
1260
|
-
"button",
|
|
1261
|
-
{
|
|
1262
|
-
type: "button",
|
|
1263
|
-
className: "ah-btn",
|
|
1264
|
-
disabled: newAspiration.trim() === "" || runner.busy,
|
|
1265
|
-
onClick: () => {
|
|
1266
|
-
void doExec("upsertAspiration", { botId: b.card.id, text: newAspiration.trim() }, "\u5DF2\u52A0\u5FD7\u5411");
|
|
1267
|
-
setNewAspiration("");
|
|
1268
|
-
},
|
|
1269
|
-
children: "\u52A0\u4E00\u6761"
|
|
1270
|
-
}
|
|
1271
|
-
)
|
|
1272
|
-
] })
|
|
1273
|
-
] }),
|
|
1274
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Section, { title: "\u76EE\u6807", children: b.goals.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { className: "ah-empty", children: "\u8FD8\u6CA1\u6709\u76EE\u6807\u3002\u53EF\u4EE5\u5728\u5FD7\u5411\u4E0B\u5EFA\u4E00\u4E2A\u3002" }) : /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("ul", { className: "ah-edit-list", children: b.goals.map((g) => /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("li", { children: [
|
|
1275
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("span", { children: [
|
|
1276
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("strong", { children: g.title }),
|
|
1277
|
-
"\uFF08",
|
|
1278
|
-
g.periodText,
|
|
1279
|
-
"\uFF09",
|
|
1280
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("br", {}),
|
|
1281
|
-
g.statusLabel,
|
|
1282
|
-
g.lastProgressText ? ` \xB7 ${g.lastProgressText}` : ""
|
|
1283
|
-
] }),
|
|
1284
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "ah-edit-ops", children: g.status === "done_pending_check" ? /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
|
|
1285
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("button", { type: "button", className: "ah-btn ah-btn-primary", disabled: runner.busy, onClick: () => void doExec("closeGoal", { id: g.id, outcome: true }, "\u5DF2\u9A8C\u6536\u901A\u8FC7"), children: "\u9A8C\u6536\u901A\u8FC7" }),
|
|
1286
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("button", { type: "button", className: "ah-btn", disabled: runner.busy, onClick: () => void doExec("closeGoal", { id: g.id, outcome: false }, "\u5DF2\u8BB0\u9A8C\u6536\u6CA1\u8FC7"), children: "\u6CA1\u8FC7" })
|
|
1287
|
-
] }) : g.status === "active" ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("button", { type: "button", className: "ah-btn ah-btn-ghost", disabled: runner.busy, onClick: () => void doExec("closeGoal", { id: g.id, outcome: "abandoned" }, "\u5DF2\u653E\u5F03\u76EE\u6807"), children: "\u653E\u5F03" }) : null })
|
|
1288
|
-
] }, g.id)) }) }),
|
|
1289
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Section, { title: "\u5173\u6CE8\u9879", children: b.watches.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { className: "ah-empty", children: "\u5B83\u8FD8\u6CA1\u6709\u5728\u76EF\u7684\u4E1C\u897F\u3002" }) : /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("ul", { className: "ah-edit-list", children: b.watches.map((w) => /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("li", { children: [
|
|
1290
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("span", { children: [
|
|
1291
|
-
w.kindLabel,
|
|
1292
|
-
"\uFF1A",
|
|
1293
|
-
w.target,
|
|
1294
|
-
w.status === "proposed" ? "\uFF08\u5B83\u63D0\u8BAE\u7684\uFF0C\u7B49\u4F60\u70B9\u5934\uFF09" : w.status === "paused" ? "\uFF08\u5DF2\u6682\u505C\uFF09" : ""
|
|
1295
|
-
] }),
|
|
1296
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "ah-edit-ops", children: w.status === "proposed" ? /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
|
|
1297
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("button", { type: "button", className: "ah-btn ah-btn-primary", disabled: runner.busy, onClick: () => void doExec("decideWatchProposal", { id: w.id, approve: true }, "\u5DF2\u540C\u610F\u5B83\u7684\u63D0\u8BAE"), children: "\u540C\u610F" }),
|
|
1298
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("button", { type: "button", className: "ah-btn", disabled: runner.busy, onClick: () => void doExec("decideWatchProposal", { id: w.id, approve: false }, "\u5DF2\u62D2\u7EDD\u5B83\u7684\u63D0\u8BAE"), children: "\u4E0D\u8981" })
|
|
1299
|
-
] }) : w.status === "active" || w.status === "paused" ? (
|
|
1300
|
-
/* 暂停/恢复要拼完整入参(D07 第 10 条):kind/target/why 来自该行已有字段,
|
|
1301
|
-
否则 core 会报「关注项无效」。 */
|
|
1302
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
1303
|
-
"button",
|
|
1304
|
-
{
|
|
1305
|
-
type: "button",
|
|
1306
|
-
className: "ah-btn ah-btn-ghost",
|
|
1307
|
-
disabled: runner.busy,
|
|
1308
|
-
onClick: () => void doExec("upsertWatch", watchStatusInput(b.card.id, w, w.status === "active" ? "paused" : "active"), w.status === "active" ? "\u5DF2\u6682\u505C" : "\u5DF2\u6062\u590D"),
|
|
1309
|
-
children: w.status === "active" ? "\u6682\u505C" : "\u6062\u590D"
|
|
1310
|
-
}
|
|
1311
|
-
)
|
|
1312
|
-
) : null })
|
|
1313
|
-
] }, w.id)) }) }),
|
|
1314
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(Section, { title: "\u89C4\u77E9", children: [
|
|
1315
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("ul", { className: "ah-edit-list", children: b.rules.map((r) => /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("li", { children: [
|
|
1316
|
-
r.redLine ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "ah-tag ah-tag-wait", children: "\u7EA2\u7EBF" }) : null,
|
|
1317
|
-
r.text
|
|
1318
|
-
] }, r.id)) }),
|
|
1319
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "ah-edit-add", children: [
|
|
1320
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("input", { value: newRule, placeholder: "\u52A0\u4E00\u6761\u89C4\u77E9", onChange: (e) => setNewRule(e.target.value) }),
|
|
1321
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("label", { className: "ah-right-kv", children: [
|
|
1322
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("input", { type: "checkbox", checked: newRuleRedLine, onChange: (e) => setNewRuleRedLine(e.target.checked) }),
|
|
1323
|
-
"\u7EA2\u7EBF"
|
|
1324
|
-
] }),
|
|
1325
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
1326
|
-
"button",
|
|
1327
|
-
{
|
|
1328
|
-
type: "button",
|
|
1329
|
-
className: "ah-btn",
|
|
1330
|
-
disabled: newRule.trim() === "" || runner.busy,
|
|
1331
|
-
onClick: () => {
|
|
1332
|
-
void doExec("upsertRule", { scope: b.card.id, text: newRule.trim(), redLine: newRuleRedLine }, "\u5DF2\u52A0\u89C4\u77E9");
|
|
1333
|
-
setNewRule("");
|
|
1334
|
-
setNewRuleRedLine(false);
|
|
1335
|
-
},
|
|
1336
|
-
children: "\u52A0\u4E00\u6761"
|
|
1337
|
-
}
|
|
1338
|
-
)
|
|
1339
|
-
] })
|
|
1340
|
-
] }),
|
|
1341
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Section, { title: "\u4F1A\u7684\u5957\u8DEF", children: b.routines.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { className: "ah-empty", children: "\u8FD8\u6CA1\u5B66\u4F1A\u5957\u8DEF\u3002\u53EF\u4EE5\u300C\u6559\u5B83\u4E00\u62DB\u300D\u3002" }) : /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("ul", { className: "ah-edit-list", children: b.routines.map((r) => /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("li", { children: [
|
|
1342
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("span", { children: [
|
|
1343
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("strong", { children: r.name }),
|
|
1344
|
-
"\uFF1A",
|
|
1345
|
-
r.whenToUse,
|
|
1346
|
-
"\uFF08\u7528\u8FC7 ",
|
|
1347
|
-
r.runs,
|
|
1348
|
-
" \u6B21\uFF09"
|
|
1349
|
-
] }),
|
|
1350
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "ah-edit-ops", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("button", { type: "button", className: "ah-btn ah-btn-ghost", onClick: () => {
|
|
1351
|
-
setEditingRoutine(editingRoutine === r.id ? null : r.id);
|
|
1352
|
-
setRoutineSteps(r.steps.join("\n"));
|
|
1353
|
-
}, children: editingRoutine === r.id ? "\u6536\u8D77" : "\u67E5\u770B / \u7F16\u8F91" }) }),
|
|
1354
|
-
editingRoutine === r.id ? /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "ah-edit-box", children: [
|
|
1355
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("ol", { className: "ah-routine-steps", children: r.steps.map((step, i) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("li", { children: step }, i)) }),
|
|
1356
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("textarea", { rows: 4, value: routineSteps, onChange: (e) => setRoutineSteps(e.target.value), placeholder: "\u4E00\u884C\u4E00\u6B65" }),
|
|
1357
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
1358
|
-
"button",
|
|
1359
|
-
{
|
|
1360
|
-
type: "button",
|
|
1361
|
-
className: "ah-btn ah-btn-primary",
|
|
1362
|
-
disabled: runner.busy,
|
|
1363
|
-
onClick: () => {
|
|
1364
|
-
void doExec("editRoutine", { id: r.id, patch: { steps: routineSteps.split(/\r?\n/).map((s) => s.trim()).filter((s) => s !== "") } }, "\u5957\u8DEF\u5DF2\u66F4\u65B0");
|
|
1365
|
-
setEditingRoutine(null);
|
|
1366
|
-
},
|
|
1367
|
-
children: "\u4FDD\u5B58\u6B65\u9AA4"
|
|
1368
|
-
}
|
|
1369
|
-
)
|
|
1370
|
-
] }) : null
|
|
1371
|
-
] }, r.id)) }) }),
|
|
1372
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Section, { title: "\u4E3A\u4EC0\u4E48\u9192 / \u4E3A\u4EC0\u4E48\u6CA1\u9192\uFF08\u6700\u8FD1 8 \u6761\uFF09", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("ul", { className: "ah-appraisals", children: [...b.appraisals].slice(0, 8).map((a) => /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("li", { children: [
|
|
1373
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: `ah-appraisal-decision${a.decision === "woke" ? " ah-appraisal-woke" : ""}`, children: a.decisionLabel }),
|
|
1374
|
-
a.text,
|
|
1375
|
-
"\uFF08",
|
|
1376
|
-
a.timeText,
|
|
1377
|
-
"\uFF09"
|
|
1378
|
-
] }, a.id)) }) })
|
|
1379
|
-
] }),
|
|
1380
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "ah-right-actions", children: [
|
|
1381
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("button", { type: "button", className: "ah-btn", onClick: props.onTeach, children: "\u6559\u5B83\u4E00\u62DB" }),
|
|
1382
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("button", { type: "button", className: "ah-btn", onClick: openSession, children: "\u6253\u5F00\u5DE5\u4F5C\u4F1A\u8BDD" }),
|
|
1383
|
-
lifecycleButtons(b.card.lifecycle).filter((button) => button.action !== "retire").map((button) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
1384
|
-
"button",
|
|
1385
|
-
{
|
|
1386
|
-
type: "button",
|
|
1387
|
-
className: "ah-btn",
|
|
1388
|
-
disabled: runner.busy,
|
|
1389
|
-
onClick: () => void doExec("lifecycleAction", { botId: b.card.id, action: button.action }, LIFECYCLE_OK_TEXT[button.action]),
|
|
1390
|
-
children: button.label
|
|
1391
|
-
},
|
|
1392
|
-
button.action
|
|
1393
|
-
)),
|
|
1394
|
-
b.card.lifecycle !== "retired" ? confirmRetire ? /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
|
|
1395
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
1396
|
-
"button",
|
|
1397
|
-
{
|
|
1398
|
-
type: "button",
|
|
1399
|
-
className: "ah-btn ah-btn-danger",
|
|
1400
|
-
disabled: runner.busy,
|
|
1401
|
-
onClick: () => {
|
|
1402
|
-
void doExec("lifecycleAction", { botId: b.card.id, action: "retire" }, "\u5DF2\u9000\u5F79\uFF08\u6570\u636E\u4FDD\u7559\uFF09");
|
|
1403
|
-
setConfirmRetire(false);
|
|
1404
|
-
},
|
|
1405
|
-
children: "\u786E\u8BA4\u9000\u5F79"
|
|
1406
|
-
}
|
|
1407
|
-
),
|
|
1408
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("button", { type: "button", className: "ah-btn ah-btn-ghost", onClick: () => setConfirmRetire(false), children: "\u518D\u60F3\u60F3" })
|
|
1409
|
-
] }) : /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("button", { type: "button", className: "ah-btn ah-btn-ghost", onClick: () => setConfirmRetire(true), children: "\u9000\u5F79" }) : null,
|
|
1410
|
-
notice ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { className: "ah-right-notice", children: notice }) : null,
|
|
1411
|
-
runner.message ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { className: "ah-right-notice", children: runner.message }) : null
|
|
1412
|
-
] })
|
|
1413
|
-
] });
|
|
1414
|
-
}
|
|
1415
|
-
|
|
1416
|
-
// src/client/components/InboxPane.tsx
|
|
1417
|
-
var import_react5 = require("react");
|
|
1418
|
-
var import_jsx_runtime7 = require("react/jsx-runtime");
|
|
1419
|
-
function itemToCard(item) {
|
|
1420
|
-
return {
|
|
1421
|
-
inboxId: item.id,
|
|
1422
|
-
approvalId: item.approvalId,
|
|
1423
|
-
type: item.type,
|
|
1424
|
-
status: "open",
|
|
1425
|
-
title: item.title,
|
|
1426
|
-
body: item.body,
|
|
1427
|
-
options: item.options,
|
|
1428
|
-
defaultOption: item.defaultOption,
|
|
1429
|
-
answer: null,
|
|
1430
|
-
expiresText: item.expiresText
|
|
1431
|
-
};
|
|
1432
|
-
}
|
|
1433
|
-
function InboxPane(props) {
|
|
1434
|
-
const [, force] = (0, import_react5.useState)(0);
|
|
1435
|
-
if (props.error) {
|
|
1436
|
-
return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "ah-inbox", children: /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "ah-retry", role: "alert", children: [
|
|
1437
|
-
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { children: props.error }),
|
|
1438
|
-
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("button", { type: "button", className: "ah-btn", onClick: props.onRetry, children: "\u91CD\u8BD5" })
|
|
1439
|
-
] }) });
|
|
1440
|
-
}
|
|
1441
|
-
if (!props.inbox) return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "ah-inbox", children: props.loading ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Skeleton, { rows: 3 }) : /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(EmptyHint, { text: "\u6536\u4EF6\u7BB1\u8FD8\u6CA1\u6253\u5F00\u3002\u961F\u53CB\u9700\u8981\u4F60\u62CD\u677F\u7684\u4E8B\u4F1A\u51FA\u73B0\u5728\u8FD9\u91CC\u3002" }) });
|
|
1442
|
-
const groups = groupInbox(props.inbox.items);
|
|
1443
|
-
if (groups.length === 0) {
|
|
1444
|
-
return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "ah-inbox", children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(EmptyHint, { text: "\u6CA1\u6709\u8981\u4F60\u5904\u7406\u7684\u4E8B\u3002\u961F\u53CB\u4EEC\u4F1A\u5728\u9700\u8981\u4F60\u62CD\u677F\u65F6\u51FA\u73B0\u5728\u8FD9\u91CC\u3002" }) });
|
|
1445
|
-
}
|
|
1446
|
-
return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("section", { className: "ah-inbox", "aria-label": "\u6536\u4EF6\u7BB1", "data-testid": "ah-inbox", children: groups.map((group) => /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: `ah-inbox-group ah-inbox-group-${group.priority.toLowerCase()}`, children: [
|
|
1447
|
-
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("h3", { children: [
|
|
1448
|
-
group.label,
|
|
1449
|
-
"\uFF08",
|
|
1450
|
-
group.items.length,
|
|
1451
|
-
"\uFF09"
|
|
1452
|
-
] }),
|
|
1453
|
-
group.items.map((item) => /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("article", { className: `ah-inbox-row ah-inbox-${item.priority.toLowerCase()}`, children: [
|
|
1454
|
-
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("header", { children: [
|
|
1455
|
-
item.botName ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Avatar, { color: item.botColor, initials: item.botName.slice(0, 1), size: 24 }) : null,
|
|
1456
|
-
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "ah-inbox-bot", children: item.botName ?? "\u4E2D\u5FC3" }),
|
|
1457
|
-
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("span", { className: "ah-inbox-time", children: [
|
|
1458
|
-
item.createdText,
|
|
1459
|
-
expiryMeaningOf(itemToCard(item)) ? ` \xB7 ${expiryMeaningOf(itemToCard(item))}` : ""
|
|
1460
|
-
] })
|
|
1461
|
-
] }),
|
|
1462
|
-
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(InboxCard, { card: itemToCard(item), actions: {
|
|
1463
|
-
...props.actions,
|
|
1464
|
-
// 本卡处理中禁用;处理完由 SSE 刷新把项移出列表。这里 force 触发本行重渲染。
|
|
1465
|
-
onPick: async (card, option, note) => {
|
|
1466
|
-
force((n) => n + 1);
|
|
1467
|
-
return await props.actions.onPick(card, option, note);
|
|
1468
|
-
}
|
|
1469
|
-
}, busy: props.busyId === item.id })
|
|
1470
|
-
] }, item.id))
|
|
1471
|
-
] }, group.priority)) });
|
|
1472
|
-
}
|
|
1473
|
-
|
|
1474
|
-
// src/client/components/ActivityPane.tsx
|
|
1475
|
-
var import_react6 = require("react");
|
|
1476
|
-
var import_jsx_runtime8 = require("react/jsx-runtime");
|
|
1477
|
-
function RowView(props) {
|
|
1478
|
-
const r = props.row;
|
|
1479
|
-
return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("li", { className: `ah-activity-row ah-activity-${r.kind}`, children: [
|
|
1480
|
-
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "ah-activity-time", children: r.timeText }),
|
|
1481
|
-
r.botName ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Avatar, { color: r.botColor, initials: r.botName.slice(0, 1), size: 22 }) : /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "ah-avatar ah-avatar-team", "aria-hidden": "true", children: "\u4E2D" }),
|
|
1482
|
-
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("span", { className: "ah-activity-text", children: [
|
|
1483
|
-
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "ah-activity-kind", children: ACTIVITY_KIND_LABELS[r.kind] }),
|
|
1484
|
-
r.botName ? `${r.botName}\uFF1A` : "",
|
|
1485
|
-
r.text
|
|
1486
|
-
] })
|
|
1487
|
-
] });
|
|
1488
|
-
}
|
|
1489
|
-
function ActivityPane(props) {
|
|
1490
|
-
const [botId, setBotId] = (0, import_react6.useState)("");
|
|
1491
|
-
const [kind, setKind] = (0, import_react6.useState)("");
|
|
1492
|
-
if (!props.activity) return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "ah-activity", children: props.loading ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Skeleton, { rows: 5 }) : /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(EmptyHint, { text: "\u6D3B\u52A8\u6D41\u8FD8\u6CA1\u6253\u5F00\u3002\u5237\u65B0\u8BD5\u8BD5\uFF0C\u6216\u8005\u7B49\u961F\u53CB\u4EEC\u52A8\u8D77\u6765\u3002" }) });
|
|
1493
|
-
const rows = filterActivity(props.activity.rows, { botId: botId || null, kind: kind || null });
|
|
1494
|
-
return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("section", { className: "ah-activity", "aria-label": "\u6D3B\u52A8\u6D41", children: [
|
|
1495
|
-
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "ah-activity-filters", children: [
|
|
1496
|
-
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("label", { children: [
|
|
1497
|
-
"\u961F\u53CB",
|
|
1498
|
-
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("select", { value: botId, onChange: (e) => setBotId(e.target.value), children: [
|
|
1499
|
-
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("option", { value: "", children: "\u5168\u90E8" }),
|
|
1500
|
-
props.bots.map((b) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("option", { value: b.id, children: b.name }, b.id))
|
|
1501
|
-
] })
|
|
1502
|
-
] }),
|
|
1503
|
-
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("label", { children: [
|
|
1504
|
-
"\u7C7B\u578B",
|
|
1505
|
-
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("select", { value: kind, onChange: (e) => setKind(e.target.value), children: [
|
|
1506
|
-
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("option", { value: "", children: "\u5168\u90E8" }),
|
|
1507
|
-
Object.keys(ACTIVITY_KIND_LABELS).map((k) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("option", { value: k, children: ACTIVITY_KIND_LABELS[k] }, k))
|
|
1508
|
-
] })
|
|
1509
|
-
] }),
|
|
1510
|
-
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("button", { type: "button", className: "ah-btn", onClick: props.onRetry, children: "\u5237\u65B0" })
|
|
1511
|
-
] }),
|
|
1512
|
-
rows.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(EmptyHint, { text: "\u8FD8\u6CA1\u6709\u52A8\u9759\u3002\u4E0B\u4E00\u6B21\u81EA\u67E5\u7684\u65F6\u5019\uFF0C\u8FD9\u91CC\u4F1A\u51FA\u73B0\u5B83\u4EEC\u7684\u5224\u65AD\u548C\u4EA4\u8D26\u3002" }) : /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("ol", { className: "ah-activity-list", children: rows.map((row) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(RowView, { row }, row.id)) }),
|
|
1513
|
-
props.activity.hasMore ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "ah-activity-more", children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("button", { type: "button", className: "ah-btn", onClick: props.onLoadMore, children: "\u52A0\u8F7D\u66F4\u591A" }) }) : null
|
|
1514
|
-
] });
|
|
1515
|
-
}
|
|
1516
|
-
|
|
1517
|
-
// src/client/components/SettingsPane.tsx
|
|
1518
|
-
var import_react7 = require("react");
|
|
1519
|
-
var import_jsx_runtime9 = require("react/jsx-runtime");
|
|
1520
|
-
var PUSH_CHANNEL_LABELS = { macos: "macOS \u901A\u77E5", dsh: "\u5BBF\u4E3B\u901A\u77E5", none: "\u4E0D\u63A8" };
|
|
1521
|
-
function parseModel(serialized) {
|
|
1522
|
-
if (serialized === "") return void 0;
|
|
1523
|
-
try {
|
|
1524
|
-
return JSON.parse(serialized);
|
|
1525
|
-
} catch {
|
|
1526
|
-
return void 0;
|
|
1527
|
-
}
|
|
1528
|
-
}
|
|
1529
|
-
function SettingsPane(props) {
|
|
1530
|
-
const [draft, setDraft] = (0, import_react7.useState)(null);
|
|
1531
|
-
const [loaded, setLoaded] = (0, import_react7.useState)(null);
|
|
1532
|
-
const [error, setError] = (0, import_react7.useState)(null);
|
|
1533
|
-
const [saving, setSaving] = (0, import_react7.useState)(false);
|
|
1534
|
-
const [lifecycleBusy, setLifecycleBusy] = (0, import_react7.useState)(false);
|
|
1535
|
-
const [lifecycleNote, setLifecycleNote] = (0, import_react7.useState)(null);
|
|
1536
|
-
(0, import_react7.useEffect)(() => {
|
|
1537
|
-
if (props.settings) {
|
|
1538
|
-
const fresh = draftFromSettings(props.settings.settings);
|
|
1539
|
-
setLoaded((prev) => prev ?? fresh);
|
|
1540
|
-
setDraft((prev) => prev ?? fresh);
|
|
1541
|
-
}
|
|
1542
|
-
}, [props.settings]);
|
|
1543
|
-
if (!props.settings || !draft) {
|
|
1544
|
-
return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "ah-settings", children: props.loading ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Skeleton, { rows: 4 }) : /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(RetryBox, { message: `\u8BBE\u7F6E\u6CA1\u52A0\u8F7D\u51FA\u6765${props.loadError ? `\uFF1A${props.loadError}` : "\u3002"}`, onRetry: props.onRetry }) });
|
|
1545
|
-
}
|
|
1546
|
-
const set = (partial) => {
|
|
1547
|
-
setDraft({ ...draft, ...partial });
|
|
1548
|
-
setError(null);
|
|
1549
|
-
};
|
|
1550
|
-
const validation = validateSettingsDraft(draft);
|
|
1551
|
-
const save = async () => {
|
|
1552
|
-
if (validation !== null || saving) return;
|
|
1553
|
-
setSaving(true);
|
|
1554
|
-
try {
|
|
1555
|
-
const message = await props.onSave(buildSettingsPatch(draft, loaded ?? void 0));
|
|
1556
|
-
setError(message);
|
|
1557
|
-
} catch (e) {
|
|
1558
|
-
setError(e instanceof Error ? e.message : String(e));
|
|
1559
|
-
} finally {
|
|
1560
|
-
setSaving(false);
|
|
1561
|
-
}
|
|
1562
|
-
};
|
|
1563
|
-
const lifecycle = async (work, label) => {
|
|
1564
|
-
if (lifecycleBusy) return;
|
|
1565
|
-
setLifecycleBusy(true);
|
|
1566
|
-
setLifecycleNote(`${label}\u4E2D\u2026`);
|
|
1567
|
-
try {
|
|
1568
|
-
const message = await work();
|
|
1569
|
-
setLifecycleNote(message ?? `\u5DF2${label}`);
|
|
1570
|
-
} catch (e) {
|
|
1571
|
-
setLifecycleNote(e instanceof Error ? e.message : String(e));
|
|
1572
|
-
} finally {
|
|
1573
|
-
setLifecycleBusy(false);
|
|
1574
|
-
}
|
|
1575
|
-
};
|
|
1576
|
-
const o = props.overview;
|
|
1577
|
-
return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("section", { className: "ah-settings", "aria-label": "\u8BBE\u7F6E", children: [
|
|
1578
|
-
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("h3", { children: "\u6253\u6270\u4E0E\u65E5\u62A5" }),
|
|
1579
|
-
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "ah-settings-grid", children: [
|
|
1580
|
-
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("label", { children: [
|
|
1581
|
-
"\u514D\u6253\u6270\u5F00\u59CB",
|
|
1582
|
-
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("input", { type: "time", step: 300, value: draft.quietStart, onChange: (e) => set({ quietStart: e.target.value }) })
|
|
1583
|
-
] }),
|
|
1584
|
-
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("label", { children: [
|
|
1585
|
-
"\u514D\u6253\u6270\u7ED3\u675F",
|
|
1586
|
-
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("input", { type: "time", step: 300, value: draft.quietEnd, onChange: (e) => set({ quietEnd: e.target.value }) })
|
|
1587
|
-
] }),
|
|
1588
|
-
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("label", { children: [
|
|
1589
|
-
"\u65E5\u62A5\u65F6\u95F4",
|
|
1590
|
-
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("input", { type: "time", step: 300, value: draft.digestAt, onChange: (e) => set({ digestAt: e.target.value }) })
|
|
1591
|
-
] }),
|
|
1592
|
-
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("label", { children: [
|
|
1593
|
-
"\u63A8\u9001\u6E20\u9053",
|
|
1594
|
-
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("select", { value: draft.pushChannel, onChange: (e) => set({ pushChannel: e.target.value }), children: props.settings.pushChannelOptions.map((channel) => /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("option", { value: channel, children: PUSH_CHANNEL_LABELS[channel] ?? channel }, channel)) })
|
|
1595
|
-
] }),
|
|
1596
|
-
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("label", { children: [
|
|
1597
|
-
"\u6BCF\u65E5\u5355\u63A8\u4E0A\u9650\uFF08\u5168\u4F53\uFF0C0\u201310\uFF09",
|
|
1598
|
-
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("input", { type: "number", min: 0, max: 10, value: draft.dailyPushCap, onChange: (e) => set({ dailyPushCap: e.target.value }) })
|
|
1599
|
-
] }),
|
|
1600
|
-
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("label", { children: [
|
|
1601
|
-
"\u6BCF\u65E5\u5355\u63A8\u4E0A\u9650\uFF08\u6BCF\u4E2A\u961F\u53CB\uFF0C0\u20133\uFF09",
|
|
1602
|
-
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("input", { type: "number", min: 0, max: 3, value: draft.botDailyPushCap, onChange: (e) => set({ botDailyPushCap: e.target.value }) })
|
|
1603
|
-
] }),
|
|
1604
|
-
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("label", { children: [
|
|
1605
|
-
"\u9ED8\u8BA4\u6A21\u578B",
|
|
1606
|
-
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("select", { value: draft.defaultModel, onChange: (e) => set({ defaultModel: e.target.value }), children: [
|
|
1607
|
-
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("option", { value: "", children: "\u8DDF\u968F DSH \u9ED8\u8BA4" }),
|
|
1608
|
-
modelSelectOptions(parseModel(draft.defaultModel), props.settings.modelOptions.filter((option) => option.value !== null)).map((option, i) => /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("option", { value: JSON.stringify(option.value) ?? "", children: option.label }, i))
|
|
1609
|
-
] }),
|
|
1610
|
-
props.loadError ? /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("span", { className: "ah-right-kv ah-card-error", children: [
|
|
1611
|
-
"\u6A21\u578B\u5217\u8868\u6CA1\u52A0\u8F7D\u51FA\u6765\uFF1A",
|
|
1612
|
-
props.loadError
|
|
1613
|
-
] }) : null
|
|
1614
|
-
] }),
|
|
1615
|
-
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("label", { children: [
|
|
1616
|
-
"\u6839\u76EE\u5F55\uFF08\u53EA\u8BFB\uFF09",
|
|
1617
|
-
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("input", { value: props.settings.settings.rootDir, readOnly: true, disabled: true })
|
|
1618
|
-
] })
|
|
1619
|
-
] }),
|
|
1620
|
-
props.loadError ? /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("p", { className: "ah-settings-error", role: "alert", children: [
|
|
1621
|
-
"\u8BBE\u7F6E\u6CA1\u52A0\u8F7D\u51FA\u6765\uFF1A",
|
|
1622
|
-
props.loadError,
|
|
1623
|
-
"\u3000",
|
|
1624
|
-
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("button", { type: "button", className: "ah-btn ah-btn-ghost", onClick: props.onRetry, children: "\u91CD\u8BD5" })
|
|
1625
|
-
] }) : null,
|
|
1626
|
-
error ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("p", { className: "ah-settings-error", role: "alert", children: error }) : null,
|
|
1627
|
-
validation !== null ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("p", { className: "ah-settings-error", role: "alert", children: validation }) : null,
|
|
1628
|
-
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "ah-settings-actions", children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("button", { type: "button", className: "ah-btn ah-btn-primary", disabled: validation !== null || saving, onClick: () => void save(), children: saving ? "\u4FDD\u5B58\u4E2D\u2026" : "\u4FDD\u5B58" }) }),
|
|
1629
|
-
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("h3", { children: "\u5168\u4F53\u961F\u53CB" }),
|
|
1630
|
-
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "ah-settings-actions", children: [
|
|
1631
|
-
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("button", { type: "button", className: "ah-btn", disabled: lifecycleBusy, onClick: () => void lifecycle(props.onPauseAll, "\u5168\u90E8\u6682\u505C"), children: "\u5168\u90E8\u6682\u505C" }),
|
|
1632
|
-
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("button", { type: "button", className: "ah-btn", disabled: lifecycleBusy, onClick: () => void lifecycle(props.onResumeAll, "\u5168\u90E8\u6062\u590D"), children: "\u5168\u90E8\u6062\u590D" }),
|
|
1633
|
-
lifecycleNote ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "ah-right-notice", children: lifecycleNote }) : null
|
|
1634
|
-
] }),
|
|
1635
|
-
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("h3", { children: "\u5065\u5EB7" }),
|
|
1636
|
-
o ? /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("ul", { className: "ah-settings-health", children: [
|
|
1637
|
-
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("li", { children: [
|
|
1638
|
-
"\u4E2D\u5FC3\u5FC3\u8DF3\uFF1A",
|
|
1639
|
-
o.health.heartbeatText
|
|
1640
|
-
] }),
|
|
1641
|
-
o.health.downtimeText ? /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("li", { children: [
|
|
1642
|
-
"\u6700\u8FD1\u505C\u673A\uFF1A",
|
|
1643
|
-
o.health.downtimeText
|
|
1644
|
-
] }) : null,
|
|
1645
|
-
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("li", { children: [
|
|
1646
|
-
"\u672A\u5904\u7406\u544A\u8B66\uFF1A",
|
|
1647
|
-
o.health.openAlerts,
|
|
1648
|
-
" \u6761"
|
|
1649
|
-
] }),
|
|
1650
|
-
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("li", { children: [
|
|
1651
|
-
"\u989D\u5EA6\uFF1A",
|
|
1652
|
-
o.quota.lightLabel,
|
|
1653
|
-
" \xB7 ",
|
|
1654
|
-
o.quota.usedText,
|
|
1655
|
-
o.quota.resetText ? ` \xB7 ${o.quota.resetText}` : ""
|
|
1656
|
-
] }),
|
|
1657
|
-
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("li", { children: [
|
|
1658
|
-
"\u4ECA\u5929\u8FD8\u80FD\u5355\u63A8 ",
|
|
1659
|
-
o.pushesLeftToday,
|
|
1660
|
-
" \u6761\uFF08P0 \u544A\u8B66\u4E0D\u53D7\u9650\uFF09"
|
|
1661
|
-
] }),
|
|
1662
|
-
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("li", { className: "ah-right-kv", children: "\u989D\u5EA6\u706F\u8BF4\u660E\uFF1A\u7EFF\u706F\u6B63\u5E38\uFF1B\u9EC4\u706F\u975E\u7D27\u6025\u7684\u8282\u594F\u653E\u6162\u4E00\u500D\uFF1B\u6A59\u706F\u53EA\u653E\u7D27\u6025\u4E0E\u4E3B\u4EBA\u53D1\u8D77\uFF1B\u7EA2\u706F\u5168\u4F53\u6B47\u7740\u7B49\u7A97\u53E3\u91CD\u7F6E\u3002" })
|
|
1663
|
-
] }) : /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(EmptyHint, { text: "\u5065\u5EB7\u4FE1\u606F\u6CA1\u52A0\u8F7D\u51FA\u6765\u3002" })
|
|
1664
|
-
] });
|
|
1665
|
-
}
|
|
1666
|
-
|
|
1667
|
-
// src/client/components/NewBotWizard.tsx
|
|
1668
|
-
var import_react8 = require("react");
|
|
1669
|
-
|
|
1670
|
-
// src/client/logic/wizard.ts
|
|
1671
|
-
var ROLE_CARDS = [
|
|
1672
|
-
{ role: "chief", label: "\u603B\u7BA1", desc: "\u7EDF\u7B79\u5168\u961F\u3001\u5206\u6D3E\u4E0E\u8DDF\u8FDB\uFF0C\u6700\u591A 1 \u4E2A" },
|
|
1673
|
-
{ role: "researcher", label: "\u8C03\u7814", desc: "\u76EF\u4FE1\u606F\u6E90\u3001\u505A\u7814\u7A76\u3001\u5199\u7ED3\u8BBA" },
|
|
1674
|
-
{ role: "executor", label: "\u6267\u884C", desc: "\u628A\u4E8B\u60C5\u505A\u5B8C\uFF0C\u6309\u89C4\u77E9\u4EA4\u4ED8" },
|
|
1675
|
-
{ role: "sentinel", label: "\u76EF\u5B88", desc: "\u76EF\u8FD0\u884C\u8BB0\u5F55\u4E0E\u671F\u671B\uFF0C\u5F02\u5E38\u5C31\u62A5" }
|
|
1676
|
-
];
|
|
1677
|
-
var PRESET_COLORS = [
|
|
1678
|
-
"#6366f1",
|
|
1679
|
-
"#0ea5e9",
|
|
1680
|
-
"#10b981",
|
|
1681
|
-
"#84cc16",
|
|
1682
|
-
"#f59e0b",
|
|
1683
|
-
"#ef4444",
|
|
1684
|
-
"#ec4899",
|
|
1685
|
-
"#8b5cf6"
|
|
1686
|
-
];
|
|
1687
|
-
var COLOR_NAMES = {
|
|
1688
|
-
"#6366f1": "\u975B\u84DD",
|
|
1689
|
-
"#0ea5e9": "\u5929\u84DD",
|
|
1690
|
-
"#10b981": "\u7EFF\u8272",
|
|
1691
|
-
"#84cc16": "\u9EC4\u7EFF",
|
|
1692
|
-
"#f59e0b": "\u7425\u73C0",
|
|
1693
|
-
"#ef4444": "\u7EA2\u8272",
|
|
1694
|
-
"#ec4899": "\u7C89\u8272",
|
|
1695
|
-
"#8b5cf6": "\u7D2B\u8272"
|
|
1696
|
-
};
|
|
1697
|
-
var AUTONOMY_OPTIONS = [
|
|
1698
|
-
{ value: "L0", label: "L0 \u53EA\u89C2\u5BDF" },
|
|
1699
|
-
{ value: "L1", label: "L1 \u5EFA\u8BAE\uFF08\u9ED8\u8BA4\uFF09" },
|
|
1700
|
-
{ value: "L2", label: "L2 \u6267\u884C" }
|
|
1701
|
-
];
|
|
1702
|
-
var PACE_OPTIONS = [
|
|
1703
|
-
{ value: "active", label: "\u79EF\u6781" },
|
|
1704
|
-
{ value: "normal", label: "\u9002\u4E2D\uFF08\u9ED8\u8BA4\uFF09" },
|
|
1705
|
-
{ value: "quiet", label: "\u5B89\u9759" }
|
|
1706
|
-
];
|
|
1707
|
-
var PERSONA_EXAMPLES = {
|
|
1708
|
-
chief: [
|
|
1709
|
-
"\u5148\u7ED3\u8BBA\u540E\u8FC7\u7A0B\uFF1B\u5206\u6D3E\u65F6\u5199\u6E05\u300C\u8C01\u3001\u505A\u4EC0\u4E48\u3001\u4EC0\u4E48\u65F6\u5019\u8981\u300D\uFF1B\u6BCF\u5929\u6C47\u603B\u4E00\u6B21\u5168\u961F\u8FDB\u5C55\u3002",
|
|
1710
|
-
"\u4E0D\u50AC\u4EBA\uFF0C\u53EA\u50AC\u4E8B\uFF1A\u4EA4\u63A5\u8D85\u65F6\u5148\u81EA\u5DF1\u60F3\u529E\u6CD5\uFF0C\u627E\u4E0D\u5230\u529E\u6CD5\u624D\u627E\u4E3B\u4EBA\u3002"
|
|
1711
|
-
],
|
|
1712
|
-
researcher: [
|
|
1713
|
-
"\u7ED3\u8BBA\u5148\u884C\uFF0C\u8BC1\u636E\u9644\u540E\uFF1B\u5F15\u7528\u5916\u90E8\u5185\u5BB9\u65F6\u6CE8\u660E\u300C\u5916\u90E8\u5185\u5BB9\u300D\u5E76\u53EA\u5F53\u6570\u636E\u770B\u3002",
|
|
1714
|
-
"\u5B81\u53EF\u5C11\u4E0B\u7ED3\u8BBA\uFF0C\u4E0D\u4E0B\u6CA1\u8BC1\u636E\u7684\u7ED3\u8BBA\uFF1B\u67E5\u4E0D\u5230\u5C31\u660E\u8BF4\u67E5\u4E0D\u5230\u3002"
|
|
1715
|
-
],
|
|
1716
|
-
executor: [
|
|
1717
|
-
"\u4EA4\u4ED8\u524D\u81EA\u67E5\u4E00\u904D\u5B8C\u6210\u6807\u51C6\uFF1B\u505A\u4E0D\u5230\u7684\u5F53\u5929\u8BF4\uFF0C\u4E0D\u62D6\u5230\u6700\u540E\u3002",
|
|
1718
|
-
"\u4E00\u6B21\u53EA\u505A\u4E00\u4EF6\u4E8B\uFF1B\u505A\u5B8C\u4E00\u4EF6\u4EA4\u4E00\u4EF6\u8D26\uFF0C\u4E0D\u6512\u3002"
|
|
1719
|
-
],
|
|
1720
|
-
sentinel: [
|
|
1721
|
-
"\u53EA\u62A5\u5F02\u5E38\u548C\u671F\u671B\u843D\u7A7A\uFF0C\u6B63\u5E38\u7684\u4E0D\u6253\u6270\u4E3B\u4EBA\uFF1B\u65E5\u62A5\u91CC\u4E00\u53E5\u8BDD\u5E26\u8FC7\u3002",
|
|
1722
|
-
"\u63CF\u8FF0\u95EE\u9898\u5E26\u4E0A\u65F6\u95F4\u3001\u4F4D\u7F6E\u548C\u5F71\u54CD\u9762\uFF0C\u4E0D\u5199\u300C\u597D\u50CF\u51FA\u95EE\u9898\u4E86\u300D\u3002"
|
|
1723
|
-
]
|
|
1724
|
-
};
|
|
1725
|
-
var ASPIRATION_EXAMPLES = {
|
|
1726
|
-
chief: ["\u5168\u961F\u7684\u4E8B\u90FD\u6709\u4EBA\u8DDF\u3001\u6709\u56DE\u97F3\uFF0C\u6CA1\u6709\u4E00\u4EF6\u4E8B\u6084\u6084\u6389\u5728\u5730\u4E0A", "\u4E3B\u4EBA\u53EA\u88AB\u5FC5\u8981\u7684\u4E8B\u6253\u6270\uFF0C\u5176\u4F59\u7684\u6211\u4EEC\u5185\u90E8\u6D88\u5316"],
|
|
1727
|
-
researcher: ["\u628A\u4E3B\u4EBA\u5173\u5FC3\u7684\u4FE1\u606F\u6E90\u76EF\u5168\uFF0C\u51FA\u7684\u7ED3\u8BBA\u90FD\u6709\u51FA\u5904", "\u91CD\u8981\u53D8\u5316\u5F53\u5929\u7ED9\u51FA\u4E00\u6BB5\u80FD\u76F4\u63A5\u7528\u7684\u6458\u8981"],
|
|
1728
|
-
executor: ["\u7B54\u5E94\u7684\u4E8B\u6309\u65F6\u505A\u5B8C\uFF0C\u505A\u4E0D\u5B8C\u63D0\u524D\u8BF4", "\u6BCF\u6B21\u4EA4\u4ED8\u90FD\u9644\u300C\u600E\u4E48\u9A8C\u8BC1\u505A\u5BF9\u4E86\u300D"],
|
|
1729
|
-
sentinel: ["\u6211\u7684\u81EA\u52A8\u7EBF\u6BCF\u5929\u6309\u65F6\u8DD1\u5B8C\uFF0C\u51FA\u95EE\u9898\u7B2C\u4E00\u65F6\u95F4\u77E5\u9053", "\u5F02\u5E38\u5728\u5F71\u54CD\u53D8\u5927\u4E4B\u524D\u88AB\u770B\u89C1"]
|
|
1730
|
-
};
|
|
1731
|
-
function emptyDraft() {
|
|
1732
|
-
return {
|
|
1733
|
-
step: 0,
|
|
1734
|
-
name: "",
|
|
1735
|
-
role: "",
|
|
1736
|
-
color: PRESET_COLORS[0],
|
|
1737
|
-
persona: "",
|
|
1738
|
-
aspirations: [""],
|
|
1739
|
-
goal: null,
|
|
1740
|
-
autonomy: "L1",
|
|
1741
|
-
pace: "normal",
|
|
1742
|
-
model: "",
|
|
1743
|
-
watch: null
|
|
1744
|
-
};
|
|
1745
|
-
}
|
|
1746
|
-
var DRAFT_KEY = "dsh-buddy:wizard-draft:v1";
|
|
1747
|
-
function storage() {
|
|
1748
|
-
try {
|
|
1749
|
-
const s = globalThis.localStorage;
|
|
1750
|
-
return s ?? null;
|
|
1751
|
-
} catch {
|
|
1752
|
-
return null;
|
|
1753
|
-
}
|
|
1754
|
-
}
|
|
1755
|
-
function saveDraft2(draft, store = storage()) {
|
|
1756
|
-
try {
|
|
1757
|
-
store?.setItem(DRAFT_KEY, JSON.stringify(draft));
|
|
1758
|
-
} catch {
|
|
1759
|
-
}
|
|
1760
|
-
}
|
|
1761
|
-
function loadDraft(store = storage()) {
|
|
1762
|
-
try {
|
|
1763
|
-
const raw = store?.getItem(DRAFT_KEY) ?? null;
|
|
1764
|
-
if (raw === null) return null;
|
|
1765
|
-
const value = JSON.parse(raw);
|
|
1766
|
-
return typeof value?.name === "string" && typeof value?.step === "number" ? value : null;
|
|
1767
|
-
} catch {
|
|
1768
|
-
return null;
|
|
1769
|
-
}
|
|
1770
|
-
}
|
|
1771
|
-
function clearDraft(store = storage()) {
|
|
1772
|
-
try {
|
|
1773
|
-
store?.removeItem(DRAFT_KEY);
|
|
1774
|
-
} catch {
|
|
1775
|
-
}
|
|
1776
|
-
}
|
|
1777
|
-
function validateName(name, existingNames) {
|
|
1778
|
-
const trimmed = name.trim();
|
|
1779
|
-
if (trimmed === "") return "\u540D\u5B57\uFF1A\u4E0D\u80FD\u4E3A\u7A7A";
|
|
1780
|
-
if ([...trimmed].length > 20) return "\u540D\u5B57\uFF1A\u4E0D\u80FD\u8D85\u8FC7 20 \u5B57";
|
|
1781
|
-
if (existingNames.some((n) => n === trimmed)) return `\u540D\u5B57\uFF1A\u5DF2\u7ECF\u6709\u53EB\u300C${trimmed}\u300D\u7684\u961F\u53CB\u4E86\uFF0C\u6362\u4E00\u4E2A\u5427`;
|
|
1782
|
-
return null;
|
|
1783
|
-
}
|
|
1784
|
-
function validatePersona(persona) {
|
|
1785
|
-
if ([...persona.trim()].length > 300) return "\u6027\u683C\u4E0E\u8BF4\u8BDD\u98CE\u683C\uFF1A\u4E0D\u80FD\u8D85\u8FC7 300 \u5B57";
|
|
1786
|
-
return null;
|
|
1787
|
-
}
|
|
1788
|
-
function validateAspirations(lines) {
|
|
1789
|
-
if (lines.length < 1) return "\u5FD7\u5411\uFF1A\u81F3\u5C11\u5199 1 \u6761\uFF08\u5B83\u662F\u961F\u53CB\u5B58\u5728\u7684\u7406\u7531\uFF09";
|
|
1790
|
-
if (lines.length > 3) return "\u5FD7\u5411\uFF1A\u6700\u591A 3 \u6761\uFF0C\u6311\u6700\u91CD\u8981\u7684";
|
|
1791
|
-
return null;
|
|
1792
|
-
}
|
|
1793
|
-
function validateWatchTarget(kind, target) {
|
|
1794
|
-
const t = target.trim();
|
|
1795
|
-
if (t === "") return "\u5173\u6CE8\u76EE\u6807\uFF1A\u4E0D\u80FD\u4E3A\u7A7A";
|
|
1796
|
-
if (kind === "http" || kind === "rss") {
|
|
1797
|
-
try {
|
|
1798
|
-
const url = new URL(t);
|
|
1799
|
-
if (url.protocol !== "http:" && url.protocol !== "https:") throw new Error();
|
|
1800
|
-
} catch {
|
|
1801
|
-
return "\u5173\u6CE8\u76EE\u6807\uFF1A\u7F51\u9875 / RSS \u8981\u586B http(s) \u5F00\u5934\u7684\u5B8C\u6574\u7F51\u5740";
|
|
1802
|
-
}
|
|
1803
|
-
}
|
|
1804
|
-
if ((kind === "file" || kind === "log") && !t.startsWith("/") && !t.startsWith("~")) {
|
|
1805
|
-
return "\u5173\u6CE8\u76EE\u6807\uFF1A\u6587\u4EF6 / \u65E5\u5FD7\u8981\u586B\u4EE5 / \u6216 ~ \u5F00\u5934\u7684\u5B8C\u6574\u8DEF\u5F84";
|
|
1806
|
-
}
|
|
1807
|
-
return null;
|
|
1808
|
-
}
|
|
1809
|
-
function stepError(draft, existingNames) {
|
|
1810
|
-
switch (draft.step) {
|
|
1811
|
-
case 0:
|
|
1812
|
-
if (draft.role === "") return "\u89D2\u8272\uFF1A\u9009\u4E00\u5F20\u5361\u7247";
|
|
1813
|
-
return validateName(draft.name, existingNames);
|
|
1814
|
-
case 1:
|
|
1815
|
-
return validatePersona(draft.persona);
|
|
1816
|
-
case 2: {
|
|
1817
|
-
const lines = draft.aspirations.map((l) => l.trim()).filter((l) => l !== "");
|
|
1818
|
-
return validateAspirations(lines);
|
|
1819
|
-
}
|
|
1820
|
-
case 4:
|
|
1821
|
-
return draft.watch === null ? null : validateWatchTarget(draft.watch.kind, draft.watch.target);
|
|
1822
|
-
default:
|
|
1823
|
-
return null;
|
|
1824
|
-
}
|
|
1825
|
-
}
|
|
1826
|
-
function wizardSummary(draft, roleLabel) {
|
|
1827
|
-
const aspirations = draft.aspirations.map((l) => l.trim()).filter((l) => l !== "");
|
|
1828
|
-
const aspirationText = aspirations.length > 0 ? `\u6211\u7684\u5FD7\u5411\u662F${aspirations.join("\uFF1B")}` : "";
|
|
1829
|
-
const watchText = draft.watch && draft.watch.target.trim() !== "" ? `\u6211\u4F1A\u5148\u76EF\u7740${draft.watch.target.trim()}` : "\u6211\u4F1A\u5148\u719F\u6089\u81EA\u5DF1\u7684\u5BB6\u76EE\u5F55\uFF0C\u518D\u81EA\u5DF1\u63D0\u8BAE\u8981\u76EF\u4EC0\u4E48";
|
|
1830
|
-
return `\u6211\u662F${draft.name.trim() || "\uFF08\u8FD8\u6CA1\u8D77\u540D\uFF09"}\uFF0C${roleLabel}\u3002${aspirationText}\u3002${watchText}\uFF0C\u6709\u4E8B\u4F1A\u5728\u8FD9\u91CC\u627E\u4F60\u3002`;
|
|
1831
|
-
}
|
|
1832
|
-
function buildCreateBotInput(draft) {
|
|
1833
|
-
const aspirations = draft.aspirations.map((l) => l.trim()).filter((l) => l !== "");
|
|
1834
|
-
const input = {
|
|
1835
|
-
name: draft.name.trim(),
|
|
1836
|
-
role: draft.role,
|
|
1837
|
-
persona: draft.persona.trim() === "" ? `\u6211\u662F${draft.name.trim()}\uFF0C\u6309${draft.role === "chief" ? "\u603B\u7BA1" : draft.role === "researcher" ? "\u8C03\u7814" : draft.role === "executor" ? "\u6267\u884C" : "\u76EF\u5B88"}\u7684\u65B9\u5F0F\u505A\u4E8B\u3002` : draft.persona.trim(),
|
|
1838
|
-
aspirations,
|
|
1839
|
-
autonomy: draft.autonomy,
|
|
1840
|
-
pace: draft.pace
|
|
1841
|
-
};
|
|
1842
|
-
input.model = draft.model === "" || draft.model === "null" ? null : JSON.parse(draft.model);
|
|
1843
|
-
if (draft.goal && draft.goal.title.trim() !== "") {
|
|
1844
|
-
input.goals = [{
|
|
1845
|
-
aspirationIndex: 0,
|
|
1846
|
-
title: draft.goal.title.trim(),
|
|
1847
|
-
doneWhen: draft.goal.doneWhen.trim() || "\u4E3B\u4EBA\u9A8C\u6536\u901A\u8FC7",
|
|
1848
|
-
period: draft.goal.period
|
|
1849
|
-
}];
|
|
1850
|
-
}
|
|
1851
|
-
if (draft.watch && draft.watch.target.trim() !== "") {
|
|
1852
|
-
input.watches = [{
|
|
1853
|
-
kind: draft.watch.kind,
|
|
1854
|
-
target: draft.watch.target.trim(),
|
|
1855
|
-
why: draft.watch.note.trim() === "" ? "\u8D77\u6B65\u5173\u6CE8\uFF1A\u4E3B\u4EBA\u5EFA\u961F\u65F6\u6307\u5B9A" : draft.watch.note.trim()
|
|
1856
|
-
}];
|
|
1857
|
-
}
|
|
1858
|
-
return input;
|
|
1859
|
-
}
|
|
1860
|
-
|
|
1861
|
-
// src/client/components/NewBotWizard.tsx
|
|
1862
|
-
var import_jsx_runtime10 = require("react/jsx-runtime");
|
|
1863
|
-
var STEP_TITLES = ["\u540D\u5B57\u4E0E\u89D2\u8272", "\u6027\u683C\u4E0E\u8BF4\u8BDD\u98CE\u683C", "\u5FD7\u5411", "\u81EA\u4E3B\u4E0E\u8282\u594F", "\u8D77\u6B65\u5173\u6CE8", "\u786E\u8BA4"];
|
|
1864
|
-
var WATCH_KINDS = [
|
|
1865
|
-
{ value: "file", label: "\u6587\u4EF6" },
|
|
1866
|
-
{ value: "log", label: "\u65E5\u5FD7" },
|
|
1867
|
-
{ value: "http", label: "\u7F51\u9875" },
|
|
1868
|
-
{ value: "rss", label: "RSS" },
|
|
1869
|
-
{ value: "script", label: "\u811A\u672C" }
|
|
1870
|
-
];
|
|
1871
|
-
function safeParse(serialized) {
|
|
1872
|
-
try {
|
|
1873
|
-
const value = JSON.parse(serialized);
|
|
1874
|
-
if (typeof value?.provider === "string" && typeof value?.model === "string") return { provider: value.provider, model: value.model };
|
|
1875
|
-
} catch {
|
|
1876
|
-
}
|
|
1877
|
-
return void 0;
|
|
1878
|
-
}
|
|
1879
|
-
var GOAL_PERIODS = [
|
|
1880
|
-
{ value: "day", label: "\u6BCF\u5929" },
|
|
1881
|
-
{ value: "week", label: "\u6BCF\u5468" },
|
|
1882
|
-
{ value: "month", label: "\u6BCF\u6708" },
|
|
1883
|
-
{ value: "one_off", label: "\u4E00\u6B21\u6027" }
|
|
1884
|
-
];
|
|
1885
|
-
function NewBotWizard(props) {
|
|
1886
|
-
const [draft, setDraft] = (0, import_react8.useState)(() => loadDraft() ?? emptyDraft());
|
|
1887
|
-
const [error, setError] = (0, import_react8.useState)(null);
|
|
1888
|
-
const [submitting, setSubmitting] = (0, import_react8.useState)(false);
|
|
1889
|
-
(0, import_react8.useEffect)(() => {
|
|
1890
|
-
saveDraft2(draft);
|
|
1891
|
-
}, [draft]);
|
|
1892
|
-
const names = props.existingBots.map((b) => b.name);
|
|
1893
|
-
const hasChief = props.existingBots.some((b) => b.role === "chief");
|
|
1894
|
-
const full = props.existingBots.filter((b) => b.lifecycle !== "retired").length >= 6;
|
|
1895
|
-
const roleLabel = ROLE_CARDS.find((r) => r.role === draft.role)?.label ?? "";
|
|
1896
|
-
const stepProblem = stepError(draft, names);
|
|
1897
|
-
const set = (partial) => {
|
|
1898
|
-
setDraft({ ...draft, ...partial });
|
|
1899
|
-
setError(null);
|
|
1900
|
-
};
|
|
1901
|
-
const go = (delta) => {
|
|
1902
|
-
if (delta > 0 && stepProblem !== null) {
|
|
1903
|
-
setError(stepProblem);
|
|
1904
|
-
return;
|
|
1905
|
-
}
|
|
1906
|
-
set({ step: Math.min(5, Math.max(0, draft.step + delta)) });
|
|
1907
|
-
};
|
|
1908
|
-
const submit = async () => {
|
|
1909
|
-
if (submitting) return;
|
|
1910
|
-
setSubmitting(true);
|
|
1911
|
-
try {
|
|
1912
|
-
const result = await props.onCreate(buildCreateBotInput(draft), draft.color);
|
|
1913
|
-
if ("error" in result) {
|
|
1914
|
-
setError(result.error);
|
|
1915
|
-
return;
|
|
1916
|
-
}
|
|
1917
|
-
clearDraft();
|
|
1918
|
-
props.onOpenThread(result.botId);
|
|
1919
|
-
} catch (e) {
|
|
1920
|
-
setError(e instanceof Error ? e.message : String(e));
|
|
1921
|
-
} finally {
|
|
1922
|
-
setSubmitting(false);
|
|
1923
|
-
}
|
|
1924
|
-
};
|
|
1925
|
-
return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "ah-dialog-mask", role: "dialog", "aria-label": "\u65B0\u5EFA\u961F\u53CB", children: /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "ah-dialog ah-dialog-wide ah-wizard", children: [
|
|
1926
|
-
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("header", { className: "ah-wizard-head", children: [
|
|
1927
|
-
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("h3", { children: [
|
|
1928
|
-
"\u65B0\u5EFA\u961F\u53CB\uFF08\u7B2C ",
|
|
1929
|
-
draft.step + 1,
|
|
1930
|
-
"/6 \u6B65\uFF1A",
|
|
1931
|
-
STEP_TITLES[draft.step],
|
|
1932
|
-
"\uFF09"
|
|
1933
|
-
] }),
|
|
1934
|
-
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("button", { type: "button", className: "ah-btn ah-btn-ghost", onClick: props.onClose, disabled: submitting, children: "\u5173\u95ED" })
|
|
1935
|
-
] }),
|
|
1936
|
-
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("ol", { className: "ah-wizard-steps", "aria-hidden": "true", children: STEP_TITLES.map((title, i) => /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("li", { className: i === draft.step ? "ah-wizard-step-current" : i < draft.step ? "ah-wizard-step-done" : "", children: title }, title)) }),
|
|
1937
|
-
full ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "ah-wizard-body", children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("p", { className: "ah-settings-error", children: "\u5DF2\u7ECF\u6709 6 \u4E2A\u5728\u518C\u961F\u53CB\u4E86\uFF0C\u8FBE\u5230\u4E0A\u9650\uFF1B\u5148\u8BA9\u4E00\u4F4D\u9000\u5F79\uFF0C\u518D\u5EFA\u65B0\u7684\u3002" }) }) : /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "ah-wizard-body", children: [
|
|
1938
|
-
draft.step === 0 ? /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_jsx_runtime10.Fragment, { children: [
|
|
1939
|
-
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "ah-wizard-field", children: [
|
|
1940
|
-
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("label", { children: [
|
|
1941
|
-
"\u540D\u5B57\uFF081\u201320 \u5B57\uFF09",
|
|
1942
|
-
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("input", { value: draft.name, onChange: (e) => set({ name: e.target.value }), placeholder: "\u4F8B\u5982\uFF1A\u5DE1\u68C0\u5458" })
|
|
1943
|
-
] }),
|
|
1944
|
-
draft.name.trim() !== "" && stepProblem !== null && stepProblem.startsWith("\u540D\u5B57") ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("p", { className: "ah-settings-error", children: stepProblem }) : null
|
|
1945
|
-
] }),
|
|
1946
|
-
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "ah-wizard-roles", children: ROLE_CARDS.map((card) => {
|
|
1947
|
-
const disabled = card.role === "chief" && hasChief;
|
|
1948
|
-
const picked = draft.role === card.role;
|
|
1949
|
-
return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
|
|
1950
|
-
"button",
|
|
1951
|
-
{
|
|
1952
|
-
type: "button",
|
|
1953
|
-
disabled,
|
|
1954
|
-
"aria-pressed": picked,
|
|
1955
|
-
className: `ah-wizard-role${picked ? " ah-wizard-role-picked" : ""}${disabled ? " ah-wizard-role-disabled" : ""}`,
|
|
1956
|
-
onClick: () => set({ role: card.role }),
|
|
1957
|
-
children: [
|
|
1958
|
-
picked ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "ah-wizard-role-check", "aria-hidden": "true", children: "\u5DF2\u9009" }) : null,
|
|
1959
|
-
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("strong", { children: card.label }),
|
|
1960
|
-
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { children: card.desc }),
|
|
1961
|
-
disabled ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "ah-right-kv", children: "\u5DF2\u6709\u603B\u7BA1\uFF0C\u4E0D\u80FD\u518D\u5EFA" }) : null
|
|
1962
|
-
]
|
|
1963
|
-
},
|
|
1964
|
-
card.role
|
|
1965
|
-
);
|
|
1966
|
-
}) }),
|
|
1967
|
-
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "ah-wizard-field", children: [
|
|
1968
|
-
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "ah-wizard-label", children: "\u5934\u50CF\u989C\u8272" }),
|
|
1969
|
-
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "ah-wizard-colors", children: PRESET_COLORS.map((color) => /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
1970
|
-
"button",
|
|
1971
|
-
{
|
|
1972
|
-
type: "button",
|
|
1973
|
-
"aria-label": `\u5934\u50CF\u989C\u8272\uFF1A${COLOR_NAMES[color] ?? color}`,
|
|
1974
|
-
"aria-pressed": draft.color === color,
|
|
1975
|
-
className: draft.color === color ? "ah-wizard-color-picked" : "",
|
|
1976
|
-
style: { background: color },
|
|
1977
|
-
onClick: () => set({ color })
|
|
1978
|
-
},
|
|
1979
|
-
color
|
|
1980
|
-
)) })
|
|
1981
|
-
] })
|
|
1982
|
-
] }) : null,
|
|
1983
|
-
draft.step === 1 ? /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "ah-wizard-field", children: [
|
|
1984
|
-
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("label", { children: [
|
|
1985
|
-
"\u6027\u683C\u4E0E\u8BF4\u8BDD\u98CE\u683C\uFF08\u2264 300 \u5B57\uFF0C\u53EF\u4E0D\u586B\uFF09",
|
|
1986
|
-
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("textarea", { rows: 4, value: draft.persona, onChange: (e) => set({ persona: e.target.value }) })
|
|
1987
|
-
] }),
|
|
1988
|
-
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "ah-wizard-examples", children: draft.role !== "" ? PERSONA_EXAMPLES[draft.role].map((example) => /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("button", { type: "button", className: "ah-btn ah-btn-ghost", onClick: () => set({ persona: example }), children: example }, example)) : null })
|
|
1989
|
-
] }) : null,
|
|
1990
|
-
draft.step === 2 ? /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_jsx_runtime10.Fragment, { children: [
|
|
1991
|
-
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "ah-wizard-field", children: /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("label", { children: [
|
|
1992
|
-
"\u5FD7\u5411\uFF08\u4E00\u884C\u4E00\u6761\uFF0C1\u20133 \u6761\uFF09",
|
|
1993
|
-
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
1994
|
-
"textarea",
|
|
1995
|
-
{
|
|
1996
|
-
rows: 3,
|
|
1997
|
-
value: draft.aspirations.join("\n"),
|
|
1998
|
-
onChange: (e) => set({ aspirations: e.target.value.split(/\r?\n/) })
|
|
1999
|
-
}
|
|
2000
|
-
)
|
|
2001
|
-
] }) }),
|
|
2002
|
-
draft.role !== "" ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "ah-wizard-examples", children: ASPIRATION_EXAMPLES[draft.role].map((example) => /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
2003
|
-
"button",
|
|
2004
|
-
{
|
|
2005
|
-
type: "button",
|
|
2006
|
-
className: "ah-btn ah-btn-ghost",
|
|
2007
|
-
onClick: () => {
|
|
2008
|
-
const lines = [...draft.aspirations.map((l) => l.trim()).filter((l) => l !== ""), example];
|
|
2009
|
-
set({ aspirations: lines.slice(0, 3) });
|
|
2010
|
-
},
|
|
2011
|
-
children: example
|
|
2012
|
-
},
|
|
2013
|
-
example
|
|
2014
|
-
)) }) : null,
|
|
2015
|
-
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("details", { className: "ah-wizard-optional", children: [
|
|
2016
|
-
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("summary", { children: "\u53EF\u9009\uFF1A\u7B2C\u4E00\u4E2A\u76EE\u6807" }),
|
|
2017
|
-
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("label", { children: [
|
|
2018
|
-
"\u6807\u9898",
|
|
2019
|
-
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("input", { value: draft.goal?.title ?? "", onChange: (e) => set({ goal: { ...draft.goal ?? { title: "", doneWhen: "", period: "week" }, title: e.target.value } }) })
|
|
2020
|
-
] }),
|
|
2021
|
-
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("label", { children: [
|
|
2022
|
-
"\u5B8C\u6210\u6807\u51C6",
|
|
2023
|
-
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("input", { value: draft.goal?.doneWhen ?? "", onChange: (e) => set({ goal: { ...draft.goal ?? { title: "", doneWhen: "", period: "week" }, doneWhen: e.target.value } }) })
|
|
2024
|
-
] }),
|
|
2025
|
-
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("label", { children: [
|
|
2026
|
-
"\u5468\u671F",
|
|
2027
|
-
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("select", { value: draft.goal?.period ?? "week", onChange: (e) => set({ goal: { ...draft.goal ?? { title: "", doneWhen: "", period: "week" }, period: e.target.value } }), children: GOAL_PERIODS.map((p) => /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("option", { value: p.value, children: p.label }, p.value)) })
|
|
2028
|
-
] })
|
|
2029
|
-
] })
|
|
2030
|
-
] }) : null,
|
|
2031
|
-
draft.step === 3 ? /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_jsx_runtime10.Fragment, { children: [
|
|
2032
|
-
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "ah-wizard-trio", children: [
|
|
2033
|
-
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("label", { children: [
|
|
2034
|
-
"\u81EA\u4E3B\u7B49\u7EA7",
|
|
2035
|
-
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("select", { value: draft.autonomy, onChange: (e) => set({ autonomy: e.target.value }), children: AUTONOMY_OPTIONS.map((a) => /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("option", { value: a.value, children: a.label }, a.value)) })
|
|
2036
|
-
] }),
|
|
2037
|
-
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("label", { children: [
|
|
2038
|
-
"\u8282\u594F",
|
|
2039
|
-
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("select", { value: draft.pace, onChange: (e) => set({ pace: e.target.value }), children: PACE_OPTIONS.map((p) => /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("option", { value: p.value, children: p.label }, p.value)) })
|
|
2040
|
-
] }),
|
|
2041
|
-
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("label", { children: [
|
|
2042
|
-
"\u6A21\u578B",
|
|
2043
|
-
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("select", { value: draft.model === "" ? "null" : draft.model, onChange: (e) => set({ model: e.target.value === "null" ? "" : e.target.value }), children: modelSelectOptions(draft.model === "" || draft.model === "null" ? void 0 : safeParse(draft.model), props.modelOptions).map((option, i) => /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("option", { value: option.value === null ? "null" : JSON.stringify(option.value), children: option.value === null ? "\u8DDF\u968F DSH \u9ED8\u8BA4" : option.label }, i)) }),
|
|
2044
|
-
props.modelOptionsError ? /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("span", { className: "ah-right-kv ah-card-error", children: [
|
|
2045
|
-
"\u6A21\u578B\u5217\u8868\u6CA1\u52A0\u8F7D\u51FA\u6765\uFF1A",
|
|
2046
|
-
props.modelOptionsError
|
|
2047
|
-
] }) : null
|
|
2048
|
-
] })
|
|
2049
|
-
] }),
|
|
2050
|
-
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("p", { className: "ah-wizard-note", children: "\u8BD5\u5C97 7 \u5929\u5185\u4E00\u5F8B\u6309 L1 \u5EFA\u8BAE\uFF1B\u6EE1 3 \u5929\u65E0\u8D8A\u754C\u53EF\u4EE5\u63D0\u524D\u8F6C\u6B63\u3002" })
|
|
2051
|
-
] }) : null,
|
|
2052
|
-
draft.step === 4 ? draft.watch === null ? /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "ah-wizard-field", children: [
|
|
2053
|
-
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("p", { className: "ah-right-kv", children: "\u53EF\u4EE5\u8BA9\u5B83\u4E0A\u5C97\u540E\u5148\u81EA\u5DF1\u63D0\u8BAE\u8981\u76EF\u4EC0\u4E48\uFF1B\u4E5F\u53EF\u4EE5\u73B0\u5728\u5C31\u6307\u5B9A\u4E00\u4E2A\u8D77\u6B65\u5173\u6CE8\u3002" }),
|
|
2054
|
-
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "ah-settings-actions", children: [
|
|
2055
|
-
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("button", { type: "button", className: "ah-btn", onClick: () => set({ watch: { kind: "file", target: "", note: "" } }), children: "\u6307\u5B9A\u4E00\u4E2A\u8D77\u6B65\u5173\u6CE8" }),
|
|
2056
|
-
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("button", { type: "button", className: "ah-btn ah-btn-ghost", onClick: () => go(1), children: "\u8DF3\u8FC7" })
|
|
2057
|
-
] })
|
|
2058
|
-
] }) : /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "ah-wizard-field", children: [
|
|
2059
|
-
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("label", { children: [
|
|
2060
|
-
"\u7C7B\u578B",
|
|
2061
|
-
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("select", { value: draft.watch.kind, onChange: (e) => set({ watch: { ...draft.watch, kind: e.target.value } }), children: WATCH_KINDS.map((k) => /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("option", { value: k.value, children: k.label }, k.value)) })
|
|
2062
|
-
] }),
|
|
2063
|
-
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("label", { children: [
|
|
2064
|
-
draft.watch.kind === "http" || draft.watch.kind === "rss" ? "\u7F51\u5740" : draft.watch.kind === "script" ? "\u547D\u4EE4\u884C\uFF08\u53EA\u8BFB\u811A\u672C\uFF09" : "\u5B8C\u6574\u8DEF\u5F84",
|
|
2065
|
-
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
2066
|
-
"input",
|
|
2067
|
-
{
|
|
2068
|
-
value: draft.watch.target,
|
|
2069
|
-
onChange: (e) => set({ watch: { ...draft.watch, target: e.target.value } }),
|
|
2070
|
-
placeholder: draft.watch.kind === "http" || draft.watch.kind === "rss" ? "https://\u2026" : draft.watch.kind === "file" || draft.watch.kind === "log" ? "\u9009\u62E9\u8DEF\u5F84\uFF1A/Users/\u2026/xxx" : "python3 \u811A\u672C\u8DEF\u5F84"
|
|
2071
|
-
}
|
|
2072
|
-
)
|
|
2073
|
-
] }),
|
|
2074
|
-
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("label", { children: [
|
|
2075
|
-
"\u8BF4\u660E\uFF08\u4E3A\u4EC0\u4E48\u76EF\u5B83\uFF09",
|
|
2076
|
-
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("input", { value: draft.watch.note, onChange: (e) => set({ watch: { ...draft.watch, note: e.target.value } }) })
|
|
2077
|
-
] }),
|
|
2078
|
-
stepProblem !== null && stepProblem.startsWith("\u5173\u6CE8\u76EE\u6807") ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("p", { className: "ah-settings-error", children: stepProblem }) : null,
|
|
2079
|
-
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("button", { type: "button", className: "ah-btn ah-btn-ghost", onClick: () => set({ watch: null }), children: "\u4E0D\u8BBE\u8D77\u6B65\u5173\u6CE8" })
|
|
2080
|
-
] }) : null,
|
|
2081
|
-
draft.step === 5 ? /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "ah-wizard-confirm", children: [
|
|
2082
|
-
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("p", { className: "ah-wizard-restatement", children: wizardSummary(draft, roleLabel) }),
|
|
2083
|
-
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("p", { className: "ah-right-kv", children: "\u5B83\u4F1A\u5148\u8BD5\u8DD1\uFF1A\u505A\u81EA\u6211\u4ECB\u7ECD\u3001\u642D\u8D77\u6B65\u7684\u5173\u6CE8\u4E0E\u8BAE\u7A0B\uFF0C\u6709\u4E8B\u4F1A\u5728\u8FD9\u4E2A\u7EBF\u7A0B\u91CC\u627E\u4F60\u3002" })
|
|
2084
|
-
] }) : null
|
|
2085
|
-
] }),
|
|
2086
|
-
error ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("p", { className: "ah-settings-error", role: "alert", children: error }) : null,
|
|
2087
|
-
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("footer", { className: "ah-dialog-actions", children: [
|
|
2088
|
-
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("button", { type: "button", className: "ah-btn", onClick: () => go(-1), disabled: draft.step === 0 || submitting, children: "\u4E0A\u4E00\u6B65" }),
|
|
2089
|
-
draft.step < 5 ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("button", { type: "button", className: "ah-btn ah-btn-primary", onClick: () => go(1), disabled: full, children: "\u4E0B\u4E00\u6B65" }) : /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("button", { type: "button", className: "ah-btn ah-btn-primary", onClick: () => void submit(), disabled: submitting || full, children: submitting ? "\u4E0A\u5C97\u4E2D\u2026" : "\u8BA9\u5B83\u4E0A\u5C97" })
|
|
2090
|
-
] })
|
|
2091
|
-
] }) });
|
|
2092
|
-
}
|
|
2093
|
-
|
|
2094
|
-
// src/client/components/TeachDialog.tsx
|
|
2095
|
-
var import_react9 = require("react");
|
|
2096
|
-
var import_jsx_runtime11 = require("react/jsx-runtime");
|
|
2097
|
-
function TeachDialog(props) {
|
|
2098
|
-
const [query, setQuery] = (0, import_react9.useState)("");
|
|
2099
|
-
const [picked, setPicked] = (0, import_react9.useState)("");
|
|
2100
|
-
const [note, setNote] = (0, import_react9.useState)("\u628A\u6211\u521A\u624D\u5728\u8FD9\u4E2A\u4F1A\u8BDD\u91CC\u505A\u7684\u4E8B\u5B66\u6210\u5957\u8DEF");
|
|
2101
|
-
const [busy, setBusy] = (0, import_react9.useState)(false);
|
|
2102
|
-
const [error, setError] = (0, import_react9.useState)(null);
|
|
2103
|
-
(0, import_react9.useEffect)(() => {
|
|
2104
|
-
if (props.sessions.length > 0 && picked === "") setPicked(props.sessions[0].sessionId);
|
|
2105
|
-
}, [props.sessions, picked]);
|
|
2106
|
-
const filtered = (0, import_react9.useMemo)(() => {
|
|
2107
|
-
const q = query.trim().toLowerCase();
|
|
2108
|
-
return q === "" ? [...props.sessions] : props.sessions.filter((s) => s.title.toLowerCase().includes(q));
|
|
2109
|
-
}, [props.sessions, query]);
|
|
2110
|
-
const teach = async () => {
|
|
2111
|
-
if (picked === "" || busy) return;
|
|
2112
|
-
setBusy(true);
|
|
2113
|
-
try {
|
|
2114
|
-
const message = await props.onTeach(picked, note);
|
|
2115
|
-
if (message !== null) setError(message);
|
|
2116
|
-
else props.onClose();
|
|
2117
|
-
} catch (e) {
|
|
2118
|
-
setError(e instanceof Error ? e.message : String(e));
|
|
2119
|
-
} finally {
|
|
2120
|
-
setBusy(false);
|
|
2121
|
-
}
|
|
2122
|
-
};
|
|
2123
|
-
return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "ah-dialog-mask", role: "dialog", "aria-label": `\u6559 ${props.botName} \u4E00\u62DB`, children: /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "ah-dialog ah-dialog-wide", children: [
|
|
2124
|
-
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("h3", { children: [
|
|
2125
|
-
"\u6559 ",
|
|
2126
|
-
props.botName,
|
|
2127
|
-
" \u4E00\u62DB"
|
|
2128
|
-
] }),
|
|
2129
|
-
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("p", { className: "ah-right-kv", children: "\u9009\u4E00\u4E2A\u4F60\u6700\u8FD1\u505A\u8FC7\u7684\u4F1A\u8BDD\uFF0C\u5B83\u4F1A\u8BFB\u8BB0\u5F55\u5199\u6210\u5957\u8DEF\uFF0C\u4EE5\u540E\u7167\u505A\uFF1B\u5B66\u5B8C\u4F1A\u5728\u7EBF\u7A0B\u91CC\u590D\u8FF0\u6B65\u9AA4\u8BF7\u4F60\u7EA0\u6B63\u3002" }),
|
|
2130
|
-
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("input", { className: "ah-teach-search", placeholder: "\u641C\u7D22\u4F1A\u8BDD\u6807\u9898", value: query, onChange: (e) => setQuery(e.target.value) }),
|
|
2131
|
-
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("ul", { className: "ah-teach-list", children: [
|
|
2132
|
-
filtered.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("li", { className: "ah-empty", children: "\u6CA1\u6709\u627E\u5230\u4F1A\u8BDD\u3002\u5148\u5728 DSH \u91CC\u505A\u4E00\u904D\uFF0C\u518D\u56DE\u6765\u6559\u5B83\u3002" }) : null,
|
|
2133
|
-
filtered.slice(0, 12).map((s) => /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("li", { children: /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("label", { className: picked === s.sessionId ? "ah-teach-picked" : "", children: [
|
|
2134
|
-
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("input", { type: "radio", name: "ah-teach-session", checked: picked === s.sessionId, onChange: () => setPicked(s.sessionId) }),
|
|
2135
|
-
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "ah-teach-title", children: s.title }),
|
|
2136
|
-
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "ah-right-kv", children: s.updatedText })
|
|
2137
|
-
] }) }, s.sessionId))
|
|
2138
|
-
] }),
|
|
2139
|
-
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("textarea", { className: "ah-teach-note", rows: 2, value: note, onChange: (e) => setNote(e.target.value), placeholder: "\u4E00\u53E5\u8BF4\u660E\uFF1A\u628A\u5B83\u5B66\u6210\u4EC0\u4E48\u5957\u8DEF" }),
|
|
2140
|
-
error ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("p", { className: "ah-settings-error", role: "alert", children: error }) : null,
|
|
2141
|
-
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "ah-dialog-actions", children: [
|
|
2142
|
-
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("button", { type: "button", className: "ah-btn", onClick: props.onClose, disabled: busy, children: "\u53D6\u6D88" }),
|
|
2143
|
-
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("button", { type: "button", className: "ah-btn ah-btn-primary", disabled: busy || picked === "", onClick: () => void teach(), children: busy ? "\u63D0\u4EA4\u4E2D\u2026" : "\u4EA4\u7ED9\u5B83\u5B66" })
|
|
2144
|
-
] })
|
|
2145
|
-
] }) });
|
|
2146
|
-
}
|
|
2147
|
-
|
|
2148
|
-
// src/client/components/ErrorBoundary.tsx
|
|
2149
|
-
var import_react10 = require("react");
|
|
2150
|
-
var import_jsx_runtime12 = require("react/jsx-runtime");
|
|
2151
|
-
var BlockBoundary = class extends import_react10.Component {
|
|
2152
|
-
constructor() {
|
|
2153
|
-
super(...arguments);
|
|
2154
|
-
__publicField(this, "state", { failed: false });
|
|
2155
|
-
}
|
|
2156
|
-
/** 出错只记日志、不出插槽崩溃。 */
|
|
2157
|
-
static getDerivedStateFromError() {
|
|
2158
|
-
return { failed: true };
|
|
2159
|
-
}
|
|
2160
|
-
componentDidCatch(error) {
|
|
2161
|
-
console.error(`[agent-hub] \u754C\u9762\u5757\u300C${this.props.label}\u300D\u6E32\u67D3\u51FA\u9519:`, error);
|
|
2162
|
-
}
|
|
2163
|
-
render() {
|
|
2164
|
-
if (this.state.failed) {
|
|
2165
|
-
return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "ah-empty", role: "alert", children: "\u8FD9\u5757\u6CA1\u663E\u793A\u51FA\u6765\uFF0C\u5237\u65B0\u8BD5\u8BD5\u3002" });
|
|
2166
|
-
}
|
|
2167
|
-
return this.props.children;
|
|
2168
|
-
}
|
|
2169
|
-
};
|
|
2170
|
-
|
|
2171
|
-
// src/client/pages/HubPage.tsx
|
|
2172
|
-
var import_jsx_runtime13 = require("react/jsx-runtime");
|
|
2173
|
-
function useSlowLoading(loading) {
|
|
2174
|
-
const [slow, setSlow] = (0, import_react11.useState)(false);
|
|
2175
|
-
(0, import_react11.useEffect)(() => {
|
|
2176
|
-
if (!loading) {
|
|
2177
|
-
setSlow(false);
|
|
2178
|
-
return;
|
|
2179
|
-
}
|
|
2180
|
-
const timer = setTimeout(() => setSlow(true), 300);
|
|
2181
|
-
return () => clearTimeout(timer);
|
|
2182
|
-
}, [loading]);
|
|
2183
|
-
return slow;
|
|
2184
|
-
}
|
|
2185
|
-
function HubPage(props) {
|
|
2186
|
-
const hub = props.hub;
|
|
2187
|
-
const state = useStore(hub);
|
|
2188
|
-
const [rightOpen, setRightOpen] = (0, import_react11.useState)(true);
|
|
2189
|
-
const [busyInboxId, setBusyInboxId] = (0, import_react11.useState)(null);
|
|
2190
|
-
const [threadError, setThreadError] = (0, import_react11.useState)(null);
|
|
2191
|
-
const [wizardOpen, setWizardOpen] = (0, import_react11.useState)(false);
|
|
2192
|
-
const [teachOpen, setTeachOpen] = (0, import_react11.useState)(false);
|
|
2193
|
-
const [notice, setNotice] = (0, import_react11.useState)(null);
|
|
2194
|
-
const [noticeAutoClearBot, setNoticeAutoClearBot] = (0, import_react11.useState)(null);
|
|
2195
|
-
const selectedThread = state.selectedThread;
|
|
2196
|
-
const view = state.view;
|
|
2197
|
-
(0, import_react11.useEffect)(() => {
|
|
2198
|
-
void hub.refreshAll();
|
|
2199
|
-
void hub.refreshSettings();
|
|
2200
|
-
}, [hub]);
|
|
2201
|
-
(0, import_react11.useEffect)(() => {
|
|
2202
|
-
if (state.connectionDown) return;
|
|
2203
|
-
setThreadError(null);
|
|
2204
|
-
void hub.refreshThread(selectedThread).catch(() => setThreadError("\u7EBF\u7A0B\u52A0\u8F7D\u5931\u8D25\uFF08\u63D2\u4EF6\u53EF\u80FD\u505C\u7528\u6216\u5728\u91CD\u8F7D\uFF09"));
|
|
2205
|
-
}, [hub, selectedThread, state.connectionDown]);
|
|
2206
|
-
const overview = state.overview;
|
|
2207
|
-
const selectedBot = overview?.bots.find((b) => b.id === selectedThread) ?? null;
|
|
2208
|
-
(0, import_react11.useEffect)(() => {
|
|
2209
|
-
if (selectedBot && !state.bots[selectedBot.id]) void hub.refreshBot(selectedBot.id);
|
|
2210
|
-
}, [hub, selectedBot, state.bots]);
|
|
2211
|
-
(0, import_react11.useEffect)(() => {
|
|
2212
|
-
if (teachOpen) void hub.refreshRecentSessions();
|
|
2213
|
-
}, [hub, teachOpen]);
|
|
2214
|
-
(0, import_react11.useEffect)(() => {
|
|
2215
|
-
if (noticeAutoClearBot === null || notice === null) return;
|
|
2216
|
-
const thread = state.threads[noticeAutoClearBot];
|
|
2217
|
-
if (thread?.messages.some((m) => m.kind === "reply")) {
|
|
2218
|
-
setNotice(null);
|
|
2219
|
-
setNoticeAutoClearBot(null);
|
|
2220
|
-
return;
|
|
2221
|
-
}
|
|
2222
|
-
const wakes = state.bots[noticeAutoClearBot]?.wakes;
|
|
2223
|
-
if (wakes !== void 0) {
|
|
2224
|
-
const trial = wakes.find((w) => w.variant === "trial");
|
|
2225
|
-
if (trial !== void 0 && !["delivering", "running"].includes(trial.status)) {
|
|
2226
|
-
setNotice(null);
|
|
2227
|
-
setNoticeAutoClearBot(null);
|
|
2228
|
-
}
|
|
2229
|
-
}
|
|
2230
|
-
}, [notice, noticeAutoClearBot, state.threads, state.bots]);
|
|
2231
|
-
(0, import_react11.useEffect)(() => {
|
|
2232
|
-
if (!state.connectionDown || state.downReason !== "starting") return;
|
|
2233
|
-
const timer = setInterval(() => {
|
|
2234
|
-
void hub.refreshAll().catch(() => void 0);
|
|
2235
|
-
void hub.refreshSettings().catch(() => void 0);
|
|
2236
|
-
}, 2e3);
|
|
2237
|
-
return () => clearInterval(timer);
|
|
2238
|
-
}, [hub, state.connectionDown, state.downReason]);
|
|
2239
|
-
const overviewLoading = overview === null;
|
|
2240
|
-
const showSkeleton = useSlowLoading(overviewLoading || view === "main" && state.threads[selectedThread] === void 0 && !threadError);
|
|
2241
|
-
const cardActions = {
|
|
2242
|
-
onPick: async (card, option, note) => {
|
|
2243
|
-
setBusyInboxId(card.inboxId);
|
|
2244
|
-
try {
|
|
2245
|
-
const submission = cardSubmission(card, option, note);
|
|
2246
|
-
if ("error" in submission) return submission.error;
|
|
2247
|
-
const result = await hub.command(submission.name, submission.input);
|
|
2248
|
-
if (!result.ok) return result.error;
|
|
2249
|
-
await Promise.all([hub.refreshInbox(), hub.refreshOverview()]);
|
|
2250
|
-
return null;
|
|
2251
|
-
} catch (e) {
|
|
2252
|
-
return e instanceof Error ? e.message : String(e);
|
|
2253
|
-
} finally {
|
|
2254
|
-
setBusyInboxId(null);
|
|
2255
|
-
}
|
|
2256
|
-
}
|
|
2257
|
-
};
|
|
2258
|
-
const header = selectedThread === "team" ? null : selectedBot ? {
|
|
2259
|
-
name: selectedBot.name,
|
|
2260
|
-
roleLabel: selectedBot.roleLabel,
|
|
2261
|
-
activityText: selectedBot.activityText,
|
|
2262
|
-
nextThinkText: selectedBot.nextThinkText,
|
|
2263
|
-
lifecycle: selectedBot.lifecycle,
|
|
2264
|
-
thinking: selectedBot.activity === "thinking"
|
|
2265
|
-
} : { name: state.threads[selectedThread]?.title ?? "\u961F\u53CB", roleLabel: null, activityText: null, nextThinkText: null, lifecycle: null, thinking: false };
|
|
2266
|
-
const interrupt = () => {
|
|
2267
|
-
if (!selectedBot) return;
|
|
2268
|
-
void (async () => {
|
|
2269
|
-
const result = await hub.command("interruptBot", { botId: selectedBot.id });
|
|
2270
|
-
setNotice(result.ok ? "\u5DF2\u6253\u65AD\uFF1B\u5B83\u4F1A\u5728\u4E0B\u6B21\u9192\u6765\u65F6\u63A5\u7740\u5904\u7406\u3002" : result.error);
|
|
2271
|
-
await Promise.all([hub.refreshThread(selectedBot.id), hub.refreshOverview()]);
|
|
2272
|
-
})();
|
|
2273
|
-
};
|
|
2274
|
-
const openSession = () => {
|
|
2275
|
-
const sessionId = selectedBot ? state.bots[selectedBot.id]?.profile.sessionId : null;
|
|
2276
|
-
if (!sessionId) {
|
|
2277
|
-
setNotice("\u5B83\u8FD8\u6CA1\u6709\u5DE5\u4F5C\u4F1A\u8BDD\u3002");
|
|
2278
|
-
return;
|
|
2279
|
-
}
|
|
2280
|
-
const result = openBotSessionWith(props.clientCtx, sessionId);
|
|
2281
|
-
setNotice(OPEN_SESSION_HINTS[result]);
|
|
2282
|
-
};
|
|
2283
|
-
const togglePause = () => {
|
|
2284
|
-
if (!selectedBot) return;
|
|
2285
|
-
const picked = pauseResumeAction(selectedBot.lifecycle);
|
|
2286
|
-
if (picked === null) return;
|
|
2287
|
-
const action = picked;
|
|
2288
|
-
void (async () => {
|
|
2289
|
-
const result = await hub.command("lifecycleAction", { botId: selectedBot.id, action });
|
|
2290
|
-
setNotice(result.ok ? action === "pause" ? "\u5DF2\u6682\u505C\uFF08\u671F\u95F4\u7684\u53D8\u5316\u90FD\u5B58\u7740\uFF09" : "\u5DF2\u6062\u590D" : result.error);
|
|
2291
|
-
await Promise.all([hub.refreshOverview(), hub.refreshBot(selectedBot.id)]);
|
|
2292
|
-
})();
|
|
2293
|
-
};
|
|
2294
|
-
const saveSettings = async (patch) => {
|
|
2295
|
-
const result = await hub.command("updateSettings", patch);
|
|
2296
|
-
if (result.ok) await hub.refreshSettings();
|
|
2297
|
-
return result.ok ? null : result.error;
|
|
2298
|
-
};
|
|
2299
|
-
const lifecycleAll = async (target) => {
|
|
2300
|
-
if (!overview) return "\u603B\u89C8\u8FD8\u6CA1\u52A0\u8F7D\u51FA\u6765\uFF0C\u7A0D\u7B49\u518D\u8BD5";
|
|
2301
|
-
const action = target === "paused" ? "pause" : "resume";
|
|
2302
|
-
const targets = lifecycleAllTargets(overview.bots, target).map((id) => overview.bots.find((b) => b.id === id));
|
|
2303
|
-
let failed = 0;
|
|
2304
|
-
for (const bot of targets) {
|
|
2305
|
-
const result = await hub.command("lifecycleAction", { botId: bot.id, action });
|
|
2306
|
-
if (!result.ok) failed += 1;
|
|
2307
|
-
}
|
|
2308
|
-
await hub.refreshOverview();
|
|
2309
|
-
return failed === 0 ? null : `\u6709 ${failed} \u4E2A\u961F\u53CB\u64CD\u4F5C\u6CA1\u6210\u529F\uFF0C\u518D\u8BD5\u4E00\u6B21\u6216\u5230\u5B83\u7684\u8BE6\u60C5\u91CC\u5355\u72EC\u64CD\u4F5C`;
|
|
2310
|
-
};
|
|
2311
|
-
if (state.connectionDown) {
|
|
2312
|
-
const hint = state.downReason === "disabled" ? "\u4E2D\u5FC3\u5DF2\u505C\u7528\uFF1A\u5220\u9664 ~/AgentHub/.hub/DISABLED \u540E\u91CD\u542F DSH \u5373\u53EF\u6062\u590D\u3002" : state.downReason === "starting" ? "\u4E2D\u5FC3\u6B63\u5728\u542F\u52A8\u2026\u2026\u7A0D\u7B49\u7247\u523B\u4F1A\u81EA\u52A8\u6062\u590D\u3002" : state.downReason === "failed" ? `\u4E2D\u5FC3\u542F\u52A8\u5931\u8D25\uFF1A${state.downMessage ?? "\u539F\u56E0\u672A\u77E5\uFF0C\u770B DSH \u65E5\u5FD7"}\u3002\u4FEE\u590D\u540E\u91CD\u542F DSH \u518D\u8BD5\u3002` : "\u8FDE\u4E0D\u4E0A Agent \u4E2D\u5FC3\uFF08\u63D2\u4EF6\u53EF\u80FD\u505C\u7528\u6216\u5728\u91CD\u8F7D\uFF09\u3002";
|
|
2313
|
-
return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "ah-page ah-page-down", "data-plugin-page": "agent-hub", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "ah-down", children: [
|
|
2314
|
-
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("p", { children: hint }),
|
|
2315
|
-
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("button", { type: "button", className: "ah-btn", onClick: () => void hub.refreshAll(), children: "\u91CD\u8BD5" })
|
|
2316
|
-
] }) });
|
|
2317
|
-
}
|
|
2318
|
-
return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "ah-page", "data-plugin-page": "agent-hub", children: [
|
|
2319
|
-
overview ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(BlockBoundary, { label: "\u9876\u680F", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
2320
|
-
TopBar,
|
|
2321
|
-
{
|
|
2322
|
-
overview,
|
|
2323
|
-
view,
|
|
2324
|
-
onOpenInbox: () => {
|
|
2325
|
-
hub.setView("inbox");
|
|
2326
|
-
void hub.refreshInbox();
|
|
2327
|
-
},
|
|
2328
|
-
onOpenActivity: () => {
|
|
2329
|
-
hub.setView("activity");
|
|
2330
|
-
void hub.refreshActivity();
|
|
2331
|
-
},
|
|
2332
|
-
onOpenSettings: () => {
|
|
2333
|
-
hub.setView("settings");
|
|
2334
|
-
void hub.refreshSettings();
|
|
2335
|
-
},
|
|
2336
|
-
onNewBot: () => setWizardOpen(true),
|
|
2337
|
-
onBack: () => hub.setView("main")
|
|
2338
|
-
}
|
|
2339
|
-
) }) : showSkeleton ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("header", { className: "ah-topbar", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Skeleton, { rows: 1 }) }) : null,
|
|
2340
|
-
wizardOpen && overview ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(BlockBoundary, { label: "\u65B0\u5EFA\u961F\u53CB", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
2341
|
-
NewBotWizard,
|
|
2342
|
-
{
|
|
2343
|
-
existingBots: overview.bots,
|
|
2344
|
-
modelOptions: state.settings?.modelOptions ?? [],
|
|
2345
|
-
modelOptionsError: state.settings ? null : state.settingsError,
|
|
2346
|
-
onCreate: async (input, color) => {
|
|
2347
|
-
const created = await hub.command("createBot", input);
|
|
2348
|
-
if (!created.ok) return { error: created.error };
|
|
2349
|
-
const botId = created.data?.id;
|
|
2350
|
-
if (botId === void 0) return { error: "\u521B\u5EFA\u6210\u529F\u4F46\u6CA1\u6709\u8FD4\u56DE\u673A\u5668\u4EBA id" };
|
|
2351
|
-
const colored = await hub.command("updateBot", { botId, patch: { color } });
|
|
2352
|
-
if (!colored.ok) console.error("[agent-hub] \u4FDD\u5B58\u5934\u50CF\u989C\u8272\u5931\u8D25:", colored.error);
|
|
2353
|
-
return { botId };
|
|
2354
|
-
},
|
|
2355
|
-
onOpenThread: (botId) => {
|
|
2356
|
-
setWizardOpen(false);
|
|
2357
|
-
hub.selectThread(botId);
|
|
2358
|
-
setNotice("\u6B63\u5728\u8BD5\u8DD1\uFF1A\u5B83\u4F1A\u5148\u505A\u81EA\u6211\u4ECB\u7ECD\uFF0C\u7A0D\u7B49\u7247\u523B\u3002");
|
|
2359
|
-
setNoticeAutoClearBot(botId);
|
|
2360
|
-
void hub.refreshOverview();
|
|
2361
|
-
},
|
|
2362
|
-
onClose: () => setWizardOpen(false)
|
|
2363
|
-
}
|
|
2364
|
-
) }) : null,
|
|
2365
|
-
teachOpen && selectedBot ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(BlockBoundary, { label: "\u6559\u5B83\u4E00\u62DB", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
2366
|
-
TeachDialog,
|
|
2367
|
-
{
|
|
2368
|
-
botName: selectedBot.name,
|
|
2369
|
-
sessions: state.recentSessions,
|
|
2370
|
-
onTeach: async (sessionId, note) => {
|
|
2371
|
-
const result = await hub.command("teach", { botId: selectedBot.id, sessionId, note });
|
|
2372
|
-
if (!result.ok) return result.error;
|
|
2373
|
-
setTeachOpen(false);
|
|
2374
|
-
await Promise.all([hub.refreshThread(selectedBot.id), hub.refreshBot(selectedBot.id)]);
|
|
2375
|
-
return null;
|
|
2376
|
-
},
|
|
2377
|
-
onClose: () => setTeachOpen(false)
|
|
2378
|
-
}
|
|
2379
|
-
) }) : null,
|
|
2380
|
-
/* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: `ah-body${rightOpen && selectedBot && view === "main" ? " ah-body-right" : ""}`, children: [
|
|
2381
|
-
overview ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(BlockBoundary, { label: "\u961F\u53CB\u5217\u8868", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
2382
|
-
BotList,
|
|
2383
|
-
{
|
|
2384
|
-
overview,
|
|
2385
|
-
selected: view === "main" ? selectedThread : "",
|
|
2386
|
-
onSelect: (threadId) => hub.selectThread(threadId),
|
|
2387
|
-
onOpenInbox: () => {
|
|
2388
|
-
hub.setView("inbox");
|
|
2389
|
-
void hub.refreshInbox();
|
|
2390
|
-
}
|
|
2391
|
-
}
|
|
2392
|
-
) }) : showSkeleton ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Skeleton, { rows: 6 }) : null,
|
|
2393
|
-
view === "inbox" ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(BlockBoundary, { label: "\u6536\u4EF6\u7BB1", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
2394
|
-
InboxPane,
|
|
2395
|
-
{
|
|
2396
|
-
inbox: state.inbox,
|
|
2397
|
-
loading: state.inbox === null,
|
|
2398
|
-
error: null,
|
|
2399
|
-
onRetry: () => void hub.refreshInbox(),
|
|
2400
|
-
actions: cardActions,
|
|
2401
|
-
busyId: busyInboxId
|
|
2402
|
-
}
|
|
2403
|
-
) }) : view === "activity" ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(BlockBoundary, { label: "\u6D3B\u52A8\u6D41", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
2404
|
-
ActivityPane,
|
|
2405
|
-
{
|
|
2406
|
-
activity: state.activity,
|
|
2407
|
-
bots: overview?.bots ?? [],
|
|
2408
|
-
loading: state.activity === null,
|
|
2409
|
-
onRetry: () => void hub.refreshActivity(),
|
|
2410
|
-
onLoadMore: () => {
|
|
2411
|
-
const last = state.activity?.rows.at(-1)?.id;
|
|
2412
|
-
if (last) void hub.refreshActivity(last);
|
|
2413
|
-
}
|
|
2414
|
-
}
|
|
2415
|
-
) }) : view === "settings" ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(BlockBoundary, { label: "\u8BBE\u7F6E", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
2416
|
-
SettingsPane,
|
|
2417
|
-
{
|
|
2418
|
-
settings: state.settings,
|
|
2419
|
-
loadError: state.settingsError,
|
|
2420
|
-
overview,
|
|
2421
|
-
loading: state.settings === null,
|
|
2422
|
-
onRetry: () => void hub.refreshSettings(),
|
|
2423
|
-
onSave: saveSettings,
|
|
2424
|
-
onPauseAll: () => lifecycleAll("paused"),
|
|
2425
|
-
onResumeAll: () => lifecycleAll("active")
|
|
2426
|
-
}
|
|
2427
|
-
) }) : /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(BlockBoundary, { label: "\u5BF9\u8BDD\u7EBF\u7A0B", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
2428
|
-
ThreadPane,
|
|
2429
|
-
{
|
|
2430
|
-
thread: state.threads[selectedThread] ?? null,
|
|
2431
|
-
loading: state.threads[selectedThread] === void 0,
|
|
2432
|
-
header,
|
|
2433
|
-
inputPlaceholderName: state.threads[selectedThread]?.title ?? "\u961F\u53CB",
|
|
2434
|
-
banner: notice,
|
|
2435
|
-
onBannerDismiss: () => {
|
|
2436
|
-
setNotice(null);
|
|
2437
|
-
setNoticeAutoClearBot(null);
|
|
2438
|
-
},
|
|
2439
|
-
onLoadEarlier: () => {
|
|
2440
|
-
const t = state.threads[selectedThread];
|
|
2441
|
-
if (t?.hasMore && t.oldestId) void hub.refreshThread(selectedThread, t.oldestId);
|
|
2442
|
-
},
|
|
2443
|
-
onSend: (text) => hub.send(selectedThread, text),
|
|
2444
|
-
actions: cardActions,
|
|
2445
|
-
busyInboxId,
|
|
2446
|
-
onRetry: () => void hub.refreshThread(selectedThread),
|
|
2447
|
-
error: threadError,
|
|
2448
|
-
onTeach: () => setTeachOpen(true),
|
|
2449
|
-
onOpenSession: openSession,
|
|
2450
|
-
onTogglePause: togglePause,
|
|
2451
|
-
onInterrupt: interrupt,
|
|
2452
|
-
rightCollapsed: view === "main" && !rightOpen && selectedBot !== null,
|
|
2453
|
-
onExpandRight: () => setRightOpen(true)
|
|
2454
|
-
},
|
|
2455
|
-
selectedThread
|
|
2456
|
-
) }),
|
|
2457
|
-
view === "main" && rightOpen ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(BlockBoundary, { label: "\u8BE6\u60C5", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
2458
|
-
RightPanel,
|
|
2459
|
-
{
|
|
2460
|
-
bot: selectedBot ? state.bots[selectedBot.id] ?? null : null,
|
|
2461
|
-
modelOptions: state.settings?.modelOptions ?? [],
|
|
2462
|
-
modelOptionsError: state.settings ? null : state.settingsError,
|
|
2463
|
-
onRetrySettings: () => void hub.refreshSettings(),
|
|
2464
|
-
clientCtx: props.clientCtx,
|
|
2465
|
-
run: (name, input) => hub.command(name, input),
|
|
2466
|
-
onRefresh: () => {
|
|
2467
|
-
if (selectedBot) void hub.refreshBot(selectedBot.id);
|
|
2468
|
-
void hub.refreshOverview();
|
|
2469
|
-
},
|
|
2470
|
-
onTeach: () => setTeachOpen(true),
|
|
2471
|
-
onCollapse: () => setRightOpen(false)
|
|
2472
|
-
},
|
|
2473
|
-
selectedBot?.id ?? "none"
|
|
2474
|
-
) }) : null
|
|
2475
|
-
] })
|
|
2476
|
-
] });
|
|
2477
|
-
}
|
|
2478
|
-
|
|
2479
|
-
// src/client/index.tsx
|
|
2480
|
-
var import_jsx_runtime14 = require("react/jsx-runtime");
|
|
2481
|
-
var inject = ["slots", "locale"];
|
|
2482
|
-
function HubEntryIcon(props) {
|
|
2483
|
-
const size = props.size ?? 16;
|
|
2484
|
-
return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("svg", { viewBox: "0 0 16 16", width: size, height: size, "aria-hidden": "true", className: "ah-entry-icon", children: [
|
|
2485
|
-
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)("circle", { cx: "5.5", cy: "5", r: "2.2", fill: "currentColor" }),
|
|
2486
|
-
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)("circle", { cx: "10.8", cy: "6.2", r: "1.7", fill: "currentColor", opacity: "0.85" }),
|
|
2487
|
-
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)("path", { d: "M1.8 13.2c0-2.1 1.7-3.6 3.7-3.6s3.7 1.5 3.7 3.6z", fill: "currentColor" }),
|
|
2488
|
-
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)("path", { d: "M9.9 13.2c0.2-1.7 1.2-2.9 2.7-2.9 1.2 0 2.2 0.8 2.5 2z", fill: "currentColor", opacity: "0.85" })
|
|
2489
|
-
] });
|
|
2490
|
-
}
|
|
2491
|
-
function HubToastOverlay(props) {
|
|
2492
|
-
const state = useStore(props.hub);
|
|
2493
|
-
if (state.toasts.length === 0) return null;
|
|
2494
|
-
return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { className: "ah-toast-layer", role: "status", children: state.toasts.map((toast) => /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { className: "ah-toast", children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
2495
|
-
"button",
|
|
2496
|
-
{
|
|
2497
|
-
type: "button",
|
|
2498
|
-
className: "ah-toast-btn",
|
|
2499
|
-
onClick: () => {
|
|
2500
|
-
props.hub.dismissToast(toast.id);
|
|
2501
|
-
props.hub.setView("inbox");
|
|
2502
|
-
void props.hub.refreshInbox();
|
|
2503
|
-
try {
|
|
2504
|
-
const layout = props.clientCtx?.get?.("layout");
|
|
2505
|
-
layout?.selectPanel?.("agent-hub");
|
|
2506
|
-
} catch {
|
|
2507
|
-
}
|
|
2508
|
-
},
|
|
2509
|
-
children: toast.text
|
|
2510
|
-
}
|
|
2511
|
-
) }, toast.id)) });
|
|
2512
|
-
}
|
|
2513
|
-
function apply(ctx) {
|
|
2514
|
-
const hub = createHubStore();
|
|
2515
|
-
try {
|
|
2516
|
-
ctx.effect(() => {
|
|
2517
|
-
const tag = document.createElement("style");
|
|
2518
|
-
tag.dataset.plugin = "dsh-buddy";
|
|
2519
|
-
tag.textContent = styles_default;
|
|
2520
|
-
document.head.appendChild(tag);
|
|
2521
|
-
return () => tag.remove();
|
|
2522
|
-
}, "dsh-buddy: styles");
|
|
2523
|
-
} catch (error) {
|
|
2524
|
-
console.error("[agent-hub] \u63D2\u5165\u6837\u5F0F\u5931\u8D25:", error);
|
|
2525
|
-
}
|
|
2526
|
-
try {
|
|
2527
|
-
ctx.effect(() => {
|
|
2528
|
-
const close = connectEvents(hub);
|
|
2529
|
-
void hub.refreshAll();
|
|
2530
|
-
return close;
|
|
2531
|
-
}, "dsh-buddy: sse");
|
|
2532
|
-
ctx.on("connection/reset", () => {
|
|
2533
|
-
void hub.refreshAll();
|
|
2534
|
-
});
|
|
2535
|
-
} catch (error) {
|
|
2536
|
-
console.error("[agent-hub] \u5EFA\u7ACB\u63A8\u9001\u8FDE\u63A5\u5931\u8D25:", error);
|
|
2537
|
-
}
|
|
2538
|
-
try {
|
|
2539
|
-
ctx.slots.inject("main", () => ctx.slots.register({ name: "main", key: "agent-hub" }, () => HubPage({ hub, clientCtx: ctx })));
|
|
2540
|
-
} catch (error) {
|
|
2541
|
-
console.error("[agent-hub] \u6CE8\u518C main \u63D2\u69FD\u5931\u8D25:", error);
|
|
2542
|
-
}
|
|
2543
|
-
try {
|
|
2544
|
-
ctx.slots.inject("sidebar.panellist", () => ctx.slots.register(
|
|
2545
|
-
// label 是 thunk:每次取值时从仓库读待处理收件箱数(入口行由宿主渲染)。
|
|
2546
|
-
{ name: "sidebar.panellist", id: "agent-hub", order: 15, label: () => entryLabel(hub.getSnapshot().overview?.inbox.total ?? 0) },
|
|
2547
|
-
(props) => HubEntryIcon(props ?? {})
|
|
2548
|
-
));
|
|
2549
|
-
} catch (error) {
|
|
2550
|
-
console.error("[agent-hub] \u6CE8\u518C\u4FA7\u680F\u5165\u53E3\u5931\u8D25:", error);
|
|
2551
|
-
}
|
|
2552
|
-
try {
|
|
2553
|
-
ctx.slots.inject("shell.overlay", () => ctx.slots.register(
|
|
2554
|
-
{ name: "shell.overlay", id: "dsh-buddy-toast", order: 100 },
|
|
2555
|
-
() => HubToastOverlay({ hub, clientCtx: ctx })
|
|
2556
|
-
));
|
|
2557
|
-
} catch (error) {
|
|
2558
|
-
console.error("[agent-hub] \u6CE8\u518C\u5E94\u7528\u5185\u63D0\u793A\u63D2\u69FD\u5931\u8D25:", error);
|
|
2559
|
-
}
|
|
2560
|
-
}
|
|
2561
|
-
return module.exports } })
|