@twinsearth/w2m-dsh-plugin 1.2.6 → 1.3.0
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 +30 -29
- package/.claude-plugin/plugin.json +29 -29
- package/CHANGELOG.md +197 -0
- package/README.md +3 -3
- package/codex/mcp-servers.toml +1 -1
- package/docs/DATA-PLANE-COLLABORATION.md +82 -0
- package/lib/client.js +942 -941
- package/package.json +236 -235
- package/plugin.json +14 -14
- package/src/agent/agent.mjs +77 -1
- package/src/plugin/merge-hint.mjs +35 -0
- package/src/plugin/task-graph.mjs +153 -147
- package/src/plugin/tools.mjs +204 -19
- package/src/relay/fleet-messages.mjs +258 -241
- package/src/relay/report.mjs +11 -0
- package/src/relay/server.mjs +16 -1
- package/src/relay/state.mjs +135 -0
- package/src/util/dataflow.mjs +24 -1
- package/src/util/reduce-suggestion.mjs +107 -0
|
@@ -1,29 +1,30 @@
|
|
|
1
|
-
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
1
|
+
{
|
|
2
|
+
"name": "twinsearth-w2m",
|
|
3
|
+
"owner": {
|
|
4
|
+
"name": "TwinsEarth"
|
|
5
|
+
},
|
|
6
|
+
"metadata": {
|
|
7
|
+
"description": "The w2m fleet plugins: one account, many machines, any of Windows, macOS or Linux.",
|
|
8
|
+
"version": "1.3.0"
|
|
9
|
+
},
|
|
10
|
+
"plugins": [
|
|
11
|
+
{
|
|
12
|
+
"name": "w2m-fleet",
|
|
13
|
+
"source": "./",
|
|
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.3.0",
|
|
16
|
+
"author": {
|
|
17
|
+
"name": "TwinsEarth"
|
|
18
|
+
},
|
|
19
|
+
"homepage": "https://github.com/TwinsEarth/dsh-windows2macos",
|
|
20
|
+
"repository": "https://github.com/TwinsEarth/dsh-windows2macos",
|
|
21
|
+
"license": "MIT",
|
|
22
|
+
"keywords": [
|
|
23
|
+
"fleet",
|
|
24
|
+
"remote-execution",
|
|
25
|
+
"mcp"
|
|
26
|
+
]
|
|
27
|
+
}
|
|
28
|
+
],
|
|
29
|
+
"version": "1.3.0"
|
|
30
|
+
}
|
|
@@ -1,29 +1,29 @@
|
|
|
1
|
-
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "w2m-fleet",
|
|
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.3.0",
|
|
5
|
+
"author": {
|
|
6
|
+
"name": "TwinsEarth"
|
|
7
|
+
},
|
|
8
|
+
"homepage": "https://github.com/TwinsEarth/dsh-windows2macos",
|
|
9
|
+
"repository": "https://github.com/TwinsEarth/dsh-windows2macos",
|
|
10
|
+
"license": "MIT",
|
|
11
|
+
"keywords": [
|
|
12
|
+
"fleet",
|
|
13
|
+
"remote-execution",
|
|
14
|
+
"windows",
|
|
15
|
+
"macos",
|
|
16
|
+
"linux",
|
|
17
|
+
"mcp",
|
|
18
|
+
"claude-code",
|
|
19
|
+
"codex"
|
|
20
|
+
],
|
|
21
|
+
"mcpServers": {
|
|
22
|
+
"w2m-fleet": {
|
|
23
|
+
"command": "node",
|
|
24
|
+
"args": [
|
|
25
|
+
"${CLAUDE_PLUGIN_ROOT}/bin/w2m-mcp.mjs"
|
|
26
|
+
]
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
}
|
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,203 @@
|
|
|
7
7
|
|
|
8
8
|
All notable changes to this project are documented here.
|
|
9
9
|
|
|
10
|
+
## [1.3.0] — 2026-10-21
|
|
11
|
+
|
|
12
|
+
The first stable release of the collaboration line. It consolidates the four betas that followed 1.2.7 and changes no protocol in a
|
|
13
|
+
way that a 1.2.7 peer cannot ignore; every addition is additive and named.
|
|
14
|
+
|
|
15
|
+
### Data plane
|
|
16
|
+
|
|
17
|
+
**A reduce phase you can actually run.** `w2m_reduce` dispatches a reduce task only from complete data: it refuses unless every
|
|
18
|
+
declared shard reported as a blob and the named reducer reported (`W2M_REDUCE_NOT_READY` with the missing indexes), never picks a
|
|
19
|
+
reducer, and refuses inline inputs that cannot be carried to another machine. The relay validates, stores, ledgers and offers
|
|
20
|
+
`reduce_of` + `reduce_inputs`; the agent fetches those content-addressed blobs before the reduce runs and exposes
|
|
21
|
+
`W2M_REDUCE_INPUTS_DIR` / `W2M_REDUCE_MANIFEST` / `W2M_REDUCE_OF`; a failed fetch refuses the whole task rather than reducing a
|
|
22
|
+
partial fleet.
|
|
23
|
+
|
|
24
|
+
**A suggestion that dispenses no action.** `w2m_wait` carries `reduce_suggestion`: ready only when every declared shard reported and
|
|
25
|
+
a reducer was named, the missing indexes otherwise, the candidate machines, and the literal next step. It is derived, never stored,
|
|
26
|
+
and it dispatches nothing.
|
|
27
|
+
|
|
28
|
+
**Message ids survive a restart, artifacts are one size everywhere.** Chat ids carry a random per-process relay epoch
|
|
29
|
+
(`msg-<epoch>-<seq>`) so a restart cannot recycle an id a client persisted; the blob transport frame is 16 MiB, matching the agent's
|
|
30
|
+
dataflow hard cap, instead of 1 MiB against it.
|
|
31
|
+
|
|
32
|
+
### Collaboration
|
|
33
|
+
|
|
34
|
+
**The panel shows the scheduler's own buckets.** The fleet-chat panel renders 准备 / 进行 / 等待 / 阻塞 counts beside the relay's task
|
|
35
|
+
list, derived from the relay's `status` and `waiting_on`; read-only, no dispatch.
|
|
36
|
+
|
|
37
|
+
**Conflicts name their next step.** `w2m_memory append` returns `merge_hint` with a 409: `re-read-then-append`, `behind_by`, the
|
|
38
|
+
unseen count, the sample size and the literal instruction to re-read, compare and append against the current revision -- never an
|
|
39
|
+
automatic merge.
|
|
40
|
+
|
|
41
|
+
**Decisions leave a trail.** `w2m_council fleet-decide` reports `trail` (`appended` / `refused` / `error` / `not-written`), and the
|
|
42
|
+
test asserts that status instead of implying a record exists.
|
|
43
|
+
|
|
44
|
+
### Verified
|
|
45
|
+
|
|
46
|
+
Gate GREEN twice, 15 of 15: 2710 tests / 2696 pass / 0 fail / 14 skip in 133 files. Two-machine live runs over the real relay cover
|
|
47
|
+
the turn state machine (ask/await over SSE with a refusal), dependency scheduling, and the missing-shard refusal, plus the panel and
|
|
48
|
+
proxy behaviour above.
|
|
49
|
+
|
|
50
|
+
### Known limits, stated
|
|
51
|
+
|
|
52
|
+
- `pipeline` keeps `index_total` at 1; blob map results come from plain commands above the inline cap.
|
|
53
|
+
- The reduce suggestion is advisory: the caller dispatches the reduce (this release does not let the relay decide to run a command).
|
|
54
|
+
- The composer panel does not render the board buckets on a host without the Connection service; the tools still work.
|
|
55
|
+
|
|
56
|
+
## [1.2.11-beta.1] — 2026-10-21
|
|
57
|
+
|
|
58
|
+
A beta by policy: GitHub prerelease only, never npm.
|
|
59
|
+
|
|
60
|
+
### The task board in the composer panel
|
|
61
|
+
|
|
62
|
+
The fleet-chat panel already listed the relay's tasks; it now also shows the four buckets the scheduler uses — 准备 / 进行 / 等待 / 阻塞 — derived from the relay's own `status` and `waiting_on`, never from a classification of its own. Read-only: the panel dispatches nothing.
|
|
63
|
+
|
|
64
|
+
### Merge hint on memory conflicts
|
|
65
|
+
|
|
66
|
+
`w2m_memory append` returns `merge_hint` with a 409: state `re-read-then-append`, `behind_by`, the number of unseen records, the sample size, and the literal next step (re-read, compare, append against the current revision — do not merge unseen records). Pure function, no automatic merge.
|
|
67
|
+
|
|
68
|
+
### Council decisions leave a trail
|
|
69
|
+
|
|
70
|
+
`w2m_council fleet-decide` reports `trail` (`appended` / `refused` / `error` / `not-written`) instead of implying a record exists; the test now asserts that status.
|
|
71
|
+
|
|
72
|
+
Verified: gate GREEN twice, 2704 tests / 2690 pass / 0 fail / 14 skip in 132 files; client-bundle 25/25 after the board line; the merge-hint and trail tests are new.
|
|
73
|
+
|
|
74
|
+
## [1.2.10-beta.1] — 2026-10-21
|
|
75
|
+
|
|
76
|
+
A beta by policy: GitHub prerelease only, never npm. This one makes the reduce phase executable.
|
|
77
|
+
|
|
78
|
+
### Reduce execution (caller-dispatched)
|
|
79
|
+
|
|
80
|
+
`w2m_reduce` dispatches a reduce only from complete data: it refuses unless every declared shard reported as a blob and the named reducer reported (`W2M_REDUCE_NOT_READY`, with the missing indexes). It never picks a reducer and never invents inputs; inline results are refused (`W2M_REDUCE_INLINE_INPUT`) because they cannot be carried to another machine.
|
|
81
|
+
|
|
82
|
+
The relay validates and carries `reduce_of` + `reduce_inputs` (at most 16 artifacts, sha256 only) on the task, the ledger and the offer; the agent fetches those content-addressed blobs BEFORE running the reduce and exposes `W2M_REDUCE_INPUTS_DIR` / `W2M_REDUCE_MANIFEST` / `W2M_REDUCE_OF` to the command. A failed fetch refuses the task (`REDUCE_INPUT_FETCH_FAILED`) rather than reducing half the fleet.
|
|
83
|
+
|
|
84
|
+
Verified: gate GREEN twice, 2701 tests / 2687 pass / 0 fail / 14 skip in 131 files; new agent e2e proves the reduce reads the exact artifact bytes; the tool has a dispatch test and a refusal test.
|
|
85
|
+
|
|
86
|
+
## [1.2.9-beta.1] — 2026-10-21
|
|
87
|
+
|
|
88
|
+
A beta by policy: **GitHub prerelease only, never npm.** The theme is the data plane and the collaboration plane: the design is
|
|
89
|
+
written down (`docs/DATA-PLANE-COLLABORATION.md`) and this release ships its first slice.
|
|
90
|
+
|
|
91
|
+
### `reduce_suggestion` on `w2m_wait`
|
|
92
|
+
|
|
93
|
+
Every terminal wait now answers three questions without acting on them: is the data complete, who could reduce it, and what the
|
|
94
|
+
caller is supposed to do next (`dispatch the reduce yourself; this tool does not run it`). It is a pure function over the machine
|
|
95
|
+
facts the aggregate already publishes:
|
|
96
|
+
|
|
97
|
+
- **ready** only when every declared shard reported and a reducer was named;
|
|
98
|
+
- **missing indexes** when a shard never reported (an expired lease cannot claim one);
|
|
99
|
+
- **candidates** listing the machines that reported, with the reason;
|
|
100
|
+
- a named reducer that never reported is refused by name (`REDUCER_UNREPORTED`) rather than silently replaced -- changing the
|
|
101
|
+
machine changes what the reduce runs against;
|
|
102
|
+
- a caller that named no reducer gets `REDUCER_MISSING` and candidates, never an invented choice.
|
|
103
|
+
|
|
104
|
+
Nothing is stored and nothing is dispatched. Two readers of the same aggregate get the same suggestion, and reading does not
|
|
105
|
+
change relay state.
|
|
106
|
+
|
|
107
|
+
### The design document states the open question
|
|
108
|
+
|
|
109
|
+
Caller-dispatched reduce (current direction) versus auto-reduce in the relay. The design leans caller-dispatched, because a relay
|
|
110
|
+
that decides to run a command is the boundary every other decision avoids; a beta that flipped that default would be the wrong
|
|
111
|
+
place to discover it. The document also names the next collaboration slices: conflict-merge UI, council decision trail to shared
|
|
112
|
+
memory, and the board in the composer panel.
|
|
113
|
+
|
|
114
|
+
### Verified
|
|
115
|
+
|
|
116
|
+
Gate GREEN twice: 2699 tests / 2685 pass / 0 fail / 14 skip in 131 files. New: `suggestReduce` unit tests (7) covering complete,
|
|
117
|
+
partial-with-missing, no-reducer, unreported-reducer and mixed inline+blob inputs; `w2m_wait` carries the suggestion for every
|
|
118
|
+
aggregate.
|
|
119
|
+
## [1.2.8-beta.1] — 2026-10-21
|
|
120
|
+
|
|
121
|
+
A beta, by policy: **not published to npm**. It is a GitHub prerelease, installable by a developer who asks for it.
|
|
122
|
+
|
|
123
|
+
### Message ids are unique across a relay restart
|
|
124
|
+
|
|
125
|
+
The relay's chat sequence resets on restart, so a bare `msg-000001` named a different message after every deploy. Clients persist
|
|
126
|
+
those ids -- an open turn, a read watermark, `reply_to` -- and live testing caught exactly that: a Windows `ask` recorded a turn, the
|
|
127
|
+
relay restarted, a new message reused the id, and the wait settled the OLD turn as `answered_after_timeout` while the reply was
|
|
128
|
+
fresh. Message ids now carry a random per-process epoch (`msg-<epoch>-<seq>`), so a restart cannot recycle an id and old clients that
|
|
129
|
+
render ids verbatim keep working.
|
|
130
|
+
|
|
131
|
+
### One size for "how large may one artifact be"
|
|
132
|
+
|
|
133
|
+
The blob transport frame was 1 MiB while the agent's dataflow hard cap is 16 MiB, so an artifact between the two was accepted by the
|
|
134
|
+
agent and then failed its upload (`BLOB_UPLOAD_FAILED`) on a relay that looked fine. `BLOB_FRAME_BYTES` is now 16 MiB, matching the
|
|
135
|
+
agent, while every JSON route keeps the 64 KiB frame limit.
|
|
136
|
+
|
|
137
|
+
### Verified
|
|
138
|
+
|
|
139
|
+
Gate GREEN twice: 2691 tests / 2677 pass / 0 fail / 14 skip in 130 files. New tests: an id is unique across two store instances
|
|
140
|
+
(same sequence, different process), an explicit epoch is honoured, and a 2 MiB blob survives the transport intact.
|
|
141
|
+
|
|
142
|
+
### Still open (unchanged from 1.2.7)
|
|
143
|
+
|
|
144
|
+
- `pipeline` keeps `index_total` at 1; blob map results come from plain commands above the inline cap.
|
|
145
|
+
- macmini runs 1.2.6 from its own checkout and needs a `git pull` + restart for the plain-command blob behaviour.
|
|
146
|
+
## [1.2.7] — 2026-10-21
|
|
147
|
+
|
|
148
|
+
**The scheduler enforces the graph, a wait survives a restart and a dropped stream, and a partial fleet can no longer call itself
|
|
149
|
+
a complete reduce.**
|
|
150
|
+
|
|
151
|
+
### Turns are a state machine on disk
|
|
152
|
+
|
|
153
|
+
A question written with `action:'ask'` becomes a persisted turn (`ask_id`, deadline). `await` attaches to that record, so a process
|
|
154
|
+
restart does not lose the question or turn a late answer into silence; a late answer is recorded as `answered_after_timeout`. The
|
|
155
|
+
wait prefers the relay's event stream, re-subscribes when the stream drops, and polls only when streaming is unavailable. A reply
|
|
156
|
+
now carries `reply_state: 'answered'|'refused'`, so a refusal is a state the waiter reads rather than wording it guesses.
|
|
157
|
+
|
|
158
|
+
### Dependencies block dispatch, and release when their prerequisite settles
|
|
159
|
+
|
|
160
|
+
A task with `depends_on` is not offered: its leases are `waiting`, which redelivery skips and the sweeper ignores. When every
|
|
161
|
+
prerequisite is settled -- **by a result, an expiry or a refusal** -- `_releaseDependents` moves those leases to offers. The graph
|
|
162
|
+
edges and `assignee` are written into the task ledger, because live testing showed a restarted relay losing them and keeping a
|
|
163
|
+
waiting task waiting forever. `assignee` is enforced, not recorded: only that machine gets a lease, and an unknown assignee is
|
|
164
|
+
refused by name. `GET /v1/tasks` now publishes a derived `status` (`waiting`/`active`/`done`/`failed`/`cancelled`) and
|
|
165
|
+
`waiting_on`, so the board and the scheduler cannot disagree.
|
|
166
|
+
|
|
167
|
+
### Dataflow: an expected shard count, and a reduce that refuses partial input
|
|
168
|
+
|
|
169
|
+
`buildReducePlan` takes `expectedIndexTotal` from the task (`index_total`) and refuses `MISSING_SHARD` (with the missing indexes),
|
|
170
|
+
`MAP_INDEX_MISSING` and `MAP_INDEX_OUT_OF_RANGE`; only machines that actually reported can claim a shard, so an expired lease no
|
|
171
|
+
longer makes a partial run look complete. Two production gaps were found by live testing and closed with it:
|
|
172
|
+
|
|
173
|
+
- **A large plain-command stdout was never a blob.** The blob path lived only in the pipeline loop, so a split/mapreduce map result
|
|
174
|
+
was always inline and a reduce plan could never see what it reduces. Any command output above the inline cap now uploads a blob
|
|
175
|
+
exactly as a pipeline stage does (best effort: a failed upload keeps the command successful and says why).
|
|
176
|
+
- **The relay's own frame limit made the blob channel unusable.** `MAX_FRAME_BYTES` (64 KiB) equals the inline threshold, so every
|
|
177
|
+
blob was by construction larger than the frame cap and a real upload failed with `FRAME_TOO_LARGE` while the fake relay in tests
|
|
178
|
+
accepted it. Blob PUTs now get a bounded 1 MiB frame (`BLOB_FRAME_BYTES`); every JSON route keeps the 64 KiB cap.
|
|
179
|
+
- The aggregate now publishes `blob_sha256`, `output_mode`, `stdout_head` and `stdout_bytes` per machine: `w2m_wait` used to read
|
|
180
|
+
`aggregate.detail.machines`, a shape the production `/v1/tasks` response never carries, so the reduce plan was unreachable
|
|
181
|
+
outside tests.
|
|
182
|
+
|
|
183
|
+
### Verified
|
|
184
|
+
|
|
185
|
+
Gate GREEN twice, 15 of 15: 2687 tests / 2673 pass / 0 fail / 14 skip in 130 files.
|
|
186
|
+
|
|
187
|
+
Two-machine live runs on Windows (ToFuture) and jp-shared over the real relay:
|
|
188
|
+
|
|
189
|
+
- **await over SSE**: Windows asks, jp-shared replies `reply_state:'refused'`; the wait returns `state=refused, via=stream`, and the
|
|
190
|
+
turn is settled on disk.
|
|
191
|
+
- **dependency chain**: B with `depends_on: [A]` is `waiting`, A settles, B is released (observed `status=active` with offers).
|
|
192
|
+
- **missing shard**: a split task with `index_total: 5` whose map results are blobs is refused as
|
|
193
|
+
`MISSING_SHARD {missing:[1,3,4], expectedIndexTotal:5}` with `dataflow_degraded: true` -- the first live exercise of the blob
|
|
194
|
+
channel end to end.
|
|
195
|
+
|
|
196
|
+
Both live-testing defects above (release only on a result; graph edges missing from the ledger) were found by these runs and are
|
|
197
|
+
covered by tests now.
|
|
198
|
+
|
|
199
|
+
### Limits, stated
|
|
200
|
+
|
|
201
|
+
- A pipeline task runs the whole chain per machine, so `index_total` stays 1 for it; blob map results come from plain commands above
|
|
202
|
+
the inline cap.
|
|
203
|
+
- The blob transport frame is 1 MiB while the agent's dataflow hard cap is 16 MiB: a single artifact above 1 MiB fails its upload
|
|
204
|
+
explicitly (`BLOB_UPLOAD_FAILED`) rather than being split across frames.
|
|
205
|
+
- The jp-shared agent was upgraded to this build; macmini runs 1.2.6 from its own checkout and needs a `git pull` + restart to get
|
|
206
|
+
the plain-command blob behaviour.
|
|
10
207
|
## [1.2.6] — 2026-10-20
|
|
11
208
|
|
|
12
209
|
**Security surface: signatures, a permission matrix, and output that no longer carries secrets — plus the reliability the chat
|
package/README.md
CHANGED
|
@@ -14,7 +14,7 @@ English | [中文](#中文说明)
|
|
|
14
14
|
|
|
15
15
|
## Install
|
|
16
16
|
|
|
17
|
-
Five routes in. They all end with **
|
|
17
|
+
Five routes in. They all end with **16 tools registered** in your agent. Pick one.
|
|
18
18
|
|
|
19
19
|
### 1. DSH plugin (recommended — zero configuration)
|
|
20
20
|
|
|
@@ -136,7 +136,7 @@ hand-maintained host list.
|
|
|
136
136
|
### Tools
|
|
137
137
|
|
|
138
138
|
`w2m_status` · `w2m_devices` · `w2m_run` · `w2m_wait` · `w2m_history` · `w2m_stats` · `w2m_report` ·
|
|
139
|
-
`w2m_memory` · `w2m_approvals` · `w2m_cancel` · `w2m_council` · `w2m_chat` · `w2m_update` `w2m_tasks`
|
|
139
|
+
`w2m_memory` · `w2m_approvals` · `w2m_cancel` · `w2m_council` · `w2m_chat` · `w2m_update` `w2m_tasks` · `w2m_reduce`
|
|
140
140
|
- `w2m_intent` — map a structured intent (run-tests, node-version, git-status, git-head, fleet-facts, shard-probe) onto an allow-listed command; unknown intents are refused by name, never guessed.
|
|
141
141
|
|
|
142
142
|
### Environment a dispatched command receives (1.1.15+)
|
|
@@ -261,7 +261,7 @@ MIT.
|
|
|
261
261
|
|
|
262
262
|
### 安装
|
|
263
263
|
|
|
264
|
-
五种方式,最终都会在你的 agent 里注册 **
|
|
264
|
+
五种方式,最终都会在你的 agent 里注册 **16 tools registered**。任选其一。
|
|
265
265
|
|
|
266
266
|
#### 1. DSH 插件(推荐,零配置)
|
|
267
267
|
|
package/codex/mcp-servers.toml
CHANGED
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
# Data plane and collaboration: the design this fleet is building toward
|
|
2
|
+
|
|
3
|
+
> Status: **design + first slice (v1.2.9-beta.1)**. The slice is a pure function that turns an aggregate into a *reduce
|
|
4
|
+
> suggestion*; it dispatches nothing. Everything below the slice is the plan the slice is measured against, not a claim that it
|
|
5
|
+
> exists.
|
|
6
|
+
|
|
7
|
+
## 1. What "data plane" means here
|
|
8
|
+
|
|
9
|
+
A task has three planes in this fleet:
|
|
10
|
+
|
|
11
|
+
| plane | what moves | owns |
|
|
12
|
+
|---|---|---|
|
|
13
|
+
| control | dispatch, leases, retries, cancellation | relay (`state.mjs`) |
|
|
14
|
+
| data | command output, stage artifacts, blobs | agent (`agent.mjs`) + relay blob store |
|
|
15
|
+
| collaboration | chat, turns, memory, council | plugin (`tools.mjs`, `ask-store.mjs`, `council-fleet.mjs`) |
|
|
16
|
+
|
|
17
|
+
The data plane is **not allowed to make a verdict**. It moves bytes; the aggregate decides. That rule is why the reduce plan is
|
|
18
|
+
computed by a reader (`w2m_wait`) from published facts, and why this release adds only a *suggestion*: a party that has the plan
|
|
19
|
+
must still be the one that says "run the reduce".
|
|
20
|
+
|
|
21
|
+
## 2. The shard contract (implemented in v1.2.7)
|
|
22
|
+
|
|
23
|
+
1. A task declares `index_total`. It is the completeness contract, not a hint.
|
|
24
|
+
2. A result claims a shard with `index`; only machines that actually reported count.
|
|
25
|
+
3. `buildReducePlan({ results, reducerMachineId, expectedIndexTotal })` refuses:
|
|
26
|
+
- `MISSING_SHARD` + `{ missing, expectedIndexTotal }`,
|
|
27
|
+
- `MAP_INDEX_MISSING`, `MAP_INDEX_OUT_OF_RANGE`,
|
|
28
|
+
- `BLOB_MISSING`, `MAP_MACHINE_MISSING`, `NO_MAP_RESULTS`.
|
|
29
|
+
4. An artifact above the inline cap is a blob (`blob_sha256` + `output_mode: 'blob'`), uploaded by the agent, addressed by its own
|
|
30
|
+
hash, transport frame 16 MiB.
|
|
31
|
+
5. **A partial fleet never reduces.** `dataflow_degraded: true` is the value; a caller that ignores it is ignoring a stated fact.
|
|
32
|
+
|
|
33
|
+
## 3. What v1.2.9-beta.1 adds: `suggestReduce`
|
|
34
|
+
|
|
35
|
+
`w2m_wait` now returns a `reduce_suggestion` alongside the verdict:
|
|
36
|
+
|
|
37
|
+
```json
|
|
38
|
+
{
|
|
39
|
+
"ready": true,
|
|
40
|
+
"plan": { "ok": true, "reducerMachineId": "…", "inputs": [ … ] },
|
|
41
|
+
"candidates": [{ "machine_id": "…", "reason": "reported-shard" }],
|
|
42
|
+
"next": "dispatch the reduce yourself; this tool does not run it"
|
|
43
|
+
}
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
Rules it encodes:
|
|
47
|
+
|
|
48
|
+
- **Ready means all declared shards reported and a reducer is named.** Anything else is a value with the missing indexes.
|
|
49
|
+
- **The reducer is not chosen by the tool.** It lists candidates (machines that reported, preferring the declared
|
|
50
|
+
`reducer_machine_id` when present) and refuses to invent one: a reduce that runs on an arbitrary machine is a second dispatch
|
|
51
|
+
decision, and dispatch belongs to the caller.
|
|
52
|
+
- **The suggestion is derived, never stored.** Two readers of the same aggregate get the same suggestion, and no relay state
|
|
53
|
+
changes by reading it.
|
|
54
|
+
|
|
55
|
+
## 4. The reduce execution question (open)
|
|
56
|
+
|
|
57
|
+
Two shapes are possible, and the fleet has not chosen one:
|
|
58
|
+
|
|
59
|
+
| shape | dispatch of reduce | trade |
|
|
60
|
+
|---|---|---|
|
|
61
|
+
| **caller-dispatched** (current direction) | the caller reads the plan and dispatches a task with `reduce_argv` to the named reducer | relay never decides to run a command; one extra round trip and the caller can ignore the plan |
|
|
62
|
+
| **auto-reduce** | the relay, on all-shards-reported, dispatches the reduce itself | fewer steps; the relay becomes an executor of a command it chose, which is the boundary every other design decision avoids |
|
|
63
|
+
|
|
64
|
+
The design leans caller-dispatched. A beta that flips that default would be the wrong place to discover it.
|
|
65
|
+
|
|
66
|
+
## 5. Collaboration plane, next
|
|
67
|
+
|
|
68
|
+
The collaboration gaps that remain after v1.2.6/v1.2.7 (turns, DAG, membership, memory CAS) are:
|
|
69
|
+
|
|
70
|
+
1. **Conflict merge UI** — `w2m_memory read` returns `behind_by`/`unread_records`; a reader can see a conflict but has no guided
|
|
71
|
+
merge. Next slice: a pure `renderMergeHint()` and a re-read flow that shows both sides of a conflicting record.
|
|
72
|
+
2. **Council decision trail** — `council-fleet.mjs` decides and reports; the decision is not written to shared memory. Next slice:
|
|
73
|
+
an explicit, caller-invoked append of the decision as a memory record (same CAS as any other write).
|
|
74
|
+
3. **DAG visibility in the client** — the board exists in `w2m_tasks`; the composer panel does not show it. Next slice: a read-only
|
|
75
|
+
board view from the same endpoint.
|
|
76
|
+
|
|
77
|
+
## 6. Acceptance for this design
|
|
78
|
+
|
|
79
|
+
- The suggestion is a pure function with unit tests for: all shards present, missing shards, no reducer named, mixed
|
|
80
|
+
inline+blob inputs, and a duplicate machine index.
|
|
81
|
+
- `w2m_wait` carries it for every complete aggregate and never dispatches anything.
|
|
82
|
+
- Gate GREEN twice before the beta tag; beta artifacts are a GitHub prerelease, never npm.
|