dsh-remote-agent 0.4.0 → 0.4.1

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/README.en.md CHANGED
@@ -59,7 +59,7 @@ leads to the same endpoint**:
59
59
 
60
60
  | Route | Hub | Worker | For |
61
61
  |---|---|---|---|
62
- | **① Zero terminal**(Windows) | Double-click `bin/双击运行-配置向导.cmd` → Enter → Web panel "副机接入" copies the pairing code | Double-click the same file → paste the pairing code → Enter writes config | Anyone who flinches at a black window |
62
+ | **① Zero terminal**(Windows) | Double-click `bin/setup.cmd` → Enter → Web panel "副机接入" copies the pairing code | Double-click the same file → paste the pairing code → Enter writes config | Anyone who flinches at a black window |
63
63
  | **② Wizard**(recommended) | Run the wizard in a terminal → Enter to confirm | Same, paste the pairing code | You can open a terminal |
64
64
  | **③ Manual** | Hand-write config per the section below | Hand-write (`inject: []` is mandatory) | You want full control |
65
65
 
@@ -72,7 +72,7 @@ node bin/dsh-remote-setup.js
72
72
  ```
73
73
 
74
74
  > **Windows, no terminal?** In the plugin's `bin/` directory **double-click
75
- > `双击运行-配置向导.cmd`** —— then just keep pressing Enter in the window
75
+ > `setup.cmd`** —— then just keep pressing Enter in the window
76
76
  > that opens.
77
77
  > The plugin lives at `%USERPROFILE%\.dsh\dsh_orb\dsh-plugin\dsh-remote-agent\bin\`.
78
78
 
package/README.md CHANGED
@@ -55,7 +55,7 @@
55
55
 
56
56
  | 路线 | 主机 | 副机 | 适合 |
57
57
  |---|---|---|---|
58
- | **① 零终端**(Windows) | 双击 `bin/双击运行-配置向导.cmd` → 回车 → Web 面板「副机接入」复制配对码 | 双击同一文件 → 粘配对码 → 回车自动写盘 | 见到黑窗口就慌 |
58
+ | **① 零终端**(Windows) | 双击 `bin/setup.cmd` → 回车 → Web 面板「副机接入」复制配对码 | 双击同一文件 → 粘配对码 → 回车自动写盘 | 见到黑窗口就慌 |
59
59
  | **② 向导**(推荐) | 终端跑向导 → 回车确认写盘 | 同左,粘配对码 | 会开终端 |
60
60
  | **③ 手动** | 参照下文配置节手写 | 手写(`inject: []` 必加) | 想完全掌控每行 |
61
61
 
@@ -67,7 +67,7 @@ node bin/dsh-remote-setup.js
67
67
  ```
68
68
 
69
69
  > **Windows 不想开终端?** 在插件的 `bin/` 目录里**双击
70
- > `双击运行-配置向导.cmd`** —— 打开的窗口里全程回车即可。
70
+ > `setup.cmd`** —— 打开的窗口里全程回车即可。
71
71
  > 插件装在 `%USERPROFILE%\.dsh\dsh_orb\dsh-plugin\dsh-remote-agent\bin\`。
72
72
 
73
73
  1. **主机上跑**:选「1=主机」→ 向导自动找本机局域网 IP、生成 `nt_` 强随机
@@ -3,8 +3,10 @@ rem ============================================================
3
3
  rem dsh-remote-agent setup launcher (double-click entry)
4
4
  rem Content is ASCII-only on purpose: cmd.exe parses batch files
5
5
  rem in the OEM codepage, non-ASCII text here WILL be garbled.
6
- rem The Chinese file name is fine (NTFS is Unicode); keep the
7
- rem file CONTENT ASCII.
6
+ rem The FILE NAME is ASCII too: npm packs into a tar archive, and a
7
+ rem non-ASCII name comes out as mojibake on extract (verified: the
8
+ rem 0.4.0 tarball shipped a mojibake name). NTFS itself is fine;
9
+ rem the tar layer is not. Keep both name and content ASCII.
8
10
  rem ============================================================
9
11
  setlocal
10
12
  cd /d "%~dp0.."
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-remote-agent",
3
- "version": "0.4.0",
3
+ "version": "0.4.1",
4
4
  "type": "module",
5
5
  "description": "把另一台电脑变成你 DSH 的远程 Agent 同事:副机本地持久跑任务、独立 Agent 循环,只回传 handoff 摘要与产物清单,成品按需拉取。",
6
6
  "license": "MIT",
@@ -44,8 +44,8 @@
44
44
  },
45
45
  "main": "./lib/index.js",
46
46
  "bin": {
47
- "dsh-remote-relay": "./bin/dsh-remote-relay.js",
48
- "dsh-remote-setup": "./bin/dsh-remote-setup.js"
47
+ "dsh-remote-relay": "bin/dsh-remote-relay.js",
48
+ "dsh-remote-setup": "bin/dsh-remote-setup.js"
49
49
  },
50
50
  "files": [
51
51
  "lib",
@@ -484,23 +484,40 @@ for (const [i, [file, why]] of MAINT_FILES.entries()) {
484
484
 
485
485
  /* ── 48. Windows 双击入口 ──
486
486
  *
487
- * 零终端用户的第一道墙是"开终端"。启动器文件有两条硬规矩:
487
+ * 零终端用户的第一道墙是"开终端"。启动器文件有**三条**硬规矩:
488
488
  * 内容必须 ASCII(cmd.exe 按 OEM 码页解析批处理,非 ASCII 必乱码),
489
- * 行尾必须 CRLF(LF-only 的批处理有解析边缘案例)。
490
- * 文件名可以是中文(NTFS 是 Unicode),用字节级断言钉住这两条。
489
+ * 行尾必须 CRLF(LF-only 的批处理有解析边缘案例),
490
+ * **文件名也必须 ASCII**(见下)。
491
+ *
492
+ * ── 文件名为什么也必须 ASCII(2026-10-16 实测翻车)──────────────────────
493
+ *
494
+ * 这条断言原本的注释写的是"文件名可以是中文(NTFS 是 Unicode)"。
495
+ * **在本地是对的,发布出去是错的。** 0.4.0 的 npm tarball 里实际躺着:
496
+ *
497
+ * package/bin/˫������-������.cmd
498
+ *
499
+ * 原名 `双击运行-配置向导.cmd`(8 个中文字符)。npm 打成 **tar 归档**,
500
+ * tar 层的文件名编码不可靠 —— NTFS 的 Unicode 文件名在这里丢了,
501
+ * 解压出来是乱码。Windows 用户看到的就是一个打不开的怪文件,
502
+ * 双击入口等于不存在。
503
+ *
504
+ * 所以现在改名 `setup.cmd`,并且这条断言用**字节级**检查两件事:
505
+ * 文件名全 ASCII、文件内容全 ASCII + CRLF。
491
506
  */
492
507
  {
493
- const cmdPath = path.join(ROOT, 'bin', '双击运行-配置向导.cmd')
508
+ const cmdName = 'setup.cmd'
509
+ const cmdPath = path.join(ROOT, 'bin', cmdName)
494
510
  const ok48 = (() => {
495
511
  if (!fs.existsSync(cmdPath)) return false
512
+ if (!/^[\x20-\x7E]+$/.test(cmdName)) return false // 文件名 ASCII(tar 安全)
496
513
  const buf = fs.readFileSync(cmdPath)
497
514
  if (buf.some((b) => b > 127)) return false // 内容 ASCII
498
515
  if (!buf.includes(Buffer.from('@echo off\r\n'))) return false // CRLF
499
516
  return buf.includes(Buffer.from('dsh-remote-setup.js')) // 确实启动向导
500
517
  })()
501
- check('48', 'Windows 双击入口存在且 ASCII/CRLF 规范,README 有双击路径',
502
- ok48 && /双击/.test(read('README.md')),
503
- 'bin/双击运行-配置向导.cmd + README.md')
518
+ check('48', 'Windows 双击入口存在且**文件名与内容**都 ASCII/CRLF,README 有双击路径',
519
+ ok48 && /双击/.test(read('README.md')) && read('README.md').includes(cmdName),
520
+ `bin/${cmdName} + README.md`)
504
521
  }
505
522
 
506
523
  /* ── 49. 真实运行时自检工具与 KNOWN-ISSUES 验证记录 ──
@@ -72,6 +72,53 @@ for (const [name, target] of Object.entries(pkg.bin ?? {})) {
72
72
  if (!exists(target)) problems.push(`bin["${name}"] 指向不存在的路径: ${target}`)
73
73
  }
74
74
 
75
+ // ── 3b) 发布清单里的文件名必须全是 ASCII ─────────────────────────────────────
76
+ //
77
+ // npm 打包成 **tar 归档**,而 tar 层的文件名编码不可靠:非 ASCII 名字解压后
78
+ // 会变成乱码。这不是理论问题 —— 0.4.0 实际发布出去的 tarball 里躺着
79
+ //
80
+ // package/bin/˫������-������.cmd
81
+ //
82
+ // 原名是 `双击运行-配置向导.cmd`(NTFS 上完全正常,问题只在 tar 层)。
83
+ // 结果:Windows 用户解压后看到一个乱码文件,双击入口等于不存在。
84
+ //
85
+ // 所以这里扫一遍 `files` 列出的每个目录,任何非 ASCII 文件名都算问题。
86
+ {
87
+ const ascii = /^[\x20-\x7E]+$/
88
+ const scan = (relDir, out = []) => {
89
+ const abs = path.join(ROOT, relDir)
90
+ if (!fs.existsSync(abs)) return out
91
+ let entries
92
+ try {
93
+ entries = fs.readdirSync(abs, { withFileTypes: true })
94
+ } catch {
95
+ return out
96
+ }
97
+ for (const e of entries) {
98
+ if (e.name === 'node_modules' || e.name === '.git') continue
99
+ const rel = path.posix.join(relDir.replace(/\\/g, '/'), e.name)
100
+ if (!ascii.test(e.name)) out.push(rel)
101
+ if (e.isDirectory()) scan(rel, out)
102
+ }
103
+ return out
104
+ }
105
+ const bad = []
106
+ for (const entry of Array.isArray(pkg.files) ? pkg.files : []) {
107
+ const abs = path.join(ROOT, entry)
108
+ if (!fs.existsSync(abs)) continue
109
+ if (fs.statSync(abs).isDirectory()) scan(entry, bad)
110
+ else if (!ascii.test(path.basename(entry))) bad.push(entry)
111
+ }
112
+ if (bad.length > 0) {
113
+ problems.push(
114
+ `发布清单里有 ${bad.length} 个非 ASCII 文件名(npm 打成 tar 后必然乱码):\n`
115
+ + bad.map((b) => ` ${b}`).join('\n'),
116
+ )
117
+ } else {
118
+ notes.push('files 清单里的文件名全是 ASCII(tar 编码安全)')
119
+ }
120
+ }
121
+
75
122
  // ── 4) dsh.bundle.patch(DSH 专用:loader 靠它插入插件行)────────────────────
76
123
  const patch = pkg.dsh?.bundle?.patch
77
124
  if (typeof patch !== 'string') {