@twinsearth/w2m-dsh-plugin 1.2.1 → 1.2.3
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 +2 -2
- package/.claude-plugin/plugin.json +1 -1
- package/CHANGELOG.md +9217 -9123
- package/README.md +3 -2
- package/codex/mcp-servers.toml +1 -1
- package/lib/client.js +91 -6
- package/package.json +100 -93
- package/plugin.json +1 -1
- package/src/plugin/council-fleet.mjs +221 -0
- package/src/plugin/dataflow.mjs +72 -0
- package/src/plugin/fleet-chat-route.mjs +86 -1
- package/src/plugin/intents.mjs +137 -0
- package/src/plugin/memory-view.mjs +60 -0
- package/src/plugin/schema-spec.mjs +49 -0
- package/src/plugin/tools.mjs +183 -3
- package/src/relay/fleet-memory.mjs +85 -0
- package/src/relay/server.mjs +34 -1
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 **13 tools registered** in your agent. Pick one.
|
|
18
18
|
|
|
19
19
|
### 1. DSH plugin (recommended — zero configuration)
|
|
20
20
|
|
|
@@ -137,6 +137,7 @@ hand-maintained host list.
|
|
|
137
137
|
|
|
138
138
|
`w2m_status` · `w2m_devices` · `w2m_run` · `w2m_wait` · `w2m_history` · `w2m_stats` · `w2m_report` ·
|
|
139
139
|
`w2m_memory` · `w2m_approvals` · `w2m_council` · `w2m_chat` · `w2m_update`
|
|
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.
|
|
140
141
|
|
|
141
142
|
### Environment a dispatched command receives (1.1.15+)
|
|
142
143
|
|
|
@@ -260,7 +261,7 @@ MIT.
|
|
|
260
261
|
|
|
261
262
|
### 安装
|
|
262
263
|
|
|
263
|
-
五种方式,最终都会在你的 agent 里注册 **
|
|
264
|
+
五种方式,最终都会在你的 agent 里注册 **13 tools registered**。任选其一。
|
|
264
265
|
|
|
265
266
|
#### 1. DSH 插件(推荐,零配置)
|
|
266
267
|
|
package/codex/mcp-servers.toml
CHANGED
package/lib/client.js
CHANGED
|
@@ -295,6 +295,17 @@ window.__ModuleLoader__.load({
|
|
|
295
295
|
'.w2mChat_empty{color:var(--dsw-alias-label-tertiary)}',
|
|
296
296
|
'.w2mChat_msg{display:flex;flex-direction:column;gap:2px}',
|
|
297
297
|
'.w2mChat_meta{color:var(--dsw-alias-label-tertiary);font-size:11px}',
|
|
298
|
+
'.w2mChat_to{font:inherit;font-size:11px;max-width:120px;border-radius:6px;border:.5px solid var(--dsw-alias-border-default);background:var(--dsw-alias-surface-default);color:var(--dsw-alias-label-primary)}',
|
|
299
|
+
'.w2mChat_reply{display:flex;align-items:center;gap:6px;padding:4px 10px;font-size:11px;color:var(--dsw-alias-label-secondary);border-top:.5px solid var(--dsw-alias-border-default)}',
|
|
300
|
+
'.w2mChat_replyCancel{margin-left:auto;border:none;background:none;color:var(--dsw-alias-label-secondary);cursor:pointer}',
|
|
301
|
+
'.w2mChat_msg{cursor:pointer}',
|
|
302
|
+
'.w2mChat_thread{margin-left:6px;opacity:.7}',
|
|
303
|
+
'.w2mChat_threadHead{font-size:11px;color:var(--dsw-alias-label-tertiary);padding:4px 10px 0}',
|
|
304
|
+
'.w2mChat_board{display:flex;flex-direction:column;gap:2px;padding:6px 10px;border-bottom:.5px solid var(--dsw-alias-border-default)}',
|
|
305
|
+
'.w2mChat_boardTitle{font-size:11px;color:var(--dsw-alias-label-tertiary)}',
|
|
306
|
+
'.w2mChat_boardRow{font-size:11px;color:var(--dsw-alias-label-secondary);font-family:ui-monospace,monospace}',
|
|
307
|
+
'.w2mChat_threadHead{font-size:11px;color:var(--dsw-alias-label-tertiary);padding:4px 10px 0}',
|
|
308
|
+
'.w2mChat_unseen{margin-left:6px;min-width:16px;padding:0 5px;border-radius:8px;background:var(--dsw-alias-accent-default);color:var(--dsw-alias-label-on-accent);font-size:10px;line-height:16px;text-align:center}',
|
|
298
309
|
'.w2mChat_text{white-space:pre-wrap;word-break:break-word}',
|
|
299
310
|
'.w2mChat_msg.is-session .w2mChat_text{color:var(--dsw-danger)}', '.w2mChat_msg.is-chat .w2mChat_text{color:var(--dsw-success)}', '.w2mChat_msg.is-remote .w2mChat_text{color:var(--dsw-text)}', '.w2mChat_avatar{display:inline-flex;width:16px;height:16px;margin-right:5px;vertical-align:-3px}',
|
|
300
311
|
'.w2mChat_compose{display:flex;gap:8px;padding:8px 10px;border-top:.5px solid var(--dsw-alias-border-l2);align-items:flex-end}',
|
|
@@ -614,6 +625,18 @@ window.__ModuleLoader__.load({
|
|
|
614
625
|
const [usage, setUsage] = React.useState(null);
|
|
615
626
|
const [localMachineName, setLocalMachineName] = React.useState(null);
|
|
616
627
|
const [roster, setRoster] = React.useState(null);
|
|
628
|
+
const [toRecipient, setToRecipient] = React.useState('all');
|
|
629
|
+
const [replyTo, setReplyTo] = React.useState(null);
|
|
630
|
+
const [tasks, setTasks] = React.useState([]);
|
|
631
|
+
const [lastSeenMs, setLastSeenMs] = React.useState(() => {
|
|
632
|
+
try {
|
|
633
|
+
const raw = globalThis.localStorage?.getItem('w2m:chat:seen:' + sessionId);
|
|
634
|
+
const parsed = Number.parseInt(raw ?? '', 10);
|
|
635
|
+
return Number.isFinite(parsed) ? parsed : 0;
|
|
636
|
+
} catch {
|
|
637
|
+
return 0;
|
|
638
|
+
}
|
|
639
|
+
});
|
|
617
640
|
const [text, setText] = React.useState('');
|
|
618
641
|
const [error, setError] = React.useState(null);
|
|
619
642
|
const [busy, setBusy] = React.useState(false);
|
|
@@ -659,6 +682,40 @@ window.__ModuleLoader__.load({
|
|
|
659
682
|
});
|
|
660
683
|
return () => controller.abort();
|
|
661
684
|
}, [open, sessionId]);
|
|
685
|
+
|
|
686
|
+
// The task board is the relay's own list: the host proxies it so the panel never holds a device token.
|
|
687
|
+
React.useEffect(() => {
|
|
688
|
+
if (!open) return undefined;
|
|
689
|
+
const controller = new AbortController();
|
|
690
|
+
chatCall({ url: '/api/w2m/tasks?limit=20', init: { signal: controller.signal } })
|
|
691
|
+
.then((result) => { if (!controller.signal.aborted) setTasks(result.ok && Array.isArray(result.data?.tasks) ? result.data.tasks : []); })
|
|
692
|
+
.catch(() => { /* the board is an extra; a failed read must not break the chat */ });
|
|
693
|
+
return () => controller.abort();
|
|
694
|
+
}, [open]);
|
|
695
|
+
|
|
696
|
+
// Unread is measured against a per-conversation watermark in local storage: the relay stays stateless, and
|
|
697
|
+
// the count answers "is there anything I have not looked at" without claiming which messages a machine read.
|
|
698
|
+
React.useEffect(() => {
|
|
699
|
+
if (!open || messages.length === 0) return undefined;
|
|
700
|
+
const latest = messages.reduce((max, message) => (Number.isFinite(message?.at_ms) ? Math.max(max, message.at_ms) : max), 0);
|
|
701
|
+
if (latest <= 0 || latest <= lastSeenMs) return undefined;
|
|
702
|
+
setLastSeenMs(latest);
|
|
703
|
+
try { globalThis.localStorage?.setItem('w2m:chat:seen:' + sessionId, String(latest)); } catch { /* storage may be unavailable */ }
|
|
704
|
+
return undefined;
|
|
705
|
+
}, [open, messages, sessionId, lastSeenMs]);
|
|
706
|
+
|
|
707
|
+
// Consecutive messages that share a thread are shown under one thread head. Grouping only consecutive runs keeps
|
|
708
|
+
// the reading order the relay assigned -- re-sorting by thread would put an answer above the question it answers.
|
|
709
|
+
const groupThreads = (list) => {
|
|
710
|
+
const groups = [];
|
|
711
|
+
for (const message of list ?? []) {
|
|
712
|
+
const threadId = typeof message?.thread_id === 'string' && message.thread_id !== '' ? message.thread_id : null;
|
|
713
|
+
const last = groups[groups.length - 1] ?? null;
|
|
714
|
+
if (last !== null && last.threadId === threadId) { last.messages.push(message); continue; }
|
|
715
|
+
groups.push({ threadId, messages: [message] });
|
|
716
|
+
}
|
|
717
|
+
return groups;
|
|
718
|
+
};
|
|
662
719
|
|
|
663
720
|
const send = React.useCallback(async () => {
|
|
664
721
|
const value = text.trim();
|
|
@@ -670,12 +727,18 @@ window.__ModuleLoader__.load({
|
|
|
670
727
|
method: 'POST',
|
|
671
728
|
credentials: 'same-origin',
|
|
672
729
|
headers: { 'content-type': 'application/json', accept: 'application/json' },
|
|
673
|
-
body: JSON.stringify({
|
|
730
|
+
body: JSON.stringify({
|
|
731
|
+
session_id: sessionId,
|
|
732
|
+
text: value,
|
|
733
|
+
...(toRecipient === 'all' ? {} : { to: toRecipient }),
|
|
734
|
+
...(replyTo === null ? {} : { reply_to: replyTo.id, ...(replyTo.threadId === null ? {} : { thread_id: replyTo.threadId }) }),
|
|
735
|
+
}),
|
|
674
736
|
},
|
|
675
737
|
});
|
|
676
738
|
setBusy(false);
|
|
677
739
|
if (result.ok) {
|
|
678
740
|
setText('');
|
|
741
|
+
setReplyTo(null);
|
|
679
742
|
await load();
|
|
680
743
|
} else {
|
|
681
744
|
setError(result.error);
|
|
@@ -683,6 +746,7 @@ window.__ModuleLoader__.load({
|
|
|
683
746
|
return undefined;
|
|
684
747
|
}, [busy, load, sessionId, text]);
|
|
685
748
|
|
|
749
|
+
const unseenCount = messages.reduce((count, message) => (Number.isFinite(message?.at_ms) && message.at_ms > lastSeenMs ? count + 1 : count), 0);
|
|
686
750
|
const disabled = typeof sessionId !== 'string' || sessionId === '';
|
|
687
751
|
const usageText = usage === null ? null : `${Math.round((usage.used_24h_bytes ?? 0) / 1024)} KiB/24h · ${usage.messages ?? 0} 条`;
|
|
688
752
|
const machineLabel = (message) => {
|
|
@@ -709,26 +773,47 @@ window.__ModuleLoader__.load({
|
|
|
709
773
|
'aria-expanded': open,
|
|
710
774
|
disabled,
|
|
711
775
|
onClick: () => setOpen((value) => !value),
|
|
712
|
-
}, '💬', h('span', { className: 'w2mChat_label' }, '编队聊天')),
|
|
776
|
+
}, '💬', h('span', { className: 'w2mChat_label' }, '编队聊天'), unseenCount > 0 && !open ? h('span', { className: 'w2mChat_unseen' }, String(unseenCount)) : null),
|
|
713
777
|
open
|
|
714
778
|
? h('div', { className: 'w2mChat_panel', role: 'dialog', 'aria-label': '编队聊天' },
|
|
715
779
|
h('div', { className: 'w2mChat_head' },
|
|
780
|
+
h('select', {
|
|
781
|
+
className: 'w2mChat_to',
|
|
782
|
+
value: toRecipient,
|
|
783
|
+
title: '收件人',
|
|
784
|
+
onChange: (event) => setToRecipient(event.target.value),
|
|
785
|
+
}, [
|
|
786
|
+
h('option', { key: '__all__', value: 'all' }, '全部'),
|
|
787
|
+
...(Array.isArray(roster?.machines) ? roster.machines.filter((machine) => machine.online === true && typeof machine.machine_id === 'string').map((machine) => h('option', { key: machine.machine_id, value: machine.machine_id }, machine.name ?? machine.machine_id)) : []),
|
|
788
|
+
]),
|
|
716
789
|
h('span', null, '编队聊天'),
|
|
717
790
|
usageText === null ? null : h('span', { className: 'w2mChat_usage' }, usageText),
|
|
718
791
|
h('button', { type: 'button', className: 'w2mChat_close', title: '关闭', onClick: () => setOpen(false) }, '×')),
|
|
792
|
+
tasks.length === 0 ? null : h('div', { className: 'w2mChat_board' }, [
|
|
793
|
+
h('div', { key: 'title', className: 'w2mChat_boardTitle' }, '任务看板'),
|
|
794
|
+
...tasks.slice(0, 6).map((task) => h('div', { key: String(task?.task_id ?? Math.random()), className: 'w2mChat_boardRow' },
|
|
795
|
+
`${String(task?.task_id ?? '').slice(0, 8)} ${task?.mode ?? '?'} ${task?.status ?? '?'}`)),
|
|
796
|
+
]),
|
|
719
797
|
h('div', { className: 'w2mChat_list' },
|
|
720
798
|
error !== null ? h('div', { className: 'w2mChat_error' }, error) : null,
|
|
721
799
|
messages.length === 0
|
|
722
800
|
? (error === null ? h('div', { className: 'w2mChat_empty' }, '本会话还没有消息') : null)
|
|
723
|
-
: messages.
|
|
801
|
+
: groupThreads(messages).flatMap((group, groupIndex) => [
|
|
802
|
+
group.threadId === null ? null : h('div', { key: 'thread:' + group.threadId + ':' + groupIndex, className: 'w2mChat_threadHead' }, '#' + group.threadId),
|
|
803
|
+
...group.messages.map((message) => {
|
|
724
804
|
var kind = messageKind(message, localMachineId);
|
|
725
|
-
return h('div', { key: message?.message_id ?? `${message?.machine_id}:${message?.at_ms}`, className: 'w2mChat_msg is-' + kind },
|
|
726
|
-
h('div', { className: 'w2mChat_meta' }, h(WhaleAvatar, { machineId: message?.machine_id }), `${machineLabel(message)} · ${timeLabel(message)}`, kind === 'session' ? ' · 来自会话' : ''),
|
|
805
|
+
return h('div', { key: message?.message_id ?? `${message?.machine_id}:${message?.at_ms}`, className: 'w2mChat_msg is-' + kind, onClick: () => setReplyTo({ id: message?.message_id ?? null, threadId: message?.thread_id ?? null, text: typeof message?.text === 'string' ? message.text : '' }) },
|
|
806
|
+
h('div', { className: 'w2mChat_meta' }, h(WhaleAvatar, { machineId: message?.machine_id }), `${machineLabel(message)} · ${timeLabel(message)}`, kind === 'session' ? ' · 来自会话' : '', message?.thread_id ? h('span', { className: 'w2mChat_thread' }, '#' + message.thread_id) : null),
|
|
727
807
|
h('div', { className: 'w2mChat_text' }, message?.text ?? ''));
|
|
728
|
-
|
|
808
|
+
}),
|
|
809
|
+
].filter((node) => node !== null))),
|
|
729
810
|
|
|
730
811
|
|
|
731
812
|
h('div', { className: 'w2mChat_compose' },
|
|
813
|
+
replyTo === null ? null : h('div', { className: 'w2mChat_reply' }, [
|
|
814
|
+
h('span', { key: 'label' }, '回复:' + (replyTo.text.length > 40 ? replyTo.text.slice(0, 40) + '…' : replyTo.text)),
|
|
815
|
+
h('button', { key: 'cancel', type: 'button', className: 'w2mChat_replyCancel', title: '取消回复', onClick: () => setReplyTo(null) }, '×'),
|
|
816
|
+
]),
|
|
732
817
|
h('textarea', {
|
|
733
818
|
className: 'w2mChat_input',
|
|
734
819
|
value: text,
|
package/package.json
CHANGED
|
@@ -1,15 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@twinsearth/w2m-dsh-plugin",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.3",
|
|
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
|
-
"main": "lib/index.js",
|
|
7
|
-
"bin": {
|
|
8
|
-
"w2m-localside": "bin/w2m-localside.mjs",
|
|
9
|
-
"w2m-mcp": "bin/w2m-mcp.mjs",
|
|
10
|
-
"w2m-rabbit": "bin/w2m-rabbit.mjs",
|
|
11
|
-
"w2m-stun": "bin/w2m-stun.mjs"
|
|
12
|
-
},
|
|
13
6
|
"exports": {
|
|
14
7
|
".": "./lib/index.js",
|
|
15
8
|
"./tools": "./lib/tools.js",
|
|
@@ -20,6 +13,16 @@
|
|
|
20
13
|
"./package.json": "./package.json",
|
|
21
14
|
"./gpw": "./lib/gpw.js"
|
|
22
15
|
},
|
|
16
|
+
"dsh": {
|
|
17
|
+
"plugin": true,
|
|
18
|
+
"kind": "server",
|
|
19
|
+
"bundle": {
|
|
20
|
+
"patch": "cordis.patch.yml"
|
|
21
|
+
},
|
|
22
|
+
"client": {
|
|
23
|
+
"platform": "web"
|
|
24
|
+
}
|
|
25
|
+
},
|
|
23
26
|
"files": [
|
|
24
27
|
"mcp.json",
|
|
25
28
|
"plugin.json",
|
|
@@ -47,80 +50,10 @@
|
|
|
47
50
|
".claude-plugin",
|
|
48
51
|
"codex"
|
|
49
52
|
],
|
|
50
|
-
"dsh": {
|
|
51
|
-
"plugin": true,
|
|
52
|
-
"kind": "server",
|
|
53
|
-
"bundle": {
|
|
54
|
-
"patch": "cordis.patch.yml"
|
|
55
|
-
},
|
|
56
|
-
"client": {
|
|
57
|
-
"platform": "web"
|
|
58
|
-
}
|
|
59
|
-
},
|
|
60
|
-
"disclosure": {
|
|
61
|
-
"cloud": true,
|
|
62
|
-
"network": [
|
|
63
|
-
"http://202.182.123.154:8787",
|
|
64
|
-
"202.182.123.154:3478",
|
|
65
|
-
"stun.cloudflare.com:3478",
|
|
66
|
-
"stun.l.google.com:19302",
|
|
67
|
-
"stun.nextcloud.com:443",
|
|
68
|
-
"ilinkai.weixin.qq.com:443",
|
|
69
|
-
"weixin.qq.com:443",
|
|
70
|
-
"api.weixin.qq.com:443"
|
|
71
|
-
],
|
|
72
|
-
"offlineMode": false,
|
|
73
|
-
"apiKeys": [
|
|
74
|
-
{
|
|
75
|
-
"env": "W2M_OPERATOR_TOKEN",
|
|
76
|
-
"storage": "profile-config"
|
|
77
|
-
},
|
|
78
|
-
{
|
|
79
|
-
"env": null,
|
|
80
|
-
"storage": "file-0600"
|
|
81
|
-
},
|
|
82
|
-
{
|
|
83
|
-
"env": null,
|
|
84
|
-
"storage": "profile-config"
|
|
85
|
-
},
|
|
86
|
-
{
|
|
87
|
-
"env": null,
|
|
88
|
-
"storage": "im-bot-token"
|
|
89
|
-
}
|
|
90
|
-
],
|
|
91
|
-
"permissions": {
|
|
92
|
-
"network": "the configured relay (default: the shared server above), STUN servers, and UDP to the peer machines. The optional chatops channels reach one instant-messaging platform each, and only when that channel is named in `channels` and the host has supplied the transport: the WeChat channel reaches ilinkai.weixin.qq.com and sends the bot token as a bearer credential, and both that host and the base url in a login response are checked against an allow-list before a token is sent anywhere",
|
|
93
|
-
"filesystem": "read/write inside the project directory and DSH_HOME; the agent writes its spool and state under --state; the chatops file fence reads inside `projectRoot` only, after resolving symlinks",
|
|
94
|
-
"env": [
|
|
95
|
-
"W2M_*"
|
|
96
|
-
]
|
|
97
|
-
},
|
|
98
|
-
"jurisdiction": [
|
|
99
|
-
"CN",
|
|
100
|
-
"JP"
|
|
101
|
-
],
|
|
102
|
-
"retention": "server"
|
|
103
|
-
},
|
|
104
53
|
"engines": {
|
|
105
54
|
"node": "\u003e=20.19.0"
|
|
106
55
|
},
|
|
107
|
-
"
|
|
108
|
-
|
|
109
|
-
},
|
|
110
|
-
"devDependencies": {
|
|
111
|
-
"@eslint/js": "^10.0.1",
|
|
112
|
-
"eslint": "^10.12.0",
|
|
113
|
-
"globals": "^17.13.0",
|
|
114
|
-
"prettier": "^3.9.9"
|
|
115
|
-
},
|
|
116
|
-
"peerDependencies": {
|
|
117
|
-
"@deepseek-ai/dsh-tools": "*"
|
|
118
|
-
},
|
|
119
|
-
"peerDependenciesMeta": {
|
|
120
|
-
"@deepseek-ai/dsh-tools": {
|
|
121
|
-
"optional": true
|
|
122
|
-
}
|
|
123
|
-
},
|
|
56
|
+
"license": "MIT",
|
|
124
57
|
"scripts": {
|
|
125
58
|
"format": "prettier --write .",
|
|
126
59
|
"format:check": "prettier --check .",
|
|
@@ -131,14 +64,14 @@
|
|
|
131
64
|
"pack": "node scripts/pack.mjs",
|
|
132
65
|
"reachability": "node scripts/reachability-check.mjs",
|
|
133
66
|
"reachability:classify": "node scripts/reachability-classify.mjs",
|
|
134
|
-
"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",
|
|
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",
|
|
135
68
|
"test:acceptance-doc": "node --test --test-force-exit test/acceptance-doc.test.mjs",
|
|
136
69
|
"test:account-identity": "node --test --test-force-exit test/account-identity.test.mjs",
|
|
137
70
|
"test:account-join": "node --test --test-force-exit test/account-join.test.mjs",
|
|
138
71
|
"test:admission": "node --test --test-force-exit test/admission.test.mjs",
|
|
139
72
|
"test:admission-routes": "node --test --test-force-exit test/admission-routes.test.mjs",
|
|
140
73
|
"test:agent": "node --test --test-force-exit test/agent.test.mjs test/memory.test.mjs",
|
|
141
|
-
"test:all": "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/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/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",
|
|
74
|
+
"test:all": "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/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/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",
|
|
142
75
|
"test:approval-gate": "node --test --test-force-exit test/approval-gate.test.mjs",
|
|
143
76
|
"test:approval-index": "node --test --test-force-exit test/approval-index.test.mjs",
|
|
144
77
|
"test:authority": "node --test --test-force-exit test/authority.test.mjs",
|
|
@@ -188,8 +121,32 @@
|
|
|
188
121
|
"test:update-channels": "node --test --test-force-exit test/update-channels.test.mjs",
|
|
189
122
|
"test:update-prerelease": "node --test --test-force-exit test/update-prerelease.test.mjs",
|
|
190
123
|
"verify": "node scripts/check-entrypoints.mjs \u0026\u0026 node --test --test-force-exit test/relay.test.mjs test/broadcast.test.mjs test/agent.test.mjs test/tools.test.mjs test/e2e.test.mjs test/crossnetwork.test.mjs test/p2p-node.test.mjs test/p2p-agent.test.mjs test/client-bundle.test.mjs test/loader-entry.test.mjs",
|
|
191
|
-
"verify:join": "node scripts/verify-join.mjs"
|
|
124
|
+
"verify:join": "node scripts/verify-join.mjs",
|
|
125
|
+
"test:intents": "node --test --test-force-exit test/intents.test.mjs",
|
|
126
|
+
"test:dataflow": "node --test --test-force-exit test/dataflow.test.mjs",
|
|
127
|
+
"test:council-fleet": "node --test --test-force-exit test/council-fleet.test.mjs",
|
|
128
|
+
"test:fleet-memory": "node --test --test-force-exit test/fleet-memory.test.mjs",
|
|
129
|
+
"test:memory-view": "node --test --test-force-exit test/memory-view.test.mjs",
|
|
130
|
+
"test:schema-spec": "node --test --test-force-exit test/schema-spec.test.mjs",
|
|
131
|
+
"test:fleet-weight-parity": "node --test --test-force-exit test/fleet-weight-parity.test.mjs"
|
|
192
132
|
},
|
|
133
|
+
"devDependencies": {
|
|
134
|
+
"@eslint/js": "^10.0.1",
|
|
135
|
+
"eslint": "^10.12.0",
|
|
136
|
+
"globals": "^17.13.0",
|
|
137
|
+
"prettier": "^3.9.9"
|
|
138
|
+
},
|
|
139
|
+
"publishConfig": {
|
|
140
|
+
"access": "public"
|
|
141
|
+
},
|
|
142
|
+
"repository": {
|
|
143
|
+
"type": "git",
|
|
144
|
+
"url": "git+https://github.com/TwinsEarth/dsh-windows2macos.git"
|
|
145
|
+
},
|
|
146
|
+
"homepage": "https://github.com/TwinsEarth/dsh-windows2macos",
|
|
147
|
+
"bugs": {
|
|
148
|
+
"url": "https://github.com/TwinsEarth/dsh-windows2macos/issues"
|
|
149
|
+
},
|
|
193
150
|
"keywords": [
|
|
194
151
|
"dsh-bundle",
|
|
195
152
|
"dsh-plugin",
|
|
@@ -203,16 +160,66 @@
|
|
|
203
160
|
"replicate",
|
|
204
161
|
"sharding"
|
|
205
162
|
],
|
|
206
|
-
"
|
|
207
|
-
|
|
208
|
-
|
|
163
|
+
"main": "lib/index.js",
|
|
164
|
+
"bin": {
|
|
165
|
+
"w2m-localside": "bin/w2m-localside.mjs",
|
|
166
|
+
"w2m-mcp": "bin/w2m-mcp.mjs",
|
|
167
|
+
"w2m-rabbit": "bin/w2m-rabbit.mjs",
|
|
168
|
+
"w2m-stun": "bin/w2m-stun.mjs"
|
|
169
|
+
},
|
|
170
|
+
"disclosure": {
|
|
171
|
+
"cloud": true,
|
|
172
|
+
"network": [
|
|
173
|
+
"http://202.182.123.154:8787",
|
|
174
|
+
"202.182.123.154:3478",
|
|
175
|
+
"stun.cloudflare.com:3478",
|
|
176
|
+
"stun.l.google.com:19302",
|
|
177
|
+
"stun.nextcloud.com:443",
|
|
178
|
+
"ilinkai.weixin.qq.com:443",
|
|
179
|
+
"weixin.qq.com:443",
|
|
180
|
+
"api.weixin.qq.com:443"
|
|
181
|
+
],
|
|
182
|
+
"offlineMode": false,
|
|
183
|
+
"apiKeys": [
|
|
184
|
+
{
|
|
185
|
+
"env": "W2M_OPERATOR_TOKEN",
|
|
186
|
+
"storage": "profile-config"
|
|
187
|
+
},
|
|
188
|
+
{
|
|
189
|
+
"env": null,
|
|
190
|
+
"storage": "file-0600"
|
|
191
|
+
},
|
|
192
|
+
{
|
|
193
|
+
"env": null,
|
|
194
|
+
"storage": "profile-config"
|
|
195
|
+
},
|
|
196
|
+
{
|
|
197
|
+
"env": null,
|
|
198
|
+
"storage": "im-bot-token"
|
|
199
|
+
}
|
|
200
|
+
],
|
|
201
|
+
"permissions": {
|
|
202
|
+
"network": "the configured relay (default: the shared server above), STUN servers, and UDP to the peer machines. The optional chatops channels reach one instant-messaging platform each, and only when that channel is named in `channels` and the host has supplied the transport: the WeChat channel reaches ilinkai.weixin.qq.com and sends the bot token as a bearer credential, and both that host and the base url in a login response are checked against an allow-list before a token is sent anywhere",
|
|
203
|
+
"filesystem": "read/write inside the project directory and DSH_HOME; the agent writes its spool and state under --state; the chatops file fence reads inside `projectRoot` only, after resolving symlinks",
|
|
204
|
+
"env": [
|
|
205
|
+
"W2M_*"
|
|
206
|
+
]
|
|
207
|
+
},
|
|
208
|
+
"jurisdiction": [
|
|
209
|
+
"CN",
|
|
210
|
+
"JP"
|
|
211
|
+
],
|
|
212
|
+
"retention": "server"
|
|
209
213
|
},
|
|
210
|
-
"
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
214
|
+
"dependencies": {
|
|
215
|
+
|
|
216
|
+
},
|
|
217
|
+
"peerDependencies": {
|
|
218
|
+
"@deepseek-ai/dsh-tools": "*"
|
|
219
|
+
},
|
|
220
|
+
"peerDependenciesMeta": {
|
|
221
|
+
"@deepseek-ai/dsh-tools": {
|
|
222
|
+
"optional": true
|
|
223
|
+
}
|
|
224
|
+
}
|
|
218
225
|
}
|
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.2.
|
|
4
|
+
"version": "1.2.3",
|
|
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": [
|