@mhfire/dsh-im-bridge 0.1.3 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.en.md +114 -82
- package/README.md +114 -82
- package/cordis.patch.yml +83 -47
- package/lib/client.js +789 -153
- package/lib/client.js.map +1 -0
- package/lib/index.js +570 -0
- package/package.json +76 -43
- package/persona.default.en.md +22 -0
- package/persona.default.md +22 -0
- package/src/client/PluginCard.module.css +153 -0
- package/src/client/PluginCard.tsx +83 -0
- package/src/client/WecomCard.tsx +135 -0
- package/src/client/card-controller.ts +146 -0
- package/src/client/card-form.ts +293 -0
- package/src/client/css-modules.d.ts +4 -0
- package/src/client/fields.module.css +124 -0
- package/src/client/fields.tsx +112 -0
- package/src/client/index.ts +37 -0
- package/src/client/locales.ts +112 -0
- package/src/index.ts +542 -0
- package/src/wecom.ts +234 -0
- package/tsconfig.json +14 -0
- package/tsdown.client.ts +109 -0
- package/tsdown.host.ts +36 -0
- package/src/index.js +0 -272
- package/src/wecom.js +0 -111
package/lib/client.js
CHANGED
|
@@ -1,153 +1,789 @@
|
|
|
1
|
-
window.__ModuleLoader__.load({
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
function
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
1
|
+
window.__ModuleLoader__.load({
|
|
2
|
+
id: "@mhfire/dsh-im-bridge",
|
|
3
|
+
factory: (require) => {
|
|
4
|
+
var module = { exports: {} };
|
|
5
|
+
var exports = module.exports;
|
|
6
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
7
|
+
let react = require("react");
|
|
8
|
+
let _deepseek_ai_dsh_client_ui_primitives = require("@deepseek-ai/dsh-client-ui-primitives");
|
|
9
|
+
let react_jsx_runtime = require("react/jsx-runtime");
|
|
10
|
+
let _deepseek_ai_dsh_client_runtime_client = require("@deepseek-ai/dsh-client-runtime/client");
|
|
11
|
+
//#region \0dsh-css:C:\Users\user\Desktop\dsh-im-bridge\plugin\src\client\PluginCard.module.css.mjs
|
|
12
|
+
const css$1 = ".yj1zEa_card{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-3);border-radius:12px;list-style:none;transition:border-color .16s,background .16s}.yj1zEa_card:hover{border-color:var(--dsw-alias-label-dimmed)}.yj1zEa_cardOpen{background:var(--dsw-alias-bg-layer-2);border-color:var(--dsw-alias-label-dimmed)}.yj1zEa_header{appearance:none;width:100%;font:inherit;color:inherit;text-align:left;cursor:pointer;background:0 0;border:0;border-radius:12px;align-items:center;gap:12px;padding:14px 16px;display:flex}.yj1zEa_header:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:-2px}.yj1zEa_headText{flex-direction:column;flex:1;gap:4px;min-width:0;display:flex}.yj1zEa_name{color:var(--dsw-alias-label-primary);font-size:15px;font-weight:600;line-height:1.4}.yj1zEa_description{color:var(--dsw-alias-label-tertiary);font-size:13px;line-height:1.5}.yj1zEa_chevron{color:var(--dsw-alias-label-tertiary);flex:none;transition:transform .16s}.yj1zEa_chevronOpen{transform:rotate(180deg)}.yj1zEa_body{border-top:1px solid var(--dsw-alias-border-l2);margin:0 16px;padding-bottom:8px}.yj1zEa_readOnly{color:var(--dsw-alias-label-tertiary);margin:12px 0 0;font-size:12px;line-height:1.5}.yj1zEa_pending{white-space:nowrap;background:var(--dsw-alias-bg-module-platform);color:var(--dsw-alias-label-secondary);border-radius:999px;flex:none;padding:1px 8px;font-size:11px;font-weight:500;line-height:17px}.yj1zEa_footer{border-top:1px solid var(--dsw-alias-border-l2);justify-content:flex-end;align-items:center;gap:8px;padding:12px 0 4px;display:flex}.yj1zEa_failed{min-width:0;color:var(--dsw-alias-label-error);flex:1;margin:0;font-size:12px;line-height:1.5}.yj1zEa_discard,.yj1zEa_save{appearance:none;font:inherit;cursor:pointer;border:1px solid #0000;border-radius:8px;padding:5px 14px;font-size:13px;line-height:1.5}.yj1zEa_discard{border-color:var(--dsw-alias-border-l2);color:var(--dsw-alias-label-secondary);background:0 0}.yj1zEa_discard:hover:not(:disabled){color:var(--dsw-alias-label-primary);border-color:var(--dsw-alias-label-dimmed)}.yj1zEa_save{background:var(--dsw-alias-label-primary);color:var(--dsw-alias-bg-layer-3)}.yj1zEa_discard:disabled,.yj1zEa_save:disabled{opacity:.4;cursor:default}.yj1zEa_discard:focus-visible,.yj1zEa_save:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:1px}";
|
|
13
|
+
const tagId$1 = "@mhfire/dsh-im-bridge/PluginCard.module.css";
|
|
14
|
+
if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$1) + "]") === null) {
|
|
15
|
+
const tag = document.createElement("style");
|
|
16
|
+
tag.dataset.plugin = "@mhfire/dsh-im-bridge";
|
|
17
|
+
tag.dataset.pluginCss = tagId$1;
|
|
18
|
+
tag.textContent = css$1;
|
|
19
|
+
document.head.appendChild(tag);
|
|
20
|
+
}
|
|
21
|
+
var PluginCard_module_css_default = {
|
|
22
|
+
"body": "yj1zEa_body",
|
|
23
|
+
"card": "yj1zEa_card",
|
|
24
|
+
"cardOpen": "yj1zEa_cardOpen",
|
|
25
|
+
"chevron": "yj1zEa_chevron",
|
|
26
|
+
"chevronOpen": "yj1zEa_chevronOpen",
|
|
27
|
+
"description": "yj1zEa_description",
|
|
28
|
+
"discard": "yj1zEa_discard",
|
|
29
|
+
"failed": "yj1zEa_failed",
|
|
30
|
+
"footer": "yj1zEa_footer",
|
|
31
|
+
"headText": "yj1zEa_headText",
|
|
32
|
+
"header": "yj1zEa_header",
|
|
33
|
+
"name": "yj1zEa_name",
|
|
34
|
+
"pending": "yj1zEa_pending",
|
|
35
|
+
"readOnly": "yj1zEa_readOnly",
|
|
36
|
+
"save": "yj1zEa_save"
|
|
37
|
+
};
|
|
38
|
+
//#endregion
|
|
39
|
+
//#region src/client/PluginCard.tsx
|
|
40
|
+
/** Expandable plugin card chrome matching the Host Plugins section. */
|
|
41
|
+
/**
|
|
42
|
+
* Render one plugin card.
|
|
43
|
+
* @param props - locale copy, form state, and controls.
|
|
44
|
+
* @returns the card, or nothing when the namespace is unavailable.
|
|
45
|
+
*/
|
|
46
|
+
function PluginCard(props) {
|
|
47
|
+
const [open, setOpen] = (0, react.useState)(false);
|
|
48
|
+
const { state } = props;
|
|
49
|
+
if (!state.available) return null;
|
|
50
|
+
const title = props.t(props.titleKey);
|
|
51
|
+
const blocked = !state.dirty || state.invalid || state.saving;
|
|
52
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("li", {
|
|
53
|
+
className: open ? `${PluginCard_module_css_default.card} ${PluginCard_module_css_default.cardOpen}` : PluginCard_module_css_default.card,
|
|
54
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
55
|
+
type: "button",
|
|
56
|
+
className: PluginCard_module_css_default.header,
|
|
57
|
+
"aria-expanded": open,
|
|
58
|
+
"aria-label": `${props.t(open ? "collapse" : "expand")}: ${title}`,
|
|
59
|
+
onClick: () => {
|
|
60
|
+
setOpen((current) => !current);
|
|
61
|
+
},
|
|
62
|
+
children: [
|
|
63
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
64
|
+
className: PluginCard_module_css_default.headText,
|
|
65
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
66
|
+
className: PluginCard_module_css_default.name,
|
|
67
|
+
children: title
|
|
68
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
69
|
+
className: PluginCard_module_css_default.description,
|
|
70
|
+
children: props.t(props.descriptionKey)
|
|
71
|
+
})]
|
|
72
|
+
}),
|
|
73
|
+
state.dirty ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
74
|
+
className: PluginCard_module_css_default.pending,
|
|
75
|
+
children: props.t("unsaved")
|
|
76
|
+
}) : null,
|
|
77
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconChevronDownOutline14, { className: open ? `${PluginCard_module_css_default.chevron} ${PluginCard_module_css_default.chevronOpen}` : PluginCard_module_css_default.chevron })
|
|
78
|
+
]
|
|
79
|
+
}), open ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
80
|
+
className: PluginCard_module_css_default.body,
|
|
81
|
+
children: [
|
|
82
|
+
!state.writable ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
83
|
+
className: PluginCard_module_css_default.readOnly,
|
|
84
|
+
role: "status",
|
|
85
|
+
children: props.t("readOnly")
|
|
86
|
+
}) : null,
|
|
87
|
+
props.children,
|
|
88
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
89
|
+
className: PluginCard_module_css_default.footer,
|
|
90
|
+
children: [
|
|
91
|
+
state.failed ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
92
|
+
className: PluginCard_module_css_default.failed,
|
|
93
|
+
role: "status",
|
|
94
|
+
children: props.t("saveFailed")
|
|
95
|
+
}) : null,
|
|
96
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
97
|
+
type: "button",
|
|
98
|
+
className: PluginCard_module_css_default.discard,
|
|
99
|
+
disabled: !state.dirty || state.saving,
|
|
100
|
+
onClick: props.onDiscard,
|
|
101
|
+
children: props.t("discard")
|
|
102
|
+
}),
|
|
103
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
104
|
+
type: "button",
|
|
105
|
+
className: PluginCard_module_css_default.save,
|
|
106
|
+
disabled: blocked,
|
|
107
|
+
onClick: props.onSave,
|
|
108
|
+
children: props.t(state.saving ? "saving" : "save")
|
|
109
|
+
})
|
|
110
|
+
]
|
|
111
|
+
})
|
|
112
|
+
]
|
|
113
|
+
}) : null]
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
//#endregion
|
|
117
|
+
//#region \0dsh-css:C:\Users\user\Desktop\dsh-im-bridge\plugin\src\client\fields.module.css.mjs
|
|
118
|
+
const css = ".OMD7cq_field{flex-direction:column;gap:6px;padding:12px 0;display:flex}.OMD7cq_field+.OMD7cq_field{border-top:1px solid var(--dsw-alias-border-l2)}.OMD7cq_head{align-items:center;gap:8px;display:flex}.OMD7cq_label{min-width:0;color:var(--dsw-alias-label-primary);flex:1;font-size:13px;font-weight:500;line-height:1.5}.OMD7cq_badges{align-items:center;gap:8px;display:inline-flex}.OMD7cq_badge{white-space:nowrap;background:var(--dsw-alias-bg-module-platform);color:var(--dsw-alias-label-secondary);border-radius:999px;padding:1px 8px;font-size:11px;font-weight:500;line-height:17px}.OMD7cq_badgeMuted{white-space:nowrap;color:var(--dsw-alias-label-tertiary);border-radius:999px;padding:1px 8px;font-size:11px;line-height:17px}.OMD7cq_reset{font:inherit;color:var(--dsw-alias-label-secondary);cursor:pointer;background:0 0;border:none;padding:0;font-size:12px;line-height:1.5}.OMD7cq_reset:hover:not(:disabled){color:var(--dsw-alias-label-primary)}.OMD7cq_reset:disabled{cursor:default}.OMD7cq_input{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-3);height:34px;font:inherit;color:var(--dsw-alias-label-primary);border-radius:8px;padding:0 12px;font-size:13px;line-height:1.5}.OMD7cq_input:focus-visible{border-color:var(--dsw-alias-brand-primary);outline:none}.OMD7cq_input:disabled{color:var(--dsw-alias-label-tertiary);cursor:default}.OMD7cq_inputInvalid{border:1px solid var(--dsw-alias-label-error);background:var(--dsw-alias-bg-layer-3);height:34px;font:inherit;color:var(--dsw-alias-label-primary);border-radius:8px;padding:0 12px;font-size:13px;line-height:1.5}.OMD7cq_inputInvalid:focus-visible{outline:none}.OMD7cq_invalid{color:var(--dsw-alias-label-error);margin:0;font-size:12px;line-height:1.5}.OMD7cq_hint{color:var(--dsw-alias-label-tertiary);margin:0;font-size:12px;line-height:1.5}";
|
|
119
|
+
const tagId = "@mhfire/dsh-im-bridge/fields.module.css";
|
|
120
|
+
if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId) + "]") === null) {
|
|
121
|
+
const tag = document.createElement("style");
|
|
122
|
+
tag.dataset.plugin = "@mhfire/dsh-im-bridge";
|
|
123
|
+
tag.dataset.pluginCss = tagId;
|
|
124
|
+
tag.textContent = css;
|
|
125
|
+
document.head.appendChild(tag);
|
|
126
|
+
}
|
|
127
|
+
var fields_module_css_default = {
|
|
128
|
+
"badge": "OMD7cq_badge",
|
|
129
|
+
"badgeMuted": "OMD7cq_badgeMuted",
|
|
130
|
+
"badges": "OMD7cq_badges",
|
|
131
|
+
"field": "OMD7cq_field",
|
|
132
|
+
"head": "OMD7cq_head",
|
|
133
|
+
"hint": "OMD7cq_hint",
|
|
134
|
+
"input": "OMD7cq_input",
|
|
135
|
+
"inputInvalid": "OMD7cq_inputInvalid",
|
|
136
|
+
"invalid": "OMD7cq_invalid",
|
|
137
|
+
"label": "OMD7cq_label",
|
|
138
|
+
"reset": "OMD7cq_reset"
|
|
139
|
+
};
|
|
140
|
+
//#endregion
|
|
141
|
+
//#region src/client/fields.tsx
|
|
142
|
+
/**
|
|
143
|
+
* A staged value field.
|
|
144
|
+
* @param props - the field's copy, staged text, and edit actions.
|
|
145
|
+
* @returns the labelled control.
|
|
146
|
+
*/
|
|
147
|
+
function ValueField(props) {
|
|
148
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
149
|
+
className: fields_module_css_default.field,
|
|
150
|
+
children: [
|
|
151
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
152
|
+
className: fields_module_css_default.head,
|
|
153
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("label", {
|
|
154
|
+
className: fields_module_css_default.label,
|
|
155
|
+
htmlFor: props.id,
|
|
156
|
+
children: props.label
|
|
157
|
+
}), props.overridden ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
158
|
+
className: fields_module_css_default.badges,
|
|
159
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
160
|
+
className: fields_module_css_default.badge,
|
|
161
|
+
children: props.overriddenLabel
|
|
162
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
163
|
+
type: "button",
|
|
164
|
+
className: fields_module_css_default.reset,
|
|
165
|
+
disabled: props.disabled,
|
|
166
|
+
onClick: props.onReset,
|
|
167
|
+
children: props.resetLabel
|
|
168
|
+
})]
|
|
169
|
+
}) : null]
|
|
170
|
+
}),
|
|
171
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
172
|
+
id: props.id,
|
|
173
|
+
className: props.invalid ? fields_module_css_default.inputInvalid : fields_module_css_default.input,
|
|
174
|
+
type: "text",
|
|
175
|
+
...props.numeric === true ? { inputMode: "numeric" } : {},
|
|
176
|
+
...props.invalid ? { "aria-invalid": true } : {},
|
|
177
|
+
value: props.text,
|
|
178
|
+
disabled: props.disabled,
|
|
179
|
+
onChange: (event) => {
|
|
180
|
+
props.onEdit(event.target.value);
|
|
181
|
+
}
|
|
182
|
+
}),
|
|
183
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
184
|
+
className: props.invalid ? fields_module_css_default.invalid : fields_module_css_default.hint,
|
|
185
|
+
children: props.invalid ? props.invalidLabel : props.hint
|
|
186
|
+
})
|
|
187
|
+
]
|
|
188
|
+
});
|
|
189
|
+
}
|
|
190
|
+
/**
|
|
191
|
+
* Write-only credential control. The literal never rides a response, so the
|
|
192
|
+
* control starts blank and reports only whether one is configured.
|
|
193
|
+
* @param props - the field's copy, staged text, and configured state.
|
|
194
|
+
* @returns the labelled control.
|
|
195
|
+
*/
|
|
196
|
+
function SecretField(props) {
|
|
197
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
198
|
+
className: fields_module_css_default.field,
|
|
199
|
+
children: [
|
|
200
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
201
|
+
className: fields_module_css_default.head,
|
|
202
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("label", {
|
|
203
|
+
className: fields_module_css_default.label,
|
|
204
|
+
htmlFor: props.id,
|
|
205
|
+
children: props.label
|
|
206
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
207
|
+
className: fields_module_css_default.badges,
|
|
208
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
209
|
+
className: props.configured ? fields_module_css_default.badge : fields_module_css_default.badgeMuted,
|
|
210
|
+
children: props.stateLabel
|
|
211
|
+
})
|
|
212
|
+
})]
|
|
213
|
+
}),
|
|
214
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
215
|
+
id: props.id,
|
|
216
|
+
className: fields_module_css_default.input,
|
|
217
|
+
type: "password",
|
|
218
|
+
autoComplete: "off",
|
|
219
|
+
value: props.text,
|
|
220
|
+
disabled: props.disabled,
|
|
221
|
+
onChange: (event) => {
|
|
222
|
+
props.onEdit(event.target.value);
|
|
223
|
+
}
|
|
224
|
+
}),
|
|
225
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
226
|
+
className: fields_module_css_default.hint,
|
|
227
|
+
children: props.hint
|
|
228
|
+
})
|
|
229
|
+
]
|
|
230
|
+
});
|
|
231
|
+
}
|
|
232
|
+
//#endregion
|
|
233
|
+
//#region src/client/WecomCard.tsx
|
|
234
|
+
/**
|
|
235
|
+
* Render the WeCom settings card.
|
|
236
|
+
* @param props - locale copy, snapshot hook, and form actions.
|
|
237
|
+
* @returns the card, or nothing when the namespace is unavailable.
|
|
238
|
+
*/
|
|
239
|
+
function WecomCard(props) {
|
|
240
|
+
const { t } = props;
|
|
241
|
+
const state = props.useWecomCard((snapshot) => snapshot);
|
|
242
|
+
const disabled = !state.writable;
|
|
243
|
+
const field = {
|
|
244
|
+
overriddenLabel: t("overridden"),
|
|
245
|
+
resetLabel: t("reset"),
|
|
246
|
+
invalidLabel: t("invalidNumber"),
|
|
247
|
+
disabled
|
|
248
|
+
};
|
|
249
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(PluginCard, {
|
|
250
|
+
t,
|
|
251
|
+
titleKey: "title",
|
|
252
|
+
descriptionKey: "description",
|
|
253
|
+
state,
|
|
254
|
+
onSave: props.save,
|
|
255
|
+
onDiscard: props.discard,
|
|
256
|
+
children: [
|
|
257
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(SecretField, {
|
|
258
|
+
id: "im-bridge-botId",
|
|
259
|
+
label: t("botId"),
|
|
260
|
+
hint: t("secretHint"),
|
|
261
|
+
disabled,
|
|
262
|
+
text: state.botId.text,
|
|
263
|
+
configured: state.botIdConfigured,
|
|
264
|
+
stateLabel: state.botIdConfigured ? t("secretConfigured") : t("secretUnset"),
|
|
265
|
+
onEdit: (text) => {
|
|
266
|
+
props.edit("botId", text);
|
|
267
|
+
}
|
|
268
|
+
}),
|
|
269
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(SecretField, {
|
|
270
|
+
id: "im-bridge-secret",
|
|
271
|
+
label: t("secret"),
|
|
272
|
+
hint: t("secretHint"),
|
|
273
|
+
disabled,
|
|
274
|
+
text: state.secret.text,
|
|
275
|
+
configured: state.secretConfigured,
|
|
276
|
+
stateLabel: state.secretConfigured ? t("secretConfigured") : t("secretUnset"),
|
|
277
|
+
onEdit: (text) => {
|
|
278
|
+
props.edit("secret", text);
|
|
279
|
+
}
|
|
280
|
+
}),
|
|
281
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(ValueField, {
|
|
282
|
+
id: "im-bridge-allowFrom",
|
|
283
|
+
label: t("allowFrom"),
|
|
284
|
+
hint: t("allowFromHint"),
|
|
285
|
+
...field,
|
|
286
|
+
...state.allowFrom,
|
|
287
|
+
onEdit: (text) => {
|
|
288
|
+
props.edit("allowFrom", text);
|
|
289
|
+
},
|
|
290
|
+
onReset: () => {
|
|
291
|
+
props.resetField("allowFrom");
|
|
292
|
+
}
|
|
293
|
+
}),
|
|
294
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(ValueField, {
|
|
295
|
+
id: "im-bridge-agentTimeoutSec",
|
|
296
|
+
label: t("agentTimeoutSec"),
|
|
297
|
+
hint: t("agentTimeoutSecHint"),
|
|
298
|
+
numeric: true,
|
|
299
|
+
...field,
|
|
300
|
+
...state.agentTimeoutSec,
|
|
301
|
+
onEdit: (text) => {
|
|
302
|
+
props.edit("agentTimeoutSec", text);
|
|
303
|
+
},
|
|
304
|
+
onReset: () => {
|
|
305
|
+
props.resetField("agentTimeoutSec");
|
|
306
|
+
}
|
|
307
|
+
}),
|
|
308
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(ValueField, {
|
|
309
|
+
id: "im-bridge-startHint",
|
|
310
|
+
label: t("startHint"),
|
|
311
|
+
hint: t("startHintHint"),
|
|
312
|
+
...field,
|
|
313
|
+
...state.startHint,
|
|
314
|
+
onEdit: (text) => {
|
|
315
|
+
props.edit("startHint", text);
|
|
316
|
+
},
|
|
317
|
+
onReset: () => {
|
|
318
|
+
props.resetField("startHint");
|
|
319
|
+
}
|
|
320
|
+
}),
|
|
321
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(ValueField, {
|
|
322
|
+
id: "im-bridge-deniedMessage",
|
|
323
|
+
label: t("deniedMessage"),
|
|
324
|
+
hint: t("deniedMessageHint"),
|
|
325
|
+
...field,
|
|
326
|
+
...state.deniedMessage,
|
|
327
|
+
onEdit: (text) => {
|
|
328
|
+
props.edit("deniedMessage", text);
|
|
329
|
+
},
|
|
330
|
+
onReset: () => {
|
|
331
|
+
props.resetField("deniedMessage");
|
|
332
|
+
}
|
|
333
|
+
}),
|
|
334
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(ValueField, {
|
|
335
|
+
id: "im-bridge-welcomeMessage",
|
|
336
|
+
label: t("welcomeMessage"),
|
|
337
|
+
hint: t("welcomeMessageHint"),
|
|
338
|
+
...field,
|
|
339
|
+
...state.welcomeMessage,
|
|
340
|
+
onEdit: (text) => {
|
|
341
|
+
props.edit("welcomeMessage", text);
|
|
342
|
+
},
|
|
343
|
+
onReset: () => {
|
|
344
|
+
props.resetField("welcomeMessage");
|
|
345
|
+
}
|
|
346
|
+
}),
|
|
347
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(ValueField, {
|
|
348
|
+
id: "im-bridge-provider",
|
|
349
|
+
label: t("provider"),
|
|
350
|
+
hint: t("providerHint"),
|
|
351
|
+
...field,
|
|
352
|
+
...state.provider,
|
|
353
|
+
onEdit: (text) => {
|
|
354
|
+
props.edit("provider", text);
|
|
355
|
+
},
|
|
356
|
+
onReset: () => {
|
|
357
|
+
props.resetField("provider");
|
|
358
|
+
}
|
|
359
|
+
}),
|
|
360
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(ValueField, {
|
|
361
|
+
id: "im-bridge-model",
|
|
362
|
+
label: t("model"),
|
|
363
|
+
hint: t("modelHint"),
|
|
364
|
+
...field,
|
|
365
|
+
...state.model,
|
|
366
|
+
onEdit: (text) => {
|
|
367
|
+
props.edit("model", text);
|
|
368
|
+
},
|
|
369
|
+
onReset: () => {
|
|
370
|
+
props.resetField("model");
|
|
371
|
+
}
|
|
372
|
+
})
|
|
373
|
+
]
|
|
374
|
+
});
|
|
375
|
+
}
|
|
376
|
+
//#endregion
|
|
377
|
+
//#region src/client/card-form.ts
|
|
378
|
+
/**
|
|
379
|
+
* Staged settings form owned by this plugin.
|
|
380
|
+
* Mirrors the Host Plugins section model without importing its chrome.
|
|
381
|
+
*/
|
|
382
|
+
/** Whole-number field. Empty draft clears. */
|
|
383
|
+
function numberField(field) {
|
|
384
|
+
return {
|
|
385
|
+
field,
|
|
386
|
+
format: (value) => typeof value === "number" ? String(value) : "",
|
|
387
|
+
parse: (text) => {
|
|
388
|
+
const trimmed = text.trim();
|
|
389
|
+
if (trimmed === "") return { kind: "clear" };
|
|
390
|
+
const parsed = Number(trimmed);
|
|
391
|
+
return Number.isFinite(parsed) ? {
|
|
392
|
+
kind: "set",
|
|
393
|
+
value: parsed
|
|
394
|
+
} : void 0;
|
|
395
|
+
}
|
|
396
|
+
};
|
|
397
|
+
}
|
|
398
|
+
/** Free-text field. Empty draft clears. */
|
|
399
|
+
function textField(field) {
|
|
400
|
+
return {
|
|
401
|
+
field,
|
|
402
|
+
format: (value) => typeof value === "string" ? value : "",
|
|
403
|
+
parse: (text) => {
|
|
404
|
+
const trimmed = text.trim();
|
|
405
|
+
return trimmed === "" ? { kind: "clear" } : {
|
|
406
|
+
kind: "set",
|
|
407
|
+
value: trimmed
|
|
408
|
+
};
|
|
409
|
+
}
|
|
410
|
+
};
|
|
411
|
+
}
|
|
412
|
+
/** Comma-separated string list. Empty draft stores []. */
|
|
413
|
+
function csvField(field) {
|
|
414
|
+
return {
|
|
415
|
+
field,
|
|
416
|
+
format: (value) => Array.isArray(value) ? value.join(",") : "",
|
|
417
|
+
parse: (text) => {
|
|
418
|
+
return {
|
|
419
|
+
kind: "set",
|
|
420
|
+
value: text.split(",").map((item) => item.trim()).filter(Boolean)
|
|
421
|
+
};
|
|
422
|
+
}
|
|
423
|
+
};
|
|
424
|
+
}
|
|
425
|
+
/** Stages edits over one settings namespace and writes them on save. */
|
|
426
|
+
var CardForm = class {
|
|
427
|
+
scope;
|
|
428
|
+
specs;
|
|
429
|
+
secretSpecs;
|
|
430
|
+
staged = /* @__PURE__ */ new Map();
|
|
431
|
+
listeners = /* @__PURE__ */ new Set();
|
|
432
|
+
saving = false;
|
|
433
|
+
failed = false;
|
|
434
|
+
/**
|
|
435
|
+
* @param scope - bound settings scope for this card's namespace.
|
|
436
|
+
* @param specs - section fields this card edits.
|
|
437
|
+
* @param secrets - write-only controls; a blank draft is a no-op.
|
|
438
|
+
*/
|
|
439
|
+
constructor(scope, specs, secrets = []) {
|
|
440
|
+
this.scope = scope;
|
|
441
|
+
this.specs = new Map(specs.map((spec) => [spec.field, spec]));
|
|
442
|
+
this.secretSpecs = new Map(secrets.map((spec) => [spec.field, spec]));
|
|
443
|
+
scope.subscribe(() => {
|
|
444
|
+
this.publish();
|
|
445
|
+
});
|
|
446
|
+
}
|
|
447
|
+
/** Publish a projection rebuilt whenever the scope or a draft changes. */
|
|
448
|
+
bind(project) {
|
|
449
|
+
const store = (0, _deepseek_ai_dsh_client_runtime_client.createSnapshotStore)(project());
|
|
450
|
+
this.listeners.add(() => {
|
|
451
|
+
store.set(project());
|
|
452
|
+
});
|
|
453
|
+
return store;
|
|
454
|
+
}
|
|
455
|
+
/** Card-level state: what the Host serves and what a save would do. */
|
|
456
|
+
shell() {
|
|
457
|
+
const snapshot = this.scope.getSnapshot();
|
|
458
|
+
const plan = this.plan();
|
|
459
|
+
return {
|
|
460
|
+
available: snapshot.status === "ready",
|
|
461
|
+
writable: snapshot.writable,
|
|
462
|
+
dirty: plan.length > 0,
|
|
463
|
+
invalid: plan.some((item) => item.run === void 0),
|
|
464
|
+
saving: this.saving,
|
|
465
|
+
failed: this.failed
|
|
466
|
+
};
|
|
467
|
+
}
|
|
468
|
+
/** One control's staged text, override badge, and validity. */
|
|
469
|
+
field(field) {
|
|
470
|
+
const staged = this.staged.get(field);
|
|
471
|
+
if (this.secretSpecs.has(field)) return {
|
|
472
|
+
text: staged?.text ?? "",
|
|
473
|
+
overridden: false,
|
|
474
|
+
invalid: false
|
|
475
|
+
};
|
|
476
|
+
const spec = this.spec(field);
|
|
477
|
+
if (staged === void 0) return {
|
|
478
|
+
text: spec.format(this.sectionValue(field)),
|
|
479
|
+
overridden: this.stored(field),
|
|
480
|
+
invalid: false
|
|
481
|
+
};
|
|
482
|
+
const write = staged.clear ? { kind: "clear" } : spec.parse(staged.text);
|
|
483
|
+
return {
|
|
484
|
+
text: staged.text,
|
|
485
|
+
overridden: write?.kind === "set",
|
|
486
|
+
invalid: write === void 0
|
|
487
|
+
};
|
|
488
|
+
}
|
|
489
|
+
/** Edit, reset, save, and discard actions bound to this form. */
|
|
490
|
+
actions() {
|
|
491
|
+
return {
|
|
492
|
+
edit: (field, text) => {
|
|
493
|
+
this.stage(field, {
|
|
494
|
+
text,
|
|
495
|
+
clear: false
|
|
496
|
+
});
|
|
497
|
+
},
|
|
498
|
+
resetField: (field) => {
|
|
499
|
+
this.stage(field, {
|
|
500
|
+
text: this.spec(field).format(this.baseValue(field)),
|
|
501
|
+
clear: true
|
|
502
|
+
});
|
|
503
|
+
},
|
|
504
|
+
save: () => {
|
|
505
|
+
this.save();
|
|
506
|
+
},
|
|
507
|
+
discard: () => {
|
|
508
|
+
if (this.staged.size === 0 && !this.failed) return;
|
|
509
|
+
this.staged.clear();
|
|
510
|
+
this.failed = false;
|
|
511
|
+
this.publish();
|
|
512
|
+
}
|
|
513
|
+
};
|
|
514
|
+
}
|
|
515
|
+
/** Write every staged edit, then re-seed from what the Host accepted. */
|
|
516
|
+
async save() {
|
|
517
|
+
const plan = this.plan();
|
|
518
|
+
const writes = plan.flatMap((item) => item.run === void 0 ? [] : [item.run]);
|
|
519
|
+
if (plan.length === 0 || this.saving || writes.length !== plan.length) return;
|
|
520
|
+
this.saving = true;
|
|
521
|
+
this.failed = false;
|
|
522
|
+
this.publish();
|
|
523
|
+
let landed = true;
|
|
524
|
+
for (const write of writes) landed = await write() && landed;
|
|
525
|
+
if (landed) this.staged.clear();
|
|
526
|
+
this.saving = false;
|
|
527
|
+
this.failed = !landed;
|
|
528
|
+
this.publish();
|
|
529
|
+
}
|
|
530
|
+
plan() {
|
|
531
|
+
const plan = [];
|
|
532
|
+
for (const [field, staged] of this.staged) {
|
|
533
|
+
const secret = this.secretSpecs.get(field);
|
|
534
|
+
if (secret !== void 0) {
|
|
535
|
+
const value = staged.text.trim();
|
|
536
|
+
if (value !== "") plan.push({
|
|
537
|
+
field,
|
|
538
|
+
run: () => secret.write(value)
|
|
539
|
+
});
|
|
540
|
+
continue;
|
|
541
|
+
}
|
|
542
|
+
const spec = this.spec(field);
|
|
543
|
+
if (staged.clear) {
|
|
544
|
+
if (this.stored(field)) plan.push({
|
|
545
|
+
field,
|
|
546
|
+
run: () => this.clear(field)
|
|
547
|
+
});
|
|
548
|
+
continue;
|
|
549
|
+
}
|
|
550
|
+
if (staged.text === spec.format(this.sectionValue(field))) continue;
|
|
551
|
+
const write = spec.parse(staged.text);
|
|
552
|
+
if (write === void 0) plan.push({
|
|
553
|
+
field,
|
|
554
|
+
run: void 0
|
|
555
|
+
});
|
|
556
|
+
else if (write.kind === "clear") plan.push({
|
|
557
|
+
field,
|
|
558
|
+
run: () => this.clear(field)
|
|
559
|
+
});
|
|
560
|
+
else plan.push({
|
|
561
|
+
field,
|
|
562
|
+
run: () => this.store(field, write.value)
|
|
563
|
+
});
|
|
564
|
+
}
|
|
565
|
+
return plan;
|
|
566
|
+
}
|
|
567
|
+
async clear(field) {
|
|
568
|
+
await this.scope.unset(field);
|
|
569
|
+
return !this.stored(field);
|
|
570
|
+
}
|
|
571
|
+
async store(field, value) {
|
|
572
|
+
await this.scope.set(field, value);
|
|
573
|
+
return this.userLayer()?.[field] === value || Array.isArray(value) && JSON.stringify(this.userLayer()?.[field]) === JSON.stringify(value);
|
|
574
|
+
}
|
|
575
|
+
stage(field, edit) {
|
|
576
|
+
this.staged.set(field, edit);
|
|
577
|
+
this.failed = false;
|
|
578
|
+
this.publish();
|
|
579
|
+
}
|
|
580
|
+
spec(field) {
|
|
581
|
+
const spec = this.specs.get(field);
|
|
582
|
+
if (spec === void 0) throw new Error(`im-bridge card has no field ${field}`);
|
|
583
|
+
return spec;
|
|
584
|
+
}
|
|
585
|
+
snapshotOf() {
|
|
586
|
+
return this.scope.getSnapshot();
|
|
587
|
+
}
|
|
588
|
+
sectionValue(field) {
|
|
589
|
+
return this.snapshotOf().value?.[field];
|
|
590
|
+
}
|
|
591
|
+
baseValue(field) {
|
|
592
|
+
return this.snapshotOf().base?.[field];
|
|
593
|
+
}
|
|
594
|
+
userLayer() {
|
|
595
|
+
return this.snapshotOf().user;
|
|
596
|
+
}
|
|
597
|
+
stored(field) {
|
|
598
|
+
const user = this.userLayer();
|
|
599
|
+
return user !== void 0 && Object.hasOwn(user, field);
|
|
600
|
+
}
|
|
601
|
+
publish() {
|
|
602
|
+
for (const listener of this.listeners) listener();
|
|
603
|
+
}
|
|
604
|
+
};
|
|
605
|
+
//#endregion
|
|
606
|
+
//#region src/client/card-controller.ts
|
|
607
|
+
/** Settings namespace paired with this card. */
|
|
608
|
+
const NS$1 = "im-bridge";
|
|
609
|
+
/** Bridges the `im-bridge` scope onto the staged card form. */
|
|
610
|
+
var WecomCardController = class {
|
|
611
|
+
scope;
|
|
612
|
+
describe;
|
|
613
|
+
form;
|
|
614
|
+
store;
|
|
615
|
+
/**
|
|
616
|
+
* @param scope - bound settings scope for the `im-bridge` namespace.
|
|
617
|
+
* @param describe - Host describe face; secret literals never ride it.
|
|
618
|
+
*/
|
|
619
|
+
constructor(scope, describe) {
|
|
620
|
+
this.scope = scope;
|
|
621
|
+
this.describe = describe;
|
|
622
|
+
this.form = new CardForm(scope, [
|
|
623
|
+
csvField("allowFrom"),
|
|
624
|
+
numberField("agentTimeoutSec"),
|
|
625
|
+
textField("startHint"),
|
|
626
|
+
textField("deniedMessage"),
|
|
627
|
+
textField("welcomeMessage"),
|
|
628
|
+
textField("provider"),
|
|
629
|
+
textField("model")
|
|
630
|
+
], [{
|
|
631
|
+
field: "botId",
|
|
632
|
+
write: (text) => this.writeSecret("botId", text)
|
|
633
|
+
}, {
|
|
634
|
+
field: "secret",
|
|
635
|
+
write: (text) => this.writeSecret("secret", text)
|
|
636
|
+
}]);
|
|
637
|
+
this.store = this.form.bind(() => this.projection());
|
|
638
|
+
}
|
|
639
|
+
projection() {
|
|
640
|
+
return {
|
|
641
|
+
...this.form.shell(),
|
|
642
|
+
botId: this.form.field("botId"),
|
|
643
|
+
secret: this.form.field("secret"),
|
|
644
|
+
botIdConfigured: this.secretConfigured("botId"),
|
|
645
|
+
secretConfigured: this.secretConfigured("secret"),
|
|
646
|
+
allowFrom: this.form.field("allowFrom"),
|
|
647
|
+
agentTimeoutSec: this.form.field("agentTimeoutSec"),
|
|
648
|
+
startHint: this.form.field("startHint"),
|
|
649
|
+
deniedMessage: this.form.field("deniedMessage"),
|
|
650
|
+
welcomeMessage: this.form.field("welcomeMessage"),
|
|
651
|
+
provider: this.form.field("provider"),
|
|
652
|
+
model: this.form.field("model")
|
|
653
|
+
};
|
|
654
|
+
}
|
|
655
|
+
/**
|
|
656
|
+
* Whether the Host reports a configured value for one secret slot.
|
|
657
|
+
* @param field - `botId` or `secret`.
|
|
658
|
+
* @returns true when describe lists that slot as set.
|
|
659
|
+
*/
|
|
660
|
+
secretConfigured(field) {
|
|
661
|
+
return (this.describe.getSnapshot().view?.namespaces.find((candidate) => candidate.ns === NS$1))?.secrets.some((slot) => slot.path[0] === field && slot.set) === true;
|
|
662
|
+
}
|
|
663
|
+
/**
|
|
664
|
+
* Write one credential into the user layer, then read configured state back.
|
|
665
|
+
* @param field - `botId` or `secret`.
|
|
666
|
+
* @param text - the staged literal.
|
|
667
|
+
* @returns whether describe reports the slot set afterwards.
|
|
668
|
+
*/
|
|
669
|
+
async writeSecret(field, text) {
|
|
670
|
+
await this.scope.set(field, text);
|
|
671
|
+
return this.secretConfigured(field);
|
|
672
|
+
}
|
|
673
|
+
/** Face the slot registration injects. */
|
|
674
|
+
inject() {
|
|
675
|
+
return {
|
|
676
|
+
hooks: { wecomCard: this.store },
|
|
677
|
+
...this.form.actions()
|
|
678
|
+
};
|
|
679
|
+
}
|
|
680
|
+
};
|
|
681
|
+
//#endregion
|
|
682
|
+
//#region src/client/locales.ts
|
|
683
|
+
/** English copy for the im-bridge card. */
|
|
684
|
+
const en = {
|
|
685
|
+
title: "WeCom Bridge",
|
|
686
|
+
description: "Credentials, allow-list, timeouts, and WeCom-only model overrides.",
|
|
687
|
+
unsaved: "Unsaved",
|
|
688
|
+
readOnly: "This document is read-only.",
|
|
689
|
+
saveFailed: "Save did not land. Correct the fields and try again.",
|
|
690
|
+
save: "Save",
|
|
691
|
+
saving: "Saving…",
|
|
692
|
+
discard: "Discard",
|
|
693
|
+
expand: "Show settings",
|
|
694
|
+
collapse: "Hide settings",
|
|
695
|
+
overridden: "Overridden",
|
|
696
|
+
reset: "Reset",
|
|
697
|
+
invalidNumber: "Enter a finite number.",
|
|
698
|
+
botId: "Bot ID",
|
|
699
|
+
secret: "Secret",
|
|
700
|
+
secretHint: "Leave blank to keep the stored value. Save, then restart the process to open the WebSocket.",
|
|
701
|
+
secretConfigured: "Configured",
|
|
702
|
+
secretUnset: "Not configured",
|
|
703
|
+
allowFrom: "Allowed sender userids",
|
|
704
|
+
allowFromHint: "Comma-separated. Empty allows everyone.",
|
|
705
|
+
agentTimeoutSec: "Task timeout (seconds)",
|
|
706
|
+
agentTimeoutSecHint: "Progress bar and remaining-time estimate.",
|
|
707
|
+
startHint: "Placeholder while thinking",
|
|
708
|
+
startHintHint: "First stream line after a message arrives.",
|
|
709
|
+
deniedMessage: "Denied-sender reply",
|
|
710
|
+
deniedMessageHint: "Sent when the userid is outside the allow-list.",
|
|
711
|
+
welcomeMessage: "Welcome message",
|
|
712
|
+
welcomeMessageHint: "Sent when a user opens the WeCom chat.",
|
|
713
|
+
provider: "WeCom-only provider",
|
|
714
|
+
providerHint: "Empty follows the GUI default model. Both provider and model must be set to override.",
|
|
715
|
+
model: "WeCom-only model",
|
|
716
|
+
modelHint: "Takes effect only together with provider."
|
|
717
|
+
};
|
|
718
|
+
/** Chinese copy for the im-bridge card. */
|
|
719
|
+
const zh = {
|
|
720
|
+
title: "企业微信桥接",
|
|
721
|
+
description: "凭证、白名单、超时和企微专用模型覆盖。",
|
|
722
|
+
unsaved: "未保存",
|
|
723
|
+
readOnly: "当前文档不可写。",
|
|
724
|
+
saveFailed: "保存未生效,请修正后重试。",
|
|
725
|
+
save: "保存",
|
|
726
|
+
saving: "保存中…",
|
|
727
|
+
discard: "放弃",
|
|
728
|
+
expand: "展开设置",
|
|
729
|
+
collapse: "收起设置",
|
|
730
|
+
overridden: "已覆盖",
|
|
731
|
+
reset: "重置",
|
|
732
|
+
invalidNumber: "请输入有效数字。",
|
|
733
|
+
botId: "Bot ID",
|
|
734
|
+
secret: "Secret",
|
|
735
|
+
secretHint: "留空保留已存值。保存后需重启进程才会连 WebSocket。",
|
|
736
|
+
secretConfigured: "已配置",
|
|
737
|
+
secretUnset: "未配置",
|
|
738
|
+
allowFrom: "允许的发送者 userid",
|
|
739
|
+
allowFromHint: "逗号分隔;空 = 允许所有人。",
|
|
740
|
+
agentTimeoutSec: "单任务超时(秒)",
|
|
741
|
+
agentTimeoutSecHint: "动画进度条和剩余估算的基准。",
|
|
742
|
+
startHint: "开始处理时的占位提示",
|
|
743
|
+
startHintHint: "收到消息后推送的第一条流式文案。",
|
|
744
|
+
deniedMessage: "非白名单拒绝文案",
|
|
745
|
+
deniedMessageHint: "发送者不在白名单时回复。",
|
|
746
|
+
welcomeMessage: "进入会话欢迎语",
|
|
747
|
+
welcomeMessageHint: "用户打开企微会话时发送。",
|
|
748
|
+
provider: "企微专用 provider",
|
|
749
|
+
providerHint: "空 = 跟随 GUI 默认模型。须与 model 同时填写才覆盖。",
|
|
750
|
+
model: "企微专用 model",
|
|
751
|
+
modelHint: "仅在同时填写 provider 时生效。"
|
|
752
|
+
};
|
|
753
|
+
//#endregion
|
|
754
|
+
//#region src/client/index.ts
|
|
755
|
+
/** Settings namespace shared with the Host half. */
|
|
756
|
+
const NS = "im-bridge";
|
|
757
|
+
/** Required browser services. */
|
|
758
|
+
const inject = [
|
|
759
|
+
"slots",
|
|
760
|
+
"locale",
|
|
761
|
+
"connection",
|
|
762
|
+
"remote",
|
|
763
|
+
"settingsScope"
|
|
764
|
+
];
|
|
765
|
+
/**
|
|
766
|
+
* Register locale copy and the Plugins-tab card.
|
|
767
|
+
* @param ctx - browser plugin context.
|
|
768
|
+
*/
|
|
769
|
+
function apply(ctx) {
|
|
770
|
+
const card = new WecomCardController(ctx.settingsScope.bind({ namespace: NS }), ctx.settingsScope.describe());
|
|
771
|
+
ctx.effect(() => ctx.locale.register(NS, {
|
|
772
|
+
zh,
|
|
773
|
+
en
|
|
774
|
+
}), "im-bridge: locale dicts");
|
|
775
|
+
ctx.slots.inject("settings.plugin.item", () => ctx.slots.register({
|
|
776
|
+
name: "settings.plugin.item",
|
|
777
|
+
key: NS,
|
|
778
|
+
locale: NS,
|
|
779
|
+
inject: () => card.inject()
|
|
780
|
+
}, WecomCard));
|
|
781
|
+
}
|
|
782
|
+
//#endregion
|
|
783
|
+
exports.apply = apply;
|
|
784
|
+
exports.inject = inject;
|
|
785
|
+
return module.exports;
|
|
786
|
+
}
|
|
787
|
+
});
|
|
788
|
+
|
|
789
|
+
//# sourceMappingURL=client.js.map
|