@twinsearth/w2m-dsh-plugin 1.9.9 → 1.9.11
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 +11 -0
- package/bin/w2m-self-update.mjs +107 -0
- package/codex/mcp-servers.toml +1 -1
- package/docs/acceptance/1.9.10/RELEASE-1910.json +21 -0
- package/docs/acceptance/1.9.11/RELEASE-1911.json +20 -0
- package/lib/client.js +84 -13
- package/package.json +4 -3
- package/plugin.json +1 -1
- package/src/plugin/tools.mjs +1 -1
- package/src/relay/report.mjs +651 -649
- package/src/relay/server.mjs +1 -2
|
@@ -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.9.
|
|
8
|
+
"version": "1.9.11"
|
|
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.9.
|
|
15
|
+
"version": "1.9.11",
|
|
16
16
|
"author": {
|
|
17
17
|
"name": "TwinsEarth"
|
|
18
18
|
},
|
|
@@ -26,5 +26,5 @@
|
|
|
26
26
|
]
|
|
27
27
|
}
|
|
28
28
|
],
|
|
29
|
-
"version": "1.9.
|
|
29
|
+
"version": "1.9.11"
|
|
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.9.
|
|
4
|
+
"version": "1.9.11",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "TwinsEarth"
|
|
7
7
|
},
|
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,17 @@
|
|
|
7
7
|
|
|
8
8
|
All notable changes to this project are documented here.
|
|
9
9
|
|
|
10
|
+
## [1.9.11] - 2026-10-28
|
|
11
|
+
|
|
12
|
+
- 修复左侧栏只剩图标:GPW 名称恢复到入口内(🌐 GPW),侧栏 label 仍为空,避免再次重复。
|
|
13
|
+
- 对话全文搜索:匹配项以黄色高亮(CSS Custom Highlight API ::highlight(w2m-conversation-search)),显示 当前/总数 计数;Enter/Shift+Enter 或 ↑/↓ 在命中项间滚动,Esc 清除。
|
|
14
|
+
|
|
15
|
+
## [1.9.10] - 2026-10-28
|
|
16
|
+
|
|
17
|
+
- 新增 `bin/w2m-self-update.mjs`:可被编队任务直接下发的自更新入口,读取 GitHub Release、校验 SHA256SUMS、调用已验证安装器,输出一行 JSON,不重启 DSH。
|
|
18
|
+
- 固化升级策略:优先下发自更新指令;失败才使用 Node 远程执行回退(macOS 用 mac-self-update,Windows 用 node 替换+备份)。
|
|
19
|
+
- 参数:--profile、--dry-run、--allow-prerelease;环境变量 W2M_PROFILE_DIR / W2M_UPDATE_REPO。
|
|
20
|
+
|
|
10
21
|
## [1.9.9] - 2026-10-28
|
|
11
22
|
|
|
12
23
|
- 对话主工作区新增全文搜索:会话头部(置顶按钮同排)🔍 图标,点击展开搜索框,Enter/Shift+Enter 或 ↑/↓ 在已渲染对话中查找并高亮(Electron/Chromium find)。
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Remote-triggerable, verified self-update for the W2M plugin.
|
|
4
|
+
*
|
|
5
|
+
* Fleet policy (operator): a machine is upgraded by dispatching this script as a task
|
|
6
|
+
* (`node <profile>/node_modules/@twinsearth/w2m-dsh-plugin/bin/w2m-self-update.mjs`), and only
|
|
7
|
+
* when that fails is a Node remote-execution fallback used. This file is therefore headless:
|
|
8
|
+
* it checks the configured GitHub release, verifies the published sha256, installs through the
|
|
9
|
+
* same updater the plugin UI uses, and prints one JSON line. It never restarts DSH.
|
|
10
|
+
*
|
|
11
|
+
* Usage:
|
|
12
|
+
* node bin/w2m-self-update.mjs [--profile <dir|name>] [--dry-run] [--allow-prerelease] [--json]
|
|
13
|
+
*
|
|
14
|
+
* Exit codes: 0 installed or already current; 1 check/install failed; 2 usage error.
|
|
15
|
+
*/
|
|
16
|
+
import { existsSync, readFileSync } from 'node:fs';
|
|
17
|
+
import { join } from 'node:path';
|
|
18
|
+
|
|
19
|
+
import { createAutoUpdater, findProfileDir } from '../src/plugin/auto-update.mjs';
|
|
20
|
+
|
|
21
|
+
const DEFAULT_REPO = 'TwinsEarth/dsh-windows2macos';
|
|
22
|
+
const PACKAGE_NAME = '@twinsearth/w2m-dsh-plugin';
|
|
23
|
+
|
|
24
|
+
function parseArgs(argv) {
|
|
25
|
+
const args = { profile: null, dryRun: false, allowPrerelease: false };
|
|
26
|
+
for (let i = 0; i < argv.length; i += 1) {
|
|
27
|
+
const arg = argv[i];
|
|
28
|
+
if (arg === '--profile') { args.profile = argv[i + 1] ?? null; i += 1; continue; }
|
|
29
|
+
if (arg === '--dry-run') { args.dryRun = true; continue; }
|
|
30
|
+
if (arg === '--allow-prerelease') { args.allowPrerelease = true; continue; }
|
|
31
|
+
if (arg === '--help' || arg === '-h') { args.help = true; continue; }
|
|
32
|
+
if (arg === '--json') { args.json = true; continue; }
|
|
33
|
+
args.unknown = arg;
|
|
34
|
+
}
|
|
35
|
+
return args;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function readInstalledVersion(profileDir) {
|
|
39
|
+
try {
|
|
40
|
+
const manifest = JSON.parse(readFileSync(join(profileDir, 'node_modules', ...PACKAGE_NAME.split('/'), 'package.json'), 'utf8'));
|
|
41
|
+
return typeof manifest.version === 'string' ? manifest.version : null;
|
|
42
|
+
} catch {
|
|
43
|
+
return null;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function resolveProfile(input) {
|
|
48
|
+
if (input !== null) {
|
|
49
|
+
if (existsSync(input)) return input;
|
|
50
|
+
// A bare profile name resolves under the DSH home directory.
|
|
51
|
+
const named = join(process.env.DSH_HOME ?? join(process.env.USERPROFILE ?? process.env.HOME ?? '', '.dsh'), 'profiles', input);
|
|
52
|
+
if (existsSync(named)) return named;
|
|
53
|
+
return null;
|
|
54
|
+
}
|
|
55
|
+
if (typeof process.env.W2M_PROFILE_DIR === 'string' && existsSync(process.env.W2M_PROFILE_DIR)) return process.env.W2M_PROFILE_DIR;
|
|
56
|
+
return findProfileDir() ?? null;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const args = parseArgs(process.argv.slice(2));
|
|
60
|
+
if (args.help === true) {
|
|
61
|
+
process.stdout.write(
|
|
62
|
+
'Usage: w2m-self-update [--profile <dir|name>] [--dry-run] [--allow-prerelease]\n' +
|
|
63
|
+
'Checks GitHub releases, verifies sha256, installs the newer plugin build for the next start.\n',
|
|
64
|
+
);
|
|
65
|
+
process.exit(0);
|
|
66
|
+
}
|
|
67
|
+
if (args.unknown !== undefined) {
|
|
68
|
+
process.stderr.write(`unknown argument: ${args.unknown}\n`);
|
|
69
|
+
process.exit(2);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
const profileDir = resolveProfile(args.profile);
|
|
73
|
+
if (profileDir === null) {
|
|
74
|
+
process.stdout.write(JSON.stringify({ ok: false, outcome: 'error', error: 'no DSH profile directory found; pass --profile <dir>' }) + '\n');
|
|
75
|
+
process.exit(2);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
const currentVersion = readInstalledVersion(profileDir);
|
|
79
|
+
const updater = createAutoUpdater({
|
|
80
|
+
profileDir,
|
|
81
|
+
currentVersion,
|
|
82
|
+
repo: process.env.W2M_UPDATE_REPO ?? DEFAULT_REPO,
|
|
83
|
+
dryRun: args.dryRun,
|
|
84
|
+
allowPrerelease: args.allowPrerelease,
|
|
85
|
+
enabled: false,
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
let result;
|
|
89
|
+
try {
|
|
90
|
+
result = await updater.check('manual');
|
|
91
|
+
} catch (error) {
|
|
92
|
+
process.stdout.write(JSON.stringify({ ok: false, outcome: 'error', error: error instanceof Error ? error.message : String(error) }) + '\n');
|
|
93
|
+
process.exit(1);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
const outcome = result?.outcome ?? 'unknown';
|
|
97
|
+
const ok = result?.ok === true && (outcome === 'installed' || outcome === 'up-to-date' || outcome === 'current' || outcome === 'skipped');
|
|
98
|
+
process.stdout.write(JSON.stringify({
|
|
99
|
+
ok,
|
|
100
|
+
outcome,
|
|
101
|
+
current: currentVersion,
|
|
102
|
+
latest: result?.tag ?? result?.to ?? null,
|
|
103
|
+
reason: result?.reason ?? null,
|
|
104
|
+
error: result?.error ?? null,
|
|
105
|
+
restart_required: outcome === 'installed',
|
|
106
|
+
}) + '\n');
|
|
107
|
+
process.exit(ok ? 0 : 1);
|
package/codex/mcp-servers.toml
CHANGED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": "1.9.10",
|
|
3
|
+
"case": "RELEASE-1910",
|
|
4
|
+
"kind": "positive",
|
|
5
|
+
"machines": [
|
|
6
|
+
"b53a37f4-1464-4512-9259-33a7df091e3e"
|
|
7
|
+
],
|
|
8
|
+
"executed_at": "2026-10-27T23:24:12.342Z",
|
|
9
|
+
"executor": "lead",
|
|
10
|
+
"task_id": "pre-release-1910-1793143452343",
|
|
11
|
+
"requirement": "V1.9.10:可下发的自更新 CLI 与编队升级策略",
|
|
12
|
+
"result": {
|
|
13
|
+
"outcome": "ok",
|
|
14
|
+
"assertions": {
|
|
15
|
+
"cli": "bin/w2m-self-update.mjs --help exit 0",
|
|
16
|
+
"dry_run": "current 1.9.9, latest v1.9.9, skipped, exit 0",
|
|
17
|
+
"policy": "prefer dispatch; Node remote-execution fallback; operator token required",
|
|
18
|
+
"gates": "full suite + preflight expected GREEN before tag"
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": "1.9.11",
|
|
3
|
+
"case": "RELEASE-1911",
|
|
4
|
+
"kind": "positive",
|
|
5
|
+
"machines": [
|
|
6
|
+
"b53a37f4-1464-4512-9259-33a7df091e3e"
|
|
7
|
+
],
|
|
8
|
+
"executed_at": "2026-10-27T23:46:34.310Z",
|
|
9
|
+
"executor": "lead",
|
|
10
|
+
"task_id": "pre-release-1911-1793144794311",
|
|
11
|
+
"requirement": "V1.9.11:修复侧栏 GPW 名称缺失与对话搜索黄色高亮",
|
|
12
|
+
"result": {
|
|
13
|
+
"outcome": "ok",
|
|
14
|
+
"assertions": {
|
|
15
|
+
"sidebar": "icon + GPW text in the entry, empty panellist label (single row)",
|
|
16
|
+
"search": "CSS Custom Highlight API with yellow ::highlight and count; Enter/Shift+Enter navigation",
|
|
17
|
+
"tests": "client-bundle 26/26 green"
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
}
|
package/lib/client.js
CHANGED
|
@@ -931,22 +931,89 @@ const PLUGIN_UPDATE_ROUTE = '/api/w2m/plugin-update';
|
|
|
931
931
|
}
|
|
932
932
|
|
|
933
933
|
/**
|
|
934
|
-
* v1.9.
|
|
935
|
-
*
|
|
936
|
-
*
|
|
934
|
+
* v1.9.11: in-conversation full-text search with visible yellow highlights.
|
|
935
|
+
*
|
|
936
|
+
* The previous version only called window.find, which the desktop shell does not reliably
|
|
937
|
+
* surface. This walks the rendered conversation text and registers the matches through the CSS
|
|
938
|
+
* Custom Highlight API (no DOM mutation, so React's tree stays intact), then scrolls to the
|
|
939
|
+
* focused match. Matches stay yellow until the query changes or the box closes.
|
|
937
940
|
*/
|
|
941
|
+
const SEARCH_HIGHLIGHT = 'w2m-conversation-search';
|
|
942
|
+
function clearSearchHighlight() {
|
|
943
|
+
try { if (typeof CSS !== 'undefined' && CSS.highlights) CSS.highlights.delete(SEARCH_HIGHLIGHT); } catch { /* unsupported */ }
|
|
944
|
+
}
|
|
938
945
|
function ConversationSearch() {
|
|
939
946
|
const [open, setOpen] = React.useState(false);
|
|
940
947
|
const [query, setQuery] = React.useState('');
|
|
948
|
+
const [count, setCount] = React.useState(0);
|
|
949
|
+
const [cursor, setCursor] = React.useState(-1);
|
|
950
|
+
const rangesRef = React.useRef([]);
|
|
941
951
|
const inputRef = React.useRef(null);
|
|
942
952
|
React.useEffect(() => { if (open && inputRef.current && inputRef.current.focus) inputRef.current.focus(); }, [open]);
|
|
943
|
-
const
|
|
944
|
-
if (query === '') return;
|
|
953
|
+
const collect = React.useCallback(() => {
|
|
954
|
+
if (query === '' || typeof document === 'undefined') return [];
|
|
955
|
+
const needle = query.toLowerCase();
|
|
956
|
+
const ranges = [];
|
|
957
|
+
try {
|
|
958
|
+
const walker = document.createTreeWalker(document.body, NodeFilter.SHOW_TEXT, {
|
|
959
|
+
acceptNode(node) {
|
|
960
|
+
const parent = node.parentElement;
|
|
961
|
+
if (parent === null) return NodeFilter.FILTER_REJECT;
|
|
962
|
+
const tag = parent.tagName;
|
|
963
|
+
if (tag === 'SCRIPT' || tag === 'STYLE' || tag === 'TEXTAREA' || tag === 'INPUT') return NodeFilter.FILTER_REJECT;
|
|
964
|
+
if (parent.closest && parent.closest('[data-w2m-search]') !== null) return NodeFilter.FILTER_REJECT;
|
|
965
|
+
return node.nodeValue && node.nodeValue.trim() !== '' ? NodeFilter.FILTER_ACCEPT : NodeFilter.FILTER_REJECT;
|
|
966
|
+
},
|
|
967
|
+
});
|
|
968
|
+
let node = walker.nextNode();
|
|
969
|
+
while (node !== null && ranges.length < 500) {
|
|
970
|
+
const text = node.nodeValue.toLowerCase();
|
|
971
|
+
let index = text.indexOf(needle);
|
|
972
|
+
while (index >= 0) {
|
|
973
|
+
const range = document.createRange();
|
|
974
|
+
range.setStart(node, index);
|
|
975
|
+
range.setEnd(node, index + query.length);
|
|
976
|
+
ranges.push(range);
|
|
977
|
+
index = text.indexOf(needle, index + query.length);
|
|
978
|
+
if (ranges.length >= 500) break;
|
|
979
|
+
}
|
|
980
|
+
node = walker.nextNode();
|
|
981
|
+
}
|
|
982
|
+
} catch { /* finding is best effort */ }
|
|
983
|
+
return ranges;
|
|
984
|
+
}, [query]);
|
|
985
|
+
const paint = React.useCallback(() => {
|
|
986
|
+
const ranges = collect();
|
|
987
|
+
rangesRef.current = ranges;
|
|
988
|
+
setCount(ranges.length);
|
|
945
989
|
try {
|
|
946
|
-
if (typeof
|
|
947
|
-
|
|
990
|
+
if (typeof CSS !== 'undefined' && CSS.highlights && typeof Highlight === 'function') {
|
|
991
|
+
CSS.highlights.set(SEARCH_HIGHLIGHT, new Highlight(...ranges));
|
|
948
992
|
}
|
|
949
|
-
} catch { /*
|
|
993
|
+
} catch { /* older engine: the count still helps */ }
|
|
994
|
+
if (ranges.length > 0) {
|
|
995
|
+
setCursor(0);
|
|
996
|
+
try {
|
|
997
|
+
const parent = ranges[0].startContainer.parentElement;
|
|
998
|
+
if (parent && parent.scrollIntoView) parent.scrollIntoView({ block: 'center', behavior: 'smooth' });
|
|
999
|
+
} catch { /* scroll is best effort */ }
|
|
1000
|
+
} else setCursor(-1);
|
|
1001
|
+
return ranges.length;
|
|
1002
|
+
}, [collect]);
|
|
1003
|
+
React.useEffect(() => {
|
|
1004
|
+
if (!open) { clearSearchHighlight(); setCount(0); setCursor(-1); return undefined; }
|
|
1005
|
+
paint();
|
|
1006
|
+
return () => clearSearchHighlight();
|
|
1007
|
+
}, [open, query, paint]);
|
|
1008
|
+
const step = (backwards) => {
|
|
1009
|
+
const ranges = rangesRef.current;
|
|
1010
|
+
if (ranges.length === 0) { paint(); return; }
|
|
1011
|
+
const next = (cursor + (backwards ? -1 : 1) + ranges.length) % ranges.length;
|
|
1012
|
+
setCursor(next);
|
|
1013
|
+
try {
|
|
1014
|
+
const parent = ranges[next].startContainer.parentElement;
|
|
1015
|
+
if (parent && parent.scrollIntoView) parent.scrollIntoView({ block: 'center', behavior: 'smooth' });
|
|
1016
|
+
} catch { /* scroll is best effort */ }
|
|
950
1017
|
};
|
|
951
1018
|
if (!open) {
|
|
952
1019
|
return h('button', {
|
|
@@ -957,7 +1024,7 @@ const PLUGIN_UPDATE_ROUTE = '/api/w2m/plugin-update';
|
|
|
957
1024
|
onClick: () => setOpen(true),
|
|
958
1025
|
}, '🔍');
|
|
959
1026
|
}
|
|
960
|
-
return h('div', { className: 'w2mSearchBox' }, [
|
|
1027
|
+
return h('div', { className: 'w2mSearchBox', 'data-w2m-search': 'box' }, [
|
|
961
1028
|
h('input', {
|
|
962
1029
|
key: 'q',
|
|
963
1030
|
ref: inputRef,
|
|
@@ -966,15 +1033,19 @@ const PLUGIN_UPDATE_ROUTE = '/api/w2m/plugin-update';
|
|
|
966
1033
|
placeholder: '搜索本对话全部内容',
|
|
967
1034
|
onChange: (event) => setQuery(event.target.value),
|
|
968
1035
|
onKeyDown: (event) => {
|
|
969
|
-
if (event.key === 'Enter') { event.preventDefault();
|
|
1036
|
+
if (event.key === 'Enter') { event.preventDefault(); step(event.shiftKey); }
|
|
970
1037
|
if (event.key === 'Escape') { setOpen(false); setQuery(''); }
|
|
971
1038
|
},
|
|
972
1039
|
}),
|
|
973
|
-
h('
|
|
974
|
-
h('button', { key: '
|
|
975
|
-
h('button', { key: '
|
|
1040
|
+
h('span', { key: 'count', className: 'w2mSearchCount' }, count === 0 ? (query === '' ? '' : '0') : whenCount(count, cursor)),
|
|
1041
|
+
h('button', { key: 'prev', type: 'button', className: 'w2mSearchBtn', title: '上一个', onClick: () => step(true) }, '↑'),
|
|
1042
|
+
h('button', { key: 'next', type: 'button', className: 'w2mSearchBtn', title: '下一个', onClick: () => step(false) }, '↓'),
|
|
1043
|
+
h('button', { key: 'close', type: 'button', className: 'w2mSearchBtn', title: '关闭搜索', onClick: () => { setOpen(false); setQuery(''); clearSearchHighlight(); } }, '×'),
|
|
976
1044
|
]);
|
|
977
1045
|
}
|
|
1046
|
+
function whenCount(total, at) {
|
|
1047
|
+
return (at >= 0 ? at + 1 : 0) + '/' + total;
|
|
1048
|
+
}
|
|
978
1049
|
|
|
979
1050
|
/** v1.9.4: the GPW tab in Settings, between Models and Plugins. */
|
|
980
1051
|
function GpwSettingsPage({ t }) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@twinsearth/w2m-dsh-plugin",
|
|
3
|
-
"version": "1.9.
|
|
3
|
+
"version": "1.9.11",
|
|
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": {
|
|
@@ -64,7 +64,7 @@
|
|
|
64
64
|
"pack": "node scripts/pack.mjs",
|
|
65
65
|
"reachability": "node scripts/reachability-check.mjs",
|
|
66
66
|
"reachability:classify": "node scripts/reachability-classify.mjs",
|
|
67
|
-
"test": "node --test --test-force-exit test/relay.test.mjs test/broadcast.test.mjs test/blake2s.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/fleet-concurrency.test.mjs test/fleet-merge-race.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/portable-plugins.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 test/admission.test.mjs test/admission-routes.test.mjs test/join-degradation.test.mjs test/account-identity.test.mjs test/join-challenge.test.mjs test/exec-env-injection.test.mjs test/account-join.test.mjs test/fleet-messages.test.mjs test/message-shards.test.mjs test/fleet-messages-http.test.mjs test/message-notify.test.mjs test/update-channels.test.mjs test/update-prerelease.test.mjs test/session-watch.test.mjs test/session-readonly.test.mjs test/session-sync.test.mjs test/fleet-chat-identity.test.mjs test/identity-reader.test.mjs test/intents.test.mjs test/dataflow.test.mjs test/council-fleet.test.mjs test/fleet-memory.test.mjs test/memory-view.test.mjs test/schema-spec.test.mjs test/fleet-weight-parity.test.mjs test/task-deps.test.mjs test/dataflow-wiring.test.mjs test/task-graph.test.mjs test/ask-store.test.mjs test/turn.test.mjs test/fleet-members.test.mjs test/redact.test.mjs test/policy-matrix.test.mjs test/envelope-signature.test.mjs test/chat-crypto.test.mjs test/reduce-suggestion.test.mjs test/merge-hint.test.mjs test/fleet-chat-route.test.mjs test/maintenance.test.mjs test/maintenance-ferry.test.mjs test/grant.test.mjs test/grant-gate.test.mjs test/worktree.test.mjs test/patch-artifact.test.mjs test/merge-queue.test.mjs test/m3-workflow.test.mjs test/project-room.test.mjs test/project-attribution.test.mjs test/project-locks.test.mjs test/project-reviews.test.mjs test/project-notifications.test.mjs test/blob-sessions.test.mjs test/outbox.test.mjs test/reliability-metrics.test.mjs test/evidence.test.mjs test/grant-issue.test.mjs test/project-refs.test.mjs test/exec-capability.test.mjs test/secondary-link.test.mjs test/bootstrap-cli.test.mjs test/bootstrap.test.mjs test/windows-hidden-task.test.mjs test/relay-failover.test.mjs test/npm-update.test.mjs test/agent-start-nonblocking.test.mjs test/fleet-chat-capture.test.mjs test/capture-route.test.mjs test/update-resolver.test.mjs test/agent-identity-safe.test.mjs test/re-pair-stale-token.test.mjs test/gpw-folder-policy.test.mjs test/gpw-activation.test.mjs test/gpw-hardening.test.mjs test/gpw-tamper-gate.test.mjs test/gpw-persistence.test.mjs test/gpw-colors.test.mjs test/gpw-recent-fold.test.mjs test/gpw-auto-approve.test.mjs test/data-plane.test.mjs test/sealed-object.test.mjs test/joint-dev-dispatch.test.mjs test/joint-dev-loop.test.mjs test/joint-dev-audit.test.mjs test/joint-dev-redline.test.mjs test/relay-redline-guard.test.mjs test/relay-p0-projection.test.mjs test/guarded-dispatch.test.mjs test/p0-single-matcher.test.mjs test/path-policy.test.mjs test/path-policy-fs.test.mjs test/gpw-inheritance-table.test.mjs test/gpw-policy-adapter.test.mjs test/target-policy.test.mjs",
|
|
67
|
+
"test": "node --test --test-force-exit test/relay.test.mjs test/broadcast.test.mjs test/blake2s.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/fleet-concurrency.test.mjs test/fleet-merge-race.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/portable-plugins.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 test/admission.test.mjs test/admission-routes.test.mjs test/join-degradation.test.mjs test/account-identity.test.mjs test/join-challenge.test.mjs test/exec-env-injection.test.mjs test/account-join.test.mjs test/fleet-messages.test.mjs test/message-shards.test.mjs test/fleet-messages-http.test.mjs test/message-notify.test.mjs test/update-channels.test.mjs test/update-prerelease.test.mjs test/session-watch.test.mjs test/session-readonly.test.mjs test/session-sync.test.mjs test/fleet-chat-identity.test.mjs test/identity-reader.test.mjs test/intents.test.mjs test/dataflow.test.mjs test/council-fleet.test.mjs test/fleet-memory.test.mjs test/memory-view.test.mjs test/schema-spec.test.mjs test/fleet-weight-parity.test.mjs test/task-deps.test.mjs test/dataflow-wiring.test.mjs test/task-graph.test.mjs test/ask-store.test.mjs test/turn.test.mjs test/fleet-members.test.mjs test/redact.test.mjs test/policy-matrix.test.mjs test/envelope-signature.test.mjs test/chat-crypto.test.mjs test/reduce-suggestion.test.mjs test/merge-hint.test.mjs test/fleet-chat-route.test.mjs test/maintenance.test.mjs test/maintenance-ferry.test.mjs test/grant.test.mjs test/grant-gate.test.mjs test/worktree.test.mjs test/patch-artifact.test.mjs test/merge-queue.test.mjs test/m3-workflow.test.mjs test/project-room.test.mjs test/project-attribution.test.mjs test/project-locks.test.mjs test/project-reviews.test.mjs test/project-notifications.test.mjs test/blob-sessions.test.mjs test/outbox.test.mjs test/reliability-metrics.test.mjs test/evidence.test.mjs test/grant-issue.test.mjs test/project-refs.test.mjs test/exec-capability.test.mjs test/secondary-link.test.mjs test/bootstrap-cli.test.mjs test/bootstrap.test.mjs test/windows-hidden-task.test.mjs test/relay-failover.test.mjs test/npm-update.test.mjs test/agent-start-nonblocking.test.mjs test/fleet-chat-capture.test.mjs test/capture-route.test.mjs test/update-resolver.test.mjs test/agent-identity-safe.test.mjs test/re-pair-stale-token.test.mjs test/gpw-folder-policy.test.mjs test/gpw-activation.test.mjs test/gpw-hardening.test.mjs test/gpw-tamper-gate.test.mjs test/gpw-persistence.test.mjs test/gpw-colors.test.mjs test/gpw-recent-fold.test.mjs test/gpw-auto-approve.test.mjs test/data-plane.test.mjs test/sealed-object.test.mjs test/joint-dev-dispatch.test.mjs test/joint-dev-loop.test.mjs test/joint-dev-audit.test.mjs test/joint-dev-redline.test.mjs test/relay-redline-guard.test.mjs test/relay-p0-projection.test.mjs test/guarded-dispatch.test.mjs test/p0-single-matcher.test.mjs test/path-policy.test.mjs test/path-policy-fs.test.mjs test/gpw-inheritance-table.test.mjs test/gpw-policy-adapter.test.mjs test/target-policy.test.mjs test/relay-redline-audit.test.mjs",
|
|
68
68
|
"test:acceptance-doc": "node --test --test-force-exit test/acceptance-doc.test.mjs",
|
|
69
69
|
"test:account-identity": "node --test --test-force-exit test/account-identity.test.mjs",
|
|
70
70
|
"test:account-join": "node --test --test-force-exit test/account-join.test.mjs",
|
|
@@ -205,7 +205,8 @@
|
|
|
205
205
|
"w2m-secondary-link": "bin/w2m-secondary-link.mjs",
|
|
206
206
|
"w2m-bootstrap": "bin/w2m-bootstrap.mjs",
|
|
207
207
|
"w2m-bootstrap-sign": "bin/w2m-bootstrap-sign.mjs",
|
|
208
|
-
"w2m-hidden-task": "bin/w2m-hidden-task.mjs"
|
|
208
|
+
"w2m-hidden-task": "bin/w2m-hidden-task.mjs",
|
|
209
|
+
"w2m-self-update": "bin/w2m-self-update.mjs"
|
|
209
210
|
},
|
|
210
211
|
"disclosure": {
|
|
211
212
|
"cloud": true,
|
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.9.
|
|
4
|
+
"version": "1.9.11",
|
|
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
|
@@ -283,7 +283,7 @@ const MAX_STAGES = 16;
|
|
|
283
283
|
* `package.json` during `scripts/pack.mjs` rather than hand-maintained, and `W2M_PLUGIN_VERSION`
|
|
284
284
|
* overrides it at runtime for tests and packagers.
|
|
285
285
|
*/
|
|
286
|
-
const PLUGIN_VERSION = '1.9.
|
|
286
|
+
const PLUGIN_VERSION = '1.9.11';
|
|
287
287
|
|
|
288
288
|
/** How long any single HTTP call may take before it is aborted, in milliseconds. */
|
|
289
289
|
const DEFAULT_REQUEST_TIMEOUT_MS = 15_000;
|