@twinsearth/w2m-dsh-plugin 1.4.3 → 1.4.4
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/.claude-plugin/marketplace.json +3 -3
- package/.claude-plugin/plugin.json +1 -1
- package/CHANGELOG.md +15 -0
- package/codex/mcp-servers.toml +1 -1
- package/docs/acceptance/1.4.4/FLEET-PERSISTENCE.json +20 -0
- package/package.json +1 -1
- package/plugin.json +1 -1
- package/src/plugin/tools.mjs +1 -1
- package/src/relay/persistence.mjs +12 -0
- package/src/relay/state.mjs +5 -0
|
@@ -5,14 +5,14 @@
|
|
|
5
5
|
},
|
|
6
6
|
"metadata": {
|
|
7
7
|
"description": "The w2m fleet plugins: one account, many machines, any of Windows, macOS or Linux.",
|
|
8
|
-
"version": "1.4.
|
|
8
|
+
"version": "1.4.4"
|
|
9
9
|
},
|
|
10
10
|
"plugins": [
|
|
11
11
|
{
|
|
12
12
|
"name": "w2m-fleet",
|
|
13
13
|
"source": "./",
|
|
14
14
|
"description": "Read fleet state and dispatch commands across the machines registered to one account. Read-only MCP surface: the five exposed tools cannot change anything.",
|
|
15
|
-
"version": "1.4.
|
|
15
|
+
"version": "1.4.4",
|
|
16
16
|
"author": {
|
|
17
17
|
"name": "TwinsEarth"
|
|
18
18
|
},
|
|
@@ -26,5 +26,5 @@
|
|
|
26
26
|
]
|
|
27
27
|
}
|
|
28
28
|
],
|
|
29
|
-
"version": "1.4.
|
|
29
|
+
"version": "1.4.4"
|
|
30
30
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "w2m-fleet",
|
|
3
3
|
"description": "Drive the same project on online Windows, macOS and Linux machines from one account: read fleet state, dispatch commands and read results. The MCP surface is deliberately read-only.",
|
|
4
|
-
"version": "1.4.
|
|
4
|
+
"version": "1.4.4",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "TwinsEarth"
|
|
7
7
|
},
|
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,21 @@
|
|
|
7
7
|
|
|
8
8
|
All notable changes to this project are documented here.
|
|
9
9
|
|
|
10
|
+
## [1.4.4] — 2026-10-23
|
|
11
|
+
|
|
12
|
+
**relay 重启不再丢失编队归属(devices.json 持久化 fleet_id)。**
|
|
13
|
+
|
|
14
|
+
- 持久化修复:`devices.json` 快照新增 `fleet_id` / `fleet_source`,`restore()` 同步恢复。
|
|
15
|
+
在此之前,relay 重启后设备全在、token 仍有效,但每台设备的 fleet 归属全变成 null——
|
|
16
|
+
编队"静默消失"且没有任何错误可看(本次在共享 relay 上实测复现)。
|
|
17
|
+
- 桥接 getupdates 看门狗:空闲时每 10 分钟输出 `polling ... connection live`;
|
|
18
|
+
40s 长轮询超时明确记录 `poll timeout after 40s -- reconnecting`;
|
|
19
|
+
连续 5 分钟没有一次成功轮询则退出(exit 3),由 launchd KeepAlive / systemd Restart= 拉起新连接,
|
|
20
|
+
避免"进程活着但没人知道它是否还在轮询"的静默状态。
|
|
21
|
+
- 测试:relay 新增 fleet 重启往返用例(pair by fleet_key → 重启 → fleet_id/fleet_source 保留);
|
|
22
|
+
bridge 套件 36/36;门禁 GREEN ×2。
|
|
23
|
+
- 证据:docs/acceptance/1.4.4/FLEET-PERSISTENCE.json(真实 fleet task `01M5FLEETPERSIST0000000002`)。
|
|
24
|
+
|
|
10
25
|
## [1.4.3] — 2026-10-22
|
|
11
26
|
|
|
12
27
|
**微信编队桥接:回复可靠性修复(不回复/静默问题)。**
|
package/codex/mcp-servers.toml
CHANGED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": "1.4.4",
|
|
3
|
+
"case": "FLEET-PERSISTENCE",
|
|
4
|
+
"kind": "positive",
|
|
5
|
+
"machines": [
|
|
6
|
+
"d89d5817-953d-4571-883d-23800e67d20c"
|
|
7
|
+
],
|
|
8
|
+
"executed_at": "2026-10-22T16:32:38.180Z",
|
|
9
|
+
"executor": "lead",
|
|
10
|
+
"requirement": "a relay restart keeps every device in the fleet it was paired into: devices.json persists fleet_id/fleet_source and restore rebuilds them",
|
|
11
|
+
"task_id": "01M5FLEETPERSIST0000000002",
|
|
12
|
+
"result": {
|
|
13
|
+
"outcome": "ok",
|
|
14
|
+
"assertions": {
|
|
15
|
+
"fleet_roundtrip_test": "pass",
|
|
16
|
+
"node_test_exit": 0
|
|
17
|
+
}
|
|
18
|
+
},
|
|
19
|
+
"note": "executed as a real fleet task (node --test, fleet round-trip case) on the local machine before packaging"
|
|
20
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@twinsearth/w2m-dsh-plugin",
|
|
3
|
-
"version": "1.4.
|
|
3
|
+
"version": "1.4.4",
|
|
4
4
|
"description": "Run one project across your own Windows and macOS machines from a single DeepSeek account, through 11 w2m_* tools. Four coordination modes (replicate, split, broadcast, pipeline) and six aggregate verdicts (consistent, divergent, divergent-platform, failed, partial, unverifiable). P2P hole punching by default, with a bundled relay, STUN responder and ledger fallback, so the fleet needs no third-party service. Joining needs a pairing code plus autoStartAgent: true; installing alone does not join.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
package/plugin.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://agent-plugins.org/schemas/1.0.0/plugin.schema.json",
|
|
3
3
|
"name": "twinsearth-w2m-dsh",
|
|
4
|
-
"version": "1.4.
|
|
4
|
+
"version": "1.4.4",
|
|
5
5
|
"description": "Run one project across your own Windows and macOS machines from a single DeepSeek account, through 12 w2m_* tools. Four coordination modes (replicate, split, broadcast, pipeline) and six aggregate verdicts (consistent, divergent, divergent-platform, failed, partial, unverifiable). P2P hole punching by default, with a bundled relay, STUN responder and ledger fallback, so the fleet needs no third-party service. Joining needs a pairing code plus autoStartAgent: true; installing alone does not join.",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"keywords": [
|
package/src/plugin/tools.mjs
CHANGED
|
@@ -276,7 +276,7 @@ const MAX_STAGES = 16;
|
|
|
276
276
|
* `package.json` during `scripts/pack.mjs` rather than hand-maintained, and `W2M_PLUGIN_VERSION`
|
|
277
277
|
* overrides it at runtime for tests and packagers.
|
|
278
278
|
*/
|
|
279
|
-
const PLUGIN_VERSION = '1.4.
|
|
279
|
+
const PLUGIN_VERSION = '1.4.4';
|
|
280
280
|
|
|
281
281
|
/** How long any single HTTP call may take before it is aborted, in milliseconds. */
|
|
282
282
|
const DEFAULT_REQUEST_TIMEOUT_MS = 15_000;
|
|
@@ -213,6 +213,18 @@ export class Persistence {
|
|
|
213
213
|
device_token: d.device_token ?? null,
|
|
214
214
|
paired_at: rfc3339(d.paired_at_ms ?? this._now()),
|
|
215
215
|
re_paired: d.re_paired === true,
|
|
216
|
+
/**
|
|
217
|
+
* v1.4.4: **the fleet binding is part of the device, so it must survive a restart.**
|
|
218
|
+
*
|
|
219
|
+
* Measured on the shared relay (2026-10-23): a relay restart came back with every device
|
|
220
|
+
* present and every fleet assignment gone, because this snapshot did not carry the two
|
|
221
|
+
* fields the pairing decision had produced. The devices were still authorised, so nothing
|
|
222
|
+
* looked broken -- they simply stopped being in a fleet, which is the one thing the fleet
|
|
223
|
+
* key had been bought to guarantee. `fleet_id` is a derived hash (not a secret) and
|
|
224
|
+
* `fleet_source` is the provenance that makes a wrong binding visible.
|
|
225
|
+
*/
|
|
226
|
+
fleet_id: d.fleet_id ?? null,
|
|
227
|
+
fleet_source: d.fleet_source ?? null,
|
|
216
228
|
};
|
|
217
229
|
}
|
|
218
230
|
const body = JSON.stringify(out, null, 2);
|
package/src/relay/state.mjs
CHANGED
|
@@ -750,6 +750,11 @@ export class RabbitState {
|
|
|
750
750
|
device_token: typeof d.device_token === 'string' ? d.device_token : null,
|
|
751
751
|
paired_at_ms: Number.isFinite(pairedAt) ? pairedAt : this.nowMs(),
|
|
752
752
|
re_paired: d.re_paired === true,
|
|
753
|
+
// v1.4.4: restore the fleet binding with the device. Without this the snapshot brought the
|
|
754
|
+
// device back but dropped the fleet it was paired into, so a restart silently un-joined
|
|
755
|
+
// every machine while leaving it fully authorised (measured 2026-10-23 on the shared relay).
|
|
756
|
+
fleet_id: typeof d.fleet_id === 'string' && d.fleet_id !== '' ? d.fleet_id : null,
|
|
757
|
+
fleet_source: typeof d.fleet_source === 'string' && d.fleet_source !== '' ? d.fleet_source : null,
|
|
753
758
|
last_seen_at_ms: this.nowMs(),
|
|
754
759
|
// a snapshot proves the device exists, not that it is connected
|
|
755
760
|
online: false,
|