@khorsheed/dsh-local-agent-dsh 0.2.0-rc.3 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/client.js CHANGED
@@ -93,6 +93,83 @@ window.__ModuleLoader__.load({
93
93
  });
94
94
  return channel;
95
95
  }
96
+ /**
97
+ * Bind a settings card to the harness's own card-settings store (card-settings.ts
98
+ * on the host) layered over the row's host settings form: reads are the
99
+ * form's value with the stored overrides on top; writes go to the store only,
100
+ * never the profile patch — so they cannot be refused when several suites
101
+ * insert the same row. A host without the store keeps the plain row scope.
102
+ * @param ctx - the provider's client context.
103
+ * @param harness - the harness name (`dsh`, `kimi`, …).
104
+ * @param entryId - the plugin row id the base values come from.
105
+ * @returns the bound scope.
106
+ */
107
+ function bindCardSettingsScope(ctx, harness, entryId) {
108
+ const row = bindSettingsScope(ctx, entryId);
109
+ const gateway = () => {
110
+ const remote = ctx.get("remote.localAgentGateway");
111
+ return typeof remote?.cardSettings === "function" && typeof remote.setCardSettings === "function" ? remote : void 0;
112
+ };
113
+ const listeners = /* @__PURE__ */ new Set();
114
+ let stored;
115
+ let cached;
116
+ const emit = () => {
117
+ for (const listener of [...listeners]) listener();
118
+ };
119
+ const load = () => {
120
+ gateway()?.cardSettings(harness).then((result) => {
121
+ if (!result.ok || result.value === void 0) return;
122
+ stored = result.value;
123
+ emit();
124
+ }).catch(() => {});
125
+ };
126
+ const write = async (patch) => {
127
+ const remote = gateway();
128
+ if (remote === void 0) return false;
129
+ try {
130
+ const result = await remote.setCardSettings(harness, patch);
131
+ if (!result.ok || result.value === void 0) return false;
132
+ stored = result.value;
133
+ emit();
134
+ return true;
135
+ } catch {
136
+ return false;
137
+ }
138
+ };
139
+ return {
140
+ getSnapshot: () => {
141
+ const rowSnapshot = row.getSnapshot();
142
+ if (cached !== void 0 && cached.rowSnapshot === rowSnapshot && cached.stored === stored) return cached.snapshot;
143
+ const overrides = stored ?? {};
144
+ const snapshot = gateway() === void 0 ? rowSnapshot : {
145
+ ...rowSnapshot,
146
+ value: rowSnapshot.value === void 0 && stored === void 0 ? void 0 : {
147
+ ...rowSnapshot.value,
148
+ ...overrides
149
+ },
150
+ writable: true,
151
+ status: rowSnapshot.status === "loading" && stored !== void 0 ? "ready" : rowSnapshot.status === "unavailable" && stored !== void 0 ? "ready" : rowSnapshot.status
152
+ };
153
+ cached = {
154
+ rowSnapshot,
155
+ stored,
156
+ snapshot
157
+ };
158
+ return snapshot;
159
+ },
160
+ subscribe: (listener) => {
161
+ if (listeners.size === 0) load();
162
+ listeners.add(listener);
163
+ const off = row.subscribe(listener);
164
+ return () => {
165
+ listeners.delete(listener);
166
+ off();
167
+ };
168
+ },
169
+ set: (field, value) => gateway() === void 0 ? row.set(field, value) : write({ [field]: value }),
170
+ unset: (field) => gateway() === void 0 ? row.unset(field) : write({ [field]: null })
171
+ };
172
+ }
96
173
  //#endregion
97
174
  //#region src/client/locales.ts
98
175
  /** `local-agent-dsh` namespace dictionaries. */
@@ -118,11 +195,6 @@ window.__ModuleLoader__.load({
118
195
  "model.applied": "已保存,下一轮委派生效;进行中的轮次不受影响",
119
196
  "model.error": "保存失败,请重试",
120
197
  "auth.host": "dsh 凭据走宿主实例的凭证设置,无需单独登录。",
121
- "enable.title": "DeepSeek 委派",
122
- "enable.switch": "启用",
123
- "enable.switch.aria": "DeepSeek 委派开关",
124
- "enable.on": "已开启:模型可使用 subagent_dsh 委派给本机 dsh",
125
- "enable.off": "已关闭:委派只走官方内置子代理工具",
126
198
  "live.title": "常驻模式(live)",
127
199
  "live.info.aria": "常驻模式说明",
128
200
  "live.info": "常驻模式 = 成员进程常驻:输出实时流入成员会话、取消不杀进程、崩溃后自动续上原会话;关闭则每轮独立进程,跑完一次性出结果。设置为全局偏好,对所有后续委派生效。",
@@ -150,11 +222,6 @@ window.__ModuleLoader__.load({
150
222
  "model.applied": "Saved — takes effect on the next delegation round; rounds in flight are unaffected",
151
223
  "model.error": "Save failed, please retry",
152
224
  "auth.host": "dsh authenticates through the host instance’s credential settings — no separate sign-in.",
153
- "enable.title": "DeepSeek delegation",
154
- "enable.switch": "Enabled",
155
- "enable.switch.aria": "DeepSeek delegation switch",
156
- "enable.on": "ON: the model can delegate to the local dsh via subagent_dsh",
157
- "enable.off": "OFF: delegation goes through the official in-process subagent tool only",
158
225
  "live.title": "Resident mode (live)",
159
226
  "live.info.aria": "About resident mode",
160
227
  "live.info": "Resident mode keeps the member process alive: output streams into the member session in real time, cancelling does not kill the process, and a crash resumes the same session. Off means every round runs as an independent one-shot process. The setting is global and applies to every later delegation.",
@@ -204,8 +271,13 @@ window.__ModuleLoader__.load({
204
271
  * re-probes so a mid-session credential loss cannot leave a stale green dot.
205
272
  * @module @khorsheed/dsh-local-agent/client — auth status bus
206
273
  */
207
- const statuses = /* @__PURE__ */ new Map();
208
- const listeners = /* @__PURE__ */ new Set();
274
+ const BUS_KEY = Symbol.for("dsh.local-agent.auth-status");
275
+ const bus = globalThis[BUS_KEY] ??= {
276
+ statuses: /* @__PURE__ */ new Map(),
277
+ listeners: /* @__PURE__ */ new Set()
278
+ };
279
+ const statuses = bus.statuses;
280
+ const listeners = bus.listeners;
209
281
  /** Record one harness's latest probe result and notify subscribers. */
210
282
  function publishAuthStatus(harnessId, status) {
211
283
  if (statuses.get(harnessId) === status) return;
@@ -263,30 +335,30 @@ window.__ModuleLoader__.load({
263
335
  document.head.appendChild(tag);
264
336
  }
265
337
  var ProviderAuthBlock_module_css_default = {
266
- "dotOn": "On5p7W_dotOn",
267
- "rows": "On5p7W_rows",
268
- "credentialDot": "On5p7W_credentialDot",
269
- "promptText": "On5p7W_promptText",
270
- "logoutButton": "On5p7W_logoutButton",
271
- "intro": "On5p7W_intro",
272
338
  "rowName": "On5p7W_rowName",
273
- "rowTag": "On5p7W_rowTag",
274
- "rowPending": "On5p7W_rowPending",
275
- "rowIdentity": "On5p7W_rowIdentity",
276
- "rowActions": "On5p7W_rowActions",
277
339
  "title": "On5p7W_title",
278
- "rowHead": "On5p7W_rowHead",
279
- "dotOff": "On5p7W_dotOff",
340
+ "credentialDot": "On5p7W_credentialDot",
341
+ "dotOn": "On5p7W_dotOn",
280
342
  "status": "On5p7W_status",
281
- "openPage": "On5p7W_openPage",
343
+ "dotPending": "On5p7W_dotPending",
344
+ "rosterError": "On5p7W_rosterError",
345
+ "rowActions": "On5p7W_rowActions",
346
+ "retryButton": "On5p7W_retryButton",
347
+ "promptText": "On5p7W_promptText",
348
+ "rows": "On5p7W_rows",
349
+ "codeInput": "On5p7W_codeInput",
282
350
  "section": "On5p7W_section",
351
+ "loginPrompt": "On5p7W_loginPrompt",
352
+ "rowIdentity": "On5p7W_rowIdentity",
353
+ "rowTag": "On5p7W_rowTag",
354
+ "dotOff": "On5p7W_dotOff",
355
+ "rowPending": "On5p7W_rowPending",
283
356
  "rowCard": "On5p7W_rowCard",
284
357
  "loginButton": "On5p7W_loginButton",
285
- "rosterError": "On5p7W_rosterError",
286
- "dotPending": "On5p7W_dotPending",
287
- "codeInput": "On5p7W_codeInput",
288
- "retryButton": "On5p7W_retryButton",
289
- "loginPrompt": "On5p7W_loginPrompt"
358
+ "intro": "On5p7W_intro",
359
+ "openPage": "On5p7W_openPage",
360
+ "rowHead": "On5p7W_rowHead",
361
+ "logoutButton": "On5p7W_logoutButton"
290
362
  };
291
363
  //#endregion
292
364
  //#region ../local-agent/src/client/ProviderAuthBlock.tsx
@@ -439,8 +511,8 @@ window.__ModuleLoader__.load({
439
511
  const statusKind = usePublishedAuthStatus(harness.id) ?? view.status;
440
512
  const authenticated = statusKind === "authenticated";
441
513
  const loginPending = pendingSince !== void 0;
442
- const loginable = view.loginable ?? true;
443
- const logoutable = view.logoutable ?? true;
514
+ const loginable = view.loginable ?? statusKind !== "unavailable";
515
+ const logoutable = view.logoutable ?? statusKind !== "unavailable";
444
516
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
445
517
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
446
518
  className: ProviderAuthBlock_module_css_default.rowHead,
@@ -473,7 +545,7 @@ window.__ModuleLoader__.load({
473
545
  statusKind === "checking" && t("loading"),
474
546
  statusKind === "authenticated" && t("settings.authenticated"),
475
547
  statusKind === "anonymous" && t("settings.notAuthenticated"),
476
- statusKind === "unavailable" && t("error")
548
+ statusKind === "unavailable" && t("settings.statusFailed")
477
549
  ]
478
550
  }),
479
551
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
@@ -565,10 +637,10 @@ window.__ModuleLoader__.load({
565
637
  document.head.appendChild(tag);
566
638
  }
567
639
  var AuthStatusDot_module_css_default = {
568
- "dotOff": "OFjNUG_dotOff",
569
- "dotPending": "OFjNUG_dotPending",
570
640
  "credentialDot": "OFjNUG_credentialDot",
571
- "dotOn": "OFjNUG_dotOn"
641
+ "dotOn": "OFjNUG_dotOn",
642
+ "dotOff": "OFjNUG_dotOff",
643
+ "dotPending": "OFjNUG_dotPending"
572
644
  };
573
645
  //#endregion
574
646
  //#region ../local-agent/src/client/AuthStatusDot.tsx
@@ -594,40 +666,40 @@ window.__ModuleLoader__.load({
594
666
  document.head.appendChild(tag);
595
667
  }
596
668
  var SettingsCard_module_css_default = {
597
- "chevron": "_3LBPpW_chevron",
669
+ "headText": "_3LBPpW_headText",
598
670
  "header": "_3LBPpW_header",
671
+ "modelMenuButton": "_3LBPpW_modelMenuButton",
672
+ "name": "_3LBPpW_name",
673
+ "blockTitle": "_3LBPpW_blockTitle",
674
+ "description": "_3LBPpW_description",
675
+ "modelItemLabel": "_3LBPpW_modelItemLabel",
676
+ "hint": "_3LBPpW_hint",
677
+ "cardOpen": "_3LBPpW_cardOpen",
599
678
  "modelMenuChevron": "_3LBPpW_modelMenuChevron",
600
- "modelInput": "_3LBPpW_modelInput",
679
+ "block": "_3LBPpW_block",
680
+ "info": "_3LBPpW_info",
681
+ "modelMenuChevronOpen": "_3LBPpW_modelMenuChevronOpen",
682
+ "chevron": "_3LBPpW_chevron",
683
+ "body": "_3LBPpW_body",
684
+ "nameRow": "_3LBPpW_nameRow",
601
685
  "modelItemCurrent": "_3LBPpW_modelItemCurrent",
602
- "modelItemDefault": "_3LBPpW_modelItemDefault",
603
- "headText": "_3LBPpW_headText",
686
+ "chevronOpen": "_3LBPpW_chevronOpen",
687
+ "modelItemCheck": "_3LBPpW_modelItemCheck",
688
+ "modelMenu": "_3LBPpW_modelMenu",
604
689
  "modelItem": "_3LBPpW_modelItem",
605
- "rowLabel": "_3LBPpW_rowLabel",
606
- "modelItemLabel": "_3LBPpW_modelItemLabel",
607
- "row": "_3LBPpW_row",
608
- "nameRow": "_3LBPpW_nameRow",
609
- "modelField": "_3LBPpW_modelField",
610
690
  "saved": "_3LBPpW_saved",
611
- "modelMenuButton": "_3LBPpW_modelMenuButton",
612
- "modelMenuChevronOpen": "_3LBPpW_modelMenuChevronOpen",
691
+ "errorText": "_3LBPpW_errorText",
692
+ "modelMenuUp": "_3LBPpW_modelMenuUp",
693
+ "modelField": "_3LBPpW_modelField",
694
+ "rowLabel": "_3LBPpW_rowLabel",
695
+ "modelInput": "_3LBPpW_modelInput",
613
696
  "switch": "_3LBPpW_switch",
614
- "switchOn": "_3LBPpW_switchOn",
615
- "modelItemCheck": "_3LBPpW_modelItemCheck",
616
- "description": "_3LBPpW_description",
617
- "hint": "_3LBPpW_hint",
697
+ "row": "_3LBPpW_row",
618
698
  "knob": "_3LBPpW_knob",
619
699
  "card": "_3LBPpW_card",
620
- "modelMenuUp": "_3LBPpW_modelMenuUp",
621
- "body": "_3LBPpW_body",
622
- "blockTitle": "_3LBPpW_blockTitle",
623
- "chevronOpen": "_3LBPpW_chevronOpen",
624
- "block": "_3LBPpW_block",
625
- "name": "_3LBPpW_name",
626
- "errorText": "_3LBPpW_errorText",
627
- "modelMenu": "_3LBPpW_modelMenu",
628
- "info": "_3LBPpW_info",
629
- "cardOpen": "_3LBPpW_cardOpen",
630
- "modelSave": "_3LBPpW_modelSave"
700
+ "switchOn": "_3LBPpW_switchOn",
701
+ "modelSave": "_3LBPpW_modelSave",
702
+ "modelItemDefault": "_3LBPpW_modelItemDefault"
631
703
  };
632
704
  //#endregion
633
705
  //#region src/client/SettingsCard.tsx
@@ -694,8 +766,9 @@ window.__ModuleLoader__.load({
694
766
  const write = (field, value) => {
695
767
  setSaved(false);
696
768
  setError(false);
697
- scope.set(field, value).then(() => {
698
- setSaved(true);
769
+ scope.set(field, value).then((accepted) => {
770
+ if (accepted === false) setError(true);
771
+ else setSaved(true);
699
772
  }, () => {
700
773
  setError(true);
701
774
  });
@@ -756,7 +829,7 @@ window.__ModuleLoader__.load({
756
829
  }
757
830
  /** The card body both settings surfaces share: the auth block, the delegation switch, the default-model block, and the resident-mode block. */
758
831
  function CardBody({ state, auth, authT, renderModelPicker, useSessions, t }) {
759
- const { snapshot, saved, error, ready, enabled, live, storedModel, modelValue, modelSaved, modelError, choices, modelMenuOpen, modelMenuUp, modelFieldRef, modelPlaceholder, modelDefaultItem, saveModel, write, toggleModelMenu, setModelDraft, setModelMenuOpen } = state;
832
+ const { snapshot, saved, error, ready, live, storedModel, modelValue, modelSaved, modelError, choices, modelMenuOpen, modelMenuUp, modelFieldRef, modelPlaceholder, modelDefaultItem, saveModel, write, toggleModelMenu, setModelDraft, setModelMenuOpen } = state;
760
833
  const modelInputElement = /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
761
834
  type: "text",
762
835
  className: SettingsCard_module_css_default.modelInput,
@@ -794,37 +867,6 @@ window.__ModuleLoader__.load({
794
867
  })
795
868
  ]
796
869
  }),
797
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
798
- className: SettingsCard_module_css_default.block,
799
- children: [
800
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("h3", {
801
- className: SettingsCard_module_css_default.blockTitle,
802
- children: t("enable.title")
803
- }),
804
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
805
- className: SettingsCard_module_css_default.row,
806
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
807
- className: SettingsCard_module_css_default.rowLabel,
808
- children: t("enable.switch")
809
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
810
- type: "button",
811
- role: "switch",
812
- "aria-checked": enabled,
813
- "aria-label": t("enable.switch.aria"),
814
- className: enabled ? `${SettingsCard_module_css_default.switch} ${SettingsCard_module_css_default.switchOn}` : SettingsCard_module_css_default.switch,
815
- disabled: !ready,
816
- onClick: () => {
817
- write("enabled", !enabled);
818
- },
819
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { className: SettingsCard_module_css_default.knob })
820
- })]
821
- }),
822
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
823
- className: SettingsCard_module_css_default.hint,
824
- children: t(enabled ? "enable.on" : "enable.off")
825
- })
826
- ]
827
- }),
828
870
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
829
871
  className: SettingsCard_module_css_default.block,
830
872
  children: [
@@ -1122,7 +1164,7 @@ window.__ModuleLoader__.load({
1122
1164
  en
1123
1165
  }), "local-agent-dsh: dictionaries");
1124
1166
  const t = ctx.locale.bind(NS);
1125
- const scope = bindSettingsScope(ctx, "local-agent-dsh");
1167
+ const scope = bindCardSettingsScope(ctx, "dsh", "local-agent-dsh");
1126
1168
  const authT = ctx.locale.bind("local-agent");
1127
1169
  const gateway = () => ctx.get("remote.localAgentGateway");
1128
1170
  const cardFace = () => ({