ethan-skill 1.15.0 → 1.15.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/CHANGELOG.md +47 -0
- package/README.md +31 -8
- package/dist/cli/index.js +95 -12
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/update-check.d.ts +8 -1
- package/dist/cli/update-check.d.ts.map +1 -1
- package/dist/cli/update-check.js +86 -11
- package/dist/cli/update-check.js.map +1 -1
- package/dist/mcp/server.d.ts.map +1 -1
- package/dist/mcp/server.js +61 -1
- package/dist/mcp/server.js.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,53 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
|
|
5
|
+
## [1.15.0] - 2026-04-12
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
|
|
9
|
+
- **`ethan upgrade` 显式升级命令**(新增 CLI):
|
|
10
|
+
- 前台执行,有实时输出(`stdio: 'inherit'`)
|
|
11
|
+
- 支持 `--force` 选项跳过版本比较强制重装
|
|
12
|
+
- 成功:清除缓存并提示重启终端;失败:显示明确错误与手动命令
|
|
13
|
+
- 不再依赖静默后台升级的黑盒机制
|
|
14
|
+
|
|
15
|
+
- **新 MCP 工具 `ethan_upgrade`**(30 → **31**):
|
|
16
|
+
- 通过 Claude Desktop 查询当前版本状态、npm 最新版本与升级缓存信息
|
|
17
|
+
- 输出升级指引(终端命令),MCP 环境下无法直接执行 npm,提供可操作指令
|
|
18
|
+
|
|
19
|
+
- **自动升级启动 banner**(`printUpdateBanner`):
|
|
20
|
+
- 检测到新版本时,在命令输出前打印一行可见提示:
|
|
21
|
+
```
|
|
22
|
+
📦 ethan v{latest} 可用(当前 v{current})— 运行 ethan upgrade 立即更新
|
|
23
|
+
```
|
|
24
|
+
- 使用缓存(24h 内)时同步输出,不增加延迟
|
|
25
|
+
|
|
26
|
+
- **`ethan doctor` 版本更新状态节**:
|
|
27
|
+
- 显示当前版本、npm 最新版、上次检查时间
|
|
28
|
+
- 有新版本时提示 `ethan upgrade`,已最新时显示 ✅
|
|
29
|
+
|
|
30
|
+
### Fixed
|
|
31
|
+
|
|
32
|
+
- **自动升级永不重试 Bug**:
|
|
33
|
+
- 根因:`upgradedVersion` 在 spawn 成功(不等于 npm install 成功)后立即写入缓存,若后台 npm 进程静默失败,下次检查时 `upgradedVersion === latest` 导致永久跳过
|
|
34
|
+
- 修复:增加条件 `&& !compareVersions(currentVersion, latest)`,若当前版本仍低于 latest(说明升级失败),则重新触发
|
|
35
|
+
|
|
36
|
+
- **后台升级失败完全静默**:
|
|
37
|
+
- spawn 失败(npm 不在 PATH):原先 `catch` 静默返回;修复后在进程退出时打印 `⚠️ 找不到 npm` 提示
|
|
38
|
+
- spawn 成功但子进程立即报错(如 EACCES 权限):新增 `child.on('error', ...)` 监听并打印提示
|
|
39
|
+
|
|
40
|
+
- **Windows 下 npm 查找失败**:
|
|
41
|
+
- detached spawn 在 Windows 未启用 shell 模式,部分 nvm-windows 环境下 npm 无法找到
|
|
42
|
+
- 修复:Windows 平台启用 `shell: true`
|
|
43
|
+
|
|
44
|
+
### Changed
|
|
45
|
+
|
|
46
|
+
- 自动升级退出消息措辞调整:
|
|
47
|
+
- 旧:`🔄 Ethan 正在后台自动升级到 v{latest},重启终端后生效。`
|
|
48
|
+
- 新:`🔄 Ethan 正在后台升级到 v{latest},完成后重启终端生效。`
|
|
49
|
+
|
|
50
|
+
---
|
|
51
|
+
|
|
5
52
|
## [1.14.0] - 2026-04-09
|
|
6
53
|
|
|
7
54
|
### Added
|
package/README.md
CHANGED
|
@@ -17,10 +17,10 @@
|
|
|
17
17
|
| **36 个 Skill** | 标准化工作流节点,覆盖需求→接口设计→安全→部署→PRD→Git→测试→系统设计→数据库→Docker→CI/CD→性能→重构→可观测性→设计模式→OpenSpec→技术债→Mock→数据迁移→LLM设计→威胁建模→绿色编码→服务目录→移动审查→数据管道→ML实验 |
|
|
18
18
|
| **11 个平台** | Cursor / Copilot / Cline / Windsurf / Zed / JetBrains / Continue / Claude Code 等 |
|
|
19
19
|
| **10 个 Pipeline** | 链式工作流(开发 / 汇报 / 质量 / 完整周期 / 故障响应 / 新功能 / Spec规范 / Bug修复 / 安全审计 / 开源发布),有状态持久化推进 |
|
|
20
|
-
| **
|
|
20
|
+
| **31 个 MCP 工具** | AI 编辑器原生调用 Skill、Pipeline、Git、记忆库、估算、DORA 指标、PR 分析、故障复盘、脚手架、合规证据、版本升级检查 |
|
|
21
21
|
| **60+ CLI 命令** | Git 集成、开发工具、记忆库、估算、分析工具(diff/deps/dora/mermaid/adr/i18n/migrate/onboard/compliance 等)、插件 OS 全覆盖 |
|
|
22
22
|
| **Slash 命令生成** | `ethan slash` 一键为 Claude Code 生成 `/ethan-xxx` 原生命令,其他平台生成速查表 |
|
|
23
|
-
| **自动升级** |
|
|
23
|
+
| **自动升级** | 启动时显示新版本 banner,自动后台 `npm install -g` 升级;失败时显示明确提示;支持 `ethan upgrade [--force]` 手动显式升级 |
|
|
24
24
|
| **自定义 Skill** | `.ethan/skills/*.yaml/.md`,YAML frontmatter + Markdown body |
|
|
25
25
|
| **自定义 Pipeline** | `.ethan/pipelines/*.yaml`,引用内置或自定义 Skill 自由组合 |
|
|
26
26
|
| **浏览器扩展** | Chrome/Edge MV3,GitHub PR 一键 Review + 右键菜单 |
|
|
@@ -122,7 +122,7 @@ npx ethan-skill install --platform cursor --lang en
|
|
|
122
122
|
}
|
|
123
123
|
```
|
|
124
124
|
|
|
125
|
-
重启 AI 编辑器后,可使用全部 **
|
|
125
|
+
重启 AI 编辑器后,可使用全部 **31 个 MCP 工具**(详见下方 MCP 工具列表)。
|
|
126
126
|
|
|
127
127
|
### 方式三:全局安装
|
|
128
128
|
|
|
@@ -347,17 +347,38 @@ ethan slash
|
|
|
347
347
|
|
|
348
348
|
## 自动升级
|
|
349
349
|
|
|
350
|
-
Ethan 每次启动都会静默检查 npm 最新版本(24h 缓存,不阻塞 CLI
|
|
350
|
+
Ethan 每次启动都会静默检查 npm 最新版本(24h 缓存,不阻塞 CLI)。检测到新版本后:
|
|
351
351
|
|
|
352
|
+
1. **命令执行前**显示 banner 提醒:
|
|
353
|
+
```
|
|
354
|
+
📦 ethan v{latest} 可用(当前 v{current})— 运行 ethan upgrade 立即更新
|
|
355
|
+
```
|
|
356
|
+
|
|
357
|
+
2. **自动在后台**执行 `npm install -g ethan-skill@latest`,退出时显示:
|
|
358
|
+
```
|
|
359
|
+
🔄 Ethan 正在后台升级到 v{latest},完成后重启终端生效。
|
|
360
|
+
```
|
|
361
|
+
|
|
362
|
+
3. **失败时给出明确提示**(权限不足、npm 找不到等),不再静默忽略
|
|
363
|
+
|
|
364
|
+
4. **智能重试**:若后台升级静默失败,下次启动自动重试(不会被缓存永久阻断)
|
|
365
|
+
|
|
366
|
+
### 手动显式升级
|
|
367
|
+
|
|
368
|
+
```bash
|
|
369
|
+
ethan upgrade # 查询最新版本并升级(有实时输出)
|
|
370
|
+
ethan upgrade --force # 跳过版本比较,强制重新安装
|
|
352
371
|
```
|
|
353
|
-
🔄 Ethan 正在后台自动升级到 v{latest},重启终端后生效。
|
|
354
|
-
```
|
|
355
372
|
|
|
356
|
-
|
|
373
|
+
### MCP 版本查询(Claude Desktop 用户)
|
|
374
|
+
|
|
375
|
+
```
|
|
376
|
+
调用 ethan_upgrade 工具查看当前版本状态与升级建议
|
|
377
|
+
```
|
|
357
378
|
|
|
358
379
|
---
|
|
359
380
|
|
|
360
|
-
##
|
|
381
|
+
## 31 个 MCP 工具
|
|
361
382
|
|
|
362
383
|
配置 MCP Server 后,AI 编辑器(Cursor / Cline / Continue 等)可直接调用:
|
|
363
384
|
|
|
@@ -394,6 +415,7 @@ Ethan 每次启动都会静默检查 npm 最新版本(24h 缓存,不阻塞 C
|
|
|
394
415
|
| `ethan_postmortem` | 生成故障复盘提示词(v1.12.0 新增)|
|
|
395
416
|
| `ethan_scaffold` | 黄金路径脚手架提示词(v1.12.0 新增)|
|
|
396
417
|
| `ethan_compliance` | 生成合规证据收集清单(soc2/gdpr/iso27001,v1.12.0 新增)|
|
|
418
|
+
| `ethan_upgrade` | 检查版本状态,输出当前版本/最新版本/升级指引(v1.15.0 新增)|
|
|
397
419
|
|
|
398
420
|
---
|
|
399
421
|
|
|
@@ -552,6 +574,7 @@ npm run test:coverage # 覆盖率报告
|
|
|
552
574
|
|
|
553
575
|
| 版本 | 主要变更 |
|
|
554
576
|
|------|---------|
|
|
577
|
+
| **v1.15.0** | 自动升级全面增强:启动 banner 提醒、智能重试(失败后不永久阻断)、错误明确提示;新增 `ethan upgrade [--force]` 显式升级命令;新增 MCP 工具 `ethan_upgrade`;`ethan doctor` 新增版本更新状态节;MCP 工具 30 → 31 |
|
|
555
578
|
| **v1.14.0** | 新增 3 个专业化 Agent(qa/security/data),内置 Agent 5 → 8;新增 4 种协作模式(`--mode sequential/parallel/review-loop/consensus`);新增 `ethan agent new` 交互式创建自定义 Agent;新增 MCP 工具 `ethan_agent_list/show`,MCP 工具 28 → 30 |
|
|
556
579
|
| **v1.13.0** | Multi-Agent 编排系统(`src/agents/`);5 个内置角色 Agent(architect/coder/reviewer/devops/pm);新增 `ethan agent list/show/run` CLI;新增 MCP 工具 `ethan_agent_orchestrate`;MCP 工具 27 → 28;新增宣传落地页 `docs/landing.html` |
|
|
557
580
|
| **v1.12.0** | 新增 10 个 Skill(技术债/Mock服务/数据迁移/LLM设计/威胁建模/绿色编码/服务目录/移动审查/数据管道/ML实验);Skills 26 → 36;新增 3 条 Pipeline(bugfix/security-audit/open-source-release);新增 19 个分析 CLI 命令(diff/deps/dora/adr/mermaid/i18n/onboard/migrate/postmortem/decision-log/knowledge/oss/prompt-lib/scaffold/benchmark/sync/compliance 等);MCP 工具 22 → 27 |
|
package/dist/cli/index.js
CHANGED
|
@@ -628,11 +628,11 @@ program
|
|
|
628
628
|
const platformDirMap = {
|
|
629
629
|
'claude-code': path.join(dir, '.claude/commands'),
|
|
630
630
|
codebuddy: path.join(dir, '.codebuddy/commands'),
|
|
631
|
-
cursor: path.join(dir, '.cursor/
|
|
631
|
+
cursor: path.join(dir, '.cursor/commands'), // v0.50+ 支持独立命令文件
|
|
632
|
+
cline: path.join(dir, '.cline/commands'), // 支持独立命令文件
|
|
633
|
+
windsurf: path.join(dir, '.windsurf/commands'), // Wave 6+ 支持独立命令文件
|
|
632
634
|
copilot: path.join(dir, '.github'),
|
|
633
|
-
|
|
634
|
-
windsurf: path.join(dir, '.windsurf/rules'),
|
|
635
|
-
zed: dir,
|
|
635
|
+
zed: path.join(dir, '.zed/prompts'), // /prompt 机制,独立 .md 文件
|
|
636
636
|
jetbrains: path.join(dir, '.github'),
|
|
637
637
|
continue: dir,
|
|
638
638
|
lingma: path.join(dir, '.lingma/rules'),
|
|
@@ -642,9 +642,11 @@ program
|
|
|
642
642
|
const outDir = platformDirMap[p];
|
|
643
643
|
if (!fs.existsSync(outDir))
|
|
644
644
|
fs.mkdirSync(outDir, { recursive: true });
|
|
645
|
-
|
|
645
|
+
// 支持独立命令文件的平台:claude-code / codebuddy / cursor / cline / windsurf
|
|
646
|
+
const INDIVIDUAL_FILE_PLATFORMS = ['claude-code', 'codebuddy', 'cursor', 'cline', 'windsurf'];
|
|
647
|
+
if (INDIVIDUAL_FILE_PLATFORMS.includes(p)) {
|
|
646
648
|
const isClaudeCode = p === 'claude-code';
|
|
647
|
-
const cmdDir =
|
|
649
|
+
const cmdDir = path.relative(dir, outDir); // 用于日志展示
|
|
648
650
|
// ── 每个 Skill 生成独立 .md slash 命令文件 ──────────────────────────────
|
|
649
651
|
for (const skill of skills) {
|
|
650
652
|
const stepsText = skill.steps
|
|
@@ -752,7 +754,7 @@ program
|
|
|
752
754
|
console.log(` ✅ claude-code → 工作流: ${cmdDir}/ethan-{cmd}.md × ${WORKFLOW_SLASH_COMMANDS.length}`);
|
|
753
755
|
console.log(` 使用方式:在 Claude Code 聊天中输入 /ethan-commit、/ethan-auto 等`);
|
|
754
756
|
console.log(` ⚡ 动态注入:提示词自动注入对话,无需复制粘贴`);
|
|
755
|
-
// ── Agent 命令(Claude Code
|
|
757
|
+
// ── Agent 命令(Claude Code:每个 Agent 一个动态 .md 文件)─────────────
|
|
756
758
|
const { getActiveAgents } = await Promise.resolve().then(() => __importStar(require('../agents/index')));
|
|
757
759
|
const agents = getActiveAgents(dir);
|
|
758
760
|
// ethan-agent-list.md
|
|
@@ -767,7 +769,7 @@ program
|
|
|
767
769
|
const agentNewContent = `---\ndescription: "Ethan — 创建自定义 Agent,生成 .ethan/agents/<id>.yaml"\n---\n\n` +
|
|
768
770
|
`$(ethan agent new $ARGUMENTS 2>/dev/null)\n`;
|
|
769
771
|
fs.writeFileSync(path.join(outDir, 'ethan-agent-new.md'), agentNewContent, 'utf-8');
|
|
770
|
-
// 每个内置 Agent
|
|
772
|
+
// 每个内置 Agent 生成独立快捷命令(动态)
|
|
771
773
|
let agentFileCount = 3;
|
|
772
774
|
for (const agent of agents) {
|
|
773
775
|
const agentSkillList = agent.skillIds.slice(0, 8).join('、') + (agent.skillIds.length > 8 ? '...' : '');
|
|
@@ -780,7 +782,7 @@ program
|
|
|
780
782
|
console.log(` ✅ claude-code → Agents: ${cmdDir}/ethan-agent-*.md × ${agentFileCount}(含 ${agents.length} 个 Agent 快捷键)`);
|
|
781
783
|
}
|
|
782
784
|
else {
|
|
783
|
-
//
|
|
785
|
+
// codebuddy / cursor / cline / windsurf:静态提示词(各 /ethan-xxx 命令文件)
|
|
784
786
|
for (const cmd of WORKFLOW_SLASH_COMMANDS) {
|
|
785
787
|
const content = `---\n` +
|
|
786
788
|
`description: "Ethan — ${cmd.name}:${cmd.description}"\n` +
|
|
@@ -789,8 +791,45 @@ program
|
|
|
789
791
|
fs.writeFileSync(path.join(outDir, `ethan-${cmd.id}.md`), content, 'utf-8');
|
|
790
792
|
total++;
|
|
791
793
|
}
|
|
792
|
-
console.log(` ✅
|
|
793
|
-
console.log(` 使用方式:在
|
|
794
|
+
console.log(` ✅ ${p.padEnd(12)} → 工作流: ${cmdDir}/ethan-{cmd}.md × ${WORKFLOW_SLASH_COMMANDS.length}`);
|
|
795
|
+
console.log(` 使用方式:在 ${p} 聊天中输入 /ethan-commit、/ethan-auto 等`);
|
|
796
|
+
// ── Agent 命令(静态提示词,适用于 codebuddy/cursor/cline/windsurf)──────
|
|
797
|
+
const { getActiveAgents: getAgentsStatic } = await Promise.resolve().then(() => __importStar(require('../agents/index')));
|
|
798
|
+
const agentsStatic = getAgentsStatic(dir);
|
|
799
|
+
// ethan-agent-list.md(静态)
|
|
800
|
+
const agentListRows = agentsStatic
|
|
801
|
+
.map((a) => `| /ethan-agent-${a.id} | ${a.emoji} ${a.name} | ${a.role} |`)
|
|
802
|
+
.join('\n');
|
|
803
|
+
fs.writeFileSync(path.join(outDir, 'ethan-agent-list.md'), `---\ndescription: "Ethan — 查看所有可用 Agent 及其 Skill 分配"\n---\n\n` +
|
|
804
|
+
`# Ethan Agent 列表\n\n` +
|
|
805
|
+
`| 命令 | Agent | 职责 |\n|------|-------|------|\n${agentListRows}\n\n` +
|
|
806
|
+
`运行:\`ethan agent list\`\n`, 'utf-8');
|
|
807
|
+
// ethan-agent-run.md(静态)
|
|
808
|
+
fs.writeFileSync(path.join(outDir, 'ethan-agent-run.md'), `---\ndescription: "Ethan — Multi-Agent 编排:将任务分配给多个专业 Agent 协作执行"\n---\n\n` +
|
|
809
|
+
`# Ethan Multi-Agent 编排\n\n` +
|
|
810
|
+
`用法:\`ethan agent run <pipeline> -c "任务描述"\`\n\n` +
|
|
811
|
+
`示例:\`ethan agent run dev-workflow -c "实现用户登录功能"\`\n\n` +
|
|
812
|
+
`可用模式:sequential / parallel / review-loop / consensus\n`, 'utf-8');
|
|
813
|
+
// ethan-agent-new.md(静态)
|
|
814
|
+
fs.writeFileSync(path.join(outDir, 'ethan-agent-new.md'), `---\ndescription: "Ethan — 创建自定义 Agent,生成 .ethan/agents/<id>.yaml"\n---\n\n` +
|
|
815
|
+
`# 创建自定义 Agent\n\n` +
|
|
816
|
+
`运行:\`ethan agent new\`\n\n` +
|
|
817
|
+
`将在 \`.ethan/agents/\` 目录下生成 Agent 配置文件。\n`, 'utf-8');
|
|
818
|
+
// 每个内置 Agent 生成独立静态命令文件
|
|
819
|
+
let staticAgentFileCount = 3;
|
|
820
|
+
for (const agent of agentsStatic) {
|
|
821
|
+
const agentSkillList = agent.skillIds.slice(0, 8).join('、') + (agent.skillIds.length > 8 ? '...' : '');
|
|
822
|
+
const agentContent = `---\ndescription: "Ethan — ${agent.emoji} ${agent.name}:${agent.role}"\n---\n\n` +
|
|
823
|
+
`# ${agent.emoji} ${agent.name}\n\n` +
|
|
824
|
+
`**职责**: ${agent.role}\n\n` +
|
|
825
|
+
`**负责 Skill**: ${agentSkillList}\n\n` +
|
|
826
|
+
`**运行方式**:\`ethan agent run --no-copy -c "<任务描述>"\`\n\n` +
|
|
827
|
+
`**示例**:\`ethan agent run --no-copy -c "对当前代码进行安全审查"\`\n`;
|
|
828
|
+
fs.writeFileSync(path.join(outDir, `ethan-agent-${agent.id}.md`), agentContent, 'utf-8');
|
|
829
|
+
staticAgentFileCount++;
|
|
830
|
+
total++;
|
|
831
|
+
}
|
|
832
|
+
console.log(` ✅ ${p.padEnd(12)} → Agents: ${cmdDir}/ethan-agent-*.md × ${staticAgentFileCount}(含 ${agentsStatic.length} 个 Agent 快捷键)`);
|
|
794
833
|
}
|
|
795
834
|
}
|
|
796
835
|
else {
|
|
@@ -861,7 +900,8 @@ program
|
|
|
861
900
|
total++;
|
|
862
901
|
}
|
|
863
902
|
}
|
|
864
|
-
const
|
|
903
|
+
const INDIVIDUAL_FILE_PLATFORMS_CHECK = ['claude-code', 'codebuddy', 'cursor', 'cline', 'windsurf'];
|
|
904
|
+
const totalFiles = INDIVIDUAL_FILE_PLATFORMS_CHECK.includes(platform)
|
|
865
905
|
? skills.length + WORKFLOW_SLASH_COMMANDS.length
|
|
866
906
|
: total;
|
|
867
907
|
console.log(`\n共生成 ${totalFiles} 个 Slash 命令文件(目录:${dir})`);
|
|
@@ -1295,6 +1335,15 @@ pipelineCmd
|
|
|
1295
1335
|
}
|
|
1296
1336
|
writeStats(stats);
|
|
1297
1337
|
});
|
|
1338
|
+
// ─── upgrade 命令 ───────────────────────────────────────────────────────────
|
|
1339
|
+
program
|
|
1340
|
+
.command('upgrade')
|
|
1341
|
+
.description('检查并升级到最新版本')
|
|
1342
|
+
.option('--force', '跳过版本检查,强制重新安装最新版本')
|
|
1343
|
+
.action(async (options) => {
|
|
1344
|
+
const { checkAndPrintUpdate } = await Promise.resolve().then(() => __importStar(require('./update-check')));
|
|
1345
|
+
await checkAndPrintUpdate(pkg.version, pkg.name, options.force ?? false);
|
|
1346
|
+
});
|
|
1298
1347
|
// ─── doctor 命令 ────────────────────────────────────────────────────────────
|
|
1299
1348
|
program
|
|
1300
1349
|
.command('doctor')
|
|
@@ -1373,6 +1422,40 @@ program
|
|
|
1373
1422
|
}
|
|
1374
1423
|
console.log('\n' + '─'.repeat(60));
|
|
1375
1424
|
const allBuilt = ruleFiles.every(({ file }) => fs.existsSync(path.join(ROOT, file)));
|
|
1425
|
+
// 版本更新状态检查
|
|
1426
|
+
console.log(`\n[版本更新状态]`);
|
|
1427
|
+
console.log(` 当前版本 : v${pkg.version}`);
|
|
1428
|
+
const updateCachePath = path.join(os.homedir(), '.ethan-update-cache.json');
|
|
1429
|
+
if (fs.existsSync(updateCachePath)) {
|
|
1430
|
+
try {
|
|
1431
|
+
const updateCache = JSON.parse(fs.readFileSync(updateCachePath, 'utf-8'));
|
|
1432
|
+
const lastCheckedAgo = Math.round((Date.now() - updateCache.lastChecked) / 1000 / 60);
|
|
1433
|
+
console.log(` npm 最新版 : v${updateCache.latestVersion}`);
|
|
1434
|
+
console.log(` 上次检查 : ${lastCheckedAgo} 分钟前`);
|
|
1435
|
+
const needsUpdate = (() => {
|
|
1436
|
+
const parse = (v) => v.replace(/^v/, '').split('.').map(Number);
|
|
1437
|
+
const [cMaj, cMin, cPat] = parse(pkg.version);
|
|
1438
|
+
const [lMaj, lMin, lPat] = parse(updateCache.latestVersion);
|
|
1439
|
+
if (lMaj !== cMaj)
|
|
1440
|
+
return lMaj > cMaj;
|
|
1441
|
+
if (lMin !== cMin)
|
|
1442
|
+
return lMin > cMin;
|
|
1443
|
+
return lPat > cPat;
|
|
1444
|
+
})();
|
|
1445
|
+
if (needsUpdate) {
|
|
1446
|
+
console.log(` 升级状态 : ⚠️ 有新版本可用,运行 ethan upgrade 升级`);
|
|
1447
|
+
}
|
|
1448
|
+
else {
|
|
1449
|
+
console.log(` 升级状态 : ✅ 已是最新`);
|
|
1450
|
+
}
|
|
1451
|
+
}
|
|
1452
|
+
catch {
|
|
1453
|
+
console.log(` 升级状态 : ⚠️ 缓存文件损坏,将在下次运行时重建`);
|
|
1454
|
+
}
|
|
1455
|
+
}
|
|
1456
|
+
else {
|
|
1457
|
+
console.log(` 升级状态 : ⏳ 尚未检查(下次运行 ethan 命令时自动检查)`);
|
|
1458
|
+
}
|
|
1376
1459
|
if (!allBuilt) {
|
|
1377
1460
|
console.log('\n💡 提示:运行 npm run build:rules 生成规则文件\n');
|
|
1378
1461
|
}
|