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
|
|
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
|
-
>
|
|
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
|
|
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
|
-
>
|
|
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
|
|
7
|
-
rem
|
|
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.
|
|
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": "
|
|
48
|
-
"dsh-remote-setup": "
|
|
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
|
-
*
|
|
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
|
|
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
|
|
502
|
-
ok48 && /双击/.test(read('README.md')),
|
|
503
|
-
|
|
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') {
|