@mhfire/dsh-im-bridge 0.3.0 → 0.4.3
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 +220 -174
- package/README.md +220 -174
- package/cordis.patch.yml +89 -83
- package/lib/client.js +128 -12
- package/lib/client.js.map +1 -1
- package/lib/index.js +8093 -33
- package/package.json +94 -77
- package/src/client/WecomCard.tsx +75 -0
- package/src/client/card-controller.ts +76 -2
- package/src/client/card-form.ts +7 -6
- package/src/client/fields.module.css +32 -0
- package/src/client/fields.tsx +3 -1
- package/src/client/index.ts +9 -3
- package/src/client/locales.ts +23 -2
- package/src/index.ts +1099 -787
- package/src/session-key.ts +1 -0
- package/src/wecom-cli.ts +1015 -0
- package/tsdown.client.ts +1 -1
- package/tsdown.host.ts +1 -0
package/lib/client.js
CHANGED
|
@@ -7,7 +7,7 @@ window.__ModuleLoader__.load({
|
|
|
7
7
|
let react = require("react");
|
|
8
8
|
let _deepseek_ai_dsh_client_ui_primitives = require("@deepseek-ai/dsh-client-ui-primitives");
|
|
9
9
|
let react_jsx_runtime = require("react/jsx-runtime");
|
|
10
|
-
let
|
|
10
|
+
let _deepseek_ai_dsh_client_store = require("@deepseek-ai/dsh-client-store");
|
|
11
11
|
//#region \0dsh-css:C:\Users\user\Desktop\dsh-im-bridge\plugin\src\client\PluginCard.module.css.mjs
|
|
12
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
13
|
const tagId$1 = "@mhfire/dsh-im-bridge/PluginCard.module.css";
|
|
@@ -115,7 +115,7 @@ window.__ModuleLoader__.load({
|
|
|
115
115
|
}
|
|
116
116
|
//#endregion
|
|
117
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}";
|
|
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_input::placeholder{color:var(--dsw-alias-label-tertiary)}.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}.OMD7cq_install{appearance:none;font:inherit;cursor:pointer;background:var(--dsw-alias-label-primary);color:var(--dsw-alias-bg-layer-3);border:1px solid #0000;border-radius:8px;align-self:flex-start;padding:5px 14px;font-size:13px;line-height:1.5}.OMD7cq_install:hover:not(:disabled){opacity:.92}.OMD7cq_install:disabled{opacity:.4;cursor:default}.OMD7cq_install:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:1px}";
|
|
119
119
|
const tagId = "@mhfire/dsh-im-bridge/fields.module.css";
|
|
120
120
|
if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId) + "]") === null) {
|
|
121
121
|
const tag = document.createElement("style");
|
|
@@ -133,6 +133,7 @@ window.__ModuleLoader__.load({
|
|
|
133
133
|
"hint": "OMD7cq_hint",
|
|
134
134
|
"input": "OMD7cq_input",
|
|
135
135
|
"inputInvalid": "OMD7cq_inputInvalid",
|
|
136
|
+
"install": "OMD7cq_install",
|
|
136
137
|
"invalid": "OMD7cq_invalid",
|
|
137
138
|
"label": "OMD7cq_label",
|
|
138
139
|
"reset": "OMD7cq_reset"
|
|
@@ -189,7 +190,8 @@ window.__ModuleLoader__.load({
|
|
|
189
190
|
}
|
|
190
191
|
/**
|
|
191
192
|
* Write-only credential control. The literal never rides a response, so the
|
|
192
|
-
* control starts blank and reports only whether one is configured.
|
|
193
|
+
* control starts blank and reports only whether one is configured. A configured
|
|
194
|
+
* empty draft shows a dots placeholder so the box does not look unset.
|
|
193
195
|
* @param props - the field's copy, staged text, and configured state.
|
|
194
196
|
* @returns the labelled control.
|
|
195
197
|
*/
|
|
@@ -217,6 +219,7 @@ window.__ModuleLoader__.load({
|
|
|
217
219
|
type: "password",
|
|
218
220
|
autoComplete: "off",
|
|
219
221
|
value: props.text,
|
|
222
|
+
placeholder: props.configured && props.text === "" ? "••••••••" : void 0,
|
|
220
223
|
disabled: props.disabled,
|
|
221
224
|
onChange: (event) => {
|
|
222
225
|
props.onEdit(event.target.value);
|
|
@@ -278,6 +281,16 @@ window.__ModuleLoader__.load({
|
|
|
278
281
|
props.edit("secret", text);
|
|
279
282
|
}
|
|
280
283
|
}),
|
|
284
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(SkillsInstall, {
|
|
285
|
+
t,
|
|
286
|
+
disabled,
|
|
287
|
+
available: state.skillsInstallAvailable,
|
|
288
|
+
status: state.skillsInstallStatus,
|
|
289
|
+
dest: state.skillsDest,
|
|
290
|
+
count: state.skillsCount,
|
|
291
|
+
error: state.skillsError,
|
|
292
|
+
onInstall: props.installSkills
|
|
293
|
+
}),
|
|
281
294
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(ValueField, {
|
|
282
295
|
id: "im-bridge-allowFrom",
|
|
283
296
|
label: t("allowFrom"),
|
|
@@ -373,6 +386,44 @@ window.__ModuleLoader__.load({
|
|
|
373
386
|
]
|
|
374
387
|
});
|
|
375
388
|
}
|
|
389
|
+
function skillsStatusText(t, status, dest, count, error, available) {
|
|
390
|
+
if (!available) return t("skillsUnavailable");
|
|
391
|
+
if (status === "ok") return t("skillsInstalled").replace("{count}", String(count)).replace("{dest}", dest);
|
|
392
|
+
if (status === "error") return error === "" ? t("skillsFailed") : `${t("skillsFailed")} ${error}`;
|
|
393
|
+
return t("skillsHint");
|
|
394
|
+
}
|
|
395
|
+
/**
|
|
396
|
+
* Host-side install of official wecomcli-* (browser never chooses the path).
|
|
397
|
+
* @param props - copy, status, and the install action.
|
|
398
|
+
* @returns the labelled control.
|
|
399
|
+
*/
|
|
400
|
+
function SkillsInstall(props) {
|
|
401
|
+
const installing = props.status === "installing";
|
|
402
|
+
const status = skillsStatusText(props.t, props.status, props.dest, props.count, props.error, props.available);
|
|
403
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
404
|
+
className: fields_module_css_default.field,
|
|
405
|
+
children: [
|
|
406
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
407
|
+
className: fields_module_css_default.head,
|
|
408
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
409
|
+
className: fields_module_css_default.label,
|
|
410
|
+
children: props.t("skillsTitle")
|
|
411
|
+
})
|
|
412
|
+
}),
|
|
413
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
414
|
+
type: "button",
|
|
415
|
+
className: fields_module_css_default.install,
|
|
416
|
+
disabled: props.disabled || !props.available || installing,
|
|
417
|
+
onClick: props.onInstall,
|
|
418
|
+
children: props.t(installing ? "skillsInstalling" : "skillsInstall")
|
|
419
|
+
}),
|
|
420
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
421
|
+
className: props.status === "error" || !props.available ? fields_module_css_default.invalid : fields_module_css_default.hint,
|
|
422
|
+
children: status
|
|
423
|
+
})
|
|
424
|
+
]
|
|
425
|
+
});
|
|
426
|
+
}
|
|
376
427
|
//#endregion
|
|
377
428
|
//#region src/client/card-form.ts
|
|
378
429
|
/**
|
|
@@ -446,7 +497,7 @@ window.__ModuleLoader__.load({
|
|
|
446
497
|
}
|
|
447
498
|
/** Publish a projection rebuilt whenever the scope or a draft changes. */
|
|
448
499
|
bind(project) {
|
|
449
|
-
const store = (0,
|
|
500
|
+
const store = (0, _deepseek_ai_dsh_client_store.createSnapshotStore)(project());
|
|
450
501
|
this.listeners.add(() => {
|
|
451
502
|
store.set(project());
|
|
452
503
|
});
|
|
@@ -577,6 +628,10 @@ window.__ModuleLoader__.load({
|
|
|
577
628
|
this.failed = false;
|
|
578
629
|
this.publish();
|
|
579
630
|
}
|
|
631
|
+
/** Rebuild bound projections for card-owned state outside the settings draft. */
|
|
632
|
+
notify() {
|
|
633
|
+
this.publish();
|
|
634
|
+
}
|
|
580
635
|
spec(field) {
|
|
581
636
|
const spec = this.specs.get(field);
|
|
582
637
|
if (spec === void 0) throw new Error(`im-bridge card has no field ${field}`);
|
|
@@ -610,15 +665,22 @@ window.__ModuleLoader__.load({
|
|
|
610
665
|
var WecomCardController = class {
|
|
611
666
|
scope;
|
|
612
667
|
describe;
|
|
668
|
+
rpc;
|
|
613
669
|
form;
|
|
614
670
|
store;
|
|
671
|
+
skillsInstallStatus = "idle";
|
|
672
|
+
skillsDest = "";
|
|
673
|
+
skillsCount = 0;
|
|
674
|
+
skillsError = "";
|
|
615
675
|
/**
|
|
616
676
|
* @param scope - bound settings scope for the `im-bridge` namespace.
|
|
617
677
|
* @param describe - Host describe face; secret literals never ride it.
|
|
678
|
+
* @param rpc - optional Connection RPC for the skills install button.
|
|
618
679
|
*/
|
|
619
|
-
constructor(scope, describe) {
|
|
680
|
+
constructor(scope, describe, rpc) {
|
|
620
681
|
this.scope = scope;
|
|
621
682
|
this.describe = describe;
|
|
683
|
+
this.rpc = rpc;
|
|
622
684
|
this.form = new CardForm(scope, [
|
|
623
685
|
csvField("allowFrom"),
|
|
624
686
|
numberField("agentTimeoutSec"),
|
|
@@ -649,7 +711,12 @@ window.__ModuleLoader__.load({
|
|
|
649
711
|
deniedMessage: this.form.field("deniedMessage"),
|
|
650
712
|
welcomeMessage: this.form.field("welcomeMessage"),
|
|
651
713
|
provider: this.form.field("provider"),
|
|
652
|
-
model: this.form.field("model")
|
|
714
|
+
model: this.form.field("model"),
|
|
715
|
+
skillsInstallAvailable: this.rpc !== void 0,
|
|
716
|
+
skillsInstallStatus: this.skillsInstallStatus,
|
|
717
|
+
skillsDest: this.skillsDest,
|
|
718
|
+
skillsCount: this.skillsCount,
|
|
719
|
+
skillsError: this.skillsError
|
|
653
720
|
};
|
|
654
721
|
}
|
|
655
722
|
/**
|
|
@@ -670,11 +737,45 @@ window.__ModuleLoader__.load({
|
|
|
670
737
|
await this.scope.set(field, text);
|
|
671
738
|
return this.secretConfigured(field);
|
|
672
739
|
}
|
|
740
|
+
/**
|
|
741
|
+
* Download official wecomcli-* into the Host-resolved directory.
|
|
742
|
+
* The browser does not choose the path.
|
|
743
|
+
*/
|
|
744
|
+
installSkills() {
|
|
745
|
+
this.runInstall();
|
|
746
|
+
}
|
|
747
|
+
async runInstall() {
|
|
748
|
+
if (this.rpc === void 0 || this.skillsInstallStatus === "installing") return;
|
|
749
|
+
this.skillsInstallStatus = "installing";
|
|
750
|
+
this.skillsError = "";
|
|
751
|
+
this.form.notify();
|
|
752
|
+
try {
|
|
753
|
+
const result = await this.rpc.call("/im-bridge", "wecomcli.installSkills", {});
|
|
754
|
+
if (!result.ok) {
|
|
755
|
+
this.skillsInstallStatus = "error";
|
|
756
|
+
this.skillsError = result.error.message;
|
|
757
|
+
this.form.notify();
|
|
758
|
+
return;
|
|
759
|
+
}
|
|
760
|
+
const value = result.value;
|
|
761
|
+
this.skillsInstallStatus = "ok";
|
|
762
|
+
this.skillsDest = typeof value.dest === "string" ? value.dest : "";
|
|
763
|
+
this.skillsCount = typeof value.count === "number" ? value.count : 0;
|
|
764
|
+
this.skillsError = "";
|
|
765
|
+
} catch (error) {
|
|
766
|
+
this.skillsInstallStatus = "error";
|
|
767
|
+
this.skillsError = error instanceof Error ? error.message : String(error);
|
|
768
|
+
}
|
|
769
|
+
this.form.notify();
|
|
770
|
+
}
|
|
673
771
|
/** Face the slot registration injects. */
|
|
674
772
|
inject() {
|
|
675
773
|
return {
|
|
676
774
|
hooks: { wecomCard: this.store },
|
|
677
|
-
...this.form.actions()
|
|
775
|
+
...this.form.actions(),
|
|
776
|
+
installSkills: () => {
|
|
777
|
+
this.installSkills();
|
|
778
|
+
}
|
|
678
779
|
};
|
|
679
780
|
}
|
|
680
781
|
};
|
|
@@ -697,7 +798,7 @@ window.__ModuleLoader__.load({
|
|
|
697
798
|
invalidNumber: "Enter a finite number.",
|
|
698
799
|
botId: "Bot ID",
|
|
699
800
|
secret: "Secret",
|
|
700
|
-
secretHint: "
|
|
801
|
+
secretHint: "The box stays empty on purpose (the stored value never rides the wire). A Configured badge means it is saved; type a new value to replace it. Save, then restart the process to open the WebSocket.",
|
|
701
802
|
secretConfigured: "Configured",
|
|
702
803
|
secretUnset: "Not configured",
|
|
703
804
|
allowFrom: "Allowed sender userids",
|
|
@@ -713,7 +814,14 @@ window.__ModuleLoader__.load({
|
|
|
713
814
|
provider: "WeCom-only provider",
|
|
714
815
|
providerHint: "Empty follows the GUI default model. Both provider and model must be set to override.",
|
|
715
816
|
model: "WeCom-only model",
|
|
716
|
-
modelHint: "Takes effect only together with provider."
|
|
817
|
+
modelHint: "Takes effect only together with provider.",
|
|
818
|
+
skillsTitle: "WeCom office skills",
|
|
819
|
+
skillsHint: "Installs wecomcli-* into the plugin directory ($DSH_HOME/wecom-cli-skills). Do not use npx skills add -g; that CLI has no --dir. An empty Bot ID / Secret box is normal.",
|
|
820
|
+
skillsInstall: "Install official skills",
|
|
821
|
+
skillsInstalling: "Installing…",
|
|
822
|
+
skillsInstalled: "Installed {count} skills into {dest}",
|
|
823
|
+
skillsFailed: "Install failed.",
|
|
824
|
+
skillsUnavailable: "Install needs the Web host Connection."
|
|
717
825
|
};
|
|
718
826
|
/** Chinese copy for the im-bridge card. */
|
|
719
827
|
const zh = {
|
|
@@ -732,7 +840,7 @@ window.__ModuleLoader__.load({
|
|
|
732
840
|
invalidNumber: "请输入有效数字。",
|
|
733
841
|
botId: "Bot ID",
|
|
734
842
|
secret: "Secret",
|
|
735
|
-
secretHint: "
|
|
843
|
+
secretHint: "框空是正常的(已存值不会传到浏览器)。徽章「已配置」即已保存;重新输入可覆盖。保存后需重启进程才会连 WebSocket。",
|
|
736
844
|
secretConfigured: "已配置",
|
|
737
845
|
secretUnset: "未配置",
|
|
738
846
|
allowFrom: "允许的发送者 userid",
|
|
@@ -748,7 +856,14 @@ window.__ModuleLoader__.load({
|
|
|
748
856
|
provider: "企微专用 provider",
|
|
749
857
|
providerHint: "空 = 跟随 GUI 默认模型。须与 model 同时填写才覆盖。",
|
|
750
858
|
model: "企微专用 model",
|
|
751
|
-
modelHint: "仅在同时填写 provider 时生效。"
|
|
859
|
+
modelHint: "仅在同时填写 provider 时生效。",
|
|
860
|
+
skillsTitle: "企微办公 skills",
|
|
861
|
+
skillsHint: "装到程序目录 $DSH_HOME/wecom-cli-skills。不要用 npx skills add -g;CLI 没有 --dir。Bot ID / Secret 框空是正常的。",
|
|
862
|
+
skillsInstall: "安装官方 skills",
|
|
863
|
+
skillsInstalling: "正在安装…",
|
|
864
|
+
skillsInstalled: "已装 {count} 个到 {dest}",
|
|
865
|
+
skillsFailed: "安装失败。",
|
|
866
|
+
skillsUnavailable: "安装需要 Web Host 的 Connection。"
|
|
752
867
|
};
|
|
753
868
|
//#endregion
|
|
754
869
|
//#region src/client/index.ts
|
|
@@ -767,7 +882,8 @@ window.__ModuleLoader__.load({
|
|
|
767
882
|
* @param ctx - browser plugin context.
|
|
768
883
|
*/
|
|
769
884
|
function apply(ctx) {
|
|
770
|
-
const
|
|
885
|
+
const connection = ctx.get("connection");
|
|
886
|
+
const card = new WecomCardController(ctx.settingsScope.bind({ namespace: NS }), ctx.settingsScope.describe(), connection?.rpc);
|
|
771
887
|
ctx.effect(() => ctx.locale.register(NS, {
|
|
772
888
|
zh,
|
|
773
889
|
en
|
package/lib/client.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.js","names":["useState","css","IconChevronDownOutline14","css","createSnapshotStore","NS"],"sources":["../src/client/PluginCard.tsx","../src/client/fields.tsx","../src/client/WecomCard.tsx","../src/client/card-form.ts","../src/client/card-controller.ts","../src/client/locales.ts","../src/client/index.ts"],"sourcesContent":["/** Expandable plugin card chrome matching the Host Plugins section. */\n\nimport { useState, type ReactElement, type ReactNode } from 'react'\nimport { IconChevronDownOutline14 } from '@deepseek-ai/dsh-client-ui-primitives'\nimport type { ImBridgeLocaleKey } from './locales.ts'\nimport type { CardShell } from './card-form.ts'\nimport css from './PluginCard.module.css'\n\n/** Card chrome shared by this plugin's settings card. */\nexport interface PluginCardProps {\n /** Locale reader for this card's copy. */\n t: (key: ImBridgeLocaleKey) => string\n /** Locale key of the plugin's name. */\n titleKey: ImBridgeLocaleKey\n /** Locale key of the line describing what these settings govern. */\n descriptionKey: ImBridgeLocaleKey\n /** The card's form state. */\n state: CardShell\n /** Write every staged edit. */\n onSave: () => void\n /** Drop every staged edit. */\n onDiscard: () => void\n /** The plugin's controls. */\n children: ReactNode\n}\n\n/**\n * Render one plugin card.\n * @param props - locale copy, form state, and controls.\n * @returns the card, or nothing when the namespace is unavailable.\n */\nexport function PluginCard(props: PluginCardProps): ReactElement | null {\n const [open, setOpen] = useState(false)\n const { state } = props\n if (!state.available) return null\n const title = props.t(props.titleKey)\n const blocked = !state.dirty || state.invalid || state.saving\n return (\n <li className={open ? `${css.card} ${css.cardOpen}` : css.card}>\n <button\n type=\"button\"\n className={css.header}\n aria-expanded={open}\n aria-label={`${props.t(open ? 'collapse' : 'expand')}: ${title}`}\n onClick={() => { setOpen(current => !current) }}\n >\n <span className={css.headText}>\n <span className={css.name}>{title}</span>\n <span className={css.description}>{props.t(props.descriptionKey)}</span>\n </span>\n {state.dirty ? <span className={css.pending}>{props.t('unsaved')}</span> : null}\n <IconChevronDownOutline14 className={open ? `${css.chevron} ${css.chevronOpen}` : css.chevron} />\n </button>\n {open\n ? (\n <div className={css.body}>\n {!state.writable ? <p className={css.readOnly} role=\"status\">{props.t('readOnly')}</p> : null}\n {props.children}\n <div className={css.footer}>\n {state.failed ? <p className={css.failed} role=\"status\">{props.t('saveFailed')}</p> : null}\n <button\n type=\"button\"\n className={css.discard}\n disabled={!state.dirty || state.saving}\n onClick={props.onDiscard}\n >\n {props.t('discard')}\n </button>\n <button\n type=\"button\"\n className={css.save}\n disabled={blocked}\n onClick={props.onSave}\n >\n {props.t(state.saving ? 'saving' : 'save')}\n </button>\n </div>\n </div>\n )\n : null}\n </li>\n )\n}\n","/** Staged value and write-only secret controls. */\n\nimport type { ReactElement } from 'react'\nimport css from './fields.module.css'\n\n/** Shared props for a labelled field control. */\nexport interface FieldProps {\n /** Stable id associating the label with its control. */\n id: string\n /** Visible label. */\n label: string\n /** One-line explanation under the control. */\n hint: string\n /** Draft text the control renders. */\n text: string\n /** Whether saving would leave a user-layer entry. */\n overridden: boolean\n /** Whether the draft is not a value this field accepts. */\n invalid: boolean\n /** Copy for the overridden badge. */\n overriddenLabel: string\n /** Copy for the reset control. */\n resetLabel: string\n /** Copy shown in place of the hint while the draft is invalid. */\n invalidLabel: string\n /** Disables every control. */\n disabled: boolean\n /** Stage draft text. */\n onEdit: (text: string) => void\n /** Stage a clear so the field re-inherits the composition layer. */\n onReset: () => void\n}\n\n/**\n * A staged value field.\n * @param props - the field's copy, staged text, and edit actions.\n * @returns the labelled control.\n */\nexport function ValueField(props: FieldProps & {\n /** Hints a numeric keypad without narrowing accepted drafts. */\n numeric?: boolean\n}): ReactElement {\n return (\n <div className={css.field}>\n <div className={css.head}>\n <label className={css.label} htmlFor={props.id}>{props.label}</label>\n {props.overridden\n ? (\n <span className={css.badges}>\n <span className={css.badge}>{props.overriddenLabel}</span>\n <button\n type=\"button\"\n className={css.reset}\n disabled={props.disabled}\n onClick={props.onReset}\n >\n {props.resetLabel}\n </button>\n </span>\n )\n : null}\n </div>\n <input\n id={props.id}\n className={props.invalid ? css.inputInvalid : css.input}\n type=\"text\"\n {...props.numeric === true ? { inputMode: 'numeric' as const } : {}}\n {...props.invalid ? { 'aria-invalid': true } : {}}\n value={props.text}\n disabled={props.disabled}\n onChange={(event) => { props.onEdit(event.target.value) }}\n />\n <p className={props.invalid ? css.invalid : css.hint}>\n {props.invalid ? props.invalidLabel : props.hint}\n </p>\n </div>\n )\n}\n\n/**\n * Write-only credential control. The literal never rides a response, so the\n * control starts blank and reports only whether one is configured.\n * @param props - the field's copy, staged text, and configured state.\n * @returns the labelled control.\n */\nexport function SecretField(props: Pick<FieldProps, 'id' | 'label' | 'hint' | 'text' | 'disabled' | 'onEdit'> & {\n /** Whether the Host reports a configured value for this secret slot. */\n configured: boolean\n /** Copy describing the configured state. */\n stateLabel: string\n}): ReactElement {\n return (\n <div className={css.field}>\n <div className={css.head}>\n <label className={css.label} htmlFor={props.id}>{props.label}</label>\n <span className={css.badges}>\n <span className={props.configured ? css.badge : css.badgeMuted}>{props.stateLabel}</span>\n </span>\n </div>\n <input\n id={props.id}\n className={css.input}\n type=\"password\"\n autoComplete=\"off\"\n value={props.text}\n disabled={props.disabled}\n onChange={(event) => { props.onEdit(event.target.value) }}\n />\n <p className={css.hint}>{props.hint}</p>\n </div>\n )\n}\n","/** WeCom settings card: owned chrome, staged fields, save/discard. */\n\nimport type { ReactElement } from 'react'\nimport type { ImBridgeLocaleKey } from './locales.ts'\nimport type { WecomCardFace, WecomCardState } from './card-controller.ts'\nimport { PluginCard } from './PluginCard.tsx'\nimport { SecretField, ValueField } from './fields.tsx'\n\n/** Props the slot renderer binds for this card. */\nexport interface WecomCardProps {\n /** Translate a dictionary key of the `im-bridge` namespace. */\n t: (key: ImBridgeLocaleKey) => string\n /** Card snapshot bound from inject.hooks.wecomCard. */\n useWecomCard: <S>(select: (state: WecomCardState) => S) => S\n /** Stage draft text for one field. */\n edit: WecomCardFace['edit']\n /** Stage a clear back to the composition layer. */\n resetField: WecomCardFace['resetField']\n /** Write every staged edit. */\n save: WecomCardFace['save']\n /** Drop every staged edit. */\n discard: WecomCardFace['discard']\n}\n\n/**\n * Render the WeCom settings card.\n * @param props - locale copy, snapshot hook, and form actions.\n * @returns the card, or nothing when the namespace is unavailable.\n */\nexport function WecomCard(props: WecomCardProps): ReactElement | null {\n const { t } = props\n const state = props.useWecomCard(snapshot => snapshot)\n const disabled = !state.writable\n const field = {\n overriddenLabel: t('overridden'),\n resetLabel: t('reset'),\n invalidLabel: t('invalidNumber'),\n disabled,\n }\n return (\n <PluginCard\n t={t}\n titleKey=\"title\"\n descriptionKey=\"description\"\n state={state}\n onSave={props.save}\n onDiscard={props.discard}\n >\n <SecretField\n id=\"im-bridge-botId\"\n label={t('botId')}\n hint={t('secretHint')}\n disabled={disabled}\n text={state.botId.text}\n configured={state.botIdConfigured}\n stateLabel={state.botIdConfigured ? t('secretConfigured') : t('secretUnset')}\n onEdit={text => { props.edit('botId', text) }}\n />\n <SecretField\n id=\"im-bridge-secret\"\n label={t('secret')}\n hint={t('secretHint')}\n disabled={disabled}\n text={state.secret.text}\n configured={state.secretConfigured}\n stateLabel={state.secretConfigured ? t('secretConfigured') : t('secretUnset')}\n onEdit={text => { props.edit('secret', text) }}\n />\n <ValueField\n id=\"im-bridge-allowFrom\"\n label={t('allowFrom')}\n hint={t('allowFromHint')}\n {...field}\n {...state.allowFrom}\n onEdit={text => { props.edit('allowFrom', text) }}\n onReset={() => { props.resetField('allowFrom') }}\n />\n <ValueField\n id=\"im-bridge-agentTimeoutSec\"\n label={t('agentTimeoutSec')}\n hint={t('agentTimeoutSecHint')}\n numeric\n {...field}\n {...state.agentTimeoutSec}\n onEdit={text => { props.edit('agentTimeoutSec', text) }}\n onReset={() => { props.resetField('agentTimeoutSec') }}\n />\n <ValueField\n id=\"im-bridge-startHint\"\n label={t('startHint')}\n hint={t('startHintHint')}\n {...field}\n {...state.startHint}\n onEdit={text => { props.edit('startHint', text) }}\n onReset={() => { props.resetField('startHint') }}\n />\n <ValueField\n id=\"im-bridge-deniedMessage\"\n label={t('deniedMessage')}\n hint={t('deniedMessageHint')}\n {...field}\n {...state.deniedMessage}\n onEdit={text => { props.edit('deniedMessage', text) }}\n onReset={() => { props.resetField('deniedMessage') }}\n />\n <ValueField\n id=\"im-bridge-welcomeMessage\"\n label={t('welcomeMessage')}\n hint={t('welcomeMessageHint')}\n {...field}\n {...state.welcomeMessage}\n onEdit={text => { props.edit('welcomeMessage', text) }}\n onReset={() => { props.resetField('welcomeMessage') }}\n />\n <ValueField\n id=\"im-bridge-provider\"\n label={t('provider')}\n hint={t('providerHint')}\n {...field}\n {...state.provider}\n onEdit={text => { props.edit('provider', text) }}\n onReset={() => { props.resetField('provider') }}\n />\n <ValueField\n id=\"im-bridge-model\"\n label={t('model')}\n hint={t('modelHint')}\n {...field}\n {...state.model}\n onEdit={text => { props.edit('model', text) }}\n onReset={() => { props.resetField('model') }}\n />\n </PluginCard>\n )\n}\n","/**\n * Staged settings form owned by this plugin.\n * Mirrors the Host Plugins section model without importing its chrome.\n */\n\nimport {\n createSnapshotStore,\n type SettingsScope,\n type SettingsScopeSnapshot,\n type SnapshotStore,\n} from '@deepseek-ai/dsh-client-runtime/client'\n\n/** Write one staged field performs on save. */\nexport type FieldWrite =\n | { kind: 'set'; value: unknown }\n | { kind: 'clear' }\n\n/** Convert one section field between stored value and draft text. */\nexport interface CardFieldSpec {\n /** Field name inside the namespace section. */\n field: string\n /** Render a stored value as draft text. */\n format: (value: unknown) => string\n /** The write this draft stages, or undefined when the text is invalid. */\n parse: (text: string) => FieldWrite | undefined\n}\n\n/**\n * A control whose literal never rides a response. The draft starts blank;\n * a blank draft writes nothing so a save cannot clear a stored secret.\n */\nexport interface CardSecretSpec {\n /** Field name addressing this control inside the card's form. */\n field: string\n /** Write the staged text; resolves to whether the Host accepted it. */\n write: (text: string) => Promise<boolean>\n}\n\n/** One field as a control renders it. */\nexport interface CardFieldState {\n /** Draft text the control renders. */\n text: string\n /** Whether saving would leave a user-layer entry. */\n overridden: boolean\n /** Whether the draft is not a value this field accepts. */\n invalid: boolean\n}\n\n/** Card-level form state. */\nexport interface CardShell {\n /** False while the namespace is not served; the card renders nothing. */\n available: boolean\n /** Whether the Host document accepts writes. */\n writable: boolean\n /** Whether the form holds edits a save would write. */\n dirty: boolean\n /** Whether any staged draft is invalid. */\n invalid: boolean\n /** Whether a save is crossing the wire. */\n saving: boolean\n /** Whether the last save did not land. */\n failed: boolean\n}\n\n/** Write actions a card's slot entry injects. */\nexport interface CardActions {\n /** Stage draft text for one field. */\n edit: (field: string, text: string) => void\n /** Stage a clear so the field re-inherits the composition layer. */\n resetField: (field: string) => void\n /** Write every staged edit, then re-seed from what the Host accepted. */\n save: () => void\n /** Drop every staged edit. */\n discard: () => void\n}\n\ninterface StagedEdit {\n text: string\n clear: boolean\n}\n\ninterface PlannedWrite {\n field: string\n run: (() => Promise<boolean>) | undefined\n}\n\n/** Whole-number field. Empty draft clears. */\nexport function numberField(field: string): CardFieldSpec {\n return {\n field,\n format: value => typeof value === 'number' ? String(value) : '',\n parse: (text) => {\n const trimmed = text.trim()\n if (trimmed === '') return { kind: 'clear' }\n const parsed = Number(trimmed)\n return Number.isFinite(parsed) ? { kind: 'set', value: parsed } : undefined\n },\n }\n}\n\n/** Free-text field. Empty draft clears. */\nexport function textField(field: string): CardFieldSpec {\n return {\n field,\n format: value => typeof value === 'string' ? value : '',\n parse: (text) => {\n const trimmed = text.trim()\n return trimmed === '' ? { kind: 'clear' } : { kind: 'set', value: trimmed }\n },\n }\n}\n\n/** Comma-separated string list. Empty draft stores []. */\nexport function csvField(field: string): CardFieldSpec {\n return {\n field,\n format: value => Array.isArray(value) ? value.join(',') : '',\n parse: (text) => {\n const items = text.split(',').map(item => item.trim()).filter(Boolean)\n return { kind: 'set', value: items }\n },\n }\n}\n\n/** Stages edits over one settings namespace and writes them on save. */\nexport class CardForm<T> {\n private readonly specs: Map<string, CardFieldSpec>\n private readonly secretSpecs: Map<string, CardSecretSpec>\n private readonly staged = new Map<string, StagedEdit>()\n private readonly listeners = new Set<() => void>()\n private saving = false\n private failed = false\n\n /**\n * @param scope - bound settings scope for this card's namespace.\n * @param specs - section fields this card edits.\n * @param secrets - write-only controls; a blank draft is a no-op.\n */\n constructor(\n private readonly scope: SettingsScope<T>,\n specs: CardFieldSpec[],\n secrets: CardSecretSpec[] = [],\n ) {\n this.specs = new Map(specs.map(spec => [spec.field, spec]))\n this.secretSpecs = new Map(secrets.map(spec => [spec.field, spec]))\n scope.subscribe(() => { this.publish() })\n }\n\n /** Publish a projection rebuilt whenever the scope or a draft changes. */\n bind<S>(project: () => S): SnapshotStore<S> {\n const store = createSnapshotStore(project())\n this.listeners.add(() => { store.set(project()) })\n return store\n }\n\n /** Card-level state: what the Host serves and what a save would do. */\n shell(): CardShell {\n const snapshot = this.scope.getSnapshot()\n const plan = this.plan()\n return {\n available: snapshot.status === 'ready',\n writable: snapshot.writable,\n dirty: plan.length > 0,\n invalid: plan.some(item => item.run === undefined),\n saving: this.saving,\n failed: this.failed,\n }\n }\n\n /** One control's staged text, override badge, and validity. */\n field(field: string): CardFieldState {\n const staged = this.staged.get(field)\n if (this.secretSpecs.has(field)) {\n return { text: staged?.text ?? '', overridden: false, invalid: false }\n }\n const spec = this.spec(field)\n if (staged === undefined) {\n return { text: spec.format(this.sectionValue(field)), overridden: this.stored(field), invalid: false }\n }\n const write = staged.clear ? { kind: 'clear' as const } : spec.parse(staged.text)\n return {\n text: staged.text,\n overridden: write?.kind === 'set',\n invalid: write === undefined,\n }\n }\n\n /** Edit, reset, save, and discard actions bound to this form. */\n actions(): CardActions {\n return {\n edit: (field, text) => { this.stage(field, { text, clear: false }) },\n resetField: (field) => {\n this.stage(field, { text: this.spec(field).format(this.baseValue(field)), clear: true })\n },\n save: () => { void this.save() },\n discard: () => {\n if (this.staged.size === 0 && !this.failed) return\n this.staged.clear()\n this.failed = false\n this.publish()\n },\n }\n }\n\n /** Write every staged edit, then re-seed from what the Host accepted. */\n async save(): Promise<void> {\n const plan = this.plan()\n const writes = plan.flatMap(item => item.run === undefined ? [] : [item.run])\n if (plan.length === 0 || this.saving || writes.length !== plan.length) return\n this.saving = true\n this.failed = false\n this.publish()\n let landed = true\n for (const write of writes) {\n landed = await write() && landed\n }\n if (landed) this.staged.clear()\n this.saving = false\n this.failed = !landed\n this.publish()\n }\n\n private plan(): PlannedWrite[] {\n const plan: PlannedWrite[] = []\n for (const [field, staged] of this.staged) {\n const secret = this.secretSpecs.get(field)\n if (secret !== undefined) {\n const value = staged.text.trim()\n if (value !== '') plan.push({ field, run: () => secret.write(value) })\n continue\n }\n const spec = this.spec(field)\n if (staged.clear) {\n if (this.stored(field)) plan.push({ field, run: () => this.clear(field) })\n continue\n }\n if (staged.text === spec.format(this.sectionValue(field))) continue\n const write = spec.parse(staged.text)\n if (write === undefined) plan.push({ field, run: undefined })\n else if (write.kind === 'clear') plan.push({ field, run: () => this.clear(field) })\n else plan.push({ field, run: () => this.store(field, write.value) })\n }\n return plan\n }\n\n private async clear(field: string): Promise<boolean> {\n await this.scope.unset(field)\n return !this.stored(field)\n }\n\n private async store(field: string, value: unknown): Promise<boolean> {\n await this.scope.set(field, value)\n return this.userLayer()?.[field] === value\n || (Array.isArray(value) && JSON.stringify(this.userLayer()?.[field]) === JSON.stringify(value))\n }\n\n private stage(field: string, edit: StagedEdit): void {\n this.staged.set(field, edit)\n this.failed = false\n this.publish()\n }\n\n private spec(field: string): CardFieldSpec {\n const spec = this.specs.get(field)\n if (spec === undefined) throw new Error(`im-bridge card has no field ${field}`)\n return spec\n }\n\n private snapshotOf(): SettingsScopeSnapshot<T> {\n return this.scope.getSnapshot()\n }\n\n private sectionValue(field: string): unknown {\n return (this.snapshotOf().value as Record<string, unknown> | undefined)?.[field]\n }\n\n private baseValue(field: string): unknown {\n return (this.snapshotOf().base as Record<string, unknown> | undefined)?.[field]\n }\n\n private userLayer(): Record<string, unknown> | undefined {\n return this.snapshotOf().user as Record<string, unknown> | undefined\n }\n\n private stored(field: string): boolean {\n const user = this.userLayer()\n return user !== undefined && Object.hasOwn(user, field)\n }\n\n private publish(): void {\n for (const listener of this.listeners) listener()\n }\n}\n","/** Staged form over the `im-bridge` settings namespace. */\n\nimport type { SettingsScope, SnapshotStore } from '@deepseek-ai/dsh-client-runtime/client'\nimport {\n CardForm,\n csvField,\n numberField,\n textField,\n type CardActions,\n type CardFieldState,\n type CardShell,\n} from './card-form.ts'\n\n/** One redacted secret slot from `settings.describe`. */\ninterface SecretSlotView {\n path: readonly string[]\n set: boolean\n}\n\n/**\n * Cross-namespace describe face. Typed locally so this out-of-tree package\n * does not value- or type-import `@deepseek-ai/dsh-client-ui-settings`.\n */\ninterface SettingsDescribeFace {\n getSnapshot(): {\n view?: {\n namespaces: ReadonlyArray<{\n ns: string\n secrets: readonly SecretSlotView[]\n }>\n }\n }\n}\n\n/** Settings namespace paired with this card. */\nconst NS = 'im-bridge'\n\n/** User-editable slice of the im-bridge settings namespace. */\nexport interface WecomCardSettings {\n allowFrom?: string[]\n agentTimeoutSec?: number\n startHint?: string\n deniedMessage?: string\n welcomeMessage?: string\n provider?: string\n model?: string\n}\n\n/** Snapshot the WeCom card renders. */\nexport interface WecomCardState extends CardShell {\n botId: CardFieldState\n secret: CardFieldState\n botIdConfigured: boolean\n secretConfigured: boolean\n allowFrom: CardFieldState\n agentTimeoutSec: CardFieldState\n startHint: CardFieldState\n deniedMessage: CardFieldState\n welcomeMessage: CardFieldState\n provider: CardFieldState\n model: CardFieldState\n}\n\n/** Face the card's slot registration injects. */\nexport interface WecomCardFace extends CardActions {\n hooks: {\n /** Card snapshot bound by the renderer as useWecomCard. */\n wecomCard: SnapshotStore<WecomCardState>\n }\n}\n\n/** Bridges the `im-bridge` scope onto the staged card form. */\nexport class WecomCardController {\n private readonly form: CardForm<WecomCardSettings>\n private readonly store: SnapshotStore<WecomCardState>\n\n /**\n * @param scope - bound settings scope for the `im-bridge` namespace.\n * @param describe - Host describe face; secret literals never ride it.\n */\n constructor(\n private readonly scope: SettingsScope<WecomCardSettings>,\n private readonly describe: SettingsDescribeFace,\n ) {\n this.form = new CardForm(\n scope,\n [\n csvField('allowFrom'),\n numberField('agentTimeoutSec'),\n textField('startHint'),\n textField('deniedMessage'),\n textField('welcomeMessage'),\n textField('provider'),\n textField('model'),\n ],\n [\n { field: 'botId', write: text => this.writeSecret('botId', text) },\n { field: 'secret', write: text => this.writeSecret('secret', text) },\n ],\n )\n this.store = this.form.bind(() => this.projection())\n }\n\n private projection(): WecomCardState {\n return {\n ...this.form.shell(),\n botId: this.form.field('botId'),\n secret: this.form.field('secret'),\n botIdConfigured: this.secretConfigured('botId'),\n secretConfigured: this.secretConfigured('secret'),\n allowFrom: this.form.field('allowFrom'),\n agentTimeoutSec: this.form.field('agentTimeoutSec'),\n startHint: this.form.field('startHint'),\n deniedMessage: this.form.field('deniedMessage'),\n welcomeMessage: this.form.field('welcomeMessage'),\n provider: this.form.field('provider'),\n model: this.form.field('model'),\n }\n }\n\n /**\n * Whether the Host reports a configured value for one secret slot.\n * @param field - `botId` or `secret`.\n * @returns true when describe lists that slot as set.\n */\n private secretConfigured(field: string): boolean {\n const row = this.describe.getSnapshot().view?.namespaces.find(candidate => candidate.ns === NS)\n return row?.secrets.some(slot => slot.path[0] === field && slot.set) === true\n }\n\n /**\n * Write one credential into the user layer, then read configured state back.\n * @param field - `botId` or `secret`.\n * @param text - the staged literal.\n * @returns whether describe reports the slot set afterwards.\n */\n private async writeSecret(field: string, text: string): Promise<boolean> {\n await this.scope.set(field, text)\n return this.secretConfigured(field)\n }\n\n /** Face the slot registration injects. */\n inject(): WecomCardFace {\n return { hooks: { wecomCard: this.store }, ...this.form.actions() }\n }\n}\n","/** Dictionary keys owned by the im-bridge settings card. */\nexport type ImBridgeLocaleKey =\n | 'title'\n | 'description'\n | 'unsaved'\n | 'readOnly'\n | 'saveFailed'\n | 'save'\n | 'saving'\n | 'discard'\n | 'expand'\n | 'collapse'\n | 'overridden'\n | 'reset'\n | 'invalidNumber'\n | 'botId'\n | 'secret'\n | 'secretHint'\n | 'secretConfigured'\n | 'secretUnset'\n | 'allowFrom'\n | 'allowFromHint'\n | 'agentTimeoutSec'\n | 'agentTimeoutSecHint'\n | 'startHint'\n | 'startHintHint'\n | 'deniedMessage'\n | 'deniedMessageHint'\n | 'welcomeMessage'\n | 'welcomeMessageHint'\n | 'provider'\n | 'providerHint'\n | 'model'\n | 'modelHint'\n\n/** English copy for the im-bridge card. */\nexport const en: Record<ImBridgeLocaleKey, string> = {\n title: 'WeCom Bridge',\n description: 'Credentials, allow-list, timeouts, and WeCom-only model overrides.',\n unsaved: 'Unsaved',\n readOnly: 'This document is read-only.',\n saveFailed: 'Save did not land. Correct the fields and try again.',\n save: 'Save',\n saving: 'Saving…',\n discard: 'Discard',\n expand: 'Show settings',\n collapse: 'Hide settings',\n overridden: 'Overridden',\n reset: 'Reset',\n invalidNumber: 'Enter a finite number.',\n botId: 'Bot ID',\n secret: 'Secret',\n secretHint: 'Leave blank to keep the stored value. Save, then restart the process to open the WebSocket.',\n secretConfigured: 'Configured',\n secretUnset: 'Not configured',\n allowFrom: 'Allowed sender userids',\n allowFromHint: 'Comma-separated. Empty allows everyone.',\n agentTimeoutSec: 'Task timeout (seconds)',\n agentTimeoutSecHint: 'Progress bar and remaining-time estimate.',\n startHint: 'Placeholder while thinking',\n startHintHint: 'First stream line after a message arrives.',\n deniedMessage: 'Denied-sender reply',\n deniedMessageHint: 'Sent when the userid is outside the allow-list.',\n welcomeMessage: 'Welcome message',\n welcomeMessageHint: 'Sent when a user opens the WeCom chat.',\n provider: 'WeCom-only provider',\n providerHint: 'Empty follows the GUI default model. Both provider and model must be set to override.',\n model: 'WeCom-only model',\n modelHint: 'Takes effect only together with provider.',\n}\n\n/** Chinese copy for the im-bridge card. */\nexport const zh: Record<ImBridgeLocaleKey, string> = {\n title: '企业微信桥接',\n description: '凭证、白名单、超时和企微专用模型覆盖。',\n unsaved: '未保存',\n readOnly: '当前文档不可写。',\n saveFailed: '保存未生效,请修正后重试。',\n save: '保存',\n saving: '保存中…',\n discard: '放弃',\n expand: '展开设置',\n collapse: '收起设置',\n overridden: '已覆盖',\n reset: '重置',\n invalidNumber: '请输入有效数字。',\n botId: 'Bot ID',\n secret: 'Secret',\n secretHint: '留空保留已存值。保存后需重启进程才会连 WebSocket。',\n secretConfigured: '已配置',\n secretUnset: '未配置',\n allowFrom: '允许的发送者 userid',\n allowFromHint: '逗号分隔;空 = 允许所有人。',\n agentTimeoutSec: '单任务超时(秒)',\n agentTimeoutSecHint: '动画进度条和剩余估算的基准。',\n startHint: '开始处理时的占位提示',\n startHintHint: '收到消息后推送的第一条流式文案。',\n deniedMessage: '非白名单拒绝文案',\n deniedMessageHint: '发送者不在白名单时回复。',\n welcomeMessage: '进入会话欢迎语',\n welcomeMessageHint: '用户打开企微会话时发送。',\n provider: '企微专用 provider',\n providerHint: '空 = 跟随 GUI 默认模型。须与 model 同时填写才覆盖。',\n model: '企微专用 model',\n modelHint: '仅在同时填写 provider 时生效。',\n}\n\ndeclare module '@deepseek-ai/dsh-client-ui-slots' {\n interface LocaleNamespaceMap {\n 'im-bridge': ImBridgeLocaleKey\n }\n}\n","/**\n * Browser half: Settings card keyed by the `im-bridge` namespace.\n */\n\nimport type { ClientContext } from '@deepseek-ai/dsh-client-runtime/client'\n// Type-only: ctx.settingsScope.describe and the keyed slot declaration.\nimport type {} from '@deepseek-ai/dsh-client-ui-settings/client'\nimport type {} from '@deepseek-ai/dsh-client-ui-settings-plugins/client'\nimport { WecomCard } from './WecomCard.tsx'\nimport { WecomCardController } from './card-controller.ts'\nimport { en, zh } from './locales.ts'\n\n/** Settings namespace shared with the Host half. */\nconst NS = 'im-bridge'\n\n/** Required browser services. */\nexport const inject = ['slots', 'locale', 'connection', 'remote', 'settingsScope']\n\n/**\n * Register locale copy and the Plugins-tab card.\n * @param ctx - browser plugin context.\n */\nexport function apply(ctx: ClientContext): void {\n const card = new WecomCardController(\n ctx.settingsScope.bind({ namespace: NS }),\n ctx.settingsScope.describe(),\n )\n\n ctx.effect(() => ctx.locale.register(NS, { zh, en }), 'im-bridge: locale dicts')\n\n ctx.slots.inject('settings.plugin.item', () => ctx.slots.register({\n name: 'settings.plugin.item',\n key: NS,\n locale: NS,\n inject: () => card.inject(),\n }, WecomCard))\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"client.js","names":["useState","css","IconChevronDownOutline14","css","css","createSnapshotStore","NS"],"sources":["../src/client/PluginCard.tsx","../src/client/fields.tsx","../src/client/WecomCard.tsx","../src/client/card-form.ts","../src/client/card-controller.ts","../src/client/locales.ts","../src/client/index.ts"],"sourcesContent":["/** Expandable plugin card chrome matching the Host Plugins section. */\n\nimport { useState, type ReactElement, type ReactNode } from 'react'\nimport { IconChevronDownOutline14 } from '@deepseek-ai/dsh-client-ui-primitives'\nimport type { ImBridgeLocaleKey } from './locales.ts'\nimport type { CardShell } from './card-form.ts'\nimport css from './PluginCard.module.css'\n\n/** Card chrome shared by this plugin's settings card. */\nexport interface PluginCardProps {\n /** Locale reader for this card's copy. */\n t: (key: ImBridgeLocaleKey) => string\n /** Locale key of the plugin's name. */\n titleKey: ImBridgeLocaleKey\n /** Locale key of the line describing what these settings govern. */\n descriptionKey: ImBridgeLocaleKey\n /** The card's form state. */\n state: CardShell\n /** Write every staged edit. */\n onSave: () => void\n /** Drop every staged edit. */\n onDiscard: () => void\n /** The plugin's controls. */\n children: ReactNode\n}\n\n/**\n * Render one plugin card.\n * @param props - locale copy, form state, and controls.\n * @returns the card, or nothing when the namespace is unavailable.\n */\nexport function PluginCard(props: PluginCardProps): ReactElement | null {\n const [open, setOpen] = useState(false)\n const { state } = props\n if (!state.available) return null\n const title = props.t(props.titleKey)\n const blocked = !state.dirty || state.invalid || state.saving\n return (\n <li className={open ? `${css.card} ${css.cardOpen}` : css.card}>\n <button\n type=\"button\"\n className={css.header}\n aria-expanded={open}\n aria-label={`${props.t(open ? 'collapse' : 'expand')}: ${title}`}\n onClick={() => { setOpen(current => !current) }}\n >\n <span className={css.headText}>\n <span className={css.name}>{title}</span>\n <span className={css.description}>{props.t(props.descriptionKey)}</span>\n </span>\n {state.dirty ? <span className={css.pending}>{props.t('unsaved')}</span> : null}\n <IconChevronDownOutline14 className={open ? `${css.chevron} ${css.chevronOpen}` : css.chevron} />\n </button>\n {open\n ? (\n <div className={css.body}>\n {!state.writable ? <p className={css.readOnly} role=\"status\">{props.t('readOnly')}</p> : null}\n {props.children}\n <div className={css.footer}>\n {state.failed ? <p className={css.failed} role=\"status\">{props.t('saveFailed')}</p> : null}\n <button\n type=\"button\"\n className={css.discard}\n disabled={!state.dirty || state.saving}\n onClick={props.onDiscard}\n >\n {props.t('discard')}\n </button>\n <button\n type=\"button\"\n className={css.save}\n disabled={blocked}\n onClick={props.onSave}\n >\n {props.t(state.saving ? 'saving' : 'save')}\n </button>\n </div>\n </div>\n )\n : null}\n </li>\n )\n}\n","/** Staged value and write-only secret controls. */\n\nimport type { ReactElement } from 'react'\nimport css from './fields.module.css'\n\n/** Shared props for a labelled field control. */\nexport interface FieldProps {\n /** Stable id associating the label with its control. */\n id: string\n /** Visible label. */\n label: string\n /** One-line explanation under the control. */\n hint: string\n /** Draft text the control renders. */\n text: string\n /** Whether saving would leave a user-layer entry. */\n overridden: boolean\n /** Whether the draft is not a value this field accepts. */\n invalid: boolean\n /** Copy for the overridden badge. */\n overriddenLabel: string\n /** Copy for the reset control. */\n resetLabel: string\n /** Copy shown in place of the hint while the draft is invalid. */\n invalidLabel: string\n /** Disables every control. */\n disabled: boolean\n /** Stage draft text. */\n onEdit: (text: string) => void\n /** Stage a clear so the field re-inherits the composition layer. */\n onReset: () => void\n}\n\n/**\n * A staged value field.\n * @param props - the field's copy, staged text, and edit actions.\n * @returns the labelled control.\n */\nexport function ValueField(props: FieldProps & {\n /** Hints a numeric keypad without narrowing accepted drafts. */\n numeric?: boolean\n}): ReactElement {\n return (\n <div className={css.field}>\n <div className={css.head}>\n <label className={css.label} htmlFor={props.id}>{props.label}</label>\n {props.overridden\n ? (\n <span className={css.badges}>\n <span className={css.badge}>{props.overriddenLabel}</span>\n <button\n type=\"button\"\n className={css.reset}\n disabled={props.disabled}\n onClick={props.onReset}\n >\n {props.resetLabel}\n </button>\n </span>\n )\n : null}\n </div>\n <input\n id={props.id}\n className={props.invalid ? css.inputInvalid : css.input}\n type=\"text\"\n {...props.numeric === true ? { inputMode: 'numeric' as const } : {}}\n {...props.invalid ? { 'aria-invalid': true } : {}}\n value={props.text}\n disabled={props.disabled}\n onChange={(event) => { props.onEdit(event.target.value) }}\n />\n <p className={props.invalid ? css.invalid : css.hint}>\n {props.invalid ? props.invalidLabel : props.hint}\n </p>\n </div>\n )\n}\n\n/**\n * Write-only credential control. The literal never rides a response, so the\n * control starts blank and reports only whether one is configured. A configured\n * empty draft shows a dots placeholder so the box does not look unset.\n * @param props - the field's copy, staged text, and configured state.\n * @returns the labelled control.\n */\nexport function SecretField(props: Pick<FieldProps, 'id' | 'label' | 'hint' | 'text' | 'disabled' | 'onEdit'> & {\n /** Whether the Host reports a configured value for this secret slot. */\n configured: boolean\n /** Copy describing the configured state. */\n stateLabel: string\n}): ReactElement {\n return (\n <div className={css.field}>\n <div className={css.head}>\n <label className={css.label} htmlFor={props.id}>{props.label}</label>\n <span className={css.badges}>\n <span className={props.configured ? css.badge : css.badgeMuted}>{props.stateLabel}</span>\n </span>\n </div>\n <input\n id={props.id}\n className={css.input}\n type=\"password\"\n autoComplete=\"off\"\n value={props.text}\n placeholder={props.configured && props.text === '' ? '••••••••' : undefined}\n disabled={props.disabled}\n onChange={(event) => { props.onEdit(event.target.value) }}\n />\n <p className={css.hint}>{props.hint}</p>\n </div>\n )\n}\n","/** WeCom settings card: owned chrome, staged fields, save/discard. */\n\nimport type { ReactElement } from 'react'\nimport type { ImBridgeLocaleKey } from './locales.ts'\nimport type { WecomCardFace, WecomCardState } from './card-controller.ts'\nimport { PluginCard } from './PluginCard.tsx'\nimport { SecretField, ValueField } from './fields.tsx'\nimport css from './fields.module.css'\n\n/** Props the slot renderer binds for this card. */\nexport interface WecomCardProps {\n /** Translate a dictionary key of the `im-bridge` namespace. */\n t: (key: ImBridgeLocaleKey) => string\n /** Card snapshot bound from inject.hooks.wecomCard. */\n useWecomCard: <S>(select: (state: WecomCardState) => S) => S\n /** Stage draft text for one field. */\n edit: WecomCardFace['edit']\n /** Stage a clear back to the composition layer. */\n resetField: WecomCardFace['resetField']\n /** Write every staged edit. */\n save: WecomCardFace['save']\n /** Drop every staged edit. */\n discard: WecomCardFace['discard']\n /** Download official wecomcli-* into the Host-resolved directory. */\n installSkills: WecomCardFace['installSkills']\n}\n\n/**\n * Render the WeCom settings card.\n * @param props - locale copy, snapshot hook, and form actions.\n * @returns the card, or nothing when the namespace is unavailable.\n */\nexport function WecomCard(props: WecomCardProps): ReactElement | null {\n const { t } = props\n const state = props.useWecomCard(snapshot => snapshot)\n const disabled = !state.writable\n const field = {\n overriddenLabel: t('overridden'),\n resetLabel: t('reset'),\n invalidLabel: t('invalidNumber'),\n disabled,\n }\n return (\n <PluginCard\n t={t}\n titleKey=\"title\"\n descriptionKey=\"description\"\n state={state}\n onSave={props.save}\n onDiscard={props.discard}\n >\n <SecretField\n id=\"im-bridge-botId\"\n label={t('botId')}\n hint={t('secretHint')}\n disabled={disabled}\n text={state.botId.text}\n configured={state.botIdConfigured}\n stateLabel={state.botIdConfigured ? t('secretConfigured') : t('secretUnset')}\n onEdit={text => { props.edit('botId', text) }}\n />\n <SecretField\n id=\"im-bridge-secret\"\n label={t('secret')}\n hint={t('secretHint')}\n disabled={disabled}\n text={state.secret.text}\n configured={state.secretConfigured}\n stateLabel={state.secretConfigured ? t('secretConfigured') : t('secretUnset')}\n onEdit={text => { props.edit('secret', text) }}\n />\n <SkillsInstall\n t={t}\n disabled={disabled}\n available={state.skillsInstallAvailable}\n status={state.skillsInstallStatus}\n dest={state.skillsDest}\n count={state.skillsCount}\n error={state.skillsError}\n onInstall={props.installSkills}\n />\n <ValueField\n id=\"im-bridge-allowFrom\"\n label={t('allowFrom')}\n hint={t('allowFromHint')}\n {...field}\n {...state.allowFrom}\n onEdit={text => { props.edit('allowFrom', text) }}\n onReset={() => { props.resetField('allowFrom') }}\n />\n <ValueField\n id=\"im-bridge-agentTimeoutSec\"\n label={t('agentTimeoutSec')}\n hint={t('agentTimeoutSecHint')}\n numeric\n {...field}\n {...state.agentTimeoutSec}\n onEdit={text => { props.edit('agentTimeoutSec', text) }}\n onReset={() => { props.resetField('agentTimeoutSec') }}\n />\n <ValueField\n id=\"im-bridge-startHint\"\n label={t('startHint')}\n hint={t('startHintHint')}\n {...field}\n {...state.startHint}\n onEdit={text => { props.edit('startHint', text) }}\n onReset={() => { props.resetField('startHint') }}\n />\n <ValueField\n id=\"im-bridge-deniedMessage\"\n label={t('deniedMessage')}\n hint={t('deniedMessageHint')}\n {...field}\n {...state.deniedMessage}\n onEdit={text => { props.edit('deniedMessage', text) }}\n onReset={() => { props.resetField('deniedMessage') }}\n />\n <ValueField\n id=\"im-bridge-welcomeMessage\"\n label={t('welcomeMessage')}\n hint={t('welcomeMessageHint')}\n {...field}\n {...state.welcomeMessage}\n onEdit={text => { props.edit('welcomeMessage', text) }}\n onReset={() => { props.resetField('welcomeMessage') }}\n />\n <ValueField\n id=\"im-bridge-provider\"\n label={t('provider')}\n hint={t('providerHint')}\n {...field}\n {...state.provider}\n onEdit={text => { props.edit('provider', text) }}\n onReset={() => { props.resetField('provider') }}\n />\n <ValueField\n id=\"im-bridge-model\"\n label={t('model')}\n hint={t('modelHint')}\n {...field}\n {...state.model}\n onEdit={text => { props.edit('model', text) }}\n onReset={() => { props.resetField('model') }}\n />\n </PluginCard>\n )\n}\n\nfunction skillsStatusText(\n t: (key: ImBridgeLocaleKey) => string,\n status: WecomCardState['skillsInstallStatus'],\n dest: string,\n count: number,\n error: string,\n available: boolean,\n): string {\n if (!available) return t('skillsUnavailable')\n if (status === 'ok') {\n return t('skillsInstalled').replace('{count}', String(count)).replace('{dest}', dest)\n }\n if (status === 'error') {\n return error === '' ? t('skillsFailed') : `${t('skillsFailed')} ${error}`\n }\n return t('skillsHint')\n}\n\n/**\n * Host-side install of official wecomcli-* (browser never chooses the path).\n * @param props - copy, status, and the install action.\n * @returns the labelled control.\n */\nfunction SkillsInstall(props: {\n t: (key: ImBridgeLocaleKey) => string\n disabled: boolean\n available: boolean\n status: WecomCardState['skillsInstallStatus']\n dest: string\n count: number\n error: string\n onInstall: () => void\n}): ReactElement {\n const installing = props.status === 'installing'\n const status = skillsStatusText(\n props.t,\n props.status,\n props.dest,\n props.count,\n props.error,\n props.available,\n )\n return (\n <div className={css.field}>\n <div className={css.head}>\n <span className={css.label}>{props.t('skillsTitle')}</span>\n </div>\n <button\n type=\"button\"\n className={css.install}\n disabled={props.disabled || !props.available || installing}\n onClick={props.onInstall}\n >\n {props.t(installing ? 'skillsInstalling' : 'skillsInstall')}\n </button>\n <p className={props.status === 'error' || !props.available ? css.invalid : css.hint}>\n {status}\n </p>\n </div>\n )\n}\n","/**\n * Staged settings form owned by this plugin.\n * Mirrors the Host Plugins section model without importing its chrome.\n */\n\nimport { createSnapshotStore, type SnapshotStore } from '@deepseek-ai/dsh-client-store'\nimport type { SettingsScope, SettingsScopeSnapshot } from '@deepseek-ai/dsh-client-ui-settings/client'\n\n/** Write one staged field performs on save. */\nexport type FieldWrite =\n | { kind: 'set'; value: unknown }\n | { kind: 'clear' }\n\n/** Convert one section field between stored value and draft text. */\nexport interface CardFieldSpec {\n /** Field name inside the namespace section. */\n field: string\n /** Render a stored value as draft text. */\n format: (value: unknown) => string\n /** The write this draft stages, or undefined when the text is invalid. */\n parse: (text: string) => FieldWrite | undefined\n}\n\n/**\n * A control whose literal never rides a response. The draft starts blank;\n * a blank draft writes nothing so a save cannot clear a stored secret.\n */\nexport interface CardSecretSpec {\n /** Field name addressing this control inside the card's form. */\n field: string\n /** Write the staged text; resolves to whether the Host accepted it. */\n write: (text: string) => Promise<boolean>\n}\n\n/** One field as a control renders it. */\nexport interface CardFieldState {\n /** Draft text the control renders. */\n text: string\n /** Whether saving would leave a user-layer entry. */\n overridden: boolean\n /** Whether the draft is not a value this field accepts. */\n invalid: boolean\n}\n\n/** Card-level form state. */\nexport interface CardShell {\n /** False while the namespace is not served; the card renders nothing. */\n available: boolean\n /** Whether the Host document accepts writes. */\n writable: boolean\n /** Whether the form holds edits a save would write. */\n dirty: boolean\n /** Whether any staged draft is invalid. */\n invalid: boolean\n /** Whether a save is crossing the wire. */\n saving: boolean\n /** Whether the last save did not land. */\n failed: boolean\n}\n\n/** Write actions a card's slot entry injects. */\nexport interface CardActions {\n /** Stage draft text for one field. */\n edit: (field: string, text: string) => void\n /** Stage a clear so the field re-inherits the composition layer. */\n resetField: (field: string) => void\n /** Write every staged edit, then re-seed from what the Host accepted. */\n save: () => void\n /** Drop every staged edit. */\n discard: () => void\n}\n\ninterface StagedEdit {\n text: string\n clear: boolean\n}\n\ninterface PlannedWrite {\n field: string\n run: (() => Promise<boolean>) | undefined\n}\n\n/** Whole-number field. Empty draft clears. */\nexport function numberField(field: string): CardFieldSpec {\n return {\n field,\n format: value => typeof value === 'number' ? String(value) : '',\n parse: (text) => {\n const trimmed = text.trim()\n if (trimmed === '') return { kind: 'clear' }\n const parsed = Number(trimmed)\n return Number.isFinite(parsed) ? { kind: 'set', value: parsed } : undefined\n },\n }\n}\n\n/** Free-text field. Empty draft clears. */\nexport function textField(field: string): CardFieldSpec {\n return {\n field,\n format: value => typeof value === 'string' ? value : '',\n parse: (text) => {\n const trimmed = text.trim()\n return trimmed === '' ? { kind: 'clear' } : { kind: 'set', value: trimmed }\n },\n }\n}\n\n/** Comma-separated string list. Empty draft stores []. */\nexport function csvField(field: string): CardFieldSpec {\n return {\n field,\n format: value => Array.isArray(value) ? value.join(',') : '',\n parse: (text) => {\n const items = text.split(',').map(item => item.trim()).filter(Boolean)\n return { kind: 'set', value: items }\n },\n }\n}\n\n/** Stages edits over one settings namespace and writes them on save. */\nexport class CardForm<T> {\n private readonly specs: Map<string, CardFieldSpec>\n private readonly secretSpecs: Map<string, CardSecretSpec>\n private readonly staged = new Map<string, StagedEdit>()\n private readonly listeners = new Set<() => void>()\n private saving = false\n private failed = false\n\n /**\n * @param scope - bound settings scope for this card's namespace.\n * @param specs - section fields this card edits.\n * @param secrets - write-only controls; a blank draft is a no-op.\n */\n constructor(\n private readonly scope: SettingsScope<T>,\n specs: CardFieldSpec[],\n secrets: CardSecretSpec[] = [],\n ) {\n this.specs = new Map(specs.map(spec => [spec.field, spec]))\n this.secretSpecs = new Map(secrets.map(spec => [spec.field, spec]))\n scope.subscribe(() => { this.publish() })\n }\n\n /** Publish a projection rebuilt whenever the scope or a draft changes. */\n bind<S>(project: () => S): SnapshotStore<S> {\n const store = createSnapshotStore(project())\n this.listeners.add(() => { store.set(project()) })\n return store\n }\n\n /** Card-level state: what the Host serves and what a save would do. */\n shell(): CardShell {\n const snapshot = this.scope.getSnapshot()\n const plan = this.plan()\n return {\n available: snapshot.status === 'ready',\n writable: snapshot.writable,\n dirty: plan.length > 0,\n invalid: plan.some(item => item.run === undefined),\n saving: this.saving,\n failed: this.failed,\n }\n }\n\n /** One control's staged text, override badge, and validity. */\n field(field: string): CardFieldState {\n const staged = this.staged.get(field)\n if (this.secretSpecs.has(field)) {\n return { text: staged?.text ?? '', overridden: false, invalid: false }\n }\n const spec = this.spec(field)\n if (staged === undefined) {\n return { text: spec.format(this.sectionValue(field)), overridden: this.stored(field), invalid: false }\n }\n const write = staged.clear ? { kind: 'clear' as const } : spec.parse(staged.text)\n return {\n text: staged.text,\n overridden: write?.kind === 'set',\n invalid: write === undefined,\n }\n }\n\n /** Edit, reset, save, and discard actions bound to this form. */\n actions(): CardActions {\n return {\n edit: (field, text) => { this.stage(field, { text, clear: false }) },\n resetField: (field) => {\n this.stage(field, { text: this.spec(field).format(this.baseValue(field)), clear: true })\n },\n save: () => { void this.save() },\n discard: () => {\n if (this.staged.size === 0 && !this.failed) return\n this.staged.clear()\n this.failed = false\n this.publish()\n },\n }\n }\n\n /** Write every staged edit, then re-seed from what the Host accepted. */\n async save(): Promise<void> {\n const plan = this.plan()\n const writes = plan.flatMap(item => item.run === undefined ? [] : [item.run])\n if (plan.length === 0 || this.saving || writes.length !== plan.length) return\n this.saving = true\n this.failed = false\n this.publish()\n let landed = true\n for (const write of writes) {\n landed = await write() && landed\n }\n if (landed) this.staged.clear()\n this.saving = false\n this.failed = !landed\n this.publish()\n }\n\n private plan(): PlannedWrite[] {\n const plan: PlannedWrite[] = []\n for (const [field, staged] of this.staged) {\n const secret = this.secretSpecs.get(field)\n if (secret !== undefined) {\n const value = staged.text.trim()\n if (value !== '') plan.push({ field, run: () => secret.write(value) })\n continue\n }\n const spec = this.spec(field)\n if (staged.clear) {\n if (this.stored(field)) plan.push({ field, run: () => this.clear(field) })\n continue\n }\n if (staged.text === spec.format(this.sectionValue(field))) continue\n const write = spec.parse(staged.text)\n if (write === undefined) plan.push({ field, run: undefined })\n else if (write.kind === 'clear') plan.push({ field, run: () => this.clear(field) })\n else plan.push({ field, run: () => this.store(field, write.value) })\n }\n return plan\n }\n\n private async clear(field: string): Promise<boolean> {\n await this.scope.unset(field)\n return !this.stored(field)\n }\n\n private async store(field: string, value: unknown): Promise<boolean> {\n await this.scope.set(field, value)\n return this.userLayer()?.[field] === value\n || (Array.isArray(value) && JSON.stringify(this.userLayer()?.[field]) === JSON.stringify(value))\n }\n\n private stage(field: string, edit: StagedEdit): void {\n this.staged.set(field, edit)\n this.failed = false\n this.publish()\n }\n\n /** Rebuild bound projections for card-owned state outside the settings draft. */\n notify(): void {\n this.publish()\n }\n\n private spec(field: string): CardFieldSpec {\n const spec = this.specs.get(field)\n if (spec === undefined) throw new Error(`im-bridge card has no field ${field}`)\n return spec\n }\n\n private snapshotOf(): SettingsScopeSnapshot<T> {\n return this.scope.getSnapshot()\n }\n\n private sectionValue(field: string): unknown {\n return (this.snapshotOf().value as Record<string, unknown> | undefined)?.[field]\n }\n\n private baseValue(field: string): unknown {\n return (this.snapshotOf().base as Record<string, unknown> | undefined)?.[field]\n }\n\n private userLayer(): Record<string, unknown> | undefined {\n return this.snapshotOf().user as Record<string, unknown> | undefined\n }\n\n private stored(field: string): boolean {\n const user = this.userLayer()\n return user !== undefined && Object.hasOwn(user, field)\n }\n\n private publish(): void {\n for (const listener of this.listeners) listener()\n }\n}\n","/** Staged form over the `im-bridge` settings namespace. */\n\nimport type { SnapshotStore } from '@deepseek-ai/dsh-client-store'\nimport type { SettingsScope } from '@deepseek-ai/dsh-client-ui-settings/client'\nimport {\n CardForm,\n csvField,\n numberField,\n textField,\n type CardActions,\n type CardFieldState,\n type CardShell,\n} from './card-form.ts'\n\n/** One redacted secret slot from `settings.describe`. */\ninterface SecretSlotView {\n path: readonly string[]\n set: boolean\n}\n\n/**\n * Cross-namespace describe face. Typed locally so this out-of-tree package\n * does not value- or type-import `@deepseek-ai/dsh-client-ui-settings`.\n */\ninterface SettingsDescribeFace {\n getSnapshot(): {\n view?: {\n namespaces: ReadonlyArray<{\n ns: string\n secrets: readonly SecretSlotView[]\n }>\n }\n }\n}\n\n/** Settings namespace paired with this card. */\nconst NS = 'im-bridge'\n\n/** User-editable slice of the im-bridge settings namespace. */\nexport interface WecomCardSettings {\n allowFrom?: string[]\n agentTimeoutSec?: number\n startHint?: string\n deniedMessage?: string\n welcomeMessage?: string\n provider?: string\n model?: string\n}\n\n/** Snapshot the WeCom card renders. */\nexport interface WecomCardState extends CardShell {\n botId: CardFieldState\n secret: CardFieldState\n botIdConfigured: boolean\n secretConfigured: boolean\n allowFrom: CardFieldState\n agentTimeoutSec: CardFieldState\n startHint: CardFieldState\n deniedMessage: CardFieldState\n welcomeMessage: CardFieldState\n provider: CardFieldState\n model: CardFieldState\n /** Whether the Host Connection RPC is available. */\n skillsInstallAvailable: boolean\n /** idle / installing / ok / error. */\n skillsInstallStatus: 'idle' | 'installing' | 'ok' | 'error'\n /** Destination after a successful install. */\n skillsDest: string\n /** Loaded wecomcli-* count after a successful install. */\n skillsCount: number\n /** Host error message after a failed install. */\n skillsError: string\n}\n\n/** Face the card's slot registration injects. */\nexport interface WecomCardFace extends CardActions {\n /** Download official wecomcli-* into the Host-resolved directory. */\n installSkills: () => void\n hooks: {\n /** Card snapshot bound by the renderer as useWecomCard. */\n wecomCard: SnapshotStore<WecomCardState>\n }\n}\n\n/** Unary RPC caller used by the install button. */\nexport interface SkillsInstallRpc {\n call(\n channel: string,\n endpoint: string,\n payload: unknown,\n signal?: AbortSignal,\n ): Promise<\n | { ok: true; value: unknown }\n | { ok: false; error: { message: string } }\n >\n}\n\n/** Bridges the `im-bridge` scope onto the staged card form. */\nexport class WecomCardController {\n private readonly form: CardForm<WecomCardSettings>\n private readonly store: SnapshotStore<WecomCardState>\n private skillsInstallStatus: WecomCardState['skillsInstallStatus'] = 'idle'\n private skillsDest = ''\n private skillsCount = 0\n private skillsError = ''\n\n /**\n * @param scope - bound settings scope for the `im-bridge` namespace.\n * @param describe - Host describe face; secret literals never ride it.\n * @param rpc - optional Connection RPC for the skills install button.\n */\n constructor(\n private readonly scope: SettingsScope<WecomCardSettings>,\n private readonly describe: SettingsDescribeFace,\n private readonly rpc: SkillsInstallRpc | undefined,\n ) {\n this.form = new CardForm(\n scope,\n [\n csvField('allowFrom'),\n numberField('agentTimeoutSec'),\n textField('startHint'),\n textField('deniedMessage'),\n textField('welcomeMessage'),\n textField('provider'),\n textField('model'),\n ],\n [\n { field: 'botId', write: text => this.writeSecret('botId', text) },\n { field: 'secret', write: text => this.writeSecret('secret', text) },\n ],\n )\n this.store = this.form.bind(() => this.projection())\n }\n\n private projection(): WecomCardState {\n return {\n ...this.form.shell(),\n botId: this.form.field('botId'),\n secret: this.form.field('secret'),\n botIdConfigured: this.secretConfigured('botId'),\n secretConfigured: this.secretConfigured('secret'),\n allowFrom: this.form.field('allowFrom'),\n agentTimeoutSec: this.form.field('agentTimeoutSec'),\n startHint: this.form.field('startHint'),\n deniedMessage: this.form.field('deniedMessage'),\n welcomeMessage: this.form.field('welcomeMessage'),\n provider: this.form.field('provider'),\n model: this.form.field('model'),\n skillsInstallAvailable: this.rpc !== undefined,\n skillsInstallStatus: this.skillsInstallStatus,\n skillsDest: this.skillsDest,\n skillsCount: this.skillsCount,\n skillsError: this.skillsError,\n }\n }\n\n /**\n * Whether the Host reports a configured value for one secret slot.\n * @param field - `botId` or `secret`.\n * @returns true when describe lists that slot as set.\n */\n private secretConfigured(field: string): boolean {\n const row = this.describe.getSnapshot().view?.namespaces.find(candidate => candidate.ns === NS)\n return row?.secrets.some(slot => slot.path[0] === field && slot.set) === true\n }\n\n /**\n * Write one credential into the user layer, then read configured state back.\n * @param field - `botId` or `secret`.\n * @param text - the staged literal.\n * @returns whether describe reports the slot set afterwards.\n */\n private async writeSecret(field: string, text: string): Promise<boolean> {\n await this.scope.set(field, text)\n return this.secretConfigured(field)\n }\n\n /**\n * Download official wecomcli-* into the Host-resolved directory.\n * The browser does not choose the path.\n */\n installSkills(): void {\n void this.runInstall()\n }\n\n private async runInstall(): Promise<void> {\n if (this.rpc === undefined || this.skillsInstallStatus === 'installing') return\n this.skillsInstallStatus = 'installing'\n this.skillsError = ''\n this.form.notify()\n try {\n const result = await this.rpc.call('/im-bridge', 'wecomcli.installSkills', {})\n if (!result.ok) {\n this.skillsInstallStatus = 'error'\n this.skillsError = result.error.message\n this.form.notify()\n return\n }\n const value = result.value as { dest?: unknown; count?: unknown }\n this.skillsInstallStatus = 'ok'\n this.skillsDest = typeof value.dest === 'string' ? value.dest : ''\n this.skillsCount = typeof value.count === 'number' ? value.count : 0\n this.skillsError = ''\n } catch (error) {\n this.skillsInstallStatus = 'error'\n this.skillsError = error instanceof Error ? error.message : String(error)\n }\n this.form.notify()\n }\n\n /** Face the slot registration injects. */\n inject(): WecomCardFace {\n return {\n hooks: { wecomCard: this.store },\n ...this.form.actions(),\n installSkills: () => { this.installSkills() },\n }\n }\n}\n","/** Dictionary keys owned by the im-bridge settings card. */\nexport type ImBridgeLocaleKey =\n | 'title'\n | 'description'\n | 'unsaved'\n | 'readOnly'\n | 'saveFailed'\n | 'save'\n | 'saving'\n | 'discard'\n | 'expand'\n | 'collapse'\n | 'overridden'\n | 'reset'\n | 'invalidNumber'\n | 'botId'\n | 'secret'\n | 'secretHint'\n | 'secretConfigured'\n | 'secretUnset'\n | 'allowFrom'\n | 'allowFromHint'\n | 'agentTimeoutSec'\n | 'agentTimeoutSecHint'\n | 'startHint'\n | 'startHintHint'\n | 'deniedMessage'\n | 'deniedMessageHint'\n | 'welcomeMessage'\n | 'welcomeMessageHint'\n | 'provider'\n | 'providerHint'\n | 'model'\n | 'modelHint'\n | 'skillsTitle'\n | 'skillsHint'\n | 'skillsInstall'\n | 'skillsInstalling'\n | 'skillsInstalled'\n | 'skillsFailed'\n | 'skillsUnavailable'\n\n/** English copy for the im-bridge card. */\nexport const en: Record<ImBridgeLocaleKey, string> = {\n title: 'WeCom Bridge',\n description: 'Credentials, allow-list, timeouts, and WeCom-only model overrides.',\n unsaved: 'Unsaved',\n readOnly: 'This document is read-only.',\n saveFailed: 'Save did not land. Correct the fields and try again.',\n save: 'Save',\n saving: 'Saving…',\n discard: 'Discard',\n expand: 'Show settings',\n collapse: 'Hide settings',\n overridden: 'Overridden',\n reset: 'Reset',\n invalidNumber: 'Enter a finite number.',\n botId: 'Bot ID',\n secret: 'Secret',\n secretHint: 'The box stays empty on purpose (the stored value never rides the wire). A Configured badge means it is saved; type a new value to replace it. Save, then restart the process to open the WebSocket.',\n secretConfigured: 'Configured',\n secretUnset: 'Not configured',\n allowFrom: 'Allowed sender userids',\n allowFromHint: 'Comma-separated. Empty allows everyone.',\n agentTimeoutSec: 'Task timeout (seconds)',\n agentTimeoutSecHint: 'Progress bar and remaining-time estimate.',\n startHint: 'Placeholder while thinking',\n startHintHint: 'First stream line after a message arrives.',\n deniedMessage: 'Denied-sender reply',\n deniedMessageHint: 'Sent when the userid is outside the allow-list.',\n welcomeMessage: 'Welcome message',\n welcomeMessageHint: 'Sent when a user opens the WeCom chat.',\n provider: 'WeCom-only provider',\n providerHint: 'Empty follows the GUI default model. Both provider and model must be set to override.',\n model: 'WeCom-only model',\n modelHint: 'Takes effect only together with provider.',\n skillsTitle: 'WeCom office skills',\n skillsHint: 'Installs wecomcli-* into the plugin directory ($DSH_HOME/wecom-cli-skills). Do not use npx skills add -g; that CLI has no --dir. An empty Bot ID / Secret box is normal.',\n skillsInstall: 'Install official skills',\n skillsInstalling: 'Installing…',\n skillsInstalled: 'Installed {count} skills into {dest}',\n skillsFailed: 'Install failed.',\n skillsUnavailable: 'Install needs the Web host Connection.',\n}\n\n/** Chinese copy for the im-bridge card. */\nexport const zh: Record<ImBridgeLocaleKey, string> = {\n title: '企业微信桥接',\n description: '凭证、白名单、超时和企微专用模型覆盖。',\n unsaved: '未保存',\n readOnly: '当前文档不可写。',\n saveFailed: '保存未生效,请修正后重试。',\n save: '保存',\n saving: '保存中…',\n discard: '放弃',\n expand: '展开设置',\n collapse: '收起设置',\n overridden: '已覆盖',\n reset: '重置',\n invalidNumber: '请输入有效数字。',\n botId: 'Bot ID',\n secret: 'Secret',\n secretHint: '框空是正常的(已存值不会传到浏览器)。徽章「已配置」即已保存;重新输入可覆盖。保存后需重启进程才会连 WebSocket。',\n secretConfigured: '已配置',\n secretUnset: '未配置',\n allowFrom: '允许的发送者 userid',\n allowFromHint: '逗号分隔;空 = 允许所有人。',\n agentTimeoutSec: '单任务超时(秒)',\n agentTimeoutSecHint: '动画进度条和剩余估算的基准。',\n startHint: '开始处理时的占位提示',\n startHintHint: '收到消息后推送的第一条流式文案。',\n deniedMessage: '非白名单拒绝文案',\n deniedMessageHint: '发送者不在白名单时回复。',\n welcomeMessage: '进入会话欢迎语',\n welcomeMessageHint: '用户打开企微会话时发送。',\n provider: '企微专用 provider',\n providerHint: '空 = 跟随 GUI 默认模型。须与 model 同时填写才覆盖。',\n model: '企微专用 model',\n modelHint: '仅在同时填写 provider 时生效。',\n skillsTitle: '企微办公 skills',\n skillsHint: '装到程序目录 $DSH_HOME/wecom-cli-skills。不要用 npx skills add -g;CLI 没有 --dir。Bot ID / Secret 框空是正常的。',\n skillsInstall: '安装官方 skills',\n skillsInstalling: '正在安装…',\n skillsInstalled: '已装 {count} 个到 {dest}',\n skillsFailed: '安装失败。',\n skillsUnavailable: '安装需要 Web Host 的 Connection。',\n}\n\ndeclare module '@deepseek-ai/dsh-client-ui-slots' {\n interface LocaleNamespaceMap {\n 'im-bridge': ImBridgeLocaleKey\n }\n}\n","/**\n * Browser half: Settings card keyed by the `im-bridge` namespace.\n */\n\nimport type { Context as ClientContext } from '@deepseek-ai/cordis'\n// Type-only: ctx.slots, ctx.locale, ctx.settingsScope.describe, and the keyed\n// slot declaration. Behavior crosses packages through services and slots only.\nimport type {} from '@deepseek-ai/dsh-client-ui-slots'\nimport type {} from '@deepseek-ai/dsh-client-ui-renderer/client'\nimport type {} from '@deepseek-ai/dsh-client-locale/client'\nimport type {} from '@deepseek-ai/dsh-client-ui-settings/client'\nimport type {} from '@deepseek-ai/dsh-client-ui-settings-plugins/client'\nimport { WecomCard } from './WecomCard.tsx'\nimport { WecomCardController, type SkillsInstallRpc } from './card-controller.ts'\nimport { en, zh } from './locales.ts'\n\n/** Settings namespace shared with the Host half. */\nconst NS = 'im-bridge'\n\n/** Required browser services. */\nexport const inject = ['slots', 'locale', 'connection', 'remote', 'settingsScope']\n\n/**\n * Register locale copy and the Plugins-tab card.\n * @param ctx - browser plugin context.\n */\nexport function apply(ctx: ClientContext): void {\n const connection = ctx.get('connection') as { rpc?: SkillsInstallRpc } | undefined\n const card = new WecomCardController(\n ctx.settingsScope.bind({ namespace: NS }),\n ctx.settingsScope.describe(),\n connection?.rpc,\n )\n\n ctx.effect(() => ctx.locale.register(NS, { zh, en }), 'im-bridge: locale dicts')\n\n ctx.slots.inject('settings.plugin.item', () => ctx.slots.register({\n name: 'settings.plugin.item',\n key: NS,\n locale: NS,\n inject: () => card.inject(),\n }, WecomCard))\n}\n"],"mappings":"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"}
|