deepminer-cli 0.1.25 → 0.1.27
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 +50 -26
- package/bin/dm-cli-darwin-amd64 +0 -0
- package/bin/dm-cli-darwin-arm64 +0 -0
- package/bin/dm-cli-linux-amd64 +0 -0
- package/bin/dm-cli-windows-amd64.exe +0 -0
- package/package.json +1 -1
- package/scripts/_dm-cli +169 -37
- package/scripts/run.js +162 -36
package/README.md
CHANGED
|
@@ -10,8 +10,7 @@ DeepMiner 系统的命令行工具,用于管理认证、配置和 AI 会话。
|
|
|
10
10
|
- **空间管理**: 查看和切换工作空间
|
|
11
11
|
- **配置管理**: API 端点配置
|
|
12
12
|
- **安全存储**: Token 以受限权限存储在本地
|
|
13
|
-
-
|
|
14
|
-
- **AI 会话**: 启动 AI 助手会话,支持自定义消息和 claw_param 参数
|
|
13
|
+
- **AI 会话**: 启动/继续/停止 AI 助手会话,支持自定义消息、文件附件、会话追问和 claw_param 参数
|
|
15
14
|
- **JSON 输出**: 所有命令支持 `--json` 结构化输出,适合 AI agent 和脚本调用
|
|
16
15
|
- **错误提示**: 错误响应包含 `hint` 字段,提供可操作的修复建议
|
|
17
16
|
- **Dry Run**: `--dry-run` 预览 HTTP 请求而不实际执行
|
|
@@ -37,6 +36,18 @@ go build -o dm-cli .
|
|
|
37
36
|
|
|
38
37
|
## 快速开始
|
|
39
38
|
|
|
39
|
+
**方式一:使用 AccessKey(推荐,无需登录)**
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
# 1. 初始化配置(带 AccessKey,无需后续登录和选择空间)
|
|
43
|
+
dm-cli config init --endpoint https://dm-dev.xmingai.com --accesskey <your_access_key>
|
|
44
|
+
|
|
45
|
+
# 2. 直接使用
|
|
46
|
+
dm-cli agent start-thread --message "你好"
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
**方式二:使用用户名密码登录**
|
|
50
|
+
|
|
40
51
|
```bash
|
|
41
52
|
# 1. 初始化配置
|
|
42
53
|
dm-cli config init --endpoint https://dm-dev.xmingai.com
|
|
@@ -49,14 +60,27 @@ dm-cli auth switch <space_id>
|
|
|
49
60
|
|
|
50
61
|
# 4. 查看状态
|
|
51
62
|
dm-cli auth status
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
**通用操作**
|
|
52
66
|
|
|
53
|
-
|
|
67
|
+
```bash
|
|
68
|
+
# 启动 AI 会话(返回 agent_run_id、thread_id)
|
|
54
69
|
dm-cli agent start-thread --message "你好"
|
|
55
70
|
|
|
56
|
-
#
|
|
57
|
-
dm-cli
|
|
71
|
+
# 带文件附件发送
|
|
72
|
+
dm-cli agent start-thread --message "请分析这个报告" --file ./report.ppt
|
|
73
|
+
|
|
74
|
+
# 在已有会话中继续追问
|
|
75
|
+
dm-cli agent start-thread --message "继续聊" --thread-id <thread_id>
|
|
58
76
|
|
|
59
|
-
#
|
|
77
|
+
# 停止正在运行的 Agent
|
|
78
|
+
dm-cli agent stop --agent-run-id <agent_run_id>
|
|
79
|
+
|
|
80
|
+
# 查看用户打开的 agent
|
|
81
|
+
dm-cli agent user-open
|
|
82
|
+
|
|
83
|
+
# 登出(仅用户名密码模式)
|
|
60
84
|
dm-cli auth logout
|
|
61
85
|
```
|
|
62
86
|
|
|
@@ -68,8 +92,8 @@ dm-cli auth logout
|
|
|
68
92
|
dm-cli auth status --json
|
|
69
93
|
# {"ok": true, "data": {"logged_in": true, "user_id": "...", "current_space": "...", ...}}
|
|
70
94
|
|
|
71
|
-
dm-cli
|
|
72
|
-
# {"ok": true, "data": {"
|
|
95
|
+
dm-cli agent start-thread --message "分析" --file ./data.xlsx --json
|
|
96
|
+
# {"ok": true, "data": {"agent_run_id": "...", "thread_id": "...", ...}}
|
|
73
97
|
```
|
|
74
98
|
|
|
75
99
|
## 命令列表
|
|
@@ -77,8 +101,9 @@ dm-cli file upload --file data.xlsx --json
|
|
|
77
101
|
### 配置
|
|
78
102
|
|
|
79
103
|
```bash
|
|
80
|
-
dm-cli config init --endpoint <url>
|
|
81
|
-
dm-cli config
|
|
104
|
+
dm-cli config init --endpoint <url> # 初始化配置(设置 API 端点)
|
|
105
|
+
dm-cli config init --endpoint <url> --accesskey <key> # 初始化配置并设置 AccessKey(无需登录)
|
|
106
|
+
dm-cli config show # 显示当前配置
|
|
82
107
|
```
|
|
83
108
|
|
|
84
109
|
### 认证
|
|
@@ -90,16 +115,24 @@ dm-cli auth status # 显示登录状态
|
|
|
90
115
|
dm-cli auth logout # 退出登录
|
|
91
116
|
```
|
|
92
117
|
|
|
93
|
-
###
|
|
118
|
+
### AI 会话
|
|
94
119
|
|
|
95
120
|
```bash
|
|
96
|
-
dm-cli
|
|
97
|
-
dm-cli
|
|
98
|
-
dm-cli
|
|
99
|
-
dm-cli
|
|
121
|
+
dm-cli agent start-thread --message <消息> # 发送文本消息
|
|
122
|
+
dm-cli agent start-thread --message <消息> --file <路径> # 附带文件
|
|
123
|
+
dm-cli agent start-thread --message <消息> --file <路径1> --file <路径2> # 附带多个文件
|
|
124
|
+
dm-cli agent start-thread --message <消息> --thread-id <会话ID> # 在已有会话中继续追问
|
|
125
|
+
dm-cli agent start-thread --message <消息> --claw-param <JSON> # 附带渠道参数
|
|
126
|
+
dm-cli agent start-thread --message <消息> --agent-mode <模式> # 指定 agent_mode(默认 auto)
|
|
127
|
+
dm-cli agent stop --agent-run-id <运行ID> # 停止正在运行的 Agent
|
|
128
|
+
dm-cli agent user-open # 列出用户打开的 agent
|
|
100
129
|
```
|
|
101
130
|
|
|
102
|
-
####
|
|
131
|
+
#### 文件附件说明
|
|
132
|
+
|
|
133
|
+
使用 `--file` 参数附带本地文件,CLI 会自动上传并拼接到消息中。可多次指定以附带多个文件。
|
|
134
|
+
|
|
135
|
+
**文件大小限制**:
|
|
103
136
|
|
|
104
137
|
| 类型 | 扩展名 | 最大大小 |
|
|
105
138
|
|------|--------|----------|
|
|
@@ -107,14 +140,6 @@ dm-cli file upload --file <路径> --id <ID> # 上传文件(指
|
|
|
107
140
|
| 音频 | mp3/wav/aac | 100 MB |
|
|
108
141
|
| 其他 | * | 300 MB |
|
|
109
142
|
|
|
110
|
-
### AI 会话
|
|
111
|
-
|
|
112
|
-
```bash
|
|
113
|
-
dm-cli agent start-thread # 使用默认消息 "你好"
|
|
114
|
-
dm-cli agent start-thread --message <消息> # 自定义消息
|
|
115
|
-
dm-cli agent start-thread --message <消息> --claw-param <JSON> # 完整参数
|
|
116
|
-
```
|
|
117
|
-
|
|
118
143
|
#### claw_param 参数说明
|
|
119
144
|
|
|
120
145
|
可选的 `--claw-param` 用于指定 DM 系统的渠道和发送者信息:
|
|
@@ -236,13 +261,13 @@ dm-cli/
|
|
|
236
261
|
│ ├── auth/ # 认证命令
|
|
237
262
|
│ ├── config/ # 配置命令
|
|
238
263
|
│ ├── agent/ # AI 命令
|
|
239
|
-
│ ├── file/ # 文件管理命令
|
|
240
264
|
│ └── schema/ # Schema 输出命令
|
|
241
265
|
├── internal/
|
|
242
266
|
│ ├── auth/ # 认证模块
|
|
243
267
|
│ ├── client/ # HTTP 客户端
|
|
244
268
|
│ ├── config/ # 配置管理
|
|
245
269
|
│ ├── cmdutil/ # 命令工具
|
|
270
|
+
│ ├── fileutil/ # 文件上传共享逻辑
|
|
246
271
|
│ ├── output/ # 输出处理
|
|
247
272
|
│ └── validate/ # 输入验证
|
|
248
273
|
├── schema/ # CLI Schema 定义(嵌入)
|
|
@@ -302,7 +327,6 @@ dm-cli <TAB> # 显示所有命令
|
|
|
302
327
|
dm-cli auth <TAB> # 显示 auth 子命令
|
|
303
328
|
dm-cli config <TAB> # 显示 config 子命令
|
|
304
329
|
dm-cli agent <TAB> # 显示 agent 子命令
|
|
305
|
-
dm-cli file <TAB> # 显示 file 子命令
|
|
306
330
|
```
|
|
307
331
|
|
|
308
332
|
## 许可证
|
package/bin/dm-cli-darwin-amd64
CHANGED
|
Binary file
|
package/bin/dm-cli-darwin-arm64
CHANGED
|
Binary file
|
package/bin/dm-cli-linux-amd64
CHANGED
|
Binary file
|
|
Binary file
|
package/package.json
CHANGED
package/scripts/_dm-cli
CHANGED
|
@@ -1,43 +1,175 @@
|
|
|
1
1
|
#compdef dm-cli
|
|
2
2
|
|
|
3
3
|
_dm_cli() {
|
|
4
|
-
local
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
;;
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
4
|
+
local curcontext="$curcontext" state state_descr line
|
|
5
|
+
typeset -A opt_args
|
|
6
|
+
|
|
7
|
+
_arguments -C \
|
|
8
|
+
'--json[以 JSON 格式输出]' \
|
|
9
|
+
'--dry-run[预览请求而不执行]' \
|
|
10
|
+
'(- *)--help[显示帮助]' \
|
|
11
|
+
'(-): :->command' \
|
|
12
|
+
'(-)*:: :->args'
|
|
13
|
+
|
|
14
|
+
case "$state" in
|
|
15
|
+
command)
|
|
16
|
+
local -a commands=(
|
|
17
|
+
'config:管理配置'
|
|
18
|
+
'auth:用户认证'
|
|
19
|
+
'agent:AI 助手相关命令'
|
|
20
|
+
'schema:输出 CLI Schema 定义'
|
|
21
|
+
'version:显示版本号'
|
|
22
|
+
)
|
|
23
|
+
_describe -t commands 'command' commands
|
|
24
|
+
;;
|
|
25
|
+
args)
|
|
26
|
+
case "${line[1]}" in
|
|
27
|
+
config) _dm_cli_config ;;
|
|
28
|
+
auth) _dm_cli_auth ;;
|
|
29
|
+
agent) _dm_cli_agent ;;
|
|
30
|
+
schema) _dm_cli_schema ;;
|
|
31
|
+
esac
|
|
32
|
+
;;
|
|
33
|
+
esac
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
_dm_cli_config() {
|
|
37
|
+
local curcontext="$curcontext" state state_descr line
|
|
38
|
+
typeset -A opt_args
|
|
39
|
+
|
|
40
|
+
_arguments -C \
|
|
41
|
+
'(-): :->subcommand' \
|
|
42
|
+
'(-)*:: :->args'
|
|
43
|
+
|
|
44
|
+
case "$state" in
|
|
45
|
+
subcommand)
|
|
46
|
+
local -a subcommands=(
|
|
47
|
+
'init:初始化配置'
|
|
48
|
+
'show:显示当前配置'
|
|
49
|
+
)
|
|
50
|
+
_describe -t subcommands 'subcommand' subcommands
|
|
51
|
+
;;
|
|
52
|
+
args)
|
|
53
|
+
case "${line[1]}" in
|
|
54
|
+
init)
|
|
55
|
+
_arguments \
|
|
56
|
+
'--endpoint=[API 端点 URL]:url' \
|
|
57
|
+
'--accesskey=[Access Key]:key' \
|
|
58
|
+
'--json[以 JSON 格式输出]' \
|
|
59
|
+
'--dry-run[预览请求]' \
|
|
60
|
+
'--help[显示帮助]'
|
|
61
|
+
;;
|
|
62
|
+
show)
|
|
63
|
+
_arguments \
|
|
64
|
+
'--json[以 JSON 格式输出]' \
|
|
65
|
+
'--dry-run[预览请求]' \
|
|
66
|
+
'--help[显示帮助]'
|
|
67
|
+
;;
|
|
68
|
+
esac
|
|
41
69
|
;;
|
|
42
70
|
esac
|
|
43
71
|
}
|
|
72
|
+
|
|
73
|
+
_dm_cli_auth() {
|
|
74
|
+
local curcontext="$curcontext" state state_descr line
|
|
75
|
+
typeset -A opt_args
|
|
76
|
+
|
|
77
|
+
_arguments -C \
|
|
78
|
+
'(-): :->subcommand' \
|
|
79
|
+
'(-)*:: :->args'
|
|
80
|
+
|
|
81
|
+
case "$state" in
|
|
82
|
+
subcommand)
|
|
83
|
+
local -a subcommands=(
|
|
84
|
+
'login:登录 DM 系统'
|
|
85
|
+
'logout:退出登录'
|
|
86
|
+
'status:显示登录状态'
|
|
87
|
+
'switch:切换空间'
|
|
88
|
+
)
|
|
89
|
+
_describe -t subcommands 'subcommand' subcommands
|
|
90
|
+
;;
|
|
91
|
+
args)
|
|
92
|
+
case "${line[1]}" in
|
|
93
|
+
login)
|
|
94
|
+
_arguments \
|
|
95
|
+
'--username=[用户名]:username' \
|
|
96
|
+
'--password=[密码]:password' \
|
|
97
|
+
'--json[以 JSON 格式输出]' \
|
|
98
|
+
'--dry-run[预览请求]' \
|
|
99
|
+
'--help[显示帮助]'
|
|
100
|
+
;;
|
|
101
|
+
logout|status)
|
|
102
|
+
_arguments \
|
|
103
|
+
'--json[以 JSON 格式输出]' \
|
|
104
|
+
'--dry-run[预览请求]' \
|
|
105
|
+
'--help[显示帮助]'
|
|
106
|
+
;;
|
|
107
|
+
switch)
|
|
108
|
+
_arguments \
|
|
109
|
+
'1:space_id' \
|
|
110
|
+
'--json[以 JSON 格式输出]' \
|
|
111
|
+
'--dry-run[预览请求]' \
|
|
112
|
+
'--help[显示帮助]'
|
|
113
|
+
;;
|
|
114
|
+
esac
|
|
115
|
+
;;
|
|
116
|
+
esac
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
_dm_cli_agent() {
|
|
120
|
+
local curcontext="$curcontext" state state_descr line
|
|
121
|
+
typeset -A opt_args
|
|
122
|
+
|
|
123
|
+
_arguments -C \
|
|
124
|
+
'(-): :->subcommand' \
|
|
125
|
+
'(-)*:: :->args'
|
|
126
|
+
|
|
127
|
+
case "$state" in
|
|
128
|
+
subcommand)
|
|
129
|
+
local -a subcommands=(
|
|
130
|
+
'start-thread:发起 AI 会话'
|
|
131
|
+
'stop:停止 Agent 运行'
|
|
132
|
+
'user-open:列出用户打开的 agent'
|
|
133
|
+
)
|
|
134
|
+
_describe -t subcommands 'subcommand' subcommands
|
|
135
|
+
;;
|
|
136
|
+
args)
|
|
137
|
+
case "${line[1]}" in
|
|
138
|
+
start-thread)
|
|
139
|
+
_arguments \
|
|
140
|
+
'--message=[消息内容]:message' \
|
|
141
|
+
'*--file=[本地文件路径]:file:_files' \
|
|
142
|
+
'--agent-mode=[Agent 模式]:mode:(auto cooperation)' \
|
|
143
|
+
'--thread-id=[会话 ID]:thread_id' \
|
|
144
|
+
'--claw-param=[JSON 参数]:json' \
|
|
145
|
+
'--json[以 JSON 格式输出]' \
|
|
146
|
+
'--dry-run[预览请求]' \
|
|
147
|
+
'--help[显示帮助]'
|
|
148
|
+
;;
|
|
149
|
+
stop)
|
|
150
|
+
_arguments \
|
|
151
|
+
'--agent-run-id=[Agent 运行 ID]:run_id' \
|
|
152
|
+
'--json[以 JSON 格式输出]' \
|
|
153
|
+
'--dry-run[预览请求]' \
|
|
154
|
+
'--help[显示帮助]'
|
|
155
|
+
;;
|
|
156
|
+
user-open)
|
|
157
|
+
_arguments \
|
|
158
|
+
'--json[以 JSON 格式输出]' \
|
|
159
|
+
'--dry-run[预览请求]' \
|
|
160
|
+
'--help[显示帮助]'
|
|
161
|
+
;;
|
|
162
|
+
esac
|
|
163
|
+
;;
|
|
164
|
+
esac
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
_dm_cli_schema() {
|
|
168
|
+
_arguments \
|
|
169
|
+
'--pretty[格式化输出 JSON]' \
|
|
170
|
+
'--json[以 JSON 格式输出]' \
|
|
171
|
+
'--dry-run[预览请求]' \
|
|
172
|
+
'--help[显示帮助]'
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
_dm_cli "$@"
|
package/scripts/run.js
CHANGED
|
@@ -4,6 +4,9 @@ const { spawn, execSync } = require('child_process');
|
|
|
4
4
|
const path = require('path');
|
|
5
5
|
const os = require('os');
|
|
6
6
|
const fs = require('fs');
|
|
7
|
+
const https = require('https');
|
|
8
|
+
|
|
9
|
+
const pkg = require('../package.json');
|
|
7
10
|
|
|
8
11
|
const platform = os.platform();
|
|
9
12
|
const arch = os.arch();
|
|
@@ -32,47 +35,170 @@ const isWindows = platform === 'win32';
|
|
|
32
35
|
const binaryName = `dm-cli-${stdPlatform}-${stdArch}${isWindows ? '.exe' : ''}`;
|
|
33
36
|
const binaryPath = path.join(__dirname, '..', 'bin', binaryName);
|
|
34
37
|
|
|
35
|
-
//
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
38
|
+
// --- Auto-update logic ---
|
|
39
|
+
|
|
40
|
+
const UPDATE_CHECK_INTERVAL = 60 * 60 * 1000; // 1 hour
|
|
41
|
+
const CACHE_DIR = path.join(os.homedir(), '.dm-cli');
|
|
42
|
+
const CACHE_FILE = path.join(CACHE_DIR, '.update-check');
|
|
43
|
+
|
|
44
|
+
function readCache() {
|
|
45
|
+
try {
|
|
46
|
+
const data = JSON.parse(fs.readFileSync(CACHE_FILE, 'utf-8'));
|
|
47
|
+
return data;
|
|
48
|
+
} catch {
|
|
49
|
+
return null;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function writeCache(latest) {
|
|
54
|
+
try {
|
|
55
|
+
if (!fs.existsSync(CACHE_DIR)) {
|
|
56
|
+
fs.mkdirSync(CACHE_DIR, { recursive: true });
|
|
47
57
|
}
|
|
58
|
+
fs.writeFileSync(CACHE_FILE, JSON.stringify({
|
|
59
|
+
checkedAt: Date.now(),
|
|
60
|
+
latest
|
|
61
|
+
}));
|
|
62
|
+
} catch {
|
|
63
|
+
// silent
|
|
48
64
|
}
|
|
49
|
-
} catch (e) {
|
|
50
|
-
// Silent fail
|
|
51
65
|
}
|
|
52
66
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
67
|
+
function fetchLatestVersion() {
|
|
68
|
+
return new Promise((resolve, reject) => {
|
|
69
|
+
const req = https.get('https://registry.npmjs.org/deepminer-cli/latest', { timeout: 5000 }, res => {
|
|
70
|
+
let data = '';
|
|
71
|
+
res.on('data', chunk => data += chunk);
|
|
72
|
+
res.on('end', () => {
|
|
73
|
+
try {
|
|
74
|
+
resolve(JSON.parse(data).version);
|
|
75
|
+
} catch {
|
|
76
|
+
reject(new Error('parse error'));
|
|
77
|
+
}
|
|
78
|
+
});
|
|
79
|
+
});
|
|
80
|
+
req.on('error', reject);
|
|
81
|
+
req.on('timeout', () => { req.destroy(); reject(new Error('timeout')); });
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
function compareVersions(a, b) {
|
|
86
|
+
const pa = a.split('.').map(Number);
|
|
87
|
+
const pb = b.split('.').map(Number);
|
|
88
|
+
for (let i = 0; i < 3; i++) {
|
|
89
|
+
if ((pa[i] || 0) < (pb[i] || 0)) return -1;
|
|
90
|
+
if ((pa[i] || 0) > (pb[i] || 0)) return 1;
|
|
64
91
|
}
|
|
65
|
-
|
|
66
|
-
}
|
|
92
|
+
return 0;
|
|
93
|
+
}
|
|
67
94
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
95
|
+
function doUpdate() {
|
|
96
|
+
console.error(`⬆️ 正在自动更新 dm-cli ...`);
|
|
97
|
+
try {
|
|
98
|
+
execSync('npm install -g deepminer-cli', { stdio: 'inherit', timeout: 60000 });
|
|
99
|
+
console.error(`✅ dm-cli 已更新到最新版本`);
|
|
100
|
+
return true;
|
|
101
|
+
} catch {
|
|
102
|
+
console.error(`⚠️ 自动更新失败,继续使用当前版本`);
|
|
103
|
+
return false;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
71
106
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
107
|
+
async function checkAndUpdate() {
|
|
108
|
+
const currentVersion = pkg.version;
|
|
109
|
+
|
|
110
|
+
// Check cache first
|
|
111
|
+
const cache = readCache();
|
|
112
|
+
if (cache && (Date.now() - cache.checkedAt) < UPDATE_CHECK_INTERVAL) {
|
|
113
|
+
// Within cache window, use cached result
|
|
114
|
+
if (cache.latest && compareVersions(currentVersion, cache.latest) < 0) {
|
|
115
|
+
return doUpdate();
|
|
116
|
+
}
|
|
117
|
+
return false;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// Fetch latest version from npm
|
|
121
|
+
try {
|
|
122
|
+
const latest = await fetchLatestVersion();
|
|
123
|
+
writeCache(latest);
|
|
124
|
+
if (compareVersions(currentVersion, latest) < 0) {
|
|
125
|
+
return doUpdate();
|
|
126
|
+
}
|
|
127
|
+
} catch {
|
|
128
|
+
// Network error, skip update check
|
|
129
|
+
}
|
|
130
|
+
return false;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// --- Main execution ---
|
|
134
|
+
|
|
135
|
+
async function main() {
|
|
136
|
+
// Skip update check for version/help commands or if DM_CLI_NO_UPDATE is set
|
|
137
|
+
const args = process.argv.slice(2);
|
|
138
|
+
const skipUpdate = process.env.DM_CLI_NO_UPDATE === '1'
|
|
139
|
+
|| args.includes('version')
|
|
140
|
+
|| args.includes('--help')
|
|
141
|
+
|| args.includes('-h');
|
|
142
|
+
|
|
143
|
+
if (!skipUpdate) {
|
|
144
|
+
const updated = await checkAndUpdate();
|
|
145
|
+
if (updated) {
|
|
146
|
+
// After update, re-exec with the new binary
|
|
147
|
+
const child = spawn(process.argv[0], process.argv.slice(1), {
|
|
148
|
+
stdio: 'inherit',
|
|
149
|
+
env: { ...process.env, DM_CLI_NO_UPDATE: '1' },
|
|
150
|
+
windowsHide: true
|
|
151
|
+
});
|
|
152
|
+
child.on('exit', code => process.exit(code || 0));
|
|
153
|
+
child.on('error', () => process.exit(1));
|
|
154
|
+
return;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
// Ensure symlink exists on first run (for global installs)
|
|
159
|
+
try {
|
|
160
|
+
const npmPrefix = execSync('npm config get prefix', { encoding: 'utf-8', stdio: 'pipe' }).trim();
|
|
161
|
+
const npmBinDir = path.join(npmPrefix, 'bin');
|
|
162
|
+
const npmBinPath = path.join(npmBinDir, 'dm-cli');
|
|
163
|
+
const thisFile = __filename;
|
|
164
|
+
|
|
165
|
+
if (!fs.existsSync(npmBinPath) && platform !== 'win32') {
|
|
166
|
+
try {
|
|
167
|
+
execSync(`ln -sf "${thisFile}" "${npmBinPath}"`, { stdio: 'ignore' });
|
|
168
|
+
} catch (e) {
|
|
169
|
+
// Silent fail
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
} catch (e) {
|
|
173
|
+
// Silent fail
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
// Spawn the binary and forward all arguments
|
|
177
|
+
const child = spawn(binaryPath, args, {
|
|
178
|
+
stdio: 'inherit',
|
|
179
|
+
windowsHide: true
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
child.on('error', (err) => {
|
|
183
|
+
if (err.code === 'ENOENT') {
|
|
184
|
+
console.error(`❌ Binary not found: ${binaryPath}`);
|
|
185
|
+
} else {
|
|
186
|
+
console.error(`❌ Error: ${err.message}`);
|
|
187
|
+
}
|
|
188
|
+
process.exit(1);
|
|
189
|
+
});
|
|
190
|
+
|
|
191
|
+
process.on('SIGINT', () => {
|
|
192
|
+
child.kill('SIGINT');
|
|
193
|
+
});
|
|
194
|
+
|
|
195
|
+
process.on('SIGTERM', () => {
|
|
196
|
+
child.kill('SIGTERM');
|
|
197
|
+
});
|
|
198
|
+
|
|
199
|
+
child.on('exit', (code) => {
|
|
200
|
+
process.exit(code);
|
|
201
|
+
});
|
|
202
|
+
}
|
|
75
203
|
|
|
76
|
-
|
|
77
|
-
process.exit(code);
|
|
78
|
-
});
|
|
204
|
+
main();
|