@twinsearth/w2m-dsh-plugin 1.0.11 → 1.0.12
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/CHANGELOG.md +55 -0
- package/package.json +4 -3
- package/plugin.json +1 -1
- package/src/plugin/tools.mjs +1 -1
- package/src/relay/state.mjs +14 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,61 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to this project are documented here.
|
|
4
4
|
|
|
5
|
+
## [1.0.12] — 2026-10-17
|
|
6
|
+
|
|
7
|
+
**The five fleet-memory actions are verified end to end, against a real relay, a real profile and a real
|
|
8
|
+
`fleet-memory.md` -- and the first attempt found a real defect.**
|
|
9
|
+
|
|
10
|
+
### What was unverified until now
|
|
11
|
+
|
|
12
|
+
`publish`, `pull`, `latest`, `diff` and `merge` had each been shipped marked **UNVERIFIED**. The merge *rule* was
|
|
13
|
+
proven exhaustively as a pure function, and the relay *routes* were proven against a real relay -- **but nothing had
|
|
14
|
+
ever executed the tool surface itself.** A caller with no execution is indistinguishable from a working one, which is
|
|
15
|
+
the same gap this project keeps restating in a different shape.
|
|
16
|
+
|
|
17
|
+
### The defect the end-to-end test found on its first run
|
|
18
|
+
|
|
19
|
+
`latest` reported `published_by: null` for a publication whose author the relay knew perfectly well.
|
|
20
|
+
|
|
21
|
+
`RabbitState.putFleetBlob` accepted a `publishedBy` argument that **nothing ever supplied**: the pointer store took
|
|
22
|
+
it, defaulted it to `null`, and the field looked implemented. Fixed by filling it from **the authenticated device's
|
|
23
|
+
`machine_id`, never from the request body** -- for the same reason the P2P announce route reads `machine_id` off the
|
|
24
|
+
token: a caller that could name itself in the body could attribute a publication to a machine that never made it.
|
|
25
|
+
|
|
26
|
+
**No unit test could have caught this**, because the unit under test was the pointer store, and it was behaving
|
|
27
|
+
exactly as written. The bug lived in the seam between two correct components, which is what an end-to-end test is for.
|
|
28
|
+
|
|
29
|
+
### What the test exercises, in the order a machine would
|
|
30
|
+
|
|
31
|
+
A real relay on an ephemeral port and a real profile, then:
|
|
32
|
+
|
|
33
|
+
1. **`publish`** — returns a 64-hex hash and the byte count.
|
|
34
|
+
2. **`latest`** — discovers that hash **without being told it**, and reports the publishing machine.
|
|
35
|
+
3. **`pull latest`** — fetches the bytes, re-hashes them, and they round-trip **exactly**.
|
|
36
|
+
4. **`diff`** — on an unchanged document: `same: true`, no difference, **and the local file untouched**.
|
|
37
|
+
5. the fleet's document is replaced out of band through the relay's own route;
|
|
38
|
+
6. **`diff`** — now reports the divergence, and the local file is **still untouched**;
|
|
39
|
+
7. **`merge`** — applies the declared rule (neither side declares a repair, so the **default layer** applies and the
|
|
40
|
+
newer publication wins), records the decision with a reason, carries the winning value into the merged text, and
|
|
41
|
+
**writes nothing to the local document.**
|
|
42
|
+
|
|
43
|
+
**`wrote_anything: false` is asserted three times**, because "these actions never edit the file they read" is the
|
|
44
|
+
property that makes it safe to let a network round trip participate at all.
|
|
45
|
+
|
|
46
|
+
### Verified
|
|
47
|
+
|
|
48
|
+
- the end-to-end suite: 1 test, passing, covering all five actions;
|
|
49
|
+
- `test/fleet-merge.test.mjs`: 13 tests over the rule itself;
|
|
50
|
+
- full suite: **2374 tests in 91 files, 2360 pass, 0 fail, 14 skip**;
|
|
51
|
+
- pre-flight **GREEN, 15 of 15 checks**.
|
|
52
|
+
|
|
53
|
+
### NOT verified, even now
|
|
54
|
+
|
|
55
|
+
**Concurrency.** Everything here is one machine at a time. Two machines publishing and merging simultaneously is
|
|
56
|
+
untested, and the pointer has no compare-and-swap, so the last writer to the pointer wins -- which is **the same rule
|
|
57
|
+
as the default layer**, but that is a coincidence rather than a guarantee. Recorded so the next person does not read
|
|
58
|
+
"end to end" as "under contention".
|
|
59
|
+
|
|
5
60
|
## [1.0.11] — 2026-10-17
|
|
6
61
|
|
|
7
62
|
**`w2m_memory {"action":"merge"}`: merge this machine's collective memory with the fleet's current blob, under the
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@twinsearth/w2m-dsh-plugin",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.12",
|
|
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
|
"main": "lib/index.js",
|
|
@@ -117,13 +117,13 @@
|
|
|
117
117
|
}
|
|
118
118
|
},
|
|
119
119
|
"scripts": {
|
|
120
|
-
"test": "node --test --test-force-exit test/relay.test.mjs test/broadcast.test.mjs test/agent.test.mjs test/plan-sec-cmd.test.mjs test/authority.test.mjs test/blocks.test.mjs test/approval-index.test.mjs test/fleet-sync.test.mjs test/fleet-merge.test.mjs test/health.test.mjs test/storage.test.mjs test/exit-channel.test.mjs test/council.test.mjs test/council-session.test.mjs test/log-bounds.test.mjs test/test-report.test.mjs test/fleet-scale.test.mjs test/fleet-state.test.mjs test/crypto-blake2s.test.mjs test/installed-version.test.mjs test/permission.test.mjs test/machine-test-packet.test.mjs test/field-authority.test.mjs test/approval-gate.test.mjs test/authority-choice.test.mjs test/reachability-check.test.mjs test/reachability-classify.test.mjs test/accepted-orphans.test.mjs test/acceptance-doc.test.mjs test/layer-model.test.mjs test/cwd-containment.test.mjs test/cwd-outside-project.test.mjs test/memory.test.mjs test/tools.test.mjs test/claims.test.mjs test/fleet-target.test.mjs test/client-bundle.test.mjs test/schedule.test.mjs test/auto-update.test.mjs test/update-source.test.mjs test/update-install.test.mjs test/update-wiring.test.mjs test/signing.test.mjs test/stress.test.mjs test/shared-config.test.mjs test/metrics.test.mjs test/metrics-route.test.mjs test/tool-cards.test.mjs test/p2p-stun.test.mjs test/p2p-transport.test.mjs test/p2p-signaling.test.mjs test/p2p-node.test.mjs test/p2p-transport-fields.test.mjs test/p2p-plugin.test.mjs test/p2p-crypto.test.mjs test/stun-server.test.mjs test/loader-entry.test.mjs test/mdns-wire.test.mjs test/mdns-discover.test.mjs test/chatops-approval.test.mjs test/chatops-policy.test.mjs test/chatops-file-safety.test.mjs test/chatops-outbound-queue.test.mjs test/chatops-commands.test.mjs test/chatops-bridge.test.mjs test/chatops-config-route.test.mjs test/chatops-apply.test.mjs test/chatops-ilink-contract.test.mjs test/chatops-fleet.test.mjs test/chatops-account.test.mjs test/chatops-auth.test.mjs test/chatops-fleet-scope.test.mjs test/chatops-handoff.test.mjs test/chatops-fleet-wiring.test.mjs test/chatops-fleet-live.test.mjs test/chatops-takeover.test.mjs test/chatops-device-signing.test.mjs test/chatops-relay-verify.test.mjs test/chatops-durability.test.mjs test/chatops-run-command.test.mjs test/secrets-guard.test.mjs test/chatops-ilink-fleet-bridge.test.mjs test/agent-plugins.test.mjs test/memory-layer.test.mjs test/mcp-server.test.mjs test/mcp-http.test.mjs test/mcp-http-live.test.mjs test/vision.test.mjs test/ilink-shape.test.mjs test/chatops-fleet-join.test.mjs",
|
|
120
|
+
"test": "node --test --test-force-exit test/relay.test.mjs test/broadcast.test.mjs test/agent.test.mjs test/plan-sec-cmd.test.mjs test/authority.test.mjs test/blocks.test.mjs test/approval-index.test.mjs test/fleet-sync.test.mjs test/fleet-merge.test.mjs test/fleet-memory-e2e.test.mjs test/health.test.mjs test/storage.test.mjs test/exit-channel.test.mjs test/council.test.mjs test/council-session.test.mjs test/log-bounds.test.mjs test/test-report.test.mjs test/fleet-scale.test.mjs test/fleet-state.test.mjs test/crypto-blake2s.test.mjs test/installed-version.test.mjs test/permission.test.mjs test/machine-test-packet.test.mjs test/field-authority.test.mjs test/approval-gate.test.mjs test/authority-choice.test.mjs test/reachability-check.test.mjs test/reachability-classify.test.mjs test/accepted-orphans.test.mjs test/acceptance-doc.test.mjs test/layer-model.test.mjs test/cwd-containment.test.mjs test/cwd-outside-project.test.mjs test/memory.test.mjs test/tools.test.mjs test/claims.test.mjs test/fleet-target.test.mjs test/client-bundle.test.mjs test/schedule.test.mjs test/auto-update.test.mjs test/update-source.test.mjs test/update-install.test.mjs test/update-wiring.test.mjs test/signing.test.mjs test/stress.test.mjs test/shared-config.test.mjs test/metrics.test.mjs test/metrics-route.test.mjs test/tool-cards.test.mjs test/p2p-stun.test.mjs test/p2p-transport.test.mjs test/p2p-signaling.test.mjs test/p2p-node.test.mjs test/p2p-transport-fields.test.mjs test/p2p-plugin.test.mjs test/p2p-crypto.test.mjs test/stun-server.test.mjs test/loader-entry.test.mjs test/mdns-wire.test.mjs test/mdns-discover.test.mjs test/chatops-approval.test.mjs test/chatops-policy.test.mjs test/chatops-file-safety.test.mjs test/chatops-outbound-queue.test.mjs test/chatops-commands.test.mjs test/chatops-bridge.test.mjs test/chatops-config-route.test.mjs test/chatops-apply.test.mjs test/chatops-ilink-contract.test.mjs test/chatops-fleet.test.mjs test/chatops-account.test.mjs test/chatops-auth.test.mjs test/chatops-fleet-scope.test.mjs test/chatops-handoff.test.mjs test/chatops-fleet-wiring.test.mjs test/chatops-fleet-live.test.mjs test/chatops-takeover.test.mjs test/chatops-device-signing.test.mjs test/chatops-relay-verify.test.mjs test/chatops-durability.test.mjs test/chatops-run-command.test.mjs test/secrets-guard.test.mjs test/chatops-ilink-fleet-bridge.test.mjs test/agent-plugins.test.mjs test/memory-layer.test.mjs test/mcp-server.test.mjs test/mcp-http.test.mjs test/mcp-http-live.test.mjs test/vision.test.mjs test/ilink-shape.test.mjs test/chatops-fleet-join.test.mjs",
|
|
121
121
|
"test:e2e": "node --test --test-force-exit test/e2e.test.mjs test/crossnetwork.test.mjs test/signing-e2e.test.mjs test/outbound-only.test.mjs test/recovery.test.mjs test/pipeline-e2e.test.mjs test/p2p-agent.test.mjs",
|
|
122
122
|
"test:relay": "node --test --test-force-exit test/relay.test.mjs",
|
|
123
123
|
"test:agent": "node --test --test-force-exit test/agent.test.mjs test/memory.test.mjs",
|
|
124
124
|
"test:tools": "node --test --test-force-exit test/tools.test.mjs",
|
|
125
125
|
"test:crossnetwork": "node --test --test-force-exit test/crossnetwork.test.mjs",
|
|
126
|
-
"test:all": "node --test --test-force-exit test/relay.test.mjs test/broadcast.test.mjs test/agent.test.mjs test/plan-sec-cmd.test.mjs test/authority.test.mjs test/blocks.test.mjs test/approval-index.test.mjs test/fleet-sync.test.mjs test/fleet-merge.test.mjs test/health.test.mjs test/storage.test.mjs test/exit-channel.test.mjs test/council.test.mjs test/council-session.test.mjs test/log-bounds.test.mjs test/test-report.test.mjs test/fleet-scale.test.mjs test/fleet-state.test.mjs test/crypto-blake2s.test.mjs test/installed-version.test.mjs test/permission.test.mjs test/machine-test-packet.test.mjs test/field-authority.test.mjs test/approval-gate.test.mjs test/authority-choice.test.mjs test/reachability-check.test.mjs test/reachability-classify.test.mjs test/accepted-orphans.test.mjs test/acceptance-doc.test.mjs test/layer-model.test.mjs test/cwd-containment.test.mjs test/cwd-outside-project.test.mjs test/memory.test.mjs test/tools.test.mjs test/claims.test.mjs test/fleet-target.test.mjs test/client-bundle.test.mjs test/schedule.test.mjs test/auto-update.test.mjs test/update-source.test.mjs test/update-install.test.mjs test/update-wiring.test.mjs test/signing.test.mjs test/stress.test.mjs test/e2e.test.mjs test/crossnetwork.test.mjs test/signing-e2e.test.mjs test/outbound-only.test.mjs test/recovery.test.mjs test/pipeline-e2e.test.mjs test/shared-config.test.mjs test/metrics.test.mjs test/metrics-route.test.mjs test/tool-cards.test.mjs test/p2p-stun.test.mjs test/p2p-transport.test.mjs test/p2p-signaling.test.mjs test/p2p-node.test.mjs test/p2p-transport-fields.test.mjs test/p2p-plugin.test.mjs test/p2p-agent.test.mjs test/stun-server.test.mjs test/loader-entry.test.mjs test/mdns-wire.test.mjs test/mdns-discover.test.mjs test/p2p-crypto.test.mjs test/chatops-approval.test.mjs test/chatops-policy.test.mjs test/chatops-file-safety.test.mjs test/chatops-outbound-queue.test.mjs test/chatops-commands.test.mjs test/chatops-bridge.test.mjs test/chatops-config-route.test.mjs test/chatops-apply.test.mjs test/chatops-ilink-contract.test.mjs test/chatops-fleet.test.mjs test/chatops-account.test.mjs test/chatops-auth.test.mjs test/chatops-fleet-scope.test.mjs test/chatops-handoff.test.mjs test/chatops-fleet-wiring.test.mjs test/chatops-fleet-live.test.mjs test/chatops-takeover.test.mjs test/chatops-device-signing.test.mjs test/chatops-relay-verify.test.mjs test/chatops-durability.test.mjs test/chatops-run-command.test.mjs test/secrets-guard.test.mjs test/chatops-ilink-fleet-bridge.test.mjs test/agent-plugins.test.mjs test/memory-layer.test.mjs test/mcp-server.test.mjs test/mcp-http.test.mjs test/mcp-http-live.test.mjs test/vision.test.mjs test/ilink-shape.test.mjs test/chatops-fleet-join.test.mjs",
|
|
126
|
+
"test:all": "node --test --test-force-exit test/relay.test.mjs test/broadcast.test.mjs test/agent.test.mjs test/plan-sec-cmd.test.mjs test/authority.test.mjs test/blocks.test.mjs test/approval-index.test.mjs test/fleet-sync.test.mjs test/fleet-merge.test.mjs test/fleet-memory-e2e.test.mjs test/health.test.mjs test/storage.test.mjs test/exit-channel.test.mjs test/council.test.mjs test/council-session.test.mjs test/log-bounds.test.mjs test/test-report.test.mjs test/fleet-scale.test.mjs test/fleet-state.test.mjs test/crypto-blake2s.test.mjs test/installed-version.test.mjs test/permission.test.mjs test/machine-test-packet.test.mjs test/field-authority.test.mjs test/approval-gate.test.mjs test/authority-choice.test.mjs test/reachability-check.test.mjs test/reachability-classify.test.mjs test/accepted-orphans.test.mjs test/acceptance-doc.test.mjs test/layer-model.test.mjs test/cwd-containment.test.mjs test/cwd-outside-project.test.mjs test/memory.test.mjs test/tools.test.mjs test/claims.test.mjs test/fleet-target.test.mjs test/client-bundle.test.mjs test/schedule.test.mjs test/auto-update.test.mjs test/update-source.test.mjs test/update-install.test.mjs test/update-wiring.test.mjs test/signing.test.mjs test/stress.test.mjs test/e2e.test.mjs test/crossnetwork.test.mjs test/signing-e2e.test.mjs test/outbound-only.test.mjs test/recovery.test.mjs test/pipeline-e2e.test.mjs test/shared-config.test.mjs test/metrics.test.mjs test/metrics-route.test.mjs test/tool-cards.test.mjs test/p2p-stun.test.mjs test/p2p-transport.test.mjs test/p2p-signaling.test.mjs test/p2p-node.test.mjs test/p2p-transport-fields.test.mjs test/p2p-plugin.test.mjs test/p2p-agent.test.mjs test/stun-server.test.mjs test/loader-entry.test.mjs test/mdns-wire.test.mjs test/mdns-discover.test.mjs test/p2p-crypto.test.mjs test/chatops-approval.test.mjs test/chatops-policy.test.mjs test/chatops-file-safety.test.mjs test/chatops-outbound-queue.test.mjs test/chatops-commands.test.mjs test/chatops-bridge.test.mjs test/chatops-config-route.test.mjs test/chatops-apply.test.mjs test/chatops-ilink-contract.test.mjs test/chatops-fleet.test.mjs test/chatops-account.test.mjs test/chatops-auth.test.mjs test/chatops-fleet-scope.test.mjs test/chatops-handoff.test.mjs test/chatops-fleet-wiring.test.mjs test/chatops-fleet-live.test.mjs test/chatops-takeover.test.mjs test/chatops-device-signing.test.mjs test/chatops-relay-verify.test.mjs test/chatops-durability.test.mjs test/chatops-run-command.test.mjs test/secrets-guard.test.mjs test/chatops-ilink-fleet-bridge.test.mjs test/agent-plugins.test.mjs test/memory-layer.test.mjs test/mcp-server.test.mjs test/mcp-http.test.mjs test/mcp-http-live.test.mjs test/vision.test.mjs test/ilink-shape.test.mjs test/chatops-fleet-join.test.mjs",
|
|
127
127
|
"pack": "node scripts/pack.mjs",
|
|
128
128
|
"verify:join": "node scripts/verify-join.mjs",
|
|
129
129
|
"lint": "eslint .",
|
|
@@ -138,6 +138,7 @@
|
|
|
138
138
|
"test:approval-index": "node --test --test-force-exit test/approval-index.test.mjs",
|
|
139
139
|
"test:fleet-sync": "node --test --test-force-exit test/fleet-sync.test.mjs",
|
|
140
140
|
"test:fleet-merge": "node --test --test-force-exit test/fleet-merge.test.mjs",
|
|
141
|
+
"test:fleet-memory-e2e": "node --test --test-force-exit test/fleet-memory-e2e.test.mjs",
|
|
141
142
|
"test:health": "node --test --test-force-exit test/health.test.mjs",
|
|
142
143
|
"test:storage": "node --test --test-force-exit test/storage.test.mjs",
|
|
143
144
|
"test:exit-channel": "node --test --test-force-exit test/exit-channel.test.mjs",
|
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.0.
|
|
4
|
+
"version": "1.0.12",
|
|
5
5
|
"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.",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"keywords": [
|
package/src/plugin/tools.mjs
CHANGED
|
@@ -211,7 +211,7 @@ const MAX_STAGES = 16;
|
|
|
211
211
|
* `package.json` during `scripts/pack.mjs` rather than hand-maintained, and `W2M_PLUGIN_VERSION`
|
|
212
212
|
* overrides it at runtime for tests and packagers.
|
|
213
213
|
*/
|
|
214
|
-
const PLUGIN_VERSION = '1.0.
|
|
214
|
+
const PLUGIN_VERSION = '1.0.12';
|
|
215
215
|
|
|
216
216
|
/** How long any single HTTP call may take before it is aborted, in milliseconds. */
|
|
217
217
|
const DEFAULT_REQUEST_TIMEOUT_MS = 15_000;
|
package/src/relay/state.mjs
CHANGED
|
@@ -560,7 +560,20 @@ export class RabbitState {
|
|
|
560
560
|
}
|
|
561
561
|
const scope = this.scopeBlobFleet(device);
|
|
562
562
|
if (scope.ok !== true) return { ok: false, reason: scope.reason, detail: scope.text };
|
|
563
|
-
|
|
563
|
+
/**
|
|
564
|
+
* v1.0.12: `publishedBy` comes from **the authenticated device, never from the request body.**
|
|
565
|
+
*
|
|
566
|
+
* The relay knows which device is writing; the request does not get a say, for the same reason `machine_id` is
|
|
567
|
+
* read off the token in the P2P announce route -- a caller that could name itself in the body could attribute a
|
|
568
|
+
* publication to a machine that never made it.
|
|
569
|
+
*
|
|
570
|
+
* An end-to-end test caught this field being `null`: the pointer store accepted a `publishedBy` argument that
|
|
571
|
+
* nothing supplied, so `latest` reported `published_by: null` for a publication whose author was right there.
|
|
572
|
+
*/
|
|
573
|
+
return this._persist.putBlob(bytes, {
|
|
574
|
+
fleetId: scope.fleetId,
|
|
575
|
+
publishedBy: typeof device?.machine_id === 'string' ? device.machine_id : null,
|
|
576
|
+
});
|
|
564
577
|
}
|
|
565
578
|
|
|
566
579
|
/**
|