@twinsearth/w2m-dsh-plugin 3.0.0 → 3.2.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 +3 -3
- package/.claude-plugin/plugin.json +1 -1
- package/CHANGELOG.md +38 -0
- package/README.md +16 -1
- package/codex/mcp-servers.toml +1 -1
- package/cordis.patch.yml +10 -0
- package/docs/acceptance/3.0.0/RELEASE-3000.json +3 -1
- package/docs/acceptance/3.1.0/RELEASE-3100.json +46 -0
- package/docs/acceptance/3.2.0/RELEASE-3200.json +47 -0
- package/lib/client.js +444 -0
- package/lib/contract.js +22 -0
- package/lib/queue-journal.js +15 -0
- package/package.json +9 -4
- package/plugin.json +1 -1
- package/src/decision-center/kernel.mjs +2 -3
- package/src/decision-center/routes.mjs +52 -26
- package/src/interop/contract/LICENSE +661 -0
- package/src/interop/contract/PROVENANCE.md +26 -0
- package/src/interop/contract/client.js +93 -0
- package/src/interop/contract/constants.js +94 -0
- package/src/interop/contract/envelope.js +83 -0
- package/src/interop/contract/index.js +20 -0
- package/src/interop/contract/negotiate.js +106 -0
- package/src/interop/contract/relay.js +229 -0
- package/src/interop/contract/server.js +77 -0
- package/src/interop/contract/transports.js +319 -0
- package/src/interop/index.mjs +270 -0
- package/src/plugin/tools.mjs +1 -1
- package/src/queue-journal/index.mjs +188 -0
- package/src/queue-journal/lib/composer-journal.mjs +128 -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": "3.
|
|
8
|
+
"version": "3.2.0"
|
|
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": "3.
|
|
15
|
+
"version": "3.2.0",
|
|
16
16
|
"author": {
|
|
17
17
|
"name": "TwinsEarth"
|
|
18
18
|
},
|
|
@@ -26,5 +26,5 @@
|
|
|
26
26
|
]
|
|
27
27
|
}
|
|
28
28
|
],
|
|
29
|
-
"version": "3.
|
|
29
|
+
"version": "3.2.0"
|
|
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": "3.
|
|
4
|
+
"version": "3.2.0",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "TwinsEarth"
|
|
7
7
|
},
|
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,44 @@ All notable changes to this project are documented here.
|
|
|
4
4
|
|
|
5
5
|
## [Unreleased]
|
|
6
6
|
|
|
7
|
+
## [3.2.0] - 2026-11-14
|
|
8
|
+
|
|
9
|
+
- 互联契约子插件:`@twinsearth/w2m-dsh-plugin/contract`,基于独立发布的版本化契约 SDK
|
|
10
|
+
`@twinsearth/dsh-fang-contract@1.1.1`(逐字节副本 + `src/interop/contract/PROVENANCE.md`,
|
|
11
|
+
`scripts/check-contract-vendor.mjs` 逐字节复核并纳入测试)。三个项目(w2m / 瓮城 dsh-fang / 房主
|
|
12
|
+
dsh-master)各自独立发布,互不 import 内部代码、互不改对方资料,只经方法表 + 信封 + 传输层互联。
|
|
13
|
+
- w2m 方法表(`w2m.*`,契约版本 `1.0.0`,与插件版本解耦):`w2m.status`、`w2m.methods`、
|
|
14
|
+
`w2m.fleet.snapshot`、`w2m.devices.list`、`w2m.tasks.list`;MINOR 只新增,删/改义升 MAJOR 并双写。
|
|
15
|
+
provider 由 `w2m.*` 宿主注入(`providers` 或 `w2mContractProviders` 服务),缺席时如实报
|
|
16
|
+
`handler-threw: … exposes no … provider`,不返回空数据冒充成功。
|
|
17
|
+
- 服务端:`createContractServer` 承载 hello/health/invoke(协议 `fang-master` v1);提供
|
|
18
|
+
`w2mContract` 服务;同宿主对端(fang/master 的 local 传输)默认找 `fangContract`,本插件在该名
|
|
19
|
+
缺席时补位、已存在时不覆盖,避免与瓮城抢服务键。HTTP 路由固定 `/api/w2m/contract/{hello,health,invoke}`,
|
|
20
|
+
不占用 fang 的 `/fang/api/contract/*`;配置 `fileDir` 时再挂 file 兜底服务端。
|
|
21
|
+
- 客户端:`createW2mContractClient` 复用 SDK 的 **local → http → file → legacy** 四级自动降级
|
|
22
|
+
(legacy 走 3.1.x 旧服务键 `fangForker` 等兜底),可调用 `fang.*` / `contract.*` / `w2m.*` 方法。
|
|
23
|
+
- 与 3.1.0 的关系:本版包含 3.0.0(决策中心)与 3.1.0(队列子插件)的全部内容,三者一起作为
|
|
24
|
+
v3.2.0 发布;版本号语义仍各自独立(插件 3.2.0 / w2m 契约 1.0.0 / 契约 SDK 1.1.1)。
|
|
25
|
+
- 测试:新增 `test/contract-interop.test.mjs` 9 项(方法表与 hello 广告、信封往返与显式拒绝、
|
|
26
|
+
provider 注入与缺席、三路由注册、服务补位/不覆盖、local/http/file/legacy 四级降级、SDK 副本逐字节一致)。
|
|
27
|
+
|
|
28
|
+
## [3.1.0] - 2026-11-14
|
|
29
|
+
|
|
30
|
+
- 队列子插件:`@twinsearth/dsh-fang-queue-journal`(瓮城)移植为 `@twinsearth/w2m-dsh-plugin/queue-journal`。
|
|
31
|
+
Fang 的包只有空宿主(`apply(){}`),HTTP 面在 fang orchestrator 里;W2M 没有 orchestrator,所以
|
|
32
|
+
`src/queue-journal/index.mjs` 自带存储与四条路由,线上形状与移植的客户端完全一致:
|
|
33
|
+
`GET/POST /api/w2m/composer/journal`(单条/恢复列表)、`GET /api/w2m/composer/journal/history`
|
|
34
|
+
(append-only 快照,可按 sessionKey 过滤)、`POST /api/w2m/composer/queue`(恢复到会话收件箱;
|
|
35
|
+
无 live agent 时返回 `session-not-live`,绝不假装入队)。
|
|
36
|
+
- 存储 `ComposerJournal` 逐字移植(`src/queue-journal/lib/composer-journal.mjs`),数据落在
|
|
37
|
+
`$DSH_HOME/xclient/queue-journal`;保存上限、历史上限与原子写保持不变。
|
|
38
|
+
- 客户端:Fang 的独立客户端模块(`window.__ModuleLoader__.load`)展开成 W2M 单一客户端 bundle 里的
|
|
39
|
+
`createQueueJournalModule()`,由根 `apply(ctx)` 挂到 `conversation.composer.dock`:草稿输入捕获、
|
|
40
|
+
queue dock 的 MutationObserver、15 秒兜底与 pagehide flush 全部保留;恢复只能由用户显式点击。
|
|
41
|
+
Fang 的 `x-fang-auth` 取 token 逻辑替换为同源占位(W2M 路由走 cookie 鉴权)。
|
|
42
|
+
- 测试:新增 `test/queue-journal.test.mjs` 4 项(保存/读回/恢复列表、历史过滤、缺 key 拒绝、
|
|
43
|
+
非 live 会话拒绝恢复);client-bundle 的座位断言更新为 17 个(新增队列 dock)。
|
|
44
|
+
|
|
7
45
|
## [3.0.0] - 2026-11-14
|
|
8
46
|
|
|
9
47
|
- 决策中心子插件:`@twinsearth/dsh-fang/decision-center`(瓮城)完整移植为
|
package/README.md
CHANGED
|
@@ -93,7 +93,7 @@ w2m-mcp --help
|
|
|
93
93
|
# 复制进你自己的 codex/mcp-servers.toml
|
|
94
94
|
[mcp_servers.w2m]
|
|
95
95
|
command = "npx"
|
|
96
|
-
args = ["-y", "@twinsearth/w2m-dsh-plugin@3.
|
|
96
|
+
args = ["-y", "@twinsearth/w2m-dsh-plugin@3.2.0", "w2m-mcp"]
|
|
97
97
|
```
|
|
98
98
|
|
|
99
99
|
### 5. 验证过的 release tarball(离线)
|
|
@@ -195,3 +195,18 @@ plugins:
|
|
|
195
195
|
- [Issues](https://github.com/TwinsEarth/dsh-windows2macos/issues)
|
|
196
196
|
|
|
197
197
|
MIT.
|
|
198
|
+
|
|
199
|
+
## 互联契约(contract 1.x)
|
|
200
|
+
|
|
201
|
+
`@twinsearth/w2m-dsh-plugin/contract` 是 w2m 与瓮城 dsh-Fang、房主 dsh-Master 之间的唯一通道:
|
|
202
|
+
三个项目各自独立发布、互不 import 内部代码,只经由版本化契约 SDK
|
|
203
|
+
`@twinsearth/dsh-fang-contract` 的方法表 + 信封 + 传输层协作。
|
|
204
|
+
|
|
205
|
+
- 子插件行:`@twinsearth/w2m-dsh-plugin/contract`(默认启用)。
|
|
206
|
+
- 服务端方法(`w2m.*`,契约版本 1.0.0):`w2m.status`、`w2m.methods`、`w2m.fleet.snapshot`、
|
|
207
|
+
`w2m.devices.list`、`w2m.tasks.list`。
|
|
208
|
+
- HTTP:`POST /api/w2m/contract/invoke`、`GET /api/w2m/contract/hello`、`GET /api/w2m/contract/health`。
|
|
209
|
+
- 同宿主互通走 local 服务:w2m 提供 `w2mContract`,并在 `fangContract` 缺席时补位(已存在则不覆盖)。
|
|
210
|
+
- 跨宿主互通走 http 或 file:客户端按 **local → http → file → legacy** 自动降级。
|
|
211
|
+
- 升级契约 SDK:`npm pack @twinsearth/dsh-fang-contract@<版本>` → 覆盖 `src/interop/contract/` →
|
|
212
|
+
重生成 `PROVENANCE.md` → `npm run verify:contract`。
|
package/codex/mcp-servers.toml
CHANGED
package/cordis.patch.yml
CHANGED
|
@@ -151,6 +151,16 @@
|
|
|
151
151
|
# floating launcher render (read through /api/w2m/decisions), and a disabled row would leave that
|
|
152
152
|
# panel with no store behind it. The store lives under $DSH_HOME/xclient/decision-center; the row
|
|
153
153
|
# carries no config so the plugin's own defaults apply.
|
|
154
|
+
# 队列日志 (queue journal): composer drafts and the queue mirror, ported from dsh-Fang's
|
|
155
|
+
# @twinsearth/dsh-fang-queue-journal in v3.1.0. Enabled so the composer dock appears.
|
|
156
|
+
# 互联契约 (contract 1.x): w2m.* methods over the published @twinsearth/dsh-fang-contract SDK.
|
|
157
|
+
# Independent from dsh-fang and dsh-master: no shared code, only method table + envelope + transport.
|
|
158
|
+
- id: dsh-w2m-contract
|
|
159
|
+
name: '@twinsearth/w2m-dsh-plugin/contract'
|
|
160
|
+
config: {}
|
|
161
|
+
- id: dsh-queue-journal
|
|
162
|
+
name: '@twinsearth/w2m-dsh-plugin/queue-journal'
|
|
163
|
+
config: {}
|
|
154
164
|
- id: dsh-decision-center
|
|
155
165
|
name: '@twinsearth/w2m-dsh-plugin/decision-center'
|
|
156
166
|
config: {}
|
|
@@ -16,6 +16,8 @@
|
|
|
16
16
|
"--test-force-exit",
|
|
17
17
|
"test/decision-center.test.mjs",
|
|
18
18
|
"test/decision-routes.test.mjs",
|
|
19
|
+
"test/decision-events.test.mjs",
|
|
20
|
+
"test/decision-ingest-client.test.mjs",
|
|
19
21
|
"test/decision-outbox.test.mjs"
|
|
20
22
|
],
|
|
21
23
|
[
|
|
@@ -42,7 +44,7 @@
|
|
|
42
44
|
"service": "apply() provides w2mDecisionCenter with 27 methods and registers request_human_decision / ask_user_choice",
|
|
43
45
|
"routes": "14 /api/w2m/decisions* routes registered on the connection fetch registry, including the SSE events and AI advise streams; create -> list -> item -> quota -> resolve round-trips through HTTP",
|
|
44
46
|
"panel": "DecisionCenterSection renders inside GpwPanel, which GpwSettingsPage embeds and GpwLauncher opens, so the GPW page and the GPW launcher show the same center; it polls every 4s, groups by level, resolves via the ticket options, abandons option-less tickets and only displays AI advice",
|
|
45
|
-
"suites": "
|
|
47
|
+
"suites": "92 tests pass: 79 ported Fang decision-center tests + 10 outbox/events/ingest tests + 3 new route-surface tests",
|
|
46
48
|
"not_ported": "decision-center-fork and decision-action-integration stay out: the former needs the Fang mother/fork role matrix, the latter the Fang orchestrator and restart-guard, neither of which exists in W2M",
|
|
47
49
|
"artifact": "scripts/pack.mjs packs dist/twinsearth-w2m-dsh-plugin-3.0.0.tgz deterministically; the published sha256 is the one release.yml writes into dist/SHA256SUMS, so the record does not restate the hash of the archive that contains it"
|
|
48
50
|
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": "3.1.0",
|
|
3
|
+
"case": "RELEASE-3100",
|
|
4
|
+
"kind": "positive",
|
|
5
|
+
"machines": [
|
|
6
|
+
"b53a37f4-1464-4512-9259-33a7df091e3e"
|
|
7
|
+
],
|
|
8
|
+
"executed_at": "2026-11-13T21:00:13.167Z",
|
|
9
|
+
"executor": "lead",
|
|
10
|
+
"task_id": "pre-release-3100",
|
|
11
|
+
"requirement": "v3.1.0: the Fang queue journal is ported to W2M as @twinsearth/w2m-dsh-plugin/queue-journal (store + four /api/w2m/composer/* routes + composer dock client UI in the single client bundle) and its tests pass",
|
|
12
|
+
"commands": [
|
|
13
|
+
[
|
|
14
|
+
"node",
|
|
15
|
+
"--test",
|
|
16
|
+
"--test-force-exit",
|
|
17
|
+
"test/queue-journal.test.mjs"
|
|
18
|
+
],
|
|
19
|
+
[
|
|
20
|
+
"node",
|
|
21
|
+
"--test",
|
|
22
|
+
"--test-force-exit",
|
|
23
|
+
"test/client-bundle.test.mjs"
|
|
24
|
+
],
|
|
25
|
+
[
|
|
26
|
+
"node",
|
|
27
|
+
"--test",
|
|
28
|
+
"--test-force-exit",
|
|
29
|
+
"test/loader-entry.test.mjs"
|
|
30
|
+
],
|
|
31
|
+
[
|
|
32
|
+
"node",
|
|
33
|
+
"scripts/pack.mjs"
|
|
34
|
+
]
|
|
35
|
+
],
|
|
36
|
+
"result": {
|
|
37
|
+
"outcome": "ok",
|
|
38
|
+
"assertions": {
|
|
39
|
+
"store": "ComposerJournal is copied verbatim from Fang (src/queue-journal/lib/composer-journal.mjs); its data directory defaults to $DSH_HOME/xclient/queue-journal",
|
|
40
|
+
"routes": "GET/POST /api/w2m/composer/journal, GET /api/w2m/composer/journal/history and POST /api/w2m/composer/queue are registered on the connection fetch registry; the restore route answers session-not-live (409) when no live agent can take the rows, exactly as the Fang route did",
|
|
41
|
+
"client": "createQueueJournalModule() in lib/client.js is the Fang factory body with only the auth-token shim and /fang/api -> /api/w2m rewrites; the root apply(ctx) mounts it on conversation.composer.dock, so the draft/queue journal UI appears in the composer dock",
|
|
42
|
+
"suites": "queue-journal 4/4 and client bundle 36/36 (the seat expectation now lists 17 seats including conversation.composer.dock)",
|
|
43
|
+
"artifact": "scripts/pack.mjs packs dist/twinsearth-w2m-dsh-plugin-3.1.0.tgz deterministically; the published sha256 is the one release.yml writes into dist/SHA256SUMS, so the record does not restate the hash of the archive that contains it"
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": "3.2.0",
|
|
3
|
+
"case": "RELEASE-3200",
|
|
4
|
+
"kind": "positive",
|
|
5
|
+
"machines": [
|
|
6
|
+
"b53a37f4-1464-4512-9259-33a7df091e3e"
|
|
7
|
+
],
|
|
8
|
+
"executed_at": "2026-11-14T01:11:13.111Z",
|
|
9
|
+
"executor": "lead",
|
|
10
|
+
"task_id": "pre-release-3200",
|
|
11
|
+
"requirement": "v3.2.0: w2m speaks the independently published, versioned interop contract SDK (@twinsearth/dsh-fang-contract 1.1.1) for w2m <-> dsh-fang and w2m <-> dsh-master interop: own w2m.* method table, server (local service + /api/w2m/contract routes + optional file fallback), client with local->http->file->legacy downgrade, and byte-identical vendored SDK copy; no dsh-fang or dsh-master source is imported or modified",
|
|
12
|
+
"commands": [
|
|
13
|
+
[
|
|
14
|
+
"node",
|
|
15
|
+
"--test",
|
|
16
|
+
"--test-force-exit",
|
|
17
|
+
"test/contract-interop.test.mjs"
|
|
18
|
+
],
|
|
19
|
+
[
|
|
20
|
+
"node",
|
|
21
|
+
"--test",
|
|
22
|
+
"--test-force-exit",
|
|
23
|
+
"test/layer-model.test.mjs",
|
|
24
|
+
"test/claims.test.mjs"
|
|
25
|
+
],
|
|
26
|
+
[
|
|
27
|
+
"node",
|
|
28
|
+
"scripts/check-contract-vendor.mjs"
|
|
29
|
+
],
|
|
30
|
+
[
|
|
31
|
+
"node",
|
|
32
|
+
"scripts/pack.mjs"
|
|
33
|
+
]
|
|
34
|
+
],
|
|
35
|
+
"result": {
|
|
36
|
+
"outcome": "ok",
|
|
37
|
+
"assertions": {
|
|
38
|
+
"independence": "the three projects stay independent: w2m imports no dsh-fang or dsh-master source, modifies neither tree, and depends only on the published @twinsearth/dsh-fang-contract package, whose 1.1.1 files are vendored byte for byte under src/interop/contract/ with sha256 recorded in PROVENANCE.md",
|
|
39
|
+
"methodTable": "w2m.* methods at contractVersion 1.0.0: w2m.status, w2m.methods, w2m.fleet.snapshot, w2m.devices.list, w2m.tasks.list; the SDK protocol (fang-master v1) and contract package version (1.1.1) stay separate from the plugin version (3.2.0)",
|
|
40
|
+
"server": "createW2mContractServer wraps the SDK server; apply() provides w2mContract, yields the fangContract name only when it is free, registers /api/w2m/contract/{hello,health,invoke} on the connection registry and mounts the SDK file contract server when fileDir is configured",
|
|
41
|
+
"client": "createW2mContractClient reuses the SDK router, so local -> http -> file -> legacy downgrade works; the legacy hop calls the 3.1.x service keys (fangForker etc.) as the last resort",
|
|
42
|
+
"suites": "contract-interop 9/9; layer model and claims 71 pass with 1 network skip; vendor checker 9/9 files match PROVENANCE.md",
|
|
43
|
+
"no_fake_data": "a handler without an injected provider answers handler-threw carrying w2m-service-absent instead of returning empty success data",
|
|
44
|
+
"artifact": "scripts/pack.mjs packs dist/twinsearth-w2m-dsh-plugin-3.2.0.tgz deterministically; the published sha256 is the one release.yml writes into dist/SHA256SUMS, so the record does not restate the hash of the archive that contains it"
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|