@sparkelf/dsh-patch-mobile-bridge-serialized-actions 0.1.0-rc.10
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/LICENSE +21 -0
- package/README.i18n.yaml +6 -0
- package/README.md +17 -0
- package/README.zh.md +17 -0
- package/package.json +37 -0
- package/patches/serialized-actions.patch +218 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 DeepSeek
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.i18n.yaml
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each
|
|
2
|
+
# side as of the last confirmed-consistent state. Both languages carry equal authority;
|
|
3
|
+
# after editing either side, bring the other along and re-record with:
|
|
4
|
+
# pnpm run verify-translation-pairing --write patches/npm/mobile-bridge-serialized-actions/README.md
|
|
5
|
+
README.md: 66c736674df9e2727ffe2237bca7c0fda7806bcd
|
|
6
|
+
README.zh.md: 3f6d959b705d4a09603d2890f8750b99bae3b78c
|
package/README.md
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# Mobile Bridge serialized-actions patch
|
|
2
|
+
|
|
3
|
+
English | [中文](README.zh.md)
|
|
4
|
+
|
|
5
|
+
This data-only npm package carries one temporary compatibility patch for the verified `@sparkelf/dsh-mobile-bridge 0.2.8` target. `dsh-plus apply` selects and applies its payload while materializing the npm profile; installing the package does not mutate dependencies through an npm lifecycle script.
|
|
6
|
+
|
|
7
|
+
The compatibility declaration covers only the verified target version. The exact patch-package, DSH, target-package, variant, and payload selection belongs to the deployment lock.
|
|
8
|
+
|
|
9
|
+
The patch preserves serialized action execution required by the accepted Plus mobile workflow. Its upstream pull request, owner, and retirement status remain in the Plus curated-plugin manifest. Remove this package from the Plus distribution when the tracked Mobile Bridge upstream release contains the same serialized-action behavior.
|
|
10
|
+
|
|
11
|
+
## Model Experience
|
|
12
|
+
|
|
13
|
+
This package does not register a Cordis plugin, add model-visible text, alter token usage, or affect KV-cache reuse. Its target plugin owns any runtime and model experience.
|
|
14
|
+
|
|
15
|
+
## Known Limitations and Deferred Work
|
|
16
|
+
|
|
17
|
+
The package supports only the declared target package and payload. It does not provide a fallback implementation when exact patch application fails.
|
package/README.zh.md
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# Mobile Bridge 串行action补丁
|
|
2
|
+
|
|
3
|
+
[English](README.md) | 中文
|
|
4
|
+
|
|
5
|
+
这个data-only npm package为已验证的`@sparkelf/dsh-mobile-bridge 0.2.8` target携带一个临时compatibility patch。`dsh-plus apply`在materialize npm profile时选择并应用payload;安装package不会通过npm lifecycle script修改依赖。
|
|
6
|
+
|
|
7
|
+
Compatibility declaration只覆盖已验证target version。精确patch-package、DSH、target-package、variant与payload选择属于deployment lock。
|
|
8
|
+
|
|
9
|
+
该patch保留已验收Plus移动工作流所需的串行action执行。其upstream pull request、owner与retirement status仍由Plus curated-plugin manifest拥有。当Mobile Bridge发布版本包含同等串行action行为时,从Plus distribution删除这个package。
|
|
10
|
+
|
|
11
|
+
## Model Experience
|
|
12
|
+
|
|
13
|
+
本package不注册Cordis plugin、不增加model-visible text、不改变token usage,也不影响KV-cache reuse。目标插件拥有其runtime与model experience。
|
|
14
|
+
|
|
15
|
+
## Known Limitations and Deferred Work
|
|
16
|
+
|
|
17
|
+
Package只支持已声明target package与payload。精确patch应用失败时不提供fallback implementation。
|
package/package.json
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
{
|
|
2
|
+
"description": "Compatibility patch for serialized Mobile Bridge actions in DeepSeek Harness Plus",
|
|
3
|
+
"dshPatch": {
|
|
4
|
+
"formatVersion": 1,
|
|
5
|
+
"variants": [
|
|
6
|
+
{
|
|
7
|
+
"dsh": ">=0.1.0-rc.8",
|
|
8
|
+
"file": "./patches/serialized-actions.patch",
|
|
9
|
+
"id": "mobile-bridge-serialized-actions",
|
|
10
|
+
"target": {
|
|
11
|
+
"kind": "npm",
|
|
12
|
+
"name": "@sparkelf/dsh-mobile-bridge",
|
|
13
|
+
"range": "0.2.8"
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
]
|
|
17
|
+
},
|
|
18
|
+
"exports": {
|
|
19
|
+
"./package.json": "./package.json",
|
|
20
|
+
"./patches/serialized-actions.patch": "./patches/serialized-actions.patch"
|
|
21
|
+
},
|
|
22
|
+
"files": [
|
|
23
|
+
"patches/*.patch"
|
|
24
|
+
],
|
|
25
|
+
"license": "MIT",
|
|
26
|
+
"name": "@sparkelf/dsh-patch-mobile-bridge-serialized-actions",
|
|
27
|
+
"publishConfig": {
|
|
28
|
+
"access": "public"
|
|
29
|
+
},
|
|
30
|
+
"repository": {
|
|
31
|
+
"directory": "patches/npm/mobile-bridge-serialized-actions",
|
|
32
|
+
"type": "git",
|
|
33
|
+
"url": "git+https://github.com/SparkElf/deepseek-harness-plus.git"
|
|
34
|
+
},
|
|
35
|
+
"type": "module",
|
|
36
|
+
"version": "0.1.0-rc.10"
|
|
37
|
+
}
|
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
diff --git a/lib/client.js b/lib/client.js
|
|
2
|
+
index 0e6c4950f69093145da9ee79e9a4520319150863..0671df4e5ae4baeef045baea306bfdc72225367e 100644
|
|
3
|
+
--- a/lib/client.js
|
|
4
|
+
+++ b/lib/client.js
|
|
5
|
+
@@ -2511,7 +2511,9 @@ window.__ModuleLoader__.load({
|
|
6
|
+
function MobileBridgeSection(props) {
|
|
7
|
+
const { connectNow, disconnectDevice, disconnectNow, loadStatus, loadValues, saveValues, subscribeStatus, t } = props;
|
|
8
|
+
const [values, setValues] = (0, react.useState)(DEFAULTS);
|
|
9
|
+
+ const draftValues = (0, react.useRef)(DEFAULTS);
|
|
10
|
+
const persistedValues = (0, react.useRef)(DEFAULTS);
|
|
11
|
+
+ const saveOperation = (0, react.useRef)(null);
|
|
12
|
+
const [status, setStatus] = (0, react.useState)(null);
|
|
13
|
+
const [loaded, setLoaded] = (0, react.useState)(false);
|
|
14
|
+
const [saving, setSaving] = (0, react.useState)(false);
|
|
15
|
+
@@ -2526,6 +2528,7 @@ window.__ModuleLoader__.load({
|
|
16
|
+
let live = true;
|
|
17
|
+
Promise.all([loadValues(), loadStatus()]).then(([nextValues, nextStatus]) => {
|
|
18
|
+
if (!live) return;
|
|
19
|
+
+ draftValues.current = nextValues;
|
|
20
|
+
persistedValues.current = nextValues;
|
|
21
|
+
setValues(nextValues);
|
|
22
|
+
setStatus(nextStatus);
|
|
23
|
+
@@ -2578,46 +2581,58 @@ window.__ModuleLoader__.load({
|
|
24
|
+
live = false;
|
|
25
|
+
};
|
|
26
|
+
}, [status?.qrUrl, t]);
|
|
27
|
+
- /** Persist one complete draft without coupling completion to relay state. */
|
|
28
|
+
- const commit = async (nextValues) => {
|
|
29
|
+
- if (nextValues === persistedValues.current) return;
|
|
30
|
+
+ /** Persist the latest draft and absorb edits made while that save is in flight. */
|
|
31
|
+
+ const commit = () => {
|
|
32
|
+
+ if (saveOperation.current !== null) return saveOperation.current;
|
|
33
|
+
+ if (draftValues.current === persistedValues.current) return Promise.resolve(true);
|
|
34
|
+
setSaving(true);
|
|
35
|
+
setMessage(t("saving"));
|
|
36
|
+
setError(null);
|
|
37
|
+
- try {
|
|
38
|
+
- const persisted = await saveValues(nextValues);
|
|
39
|
+
- persistedValues.current = persisted;
|
|
40
|
+
- setValues(persisted);
|
|
41
|
+
- setMessage(t("saved"));
|
|
42
|
+
- } catch (caught) {
|
|
43
|
+
- console.error("[dsh-mobile-bridge] settings save failed", caught);
|
|
44
|
+
- setValues(persistedValues.current);
|
|
45
|
+
- setMessage(null);
|
|
46
|
+
- setError(t("saveFailed"));
|
|
47
|
+
- } finally {
|
|
48
|
+
- setSaving(false);
|
|
49
|
+
- }
|
|
50
|
+
+ const operation = (async () => {
|
|
51
|
+
+ try {
|
|
52
|
+
+ while (draftValues.current !== persistedValues.current) {
|
|
53
|
+
+ const candidate = draftValues.current;
|
|
54
|
+
+ const persisted = await saveValues(candidate);
|
|
55
|
+
+ persistedValues.current = persisted;
|
|
56
|
+
+ if (draftValues.current === candidate) {
|
|
57
|
+
+ draftValues.current = persisted;
|
|
58
|
+
+ setValues(persisted);
|
|
59
|
+
+ }
|
|
60
|
+
+ }
|
|
61
|
+
+ setMessage(t("saved"));
|
|
62
|
+
+ return true;
|
|
63
|
+
+ } catch {
|
|
64
|
+
+ draftValues.current = persistedValues.current;
|
|
65
|
+
+ setValues(persistedValues.current);
|
|
66
|
+
+ setMessage(null);
|
|
67
|
+
+ setError(t("saveFailed"));
|
|
68
|
+
+ return false;
|
|
69
|
+
+ } finally {
|
|
70
|
+
+ saveOperation.current = null;
|
|
71
|
+
+ setSaving(false);
|
|
72
|
+
+ }
|
|
73
|
+
+ })();
|
|
74
|
+
+ saveOperation.current = operation;
|
|
75
|
+
+ return operation;
|
|
76
|
+
};
|
|
77
|
+
const set = (key, value) => {
|
|
78
|
+
- setValues((current) => ({
|
|
79
|
+
- ...current,
|
|
80
|
+
- [key]: value
|
|
81
|
+
- }));
|
|
82
|
+
- setMessage(null);
|
|
83
|
+
- };
|
|
84
|
+
- const setAndCommit = (key, value) => {
|
|
85
|
+
const nextValues = {
|
|
86
|
+
- ...values,
|
|
87
|
+
+ ...draftValues.current,
|
|
88
|
+
[key]: value
|
|
89
|
+
};
|
|
90
|
+
+ draftValues.current = nextValues;
|
|
91
|
+
setValues(nextValues);
|
|
92
|
+
setMessage(null);
|
|
93
|
+
- commit(nextValues);
|
|
94
|
+
+ };
|
|
95
|
+
+ const setAndCommit = (key, value) => {
|
|
96
|
+
+ set(key, value);
|
|
97
|
+
+ commit();
|
|
98
|
+
};
|
|
99
|
+
const refreshStatus = async () => {
|
|
100
|
+
setRefreshing(true);
|
|
101
|
+
setError(null);
|
|
102
|
+
try {
|
|
103
|
+
+ if (!await commit()) return;
|
|
104
|
+
setStatus(await loadStatus());
|
|
105
|
+
} catch (caught) {
|
|
106
|
+
console.error("[dsh-mobile-bridge] status refresh failed", caught);
|
|
107
|
+
@@ -2633,6 +2648,7 @@ window.__ModuleLoader__.load({
|
|
108
|
+
setMessage(null);
|
|
109
|
+
setError(null);
|
|
110
|
+
try {
|
|
111
|
+
+ if (!await commit()) return;
|
|
112
|
+
setStatus(await (action === "connect" ? connectNow() : disconnectNow()));
|
|
113
|
+
} catch (caught) {
|
|
114
|
+
console.error("[dsh-mobile-bridge] connection action failed", caught);
|
|
115
|
+
@@ -2708,9 +2724,10 @@ window.__ModuleLoader__.load({
|
|
116
|
+
}),
|
|
117
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("form", {
|
|
118
|
+
className: MobileBridgeSection_module_css_default.form,
|
|
119
|
+
+ "aria-busy": saving,
|
|
120
|
+
onSubmit: (event) => {
|
|
121
|
+
event.preventDefault();
|
|
122
|
+
- commit(values);
|
|
123
|
+
+ commit();
|
|
124
|
+
},
|
|
125
|
+
children: [
|
|
126
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
127
|
+
@@ -2727,10 +2744,10 @@ window.__ModuleLoader__.load({
|
|
128
|
+
className: MobileBridgeSection_module_css_default.control,
|
|
129
|
+
type: "url",
|
|
130
|
+
value: values.serverUrl,
|
|
131
|
+
- disabled: !loaded || saving,
|
|
132
|
+
+ disabled: !loaded,
|
|
133
|
+
onChange: (event) => set("serverUrl", event.currentTarget.value),
|
|
134
|
+
onBlur: () => {
|
|
135
|
+
- commit(values);
|
|
136
|
+
+ commit();
|
|
137
|
+
}
|
|
138
|
+
})]
|
|
139
|
+
}),
|
|
140
|
+
@@ -2747,10 +2764,10 @@ window.__ModuleLoader__.load({
|
|
141
|
+
min: 1,
|
|
142
|
+
step: 1,
|
|
143
|
+
value: values.localPort,
|
|
144
|
+
- disabled: !loaded || saving,
|
|
145
|
+
+ disabled: !loaded,
|
|
146
|
+
onChange: (event) => set("localPort", event.currentTarget.valueAsNumber),
|
|
147
|
+
onBlur: () => {
|
|
148
|
+
- commit(values);
|
|
149
|
+
+ commit();
|
|
150
|
+
}
|
|
151
|
+
})]
|
|
152
|
+
}),
|
|
153
|
+
@@ -2768,10 +2785,10 @@ window.__ModuleLoader__.load({
|
|
154
|
+
max: 365,
|
|
155
|
+
step: 1,
|
|
156
|
+
value: values.sessionDays,
|
|
157
|
+
- disabled: !loaded || saving,
|
|
158
|
+
+ disabled: !loaded,
|
|
159
|
+
onChange: (event) => set("sessionDays", event.currentTarget.valueAsNumber),
|
|
160
|
+
onBlur: () => {
|
|
161
|
+
- commit(values);
|
|
162
|
+
+ commit();
|
|
163
|
+
}
|
|
164
|
+
})]
|
|
165
|
+
}),
|
|
166
|
+
@@ -2786,10 +2803,10 @@ window.__ModuleLoader__.load({
|
|
167
|
+
className: MobileBridgeSection_module_css_default.control,
|
|
168
|
+
type: "password",
|
|
169
|
+
value: values.userKey,
|
|
170
|
+
- disabled: !loaded || saving,
|
|
171
|
+
+ disabled: !loaded,
|
|
172
|
+
onChange: (event) => set("userKey", event.currentTarget.value),
|
|
173
|
+
onBlur: () => {
|
|
174
|
+
- commit(values);
|
|
175
|
+
+ commit();
|
|
176
|
+
}
|
|
177
|
+
})]
|
|
178
|
+
}),
|
|
179
|
+
@@ -2804,10 +2821,10 @@ window.__ModuleLoader__.load({
|
|
180
|
+
className: MobileBridgeSection_module_css_default.control,
|
|
181
|
+
type: "email",
|
|
182
|
+
value: values.ownerEmail,
|
|
183
|
+
- disabled: !loaded || saving,
|
|
184
|
+
+ disabled: !loaded,
|
|
185
|
+
onChange: (event) => set("ownerEmail", event.currentTarget.value),
|
|
186
|
+
onBlur: () => {
|
|
187
|
+
- commit(values);
|
|
188
|
+
+ commit();
|
|
189
|
+
}
|
|
190
|
+
})]
|
|
191
|
+
})
|
|
192
|
+
@@ -2824,7 +2841,7 @@ window.__ModuleLoader__.load({
|
|
193
|
+
className: MobileBridgeSection_module_css_default.checkbox,
|
|
194
|
+
type: "checkbox",
|
|
195
|
+
checked: values.emailTwoFactor,
|
|
196
|
+
- disabled: !loaded || saving,
|
|
197
|
+
+ disabled: !loaded,
|
|
198
|
+
onChange: (event) => setAndCommit("emailTwoFactor", event.currentTarget.checked)
|
|
199
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t("twoFactor") })]
|
|
200
|
+
}),
|
|
201
|
+
@@ -2836,7 +2853,7 @@ window.__ModuleLoader__.load({
|
|
202
|
+
className: MobileBridgeSection_module_css_default.checkbox,
|
|
203
|
+
type: "checkbox",
|
|
204
|
+
checked: values.autoConnect,
|
|
205
|
+
- disabled: !loaded || saving,
|
|
206
|
+
+ disabled: !loaded,
|
|
207
|
+
onChange: (event) => setAndCommit("autoConnect", event.currentTarget.checked)
|
|
208
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t("autoConnect") })]
|
|
209
|
+
}),
|
|
210
|
+
@@ -2848,7 +2865,7 @@ window.__ModuleLoader__.load({
|
|
211
|
+
className: MobileBridgeSection_module_css_default.checkbox,
|
|
212
|
+
type: "checkbox",
|
|
213
|
+
checked: values.autoReconnect,
|
|
214
|
+
- disabled: !loaded || saving,
|
|
215
|
+
+ disabled: !loaded,
|
|
216
|
+
onChange: (event) => setAndCommit("autoReconnect", event.currentTarget.checked)
|
|
217
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t("autoReconnect") })]
|
|
218
|
+
})
|