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.
- package/README.md +12 -0
- package/client.js +30 -8
- 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
|
|
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.
|
|
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
|
-
|
|
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
|
-
//
|
|
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
|
|
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