@twinsearth/w2m-dsh-plugin 1.9.9 → 1.9.10

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.
@@ -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.9"
8
+ "version": "1.9.10"
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.9",
15
+ "version": "1.9.10",
16
16
  "author": {
17
17
  "name": "TwinsEarth"
18
18
  },
@@ -26,5 +26,5 @@
26
26
  ]
27
27
  }
28
28
  ],
29
- "version": "1.9.9"
29
+ "version": "1.9.10"
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.9",
4
+ "version": "1.9.10",
5
5
  "author": {
6
6
  "name": "TwinsEarth"
7
7
  },
package/CHANGELOG.md CHANGED
@@ -7,6 +7,12 @@
7
7
 
8
8
  All notable changes to this project are documented here.
9
9
 
10
+ ## [1.9.10] - 2026-10-28
11
+
12
+ - 新增 `bin/w2m-self-update.mjs`:可被编队任务直接下发的自更新入口,读取 GitHub Release、校验 SHA256SUMS、调用已验证安装器,输出一行 JSON,不重启 DSH。
13
+ - 固化升级策略:优先下发自更新指令;失败才使用 Node 远程执行回退(macOS 用 mac-self-update,Windows 用 node 替换+备份)。
14
+ - 参数:--profile、--dry-run、--allow-prerelease;环境变量 W2M_PROFILE_DIR / W2M_UPDATE_REPO。
15
+
10
16
  ## [1.9.9] - 2026-10-28
11
17
 
12
18
  - 对话主工作区新增全文搜索:会话头部(置顶按钮同排)🔍 图标,点击展开搜索框,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);
@@ -12,6 +12,6 @@
12
12
 
13
13
  [mcp_servers.w2m-fleet]
14
14
  command = "npx"
15
- args = ["-y", "-p", "@twinsearth/w2m-dsh-plugin@1.9.9", "w2m-mcp"]
15
+ args = ["-y", "-p", "@twinsearth/w2m-dsh-plugin@1.9.10", "w2m-mcp"]
16
16
  startup_timeout_sec = 20
17
17
  tool_timeout_sec = 60
@@ -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
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@twinsearth/w2m-dsh-plugin",
3
- "version": "1.9.9",
3
+ "version": "1.9.10",
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": {
@@ -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.9",
4
+ "version": "1.9.10",
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": [
@@ -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.9';
286
+ const PLUGIN_VERSION = '1.9.10';
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;