omnicrawl-cli 0.1.71 → 0.2.0
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.md +36 -52
- package/bin/omnicrawl.mjs +118 -29
- package/package.json +8 -7
package/README.md
CHANGED
|
@@ -1,75 +1,59 @@
|
|
|
1
1
|
# omnicrawl-cli
|
|
2
2
|
|
|
3
|
-
OmniCrawl 启动器:按 `platform-arch`
|
|
4
|
-
|
|
3
|
+
OmniCrawl 启动器:按 `platform-arch` 选平台分包,默认启动**完整宿主**(工作台 / `api` / 插件 CLI);
|
|
4
|
+
`kernel` 子命令把 stdio 交给内核二进制(协议调试与 e2e)。
|
|
5
5
|
|
|
6
6
|
## 分发形态
|
|
7
7
|
|
|
8
8
|
| npm 包 | 内容 |
|
|
9
9
|
| --- | --- |
|
|
10
10
|
| `omnicrawl-cli` | JS 启动器(`bin/omnicrawl.mjs`) |
|
|
11
|
-
| `@omnicrawl/cli-
|
|
12
|
-
| `@omnicrawl/cli-linux-
|
|
13
|
-
| `@omnicrawl/cli-linux-arm64-musl` |
|
|
14
|
-
| `@omnicrawl/cli-win32-
|
|
11
|
+
| `@omnicrawl/cli-win32-x64` | 内核二进制 + 宿主载荷(Windows x64) |
|
|
12
|
+
| `@omnicrawl/cli-linux-x64` | 内核二进制 + 宿主载荷(Linux x64,内核为 musl 静态) |
|
|
13
|
+
| `@omnicrawl/cli-linux-arm64-musl` | 内核二进制 + 宿主载荷(Linux arm64) |
|
|
14
|
+
| `@omnicrawl/cli-win32-ia32` | 仅内核(32 位 Windows 缺运行期轮子) |
|
|
15
|
+
| `@omnicrawl/cli-linux-arm-musl` | 仅内核(armv7 嵌入式目标) |
|
|
16
|
+
|
|
17
|
+
宿主载荷是 PyInstaller one-dir 产物(`host/`):CPython 运行时、依赖、代码与资源都在里面,
|
|
18
|
+
用户机器不需要 Python 或 pip。没有宿主载荷的平台由启动器退回内核直连,并打印这一边界。
|
|
15
19
|
|
|
16
20
|
**平台分包、`os`/`cpu` 与平台依赖只出现在发布产物里**(`dist/npm/`)。仓库内的 `packages/cli*/package.json`
|
|
17
21
|
刻意不带 `os`/`cpu`、也不声明平台分包依赖:npm 安装时会校验工作区成员的 `os`/`cpu`,带上就直接
|
|
18
22
|
`notsup` 失败。发布产物由 `scripts/prepare.mjs` 生成。
|
|
19
23
|
|
|
20
|
-
##
|
|
24
|
+
## 命令面
|
|
21
25
|
|
|
22
|
-
```
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
26
|
+
```
|
|
27
|
+
omnicrawl 启动工作台(TUI)
|
|
28
|
+
omnicrawl api 启动本地 HTTP 服务(无头/服务器场景)
|
|
29
|
+
omnicrawl plugin ... 插件管理
|
|
30
|
+
omnicrawl kernel ... 直连内核进程(协议调试)
|
|
31
|
+
omnicrawl --version 打印启动器、平台包、宿主与内核版本
|
|
27
32
|
```
|
|
28
33
|
|
|
29
|
-
|
|
30
|
-
`OMNICRAWL_BINARY` 是直接指定二进制的逃生口(e2e 用的就是它)。e2e 需要 `rust/target/release`
|
|
31
|
-
里有产物,否则跳过并打印构建命令。
|
|
32
|
-
|
|
33
|
-
## 发布
|
|
34
|
-
|
|
35
|
-
手动发布前先 `npm login`(CI 走 Trusted Publishing,无需登录与 token)。
|
|
36
|
-
|
|
37
|
-
1. 交叉编译各平台(Linux 走 musl 静态,嵌入式目标优先):
|
|
38
|
-
|
|
39
|
-
```bash
|
|
40
|
-
cargo build --release -p omnicrawl-cli --target x86_64-pc-windows-msvc
|
|
41
|
-
cargo build --release -p omnicrawl-cli --target x86_64-unknown-linux-musl
|
|
42
|
-
cargo build --release -p omnicrawl-cli --target aarch64-unknown-linux-musl
|
|
43
|
-
cargo build --release -p omnicrawl-cli --target armv7-unknown-linux-musleabihf
|
|
44
|
-
```
|
|
45
|
-
|
|
46
|
-
非 Linux 宿主没有 musl 链接器,Linux 目标改用 `cargo zigbuild`(需 `zig` 与
|
|
47
|
-
`rustup target add <triple>`):
|
|
48
|
-
|
|
49
|
-
```bash
|
|
50
|
-
cargo zigbuild --release -p omnicrawl-cli --target armv7-unknown-linux-musleabihf
|
|
51
|
-
```
|
|
52
|
-
|
|
53
|
-
2. 门槛检查(缺任何平台会失败并列出缺失平台):
|
|
34
|
+
无交互式终端时宿主会直接给出改用 `api` 的提示并以 2 退出,不会停在协议等待状态。
|
|
54
35
|
|
|
55
|
-
|
|
56
|
-
node packages/cli/scripts/prepare.mjs --require-all
|
|
57
|
-
```
|
|
36
|
+
## 本地开发
|
|
58
37
|
|
|
59
|
-
|
|
38
|
+
```bash
|
|
39
|
+
cargo build --release -p omnicrawl-cli # 产物:rust/target/release/omnicrawl[.exe]
|
|
40
|
+
node packages/cli/scripts/build-host.mjs # 宿主载荷:dist/host/<platform>/payload
|
|
41
|
+
node packages/cli/scripts/prepare.mjs # 暂存发布产物(缺的平台只警告)
|
|
42
|
+
node packages/cli/scripts/host-smoke.mjs # 宿主冒烟:无终端提示 + 退出码
|
|
43
|
+
node packages/cli/scripts/install-smoke.mjs # 安装冒烟:干净前缀里真装真跑
|
|
44
|
+
npm test -w omnicrawl-cli # e2e:真二进制 + 协议 v1
|
|
45
|
+
```
|
|
60
46
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
npm publish dist/npm/cli-linux-arm-musl
|
|
64
|
-
npm publish dist/npm/cli-linux-arm64-musl
|
|
65
|
-
npm publish dist/npm/cli-win32-x64
|
|
66
|
-
npm publish dist/npm/cli
|
|
67
|
-
```
|
|
47
|
+
宿主载荷只能与构建机同架构(里面有 CPython 与原生扩展),交叉构建不成立:
|
|
48
|
+
其它平台由 CI 在各自 runner 上构建(见 `.github/workflows/publish-npm.yml`)。
|
|
68
49
|
|
|
69
|
-
|
|
50
|
+
两个逃生口:`OMNICRAWL_HOST` 直接指定宿主、`OMNICRAWL_BINARY` 直接指定内核(此时启动器是纯透传)。
|
|
70
51
|
|
|
71
|
-
|
|
52
|
+
## 发布
|
|
72
53
|
|
|
73
|
-
|
|
54
|
+
1. 升 `packages/cli/package.json` 版本(平台包与启动器同版本)。
|
|
55
|
+
2. 推 `npm-v<版本>` tag(CI 会校验 tag 与包版本一致)或手动触发 workflow:
|
|
56
|
+
矩阵各平台构建内核(+ 宿主)→ 宿主冒烟 → 暂存并上传产物;
|
|
57
|
+
发布任务下载全部产物 → 暂存启动器 → 安装冒烟 → 平台包在前、启动器在后依次发布。
|
|
74
58
|
|
|
75
|
-
|
|
59
|
+
发布前自检:`cargo test --workspace`、`npm test --workspaces`、`prepare.mjs --require-all --require-host`。
|
package/bin/omnicrawl.mjs
CHANGED
|
@@ -1,9 +1,12 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
// OmniCrawl 启动器:按 platform/arch
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// OmniCrawl 启动器:按 platform/arch 选出平台分包,默认启动完整宿主(工作台 / api / plugin 指令),
|
|
3
|
+
// `kernel` 子命令把 stdio 交给内核二进制(协议调试与 e2e)。
|
|
3
4
|
//
|
|
4
|
-
//
|
|
5
|
+
// 两个逃生口(开发与协议测试用):
|
|
6
|
+
// OMNICRAWL_HOST=<可执行文件> 直接指定宿主,跳过平台分包
|
|
7
|
+
// OMNICRAWL_BINARY=<可执行文件> 直接指定内核;此时启动器退化为纯透传,便于协议测试
|
|
5
8
|
import { spawn } from 'node:child_process'
|
|
6
|
-
import { existsSync } from 'node:fs'
|
|
9
|
+
import { existsSync, readFileSync } from 'node:fs'
|
|
7
10
|
import { createRequire } from 'node:module'
|
|
8
11
|
import { dirname, join } from 'node:path'
|
|
9
12
|
import process from 'node:process'
|
|
@@ -16,44 +19,130 @@ const PLATFORM_PACKAGES = {
|
|
|
16
19
|
'win32-ia32': '@omnicrawl/cli-win32-ia32',
|
|
17
20
|
}
|
|
18
21
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
+
const IS_WINDOWS = process.platform === 'win32'
|
|
23
|
+
const HOST_FILE = IS_WINDOWS ? 'omnicrawl-host.exe' : 'omnicrawl-host'
|
|
24
|
+
const KERNEL_FILE = IS_WINDOWS ? 'omnicrawl.exe' : 'omnicrawl'
|
|
25
|
+
const KERNEL_COMMAND = 'kernel'
|
|
22
26
|
|
|
27
|
+
const launcherVersion = JSON.parse(
|
|
28
|
+
readFileSync(new URL('../package.json', import.meta.url), 'utf8'),
|
|
29
|
+
).version
|
|
30
|
+
|
|
31
|
+
function fail(message) {
|
|
32
|
+
console.error(message)
|
|
33
|
+
process.exit(1)
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/** 解析平台分包根目录;拿不到分包时抛出可直接展示的错误。 */
|
|
37
|
+
function resolvePlatform() {
|
|
23
38
|
const key = `${process.platform}-${process.arch}`
|
|
24
39
|
const packageName = PLATFORM_PACKAGES[key]
|
|
25
40
|
if (!packageName) {
|
|
26
41
|
throw new Error(`不支持的平台 ${key};已支持:${Object.keys(PLATFORM_PACKAGES).join('、')}`)
|
|
27
42
|
}
|
|
28
|
-
|
|
29
43
|
const require = createRequire(import.meta.url)
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
44
|
+
return { packageName, root: dirname(require.resolve(`${packageName}/package.json`)) }
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/** 目标可执行文件:宿主优先,内核兜底;两个环境变量各自覆盖。 */
|
|
48
|
+
function resolveTargets() {
|
|
49
|
+
if (process.env.OMNICRAWL_HOST) {
|
|
50
|
+
return { host: process.env.OMNICRAWL_HOST, kernel: process.env.OMNICRAWL_BINARY ?? null, passthrough: false }
|
|
51
|
+
}
|
|
52
|
+
if (process.env.OMNICRAWL_BINARY) {
|
|
53
|
+
return { host: null, kernel: process.env.OMNICRAWL_BINARY, passthrough: true }
|
|
54
|
+
}
|
|
55
|
+
const { packageName, root } = resolvePlatform()
|
|
56
|
+
return {
|
|
57
|
+
host: join(root, 'host', HOST_FILE),
|
|
58
|
+
kernel: join(root, 'bin', KERNEL_FILE),
|
|
59
|
+
packageName,
|
|
60
|
+
root,
|
|
61
|
+
passthrough: false,
|
|
34
62
|
}
|
|
35
|
-
return binary
|
|
36
63
|
}
|
|
37
64
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
65
|
+
function readPayloadMeta(root) {
|
|
66
|
+
if (!root) return null
|
|
67
|
+
try {
|
|
68
|
+
return JSON.parse(readFileSync(join(root, 'version.json'), 'utf8'))
|
|
69
|
+
} catch {
|
|
70
|
+
return null
|
|
71
|
+
}
|
|
44
72
|
}
|
|
45
73
|
|
|
46
|
-
|
|
74
|
+
function printVersion(targets) {
|
|
75
|
+
const meta = readPayloadMeta(targets.root)
|
|
76
|
+
const lines = [`omnicrawl ${launcherVersion}`]
|
|
77
|
+
lines.push(
|
|
78
|
+
targets.packageName
|
|
79
|
+
? `${targets.packageName} ${meta?.version ?? '未知'}(${process.platform}-${process.arch} 平台包)`
|
|
80
|
+
: `omnicrawl-cli ${launcherVersion}(启动器)`,
|
|
81
|
+
)
|
|
82
|
+
if (meta?.hostVersion) lines.push(`omnicrawl-agent ${meta.hostVersion}(宿主)`)
|
|
83
|
+
if (meta?.kernelVersion) lines.push(`omnicrawl ${meta.kernelVersion}(内核)`)
|
|
84
|
+
console.log(lines.join('\n'))
|
|
85
|
+
}
|
|
47
86
|
|
|
48
|
-
|
|
49
|
-
console.
|
|
50
|
-
|
|
51
|
-
|
|
87
|
+
function printHelp() {
|
|
88
|
+
console.log(
|
|
89
|
+
`用法:omnicrawl [选项] [指令]\n\n\
|
|
90
|
+
无参数 启动工作台(TUI)\n\
|
|
91
|
+
api 启动本地 HTTP 服务(无头/服务器场景)\n\
|
|
92
|
+
plugin ... 插件管理\n\
|
|
93
|
+
kernel ... 直连内核进程(协议调试)\n\n\
|
|
94
|
+
--resume <会话 ID> 启动时恢复指定会话\n\
|
|
95
|
+
--version, -V 打印启动器、平台包、宿主与内核版本\n\
|
|
96
|
+
--help, -h 打印本说明`,
|
|
97
|
+
)
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/** 把 stdio 交给目标可执行文件,并把它的退出码/信号作为本次退出状态。 */
|
|
101
|
+
function run(executable, args) {
|
|
102
|
+
if (!executable || !existsSync(executable)) {
|
|
103
|
+
fail(`omnicrawl:找不到可执行文件 ${executable ?? '(未解析到)'}。请重装对应的平台包。`)
|
|
104
|
+
}
|
|
105
|
+
const child = spawn(executable, args, { stdio: 'inherit' })
|
|
52
106
|
|
|
53
|
-
child.on('
|
|
54
|
-
|
|
55
|
-
console.error(`omnicrawl:内核被信号 ${signal} 终止`)
|
|
107
|
+
child.on('error', (error) => {
|
|
108
|
+
console.error(`omnicrawl:无法启动 ${executable}:${error.message}`)
|
|
56
109
|
process.exit(1)
|
|
110
|
+
})
|
|
111
|
+
|
|
112
|
+
child.on('exit', (code, signal) => {
|
|
113
|
+
if (signal) {
|
|
114
|
+
console.error(`omnicrawl:${executable} 被信号 ${signal} 终止`)
|
|
115
|
+
process.exit(1)
|
|
116
|
+
}
|
|
117
|
+
process.exit(code ?? 0)
|
|
118
|
+
})
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
function main() {
|
|
122
|
+
let targets
|
|
123
|
+
try {
|
|
124
|
+
targets = resolveTargets()
|
|
125
|
+
} catch (error) {
|
|
126
|
+
fail(`omnicrawl:${error.message}`)
|
|
57
127
|
}
|
|
58
|
-
|
|
59
|
-
|
|
128
|
+
|
|
129
|
+
const args = process.argv.slice(2)
|
|
130
|
+
|
|
131
|
+
// 内核透传模式(OMNICRAWL_BINARY):启动器不介入 stdio 上的协议帧。
|
|
132
|
+
if (targets.passthrough) return run(targets.kernel, args)
|
|
133
|
+
|
|
134
|
+
if (args[0] === KERNEL_COMMAND) return run(targets.kernel, args.slice(1))
|
|
135
|
+
if (args.includes('--version') || args.includes('-V')) return printVersion(targets)
|
|
136
|
+
if (args.includes('--help') || args.includes('-h')) return printHelp()
|
|
137
|
+
|
|
138
|
+
if (targets.host && existsSync(targets.host)) return run(targets.host, args)
|
|
139
|
+
|
|
140
|
+
// 嵌入式目标(armv7 等)没有宿主载荷:退回内核直连,并说明这一平台的边界。
|
|
141
|
+
console.error(
|
|
142
|
+
`omnicrawl:平台包 ${targets.packageName ?? '(未指定)'} 没有宿主载荷,退回内核直连;` +
|
|
143
|
+
'该平台只支持协议模式(用 omnicrawl kernel 显式进入)。',
|
|
144
|
+
)
|
|
145
|
+
return run(targets.kernel, args)
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
main()
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "omnicrawl-cli",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "OmniCrawl
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"description": "OmniCrawl 启动器:按平台启动完整宿主(工作台 / api / 插件)",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
7
7
|
"url": "git+https://github.com/cccchiban/omnicrawl.git",
|
|
@@ -20,14 +20,15 @@
|
|
|
20
20
|
},
|
|
21
21
|
"scripts": {
|
|
22
22
|
"test": "node --test",
|
|
23
|
+
"build:host": "node scripts/build-host.mjs",
|
|
23
24
|
"prepare:binaries": "node scripts/prepare.mjs"
|
|
24
25
|
},
|
|
25
26
|
"license": "MIT",
|
|
26
27
|
"optionalDependencies": {
|
|
27
|
-
"@omnicrawl/cli-win32-x64": "0.
|
|
28
|
-
"@omnicrawl/cli-win32-ia32": "0.
|
|
29
|
-
"@omnicrawl/cli-linux-x64": "0.
|
|
30
|
-
"@omnicrawl/cli-linux-arm-musl": "0.
|
|
31
|
-
"@omnicrawl/cli-linux-arm64-musl": "0.
|
|
28
|
+
"@omnicrawl/cli-win32-x64": "0.2.0",
|
|
29
|
+
"@omnicrawl/cli-win32-ia32": "0.2.0",
|
|
30
|
+
"@omnicrawl/cli-linux-x64": "0.2.0",
|
|
31
|
+
"@omnicrawl/cli-linux-arm-musl": "0.2.0",
|
|
32
|
+
"@omnicrawl/cli-linux-arm64-musl": "0.2.0"
|
|
32
33
|
}
|
|
33
34
|
}
|