markpilot-cm6 0.0.0-stage → 3.6.21
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/LICENSE +21 -0
- package/README.md +36 -2
- package/SHA256SUMS-3.6.21.txt +2 -0
- package/THIRD-PARTY-NOTICES.md +13 -0
- package/bin/markpilot.cjs +195 -0
- package/package.json +42 -4
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 ltmroberthk915
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,3 +1,37 @@
|
|
|
1
|
-
#
|
|
1
|
+
# MarkPilot 独立桌面版 3.6.21
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
MarkPilot 是一款即时渲染的 Markdown 编辑器:公式、代码块、表格、图片、Mermaid 图表和长文稿都能在熟悉的编辑界面里完成,保存、导出与多窗口协作按同一套文档模型工作。Windows 同时提供安装版与免安装便携版。
|
|
4
|
+
|
|
5
|
+
这个 npm 包是 MarkPilot 桌面版的下载与启动入口。安装包本身体积很大,不适合塞进 npm 注册表,所以这里只提供一条可核对 SHA-256 的下载通道,真正的安装包从对应的 GitHub Release 获取。
|
|
6
|
+
|
|
7
|
+
## 安装
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npm install -g markpilot-cm6
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
需要 Node.js 18 及以上,仅支持 Windows。
|
|
14
|
+
|
|
15
|
+
## 使用
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
markpilot --download # 下载安装版 Setup 并校验 SHA-256
|
|
19
|
+
markpilot --download --portable # 下载便携版
|
|
20
|
+
markpilot --download --out D:\Downloads
|
|
21
|
+
markpilot # 启动已安装的 MarkPilot
|
|
22
|
+
markpilot 笔记.md # 用 MarkPilot 打开文件
|
|
23
|
+
markpilot --path # 查看找到的 MarkPilot.exe
|
|
24
|
+
markpilot --version
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
下载完成后运行 `markpilot-Setup-3.6.21.exe` 即可安装或覆盖升级,原有文档、主题、字体和最近文件设置都会保留。便携版是单个 EXE,双击即用,不需要安装。
|
|
28
|
+
|
|
29
|
+
## 直接下载
|
|
30
|
+
|
|
31
|
+
- [安装版](https://github.com/ltmroberthk915/markpilot/releases/download/v3.6.21/markpilot-Setup-3.6.21.exe)
|
|
32
|
+
- [便携版](https://github.com/ltmroberthk915/markpilot/releases/download/v3.6.21/markpilot-3.6.21-portable.exe)
|
|
33
|
+
- [发布页](https://github.com/ltmroberthk915/markpilot/releases/tag/v3.6.21)
|
|
34
|
+
|
|
35
|
+
## 许可
|
|
36
|
+
|
|
37
|
+
MIT。随安装包分发的第三方组件许可见 `THIRD-PARTY-NOTICES.md`。
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# Third-party notices
|
|
2
|
+
|
|
3
|
+
MarkPilot 的 Windows 安装包与便携版包含或依赖以下开源项目:
|
|
4
|
+
|
|
5
|
+
- **Electron** — MIT — <https://github.com/electron/electron>
|
|
6
|
+
- **Chromium** — BSD-style and other licenses — <https://www.chromium.org/Home>
|
|
7
|
+
- **CodeMirror 6** — MIT — <https://github.com/codemirror/dev>
|
|
8
|
+
- **Mermaid** — MIT — <https://github.com/mermaid-js/mermaid>
|
|
9
|
+
- **KaTeX** — MIT — <https://github.com/KaTeX/KaTeX>
|
|
10
|
+
- **KaTeX fonts** — SIL Open Font License 1.1 — <https://github.com/KaTeX/KaTeX/tree/main/fonts>
|
|
11
|
+
- **Knuth–Plass 排版实现** — MIT — <https://github.com/ltmroberthk915/markpilot>
|
|
12
|
+
|
|
13
|
+
安装目录内的 `LICENSE.electron.txt` 与 `LICENSES.chromium.html` 是 Electron/Chromium 随附的完整许可文本。
|
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
'use strict';
|
|
3
|
+
/**
|
|
4
|
+
* markpilot-cm6 — MarkPilot 桌面版的 npm 分发包。
|
|
5
|
+
*
|
|
6
|
+
* 这个包本身不内嵌 100 MB 级的 EXE(npm 注册表的单包大小不适合装桌面安装包),
|
|
7
|
+
* 它提供一条可核对 SHA-256 的下载/启动通道:安装后运行 `markpilot --download`,
|
|
8
|
+
* 从对应的 GitHub Release 取安装版或便携版,再 `markpilot` 启动。
|
|
9
|
+
*/
|
|
10
|
+
const fs = require('node:fs');
|
|
11
|
+
const path = require('node:path');
|
|
12
|
+
const os = require('node:os');
|
|
13
|
+
const crypto = require('node:crypto');
|
|
14
|
+
const { spawn, execFileSync } = require('node:child_process');
|
|
15
|
+
|
|
16
|
+
const pkg = require('../package.json');
|
|
17
|
+
const VERSION = pkg.version;
|
|
18
|
+
const TAG = 'v' + VERSION;
|
|
19
|
+
const RELEASE_BASE = process.env.MARKPILOT_RELEASE_BASE
|
|
20
|
+
|| 'https://github.com/ltmroberthk915/markpilot/releases/download/' + TAG;
|
|
21
|
+
const ASSETS = {
|
|
22
|
+
setup: 'markpilot-Setup-' + VERSION + '.exe',
|
|
23
|
+
portable: 'markpilot-' + VERSION + '-portable.exe',
|
|
24
|
+
};
|
|
25
|
+
const SUMS_FILE = 'SHA256SUMS-' + VERSION + '.txt';
|
|
26
|
+
|
|
27
|
+
function usage() {
|
|
28
|
+
console.log([
|
|
29
|
+
'MarkPilot 独立桌面版 ' + VERSION,
|
|
30
|
+
'',
|
|
31
|
+
'用法:',
|
|
32
|
+
' markpilot 启动已安装的 MarkPilot(可跟一个 .md 文件)',
|
|
33
|
+
' markpilot <file.md> 用已安装的 MarkPilot 打开文件',
|
|
34
|
+
' markpilot --download 下载安装版 Setup 到本地并校验 SHA-256',
|
|
35
|
+
' markpilot --download --portable 下载便携版并校验 SHA-256',
|
|
36
|
+
' markpilot --download --out <dir> 指定下载目录',
|
|
37
|
+
' markpilot --path 打印探测到的 MarkPilot.exe 路径',
|
|
38
|
+
' markpilot --exe <path> 指定 MarkPilot.exe 后启动',
|
|
39
|
+
' markpilot --version 打印版本',
|
|
40
|
+
'',
|
|
41
|
+
'发布页:https://github.com/ltmroberthk915/markpilot/releases/tag/' + TAG,
|
|
42
|
+
].join('\n'));
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function fail(message, code = 1) {
|
|
46
|
+
console.error('markpilot: ' + message);
|
|
47
|
+
process.exit(code);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function sums() {
|
|
51
|
+
const file = path.join(__dirname, '..', SUMS_FILE);
|
|
52
|
+
const map = new Map();
|
|
53
|
+
for (const line of fs.readFileSync(file, 'utf8').split(/\r?\n/)) {
|
|
54
|
+
const match = /^([0-9a-f]{64})\s+\*?(.+)$/i.exec(line.trim());
|
|
55
|
+
if (match) map.set(match[2].trim(), match[1].toLowerCase());
|
|
56
|
+
}
|
|
57
|
+
return map;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function sha256File(file) {
|
|
61
|
+
return new Promise((resolve, reject) => {
|
|
62
|
+
const hash = crypto.createHash('sha256');
|
|
63
|
+
fs.createReadStream(file)
|
|
64
|
+
.on('data', (chunk) => hash.update(chunk))
|
|
65
|
+
.on('error', reject)
|
|
66
|
+
.on('end', () => resolve(hash.digest('hex')));
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
async function download(kind, outDir) {
|
|
71
|
+
const asset = ASSETS[kind];
|
|
72
|
+
const expected = sums().get(asset);
|
|
73
|
+
if (!expected) fail('缺少 ' + asset + ' 的校验值');
|
|
74
|
+
const url = RELEASE_BASE + '/' + asset;
|
|
75
|
+
fs.mkdirSync(outDir, { recursive: true });
|
|
76
|
+
const target = path.join(outDir, asset);
|
|
77
|
+
const partial = target + '.part';
|
|
78
|
+
console.log('下载 ' + asset + '\n 从 ' + url + '\n 到 ' + target);
|
|
79
|
+
const response = await fetch(url, { redirect: 'follow' });
|
|
80
|
+
if (!response.ok || !response.body) fail('下载失败:HTTP ' + response.status + ' ' + response.statusText);
|
|
81
|
+
const total = Number(response.headers.get('content-length') || 0);
|
|
82
|
+
let read = 0;
|
|
83
|
+
let lastTick = 0;
|
|
84
|
+
const stream = fs.createWriteStream(partial);
|
|
85
|
+
for await (const chunk of response.body) {
|
|
86
|
+
read += chunk.length;
|
|
87
|
+
if (!stream.write(chunk)) await new Promise((r) => stream.once('drain', r));
|
|
88
|
+
const now = Date.now();
|
|
89
|
+
if (total && now - lastTick > 1000) {
|
|
90
|
+
lastTick = now;
|
|
91
|
+
process.stdout.write('\r ' + (read / 1048576).toFixed(1) + ' / ' + (total / 1048576).toFixed(1) + ' MB ');
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
await new Promise((resolve, reject) => stream.end((err) => (err ? reject(err) : resolve())));
|
|
95
|
+
if (total) process.stdout.write('\r ' + (total / 1048576).toFixed(1) + ' MB 完成\n');
|
|
96
|
+
const actual = await sha256File(partial);
|
|
97
|
+
if (actual !== expected) {
|
|
98
|
+
fs.rmSync(partial, { force: true });
|
|
99
|
+
fail('SHA-256 不匹配:期望 ' + expected + ',实际 ' + actual);
|
|
100
|
+
}
|
|
101
|
+
fs.renameSync(partial, target);
|
|
102
|
+
console.log(' 校验通过 sha256=' + actual);
|
|
103
|
+
console.log(' 已保存 ' + target);
|
|
104
|
+
if (kind === 'setup') console.log(' 运行安装器即可覆盖升级,原有文档与设置保留。');
|
|
105
|
+
else console.log(' 便携版可直接双击运行,不需要安装。');
|
|
106
|
+
return target;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
function registryInstallDirs() {
|
|
110
|
+
const roots = [
|
|
111
|
+
'HKCU\\Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall',
|
|
112
|
+
'HKLM\\Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall',
|
|
113
|
+
'HKLM\\Software\\WOW6432Node\\Microsoft\\Windows\\CurrentVersion\\Uninstall',
|
|
114
|
+
];
|
|
115
|
+
const dirs = [];
|
|
116
|
+
for (const root of roots) {
|
|
117
|
+
let output;
|
|
118
|
+
try {
|
|
119
|
+
output = execFileSync('reg.exe', ['query', root, '/s'], { encoding: 'utf8', windowsHide: true, timeout: 15000 });
|
|
120
|
+
} catch { continue; }
|
|
121
|
+
for (const block of output.split(/\r?\n\r?\n/)) {
|
|
122
|
+
if (!/DisplayName\s+REG_(?:SZ|EXPAND_SZ)\s+MarkPilot/i.test(block)) continue;
|
|
123
|
+
const uninstall = /UninstallString\s+REG_(?:SZ|EXPAND_SZ)\s+"?([^"\r\n]+\.exe)"?/i.exec(block);
|
|
124
|
+
if (uninstall) dirs.push(path.dirname(uninstall[1]));
|
|
125
|
+
const location = /InstallLocation\s+REG_(?:SZ|EXPAND_SZ)\s+(.+)/i.exec(block);
|
|
126
|
+
if (location && location[1].trim()) dirs.push(location[1].trim());
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
return dirs;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
function candidates() {
|
|
133
|
+
const local = process.env.LOCALAPPDATA || path.join(os.homedir(), 'AppData', 'Local');
|
|
134
|
+
const programFiles = process.env.ProgramFiles || 'C:\\Program Files';
|
|
135
|
+
const programFilesX86 = process.env['ProgramFiles(x86)'] || 'C:\\Program Files (x86)';
|
|
136
|
+
const declared = registryInstallDirs().map((dir) => path.join(dir, 'MarkPilot.exe'));
|
|
137
|
+
return [
|
|
138
|
+
...declared,
|
|
139
|
+
path.join(local, 'Programs', 'MarkPilot CM6', 'MarkPilot.exe'),
|
|
140
|
+
path.join(local, 'Programs', 'MarkPilot', 'MarkPilot.exe'),
|
|
141
|
+
path.join(programFiles, 'MarkPilot', 'MarkPilot.exe'),
|
|
142
|
+
path.join(programFilesX86, 'MarkPilot', 'MarkPilot.exe'),
|
|
143
|
+
];
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
function findExecutable() {
|
|
147
|
+
for (const candidate of candidates()) {
|
|
148
|
+
try { if (fs.existsSync(candidate)) return candidate; } catch { }
|
|
149
|
+
}
|
|
150
|
+
return null;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
function launch(exe, file) {
|
|
154
|
+
const args = file ? [path.resolve(file)] : [];
|
|
155
|
+
const child = spawn(exe, args, { detached: true, stdio: 'ignore', windowsHide: false });
|
|
156
|
+
child.unref();
|
|
157
|
+
console.log('已启动 ' + exe + (file ? ' ' + file : ''));
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
async function main() {
|
|
161
|
+
const args = process.argv.slice(2);
|
|
162
|
+
if (args.includes('--version') || args.includes('-v')) { console.log(VERSION); return; }
|
|
163
|
+
if (args.includes('--help') || args.includes('-h')) { usage(); return; }
|
|
164
|
+
|
|
165
|
+
if (args.includes('--download')) {
|
|
166
|
+
const portable = args.includes('--portable');
|
|
167
|
+
const setup = args.includes('--setup');
|
|
168
|
+
if (portable && setup) fail('--portable 与 --setup 只能选一个');
|
|
169
|
+
const outIndex = args.indexOf('--out');
|
|
170
|
+
const outDir = outIndex >= 0 && args[outIndex + 1]
|
|
171
|
+
? path.resolve(args[outIndex + 1])
|
|
172
|
+
: path.join(process.env.LOCALAPPDATA || path.join(os.homedir(), 'AppData', 'Local'), 'MarkPilot', 'downloads');
|
|
173
|
+
await download(portable ? 'portable' : 'setup', outDir);
|
|
174
|
+
return;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
const exeIndex = args.indexOf('--exe');
|
|
178
|
+
const exe = exeIndex >= 0 && args[exeIndex + 1] ? path.resolve(args[exeIndex + 1]) : findExecutable();
|
|
179
|
+
if (args.includes('--path')) {
|
|
180
|
+
if (!exe || !fs.existsSync(exe)) fail('没有找到已安装的 MarkPilot.exe;先运行 markpilot --download 安装,或用 --exe 指定。', 2);
|
|
181
|
+
console.log(exe);
|
|
182
|
+
return;
|
|
183
|
+
}
|
|
184
|
+
if (!exe || !fs.existsSync(exe)) {
|
|
185
|
+
console.error('没有找到已安装的 MarkPilot。');
|
|
186
|
+
console.error(' 安装版:markpilot --download 然后运行下载到的 markpilot-Setup-' + VERSION + '.exe');
|
|
187
|
+
console.error(' 便携版:markpilot --download --portable');
|
|
188
|
+
console.error(' 或从发布页直接下载:https://github.com/ltmroberthk915/markpilot/releases/tag/' + TAG);
|
|
189
|
+
process.exit(2);
|
|
190
|
+
}
|
|
191
|
+
const file = args.find((a, i) => !a.startsWith('-') && args[i - 1] !== '--exe' && args[i - 1] !== '--out');
|
|
192
|
+
launch(exe, file);
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
main().catch((e) => fail(String(e && e.message || e)));
|
package/package.json
CHANGED
|
@@ -1,6 +1,44 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "markpilot-cm6",
|
|
3
|
-
"version": "
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
|
|
3
|
+
"version": "3.6.21",
|
|
4
|
+
"description": "MarkPilot 独立桌面版 3.6.21:为 Windows 下载并启动安装版或便携版",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"author": "jinxi",
|
|
7
|
+
"type": "commonjs",
|
|
8
|
+
"bin": {
|
|
9
|
+
"markpilot": "bin/markpilot.cjs"
|
|
10
|
+
},
|
|
11
|
+
"files": [
|
|
12
|
+
"bin",
|
|
13
|
+
"README.md",
|
|
14
|
+
"LICENSE",
|
|
15
|
+
"THIRD-PARTY-NOTICES.md",
|
|
16
|
+
"SHA256SUMS-3.6.21.txt"
|
|
17
|
+
],
|
|
18
|
+
"os": [
|
|
19
|
+
"win32"
|
|
20
|
+
],
|
|
21
|
+
"engines": {
|
|
22
|
+
"node": ">=18"
|
|
23
|
+
},
|
|
24
|
+
"keywords": [
|
|
25
|
+
"markpilot",
|
|
26
|
+
"markdown",
|
|
27
|
+
"editor",
|
|
28
|
+
"typora",
|
|
29
|
+
"desktop",
|
|
30
|
+
"windows"
|
|
31
|
+
],
|
|
32
|
+
"repository": {
|
|
33
|
+
"type": "git",
|
|
34
|
+
"url": "git+https://github.com/ltmroberthk915/markpilot.git",
|
|
35
|
+
"directory": "npm/markpilot-cm6"
|
|
36
|
+
},
|
|
37
|
+
"homepage": "https://github.com/ltmroberthk915/markpilot/tree/main/npm/markpilot-cm6",
|
|
38
|
+
"bugs": {
|
|
39
|
+
"url": "https://github.com/ltmroberthk915/markpilot/issues"
|
|
40
|
+
},
|
|
41
|
+
"publishConfig": {
|
|
42
|
+
"access": "public"
|
|
43
|
+
}
|
|
44
|
+
}
|