dsh-tool-vision 0.3.6 → 0.3.8

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.
Files changed (3) hide show
  1. package/README.md +12 -0
  2. package/client.js +30 -8
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -125,6 +125,18 @@ Example endpoints (`baseURL`):
125
125
  - **Moonshot (Kimi)**: `https://api.moonshot.cn/v1` — `moonshot-v1-8k-vision-preview`
126
126
  - **Ollama local**: `http://localhost:11434/v1` — `llama3.2-vision` (no key)
127
127
 
128
+
129
+ > **Note for users**
130
+ > - `dsh plugin` prints "declares no dsh.bundle — installed as a plain
131
+ > dependency" — **expected**: this plugin mounts via `cordis.patch.yml`.
132
+ > - The settings section needs the `dsh-host-apiproxy` namespace allowlist;
133
+ > the plugin patches it automatically on first start — **restart `dsh web`
134
+ > once more** and the section appears. A dsh update overwrites the patch;
135
+ > the next plugin start re-applies it.
136
+ > - Settings changes hot-apply (no restart needed).
137
+ > - Tested against DSH `0.1.0-rc.6`.
138
+
139
+
128
140
  ## Limitations
129
141
 
130
142
  - A bridged image enters the conversation as a text hint (a transcript, not
package/client.js CHANGED
@@ -30,7 +30,7 @@ window.__ModuleLoader__.load({
30
30
  ".__tv_btn{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-3);color:var(--dsw-alias-label-primary);border-radius:8px;padding:6px 14px;font:inherit;font-size:13px;cursor:pointer}" +
31
31
  ".__tv_btn:hover:not(:disabled){border-color:var(--dsw-alias-state-business-primary)}" +
32
32
  ".__tv_btn:disabled{opacity:.5;cursor:default}" +
33
- ".__tv_btnPrimary{border-color:var(--dsw-alias-state-business-primary);background:var(--dsw-alias-state-business-primary);color:var(--dsw-alias-label-on-accent)}" +
33
+ ".__tv_btnPrimary{border-color:var(--dsw-alias-state-business-primary, #3964fe);background:var(--dsw-alias-state-business-primary, #3964fe);color:#fff}" +
34
34
  ".__tv_status{font-size:12px;color:var(--dsw-alias-label-tertiary)}" +
35
35
  ".__tv_error{font-size:12px;color:var(--dsw-alias-state-error-primary)}" +
36
36
  ".__tv_unavailable{font-size:13px;color:var(--dsw-alias-label-tertiary)}";
@@ -116,10 +116,7 @@ window.__ModuleLoader__.load({
116
116
  function VisionSection(props) {
117
117
  var t = props.t;
118
118
  var scope = props.scope;
119
- var snapshot = react.useSyncExternalStore(
120
- function (cb) { return scope.subscribe(cb); },
121
- function () { return scope.getSnapshot(); }
122
- );
119
+ var [snapshot, setSnapshot] = react.useState(function () { return scope.getSnapshot(); });
123
120
  var ready = snapshot.status === "ready" && snapshot.value !== void 0;
124
121
  var [draft, setDraft] = react.useState({});
125
122
  var [busy, setBusy] = react.useState(false);
@@ -128,13 +125,19 @@ window.__ModuleLoader__.load({
128
125
 
129
126
  react.useEffect(function () {
130
127
  scope.load();
131
- return function () { scope.dispose(); };
128
+ var alive = true;
129
+ var sync = function () { if (alive) setSnapshot(scope.getSnapshot()); };
130
+ var un = typeof scope.subscribe === "function" ? scope.subscribe(sync) : null;
131
+ return function () { alive = false; if (un) un(); if (scope.dispose) scope.dispose(); };
132
132
  }, [scope]);
133
- // Re-seed the draft when the snapshot value changes (after a save or a host change).
133
+ // Seed the draft ONLY when the snapshot becomes ready — never on value
134
+ // churn. settingsScope.getSnapshot() returns a fresh object per call,
135
+ // so depending on snapshot.value would reset user input on every render
136
+ // (typing appears dead).
134
137
  react.useEffect(function () {
135
138
  if (ready) setDraft(function (prev) { return Object.assign({}, prev, valueToDraft(snapshot.value)); });
136
139
  // eslint-disable-next-line react-hooks/exhaustive-deps
137
- }, [ready, snapshot.value]);
140
+ }, [ready]);
138
141
 
139
142
  if (snapshot.status === "unavailable") {
140
143
  return h("p", { className: "__tv_unavailable" }, t("unavailable"));
@@ -184,15 +187,34 @@ window.__ModuleLoader__.load({
184
187
  });
185
188
  Promise.all(writes).then(function () {
186
189
  setBusy(false); setNotice(t("saved"));
190
+ if (scope.load) scope.load();
187
191
  }).catch(function (e) {
188
192
  setBusy(false); setError(t("error") + ": " + String(e && e.message || e));
189
193
  });
190
194
  }
191
195
 
196
+ function reseedDraft() {
197
+ if (typeof scope.load === "function") {
198
+ var p = scope.load();
199
+ if (p && typeof p.then === "function") {
200
+ p.then(function () {
201
+ var fresh = scope.getSnapshot();
202
+ if (fresh.status === "ready" && fresh.value !== void 0) setDraft(Object.assign({}, valueToDraft(fresh.value)));
203
+ }).catch(function () {});
204
+ return;
205
+ }
206
+ }
207
+ setTimeout(function () {
208
+ var fresh = scope.getSnapshot();
209
+ if (fresh.status === "ready" && fresh.value !== void 0) setDraft(Object.assign({}, valueToDraft(fresh.value)));
210
+ }, 120);
211
+ }
212
+
192
213
  function onReset() {
193
214
  setBusy(true); setNotice(null); setError(null);
194
215
  Promise.all(FIELDS.map(function (f) { return scope.unset(f.key); })).then(function () {
195
216
  setBusy(false); setNotice(t("saved"));
217
+ reseedDraft();
196
218
  }).catch(function (e) {
197
219
  setBusy(false); setError(t("error") + ": " + String(e && e.message || e));
198
220
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-tool-vision",
3
- "version": "0.3.6",
3
+ "version": "0.3.8",
4
4
  "description": "DeepSeek Harness 外置视觉模型插件:inspect_image 把本地图片或 http(s) 图片 URL 发给任意 OpenAI 兼容端点,视觉模型看图的文字回答直接带回对话;附 Web UI 设置栏。",
5
5
  "type": "module",
6
6
  "main": "index.js",