@twinsearth/w2m-dsh-plugin 1.0.2 → 1.0.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/CHANGELOG.md CHANGED
@@ -2,6 +2,103 @@
2
2
 
3
3
  All notable changes to this project are documented here.
4
4
 
5
+ ## [1.0.4] — 2026-10-17
6
+
7
+ **The description described a different package, and it is the only thing many readers see.**
8
+
9
+ ### Two numbers were wrong, and both were checkable
10
+
11
+ The text had been carried forward since an earlier release and said:
12
+
13
+ ... eight DSH tools (replicate / split), nine aggregate verdicts and signed requests.
14
+
15
+ **Measured: eleven tools, six verdicts.** The tools are the `name: 'w2m_…'` registration sites in
16
+ `src/plugin/tools.mjs`; the verdicts are named in `src/relay/report.mjs:19-25` -- `consistent`, `divergent`,
17
+ `divergent-platform`, `failed`, `partial`, `unverifiable`. **Four coordination modes, not the two a
18
+ parenthetical named.**
19
+
20
+ ### What mattered more than the numbers: it never mentioned joining
21
+
22
+ A reader finished that sentence knowing the plugin exists and **nothing about the step every new machine gets
23
+ wrong** -- which is the one this release's predecessor spent hours on. **A description that omits the join
24
+ requirement produces exactly the "I installed it and nothing happened" report.**
25
+
26
+ So the description now ends with it, as a flat fact: **"Joining needs a pairing code plus `autoStartAgent:
27
+ true`; installing alone does not join."**
28
+
29
+ ### The replacement
30
+
31
+ Run one project across your own Windows and macOS machines from a single DeepSeek account, through 11
32
+ w2m_* tools. Four coordination modes (replicate, split, broadcast, pipeline) and six aggregate verdicts
33
+ (consistent, divergent, divergent-platform, failed, partial, unverifiable). P2P hole punching by default,
34
+ with a bundled relay, STUN responder and ledger fallback, so the fleet needs no third-party service.
35
+ Joining needs a pairing code plus autoStartAgent: true; installing alone does not join.
36
+
37
+ **Exactly 500 characters, because registries truncate and a description cut mid-sentence is worse than a shorter
38
+ one.** The first candidate was 502; the trim removed two words and **was reported rather than applied silently**.
39
+ Both `package.json` and `plugin.json` carry it -- they previously disagreed, which is its own small defect: two
40
+ descriptions of one package.
41
+
42
+ **No code change.** Full suite 2352 in 89 files, 0 fail. Pre-flight GREEN with FIFTEEN checks.
43
+
44
+ ## [1.0.3] — 2026-10-17
45
+
46
+ **The warning that predicted this failure now says what to do about it.**
47
+
48
+ ### What was wrong with the old line
49
+
50
+ w2m: no agent is running on this machine, so it is in no fleet and will receive no work.
51
+ Set autoStartAgent: true to join (the fleet key is derived from the signed-in account),
52
+ or run w2m-localside yourself and point it at the relay.
53
+
54
+ **Accurate, and insufficient.** It names **one** of the two things required and does not say *where* to set it.
55
+
56
+ **Measured on a real machine:** plugin installed, activated, **no error anywhere**, and
57
+ `device_token: null` with `autoStartAgent: false`. The operator's own summary was *"it installed but the machine
58
+ is not in the fleet"* -- **exactly what this warning predicts, and nothing in it resolved that.** The line was
59
+ written for the v0.8.5 failure mode and the operator still had to discover both steps.
60
+
61
+ ### The guidance is now a procedure, and it is ordered
62
+
63
+ ```
64
+ This machine is NOT paired yet, so both steps below are required.
65
+ To join, two things are needed:
66
+ 1. a one-time pairing code. `w2m-rabbit` prints it once, in its startup banner:
67
+ [w2m-rabbit] listening on <url> pairing code: PAIR-XXXXXXXX
68
+ It lives in memory only and is never written to the state directory...
69
+ 2. `autoStartAgent: true` plus that code, on the `w2m` row that ALREADY EXISTS...
70
+ - id: w2m
71
+ config:
72
+ autoStartAgent: true
73
+ pairingCode: PAIR-XXXXXXXX
74
+ Do NOT add an `insert:` for it. An insert appends a SECOND entry with the same id, and the
75
+ client then refuses to open -- measured on this project, not theorised.
76
+ ```
77
+
78
+ **It states the current pairing state, because the two cases need different first steps.** An unpaired machine
79
+ must fetch a code; a paired one only has to turn the switch on, and **sending that machine after a code would send
80
+ it somewhere it has no business.** Verifying that branch required reading `device.json` and finding
81
+ `device_token: null`, which is exactly what the rendered warning then said.
82
+
83
+ **Why pairing cannot be automatic, stated where the operator will read it:** the relay's own header says *"the
84
+ pairing code is the only credential that grants admission"*, and **a plugin able to join unattended would be one
85
+ that lets any machine holding the package into the fleet.** So the fix is guidance, not auto-joining.
86
+
87
+ ### A parameter I wrote into the text before checking that it exists
88
+
89
+ The first draft told the operator to use **`--print-pairing-code`**. **There is no such flag.** Measured from
90
+ `w2m-rabbit --help`, the real options are:
91
+
92
+ --pairing-code <c> Use a fixed pairing code instead of a generated one.
93
+ --pair-rate-limit <n> Pairing attempts per IP per minute. Default 5. 0 = off.
94
+
95
+ **And `--pairing-code` does the opposite of what I described**: it *chooses* a known code rather than printing an
96
+ existing one. The text now says that, **because a command in an error message is read as an instruction and is
97
+ followed.**
98
+
99
+ The warning was also **rendered and read** rather than assumed -- a warning nobody has printed is a warning whose
100
+ formatting is guesswork.
101
+
5
102
  ## [1.0.2] — 2026-10-16
6
103
 
7
104
  **One missing line made the whole plugin fail to mount, and it had been missing since v0.41.0.**
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@twinsearth/w2m-dsh-plugin",
3
- "version": "1.0.2",
4
- "description": "DSH: Windows2MacOS — drive the same project on online Windows and macOS machines from one DeepSeek account, across networks and regions. P2P hole punching is the default path (relay + shared server as rendezvous, ledger and fallback), with a bundled STUN responder, Tailscale/public-VPS/tunnel shapes, Rabbit relay + per-machine Localside + eight DSH tools (replicate / split), nine aggregate verdicts and signed requests.",
3
+ "version": "1.0.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",
7
7
  "bin": {
package/plugin.json CHANGED
@@ -1,8 +1,8 @@
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.2",
5
- "description": "Cross-platform fleet execution between Windows and macOS: one DeepSeek Harness account, a Rabbit relay, and signed device identity. Ships four Agent Skills describing fleet dispatch, field-level memory acceptance, session references, and resource scheduling.",
4
+ "version": "1.0.4",
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": [
8
8
  "agent-skills",
@@ -149,7 +149,7 @@ import { AUTHORITY_CHOICES, resolveConfiguredLevel } from '../agent/authority-ch
149
149
  // rather than reimplemented: the dispatcher and the executor have to derive the *same* keys, and two
150
150
  // implementations of a handshake are two chances to disagree about it.
151
151
  import { DeviceKey } from '../agent/crypto.mjs';
152
- import { loadOrCreateIdentity, saveDeviceToken } from '../agent/identity.mjs';
152
+ import { loadIdentity, loadOrCreateIdentity, saveDeviceToken } from '../agent/identity.mjs';
153
153
  import { probeCapsDetailed, detectPlatform } from '../agent/caps.mjs';
154
154
  import { resolveStateDir } from '../util/cli.mjs';
155
155
  import { parseServer } from '../agent/stun.mjs';
@@ -208,7 +208,7 @@ const MAX_STAGES = 16;
208
208
  * `package.json` during `scripts/pack.mjs` rather than hand-maintained, and `W2M_PLUGIN_VERSION`
209
209
  * overrides it at runtime for tests and packagers.
210
210
  */
211
- const PLUGIN_VERSION = '1.0.2';
211
+ const PLUGIN_VERSION = '1.0.4';
212
212
 
213
213
  /** How long any single HTTP call may take before it is aborted, in milliseconds. */
214
214
  const DEFAULT_REQUEST_TIMEOUT_MS = 15_000;
@@ -4655,11 +4655,91 @@ export async function apply(ctx, config = {}) {
4655
4655
  * A silent no-op that looks like success is the worst failure mode this plugin has had. One
4656
4656
  * line at warn level turns *"why is this machine not in my fleet"* from an investigation into a
4657
4657
  * log search.
4658
+ *
4659
+ * ## v1.0.3: the line was accurate and still left the operator stuck
4660
+ *
4661
+ * "Set `autoStartAgent: true` to join" names **one** of the two things required and does not say where to set
4662
+ * it. **Both omissions were measured on a real machine**: installed, activated, no error anywhere, and
4663
+ * `device_token: null` with `autoStartAgent: false`. The operator's own summary was *"it installed but the
4664
+ * machine is not in the fleet"* -- exactly what this warning predicts, and nothing in it resolves that.
4665
+ *
4666
+ * So the guidance is now **a procedure, and the procedure is ordered**:
4667
+ *
4668
+ * 1. Pairing needs a **one-time code the operator obtains**. It cannot be self-issued, and that is design
4669
+ * rather than oversight -- the relay's own header says *"the pairing code is the only credential that
4670
+ * grants admission"*, and a plugin able to join unattended would be one that lets any machine holding
4671
+ * the package into the fleet.
4672
+ * 2. `autoStartAgent: true` goes on **the `w2m` row that already exists**, matched by `id` -- **not** as an
4673
+ * `insert:`, which appends a second row with the same `id` and stops the client from opening.
4674
+ *
4675
+ * **The warning also states the current pairing state, because the two cases need different first steps.**
4676
+ * An unpaired machine must fetch a code; a paired one only has to turn the switch on, and sending *that*
4677
+ * machine after a code would send it somewhere it has no business.
4678
+ */
4679
+ let paired = false;
4680
+ /**
4681
+ * Read the pairing state, **read-only**, and only when a state directory is configured.
4682
+ *
4683
+ * ## Two defects this line caused before it was right, both measured
4684
+ *
4685
+ * **First it called `loadOrCreateIdentity({ dir: cfg.stateDir ?? undefined })`.**
4686
+ *
4687
+ * * With `stateDir` unset -- the default -- that `undefined` falls back to `~/.dsh/xclient/device.json`,
4688
+ * **the operator's real file**, and `loadOrCreateIdentity` **creates it when absent**. A message about
4689
+ * the machine's state must not be able to change it. Four tests in `test/update-wiring.test.mjs` failed
4690
+ * because the plugin read the real home instead of the profile they supplied.
4691
+ * * Guarding on `stateDir` fixed those, **and broke a different one**: `test/tools.test.mjs:593` sets an
4692
+ * empty `stateDir` and asserts `reason_code: DEVICE_NOT_PAIRED` for an **absent** `device.json`.
4693
+ * `loadOrCreateIdentity` **created that file**, so the very next read found it present-but-unpaired and
4694
+ * reported `DEVICE_TOKEN_ABSENT` instead. Isolated both ways: `tools.mjs` at 1.0.2 gives `115 pass,
4695
+ * 0 fail`; the version with this call gave `114 pass, 1 fail`.
4696
+ *
4697
+ * **`loadIdentity` is the read-only one** -- `ENOENT` returns `exists: false` and creates nothing -- which is
4698
+ * the only behaviour a diagnostic is entitled to.
4699
+ *
4700
+ * With nothing configured there is no location to consult, so the state is reported as unknown rather than
4701
+ * guessed at, which is what `w2m_status` already says for the same reason (`"stateDir is not set, so no agent
4702
+ * state could be located"`).
4658
4703
  */
4704
+ let stateDirConfigured = false;
4705
+ try {
4706
+ stateDirConfigured = typeof cfg.stateDir === 'string' && cfg.stateDir.trim() !== '';
4707
+ if (stateDirConfigured) {
4708
+ const { identity } = loadIdentity({ dir: cfg.stateDir });
4709
+ paired = typeof identity?.device_token === 'string' && identity.device_token !== '';
4710
+ }
4711
+ } catch {
4712
+ // An unreadable identity is `w2m_status`' business; this line is about joining, so it stays quiet.
4713
+ stateDirConfigured = false;
4714
+ }
4659
4715
  ctx.logger?.warn?.(
4660
- 'w2m: no agent is running on this machine, so it is in no fleet and will receive no work. '
4661
- + 'Set autoStartAgent: true to join (the fleet key is derived from the signed-in account), '
4662
- + 'or run w2m-localside yourself and point it at the relay.',
4716
+ 'w2m: no agent is running on this machine, so it is in no fleet, will receive no work, and no dispatch '
4717
+ + 'will ever reach it.\n'
4718
+ + ` ${stateDirConfigured
4719
+ ? (paired
4720
+ ? 'This machine IS paired, so step 1 is already done -- only the switch is missing.'
4721
+ : 'This machine is NOT paired yet, so both steps below are required.')
4722
+ : 'No stateDir is configured, so this machine\'s pairing state could not be read; assume it is not '
4723
+ + 'paired and treat both steps below as required.'}\n`
4724
+ + ' To join, two things are needed:\n'
4725
+ + ' 1. a one-time pairing code. `w2m-rabbit` prints it once, in its startup banner:\n'
4726
+ + ' [w2m-rabbit] listening on <url> pairing code: PAIR-XXXXXXXX\n'
4727
+ + ' It lives in memory only and is never written to the state directory, so it is read from\n'
4728
+ + ' the relay\'s console. There is no flag that prints an existing code; starting the relay\n'
4729
+ + ' with `--pairing-code <c>` chooses a KNOWN code instead of a generated one, which is the\n'
4730
+ + ' supported way to make pairing repeatable.\n'
4731
+ + ' 2. `autoStartAgent: true` plus that code, on the `w2m` row that ALREADY EXISTS in the\n'
4732
+ + ' profile\'s cordis.patch.yml, matched by id:\n'
4733
+ + ' - id: w2m\n'
4734
+ + ' config:\n'
4735
+ + ' autoStartAgent: true\n'
4736
+ + ' pairingCode: PAIR-XXXXXXXX\n'
4737
+ + ' Do NOT add an `insert:` for it. An insert appends a SECOND entry with the same id, and the\n'
4738
+ + ' client then refuses to open -- measured on this project, not theorised.\n'
4739
+ + ' Or pair without touching this profile at all: run\n'
4740
+ + ' w2m-localside --rabbit <url> --pair <CODE>\n'
4741
+ + ' `w2m_status` reports both facts this line is about -- `identity.paired` and\n'
4742
+ + ' `config.autoStartAgent` -- and is the first thing to read when it appears.',
4663
4743
  );
4664
4744
  }
4665
4745