@deveco-test/deveco-code 0.3.0-4.2 → 1.0.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/CHANGELOG.md CHANGED
@@ -1,110 +1,5 @@
1
1
  # Changelog
2
2
 
3
- ## v0.2.0 (2026-09-20)
4
-
5
- ### DevEco Code 核心
6
-
7
- #### 新特性
8
-
9
- - 支持第三方 Provider 直接接入使用,DevEco Code内置模型改用使用账号登录与实名认证(`c6f4854`)
10
- - worktree 特性默认开启(`c97716f`)
11
- - 向生成 `.ets` 代码的 agent 注入 ArkTS/ArkUI 代码规范(`fc6488e`)
12
- - 支持在非空目录中安全创建项目(`884c5ff`)
13
- - 文档检索命令统一经由内置 CLI 代理(`1d76bfd`)
14
-
15
- #### 优化
16
-
17
- - 构建、运行、日志能力收敛至内置 DevEco CLI,统一由 `devecocli` 承接,新增日志清理、`--tail` 校验、创建冲突检测与模拟器自动启动(`3f6eb64`、`559922d`、`1d60720`)
18
- - 更新 UI 验证 MCP(`b24c309`)
19
-
20
- #### 缺陷修复
21
-
22
- - 修复自动启动模拟器后未等待就绪即运行导致阻塞(`5473f6d`)
23
- - 恢复内置 CLI 技能加载(`2574319`)
24
- - 修复 Windows 下 Bun 虚拟路径识别(`9cb1dc2`)
25
- - 修复日志清理未校验目标设备、失败被误报为成功(`8bc95e6`)
26
- - 修复文档预览截断后无法读取完整内容(`e65b278`)
27
- - 修复 goal 模式文档检索范围与 build 模式不一致(`f71cc15`)
28
- - 快照排除 `.codegenie` 目录(`431d772`)
29
- - 修复 trace 上报字段因空值被平台丢弃(`e5bc1fa`)
30
- - 升级 Bun 至 1.4.2,修复 pty 状态卡在运行中、SSE 超时未捕获异常(`aeb4536`)
31
- - 修复自动合并工作流在合并失败时仍提示成功(`9d90028`)
32
-
33
- #### 文档
34
-
35
- - 对齐内置 CLI 技能文档(`29799f4`)
36
-
37
- ### TUI 终端界面
38
-
39
- #### 新特性
40
-
41
- - 会话滚动至非边缘时显示跳转提示,点击可跳至最早/最新消息并重新吸附(`8f6bf1a`)
42
-
43
- #### 缺陷修复
44
-
45
- - 修复 token 耗尽时按 Esc 导致上下文丢失(`eee4fce`)
46
-
47
- ## v0.1.12 (2026-09-04)
48
-
49
- ### DevEco Code 核心
50
-
51
- #### 新特性
52
-
53
- - 云端模型配置无损保留,支持 `Ctrl+T` 切换推理强度档位,状态栏展示当前生效档位(`a1568e0`)
54
- - 更新内置 DevEco CLI 至 v1.3.2(`acfaa13`)
55
-
56
- #### 缺陷修复
57
-
58
- - 修复推理模型的思考内容被误用作会话标题(`6a78fac`)
59
-
60
- ## v0.1.11 (2026-09-02)
61
-
62
- ### DevEco Code 核心
63
-
64
- #### 缺陷修复
65
-
66
- - 实名认证复核改为复用浏览器登录流程,简化重新验证操作(`849623b9ce`)
67
-
68
- #### 文档
69
-
70
- - Provider 配置示例改用通用占位符,消除误导性内置 provider 示例(`0e75e01467`)
71
-
72
- ### TUI 终端界面
73
-
74
- #### 新特性
75
-
76
- - 新增 `/usage` 和 `/stats` 命令,打开标签式面板展示用量与配额统计,含热力图、模型卡片及配额进度(`a063068cf2`)
77
-
78
- ## v0.1.10 (2026-08-29)
79
-
80
- ### DevEco Code 核心
81
-
82
- #### 新特性
83
-
84
- - 新增 `--auto`/`--yolo` 权限自动批准标志,跳过工具调用确认(`89c7804`)
85
- - 更新内置 DevEco CLI 至 v1.3.0(`c95e744`、`ecd05b6`)
86
-
87
- #### 优化
88
-
89
- - 移除过时的 `DEVECO_DEFAULTS` 回退逻辑(`f353e9a`)
90
-
91
- #### 缺陷修复
92
-
93
- - 修复登录 URL 在 Windows 上无法通过 shell 打开的问题(`185b685`)
94
- - 限制会话重试次数,配额耗尽时提前终止(`10f8246`)
95
-
96
- ### TUI 终端界面
97
-
98
- #### 新特性
99
-
100
- - 新增 subagent 监控侧边栏面板(`57be7fa`)
101
- - 流式编辑统计改为按行计数(`690909f`)
102
-
103
- #### 缺陷修复
104
-
105
- - 修复模板化技能体的技能徽章渲染问题(`0c326df`)
106
- - 优化收集对话框交互细节(`e1816523`)
107
-
108
3
  ## v0.1.9 (2026-08-20)
109
4
 
110
5
  ### DevEco Code 核心
package/README.md CHANGED
@@ -1,333 +1,129 @@
1
1
  <p align="center">
2
- <h1 align="center">DevEco Code</h1>
2
+ <a href="https://opencode.ai">
3
+ <picture>
4
+ <source srcset="packages/console/app/src/asset/logo-ornate-dark.svg" media="(prefers-color-scheme: dark)">
5
+ <source srcset="packages/console/app/src/asset/logo-ornate-light.svg" media="(prefers-color-scheme: light)">
6
+ <img src="packages/console/app/src/asset/logo-ornate-light.svg" alt="OpenCode logo">
7
+ </picture>
8
+ </a>
3
9
  </p>
4
- <p align="center">面向 HarmonyOS 开发场景的 AI Agent 工具。</p>
10
+ <p align="center">The open source AI coding agent.</p>
5
11
  <p align="center">
6
- <a href="README.en.md">English</a> · 简体中文
12
+ <a href="https://opencode.ai/discord"><img alt="Discord" src="https://img.shields.io/discord/1391832426048651334?style=flat-square&label=discord" /></a>
13
+ <a href="https://www.npmjs.com/package/opencode-ai"><img alt="npm" src="https://img.shields.io/npm/v/opencode-ai?style=flat-square" /></a>
14
+ <a href="https://github.com/anomalyco/opencode/actions/workflows/publish.yml"><img alt="Build status" src="https://img.shields.io/github/actions/workflow/status/anomalyco/opencode/publish.yml?style=flat-square&branch=dev" /></a>
7
15
  </p>
8
16
 
9
17
  <p align="center">
10
- <a href="https://www.npmjs.com/package/@deveco/deveco-code"><img alt="NPM Version" src="https://img.shields.io/npm/v/@deveco/deveco-code.svg" /></a>
11
- <a href="https://www.npmjs.com/package/@deveco/deveco-code"><img alt="NPM Downloads" src="https://img.shields.io/npm/dm/@deveco/deveco-code.svg" /></a>
12
- <img alt="Node.js" src="https://img.shields.io/badge/Node.js-%3E%3D22-green.svg" />
13
- <img alt="platform" src="https://img.shields.io/badge/platform-macOS%20(Arm%20%7C%20x64)%20%7C%20Windows-blue.svg" />
14
- <a href="https://developer.huawei.com/consumer/cn/deveco-studio/"><img alt="DevEco Studio" src="https://img.shields.io/badge/DevEco%20Studio-%3E%3D6.1-orange.svg" /></a>
15
- <a href="https://gitcode.com/openharmony-sig/deveco-code/blob/develop/LICENSE"><img alt="License" src="https://img.shields.io/badge/license-MIT-green.svg" /></a>
18
+ <a href="README.md">English</a> |
19
+ <a href="README.zh.md">简体中文</a> |
20
+ <a href="README.zht.md">繁體中文</a> |
21
+ <a href="README.ko.md">한국어</a> |
22
+ <a href="README.de.md">Deutsch</a> |
23
+ <a href="README.es.md">Español</a> |
24
+ <a href="README.fr.md">Français</a> |
25
+ <a href="README.it.md">Italiano</a> |
26
+ <a href="README.da.md">Dansk</a> |
27
+ <a href="README.ja.md">日本語</a> |
28
+ <a href="README.pl.md">Polski</a> |
29
+ <a href="README.ru.md">Русский</a> |
30
+ <a href="README.bs.md">Bosanski</a> |
31
+ <a href="README.ar.md">العربية</a> |
32
+ <a href="README.no.md">Norsk</a> |
33
+ <a href="README.br.md">Português (Brasil)</a> |
34
+ <a href="README.th.md">ไทย</a> |
35
+ <a href="README.tr.md">Türkçe</a> |
36
+ <a href="README.uk.md">Українська</a> |
37
+ <a href="README.bn.md">বাংলা</a> |
38
+ <a href="README.gr.md">Ελληνικά</a> |
39
+ <a href="README.vi.md">Tiếng Việt</a>
16
40
  </p>
17
41
 
18
- <p align="center">
19
- <img src="https://raw.gitcode.com/openharmony-sig/deveco-code/raw/develop/assets/readme/readme-screenshot.png" alt="DevEco Code" width="600">
20
- </p>
21
-
22
- ***
23
-
24
- ## 快速开始
25
-
26
- ```bash
27
- # 1. 安装
28
- npm install -g @deveco/deveco-code
29
-
30
- # 2. 启动
31
- deveco
32
-
33
- # 3. 开始对话 —— 在终端中直接描述你的 HarmonyOS 开发需求
34
- 提示词示例:
35
- - 解释一下代码库的架构
36
- - 帮我重构login_check这个函数
37
- - 帮我检查并修复语法错误
38
- ```
39
-
40
- > 建议使用 [npm 官方源](https://registry.npmjs.org/) 或 [淘宝镜像源](https://registry.npmmirror.com/) 安装,其他镜像源可能因同步延迟导致安装失败或版本滞后。
41
-
42
- > 如需编译构建、设备运行等能力,请先安装 [DevEco Studio](https://developer.huawei.com/consumer/cn/deveco-studio/) 并配置 `DEVECO_HOME` 环境变量。
43
-
44
- ## 简介
45
-
46
- DevEco Code 是一款面向 HarmonyOS 开发场景的 AI Agent 工具,支持代码编写、编译构建、设备运行、文档查阅、运行时调试及 ArkTS 问题修复等能力。
47
-
48
- DevEco Code 基于开源项目 OpenCode 扩展开发,保留了 OpenCode 的终端交互、配置体系、 Provider / MCP / Skill / Plugin 等能力,并针对 HarmonyOS 工程增加了 DevEco Studio、Hvigor、HDC、Skill、HarmonyOS 知识库、ArkTS 检查和设备调试相关集成。
49
-
50
- ## 支持平台
51
-
52
- DevEco Code 当前通过 npm 提供以下平台安装包:
53
-
54
- | 平台 | 架构 | 说明 |
55
- | --- | --- | --- |
56
- | Windows | x64 | Windows 11 |
57
- | macOS | arm64(Apple Silicon) | M 系列芯片 |
58
- | macOS | x64(Intel) | Intel 芯片 Mac |
59
-
60
- > 暂不支持 Linux。HarmonyOS 编译构建、模拟器与真机调试依赖 [DevEco Studio](https://developer.huawei.com/consumer/cn/deveco-studio/),且目前仅提供 Windows 与 macOS 版本。
61
-
62
- ## 推荐配置
63
-
64
- **操作系统**
65
-
66
- - **Windows**:Windows 11 22H2 及以上
67
- - **macOS**:macOS 15 Sequoia 及以上
68
-
69
- **硬件**
70
-
71
- - **日常使用**(短会话、单模块改动、以对话与代码编辑为主):8 GB 及以上内存
72
- - **重度使用**(大工程、长会话、频繁编译构建与模拟器/真机调试):16 GB 及以上内存;建议为 DevEco Studio、SDK、模拟器与构建缓存预留 20 GB 及以上可用磁盘空间
73
-
74
- **运行时与工具链**
75
-
76
- - [Node.js](https://nodejs.org) **22 及以上**
77
- - [DevEco Studio](https://developer.huawei.com/consumer/cn/deveco-studio/) **6.1 及以上**(编译构建、Hvigor、HDC、模拟器/真机运行)
78
- - 已配置 `DEVECO_HOME` 环境变量,指向 DevEco Studio 安装目录
79
-
80
- **终端 Shell**
81
-
82
- - Windows:PowerShell 7+(推荐)、Windows PowerShell 5.1+
83
- - macOS:Zsh(推荐)、Bash
84
-
85
- **网络**
86
-
87
- - 需要稳定的互联网连接(华为账号登录、模型调用、HarmonyOS 知识库检索等)
88
-
89
- ## 安装前置
90
-
91
- DevEco Code 通过 npm 分发,安装前请先准备以下环境:
92
-
93
- 1. 安装 [Node.js](https://nodejs.org),**推荐使用 22 及更高版本**
94
- 2. (可选)安装 [DevEco Studio](https://developer.huawei.com/consumer/cn/deveco-studio/),**推荐使用 6.1 及更高版本**;若不安装,HarmonyOS 应用构建、推包等工具将无法使用
95
- 3. (可选)配置 `DEVECO_HOME` 环境变量指向 DevEco Studio 安装目录,默认路径示例:
96
- - **macOS**:`/Applications/DevEco-Studio.app`
97
- - **Windows**:`C:\Program Files\Huawei\DevEco Studio`
98
-
99
- 可先在终端验证 Node.js 环境:
100
-
101
- ```bash
102
- node -v
103
- npm -v
104
- ```
105
-
106
- ## 安装与卸载
107
-
108
- 安装:
109
-
110
- ```bash
111
- npm install -g @deveco/deveco-code
112
- ```
113
-
114
- 查看版本、启动:
115
-
116
- ```bash
117
- deveco --version
118
- deveco
119
- ```
120
-
121
- 更新:
122
-
123
- ```bash
124
- deveco upgrade
125
- ```
126
-
127
- 卸载运行时数据与全局包:
128
-
129
- ```bash
130
- deveco uninstall
131
- npm uninstall -g @deveco/deveco-code
132
- ```
133
-
134
- ## 登录与登出
42
+ [![OpenCode Terminal UI](packages/web/src/assets/lander/screenshot.png)](https://opencode.ai)
135
43
 
136
- 使用 DevEco Code 需先通过华为账号登录。首次执行 `deveco` 时会在终端内引导完成登录;也可单独执行登录命令:
44
+ ---
137
45
 
138
- ```bash
139
- deveco auth login
140
- ```
141
-
142
- 登出会清除当前华为账号的本地登录状态,下次启动需重新登录。执行:
46
+ ### Installation
143
47
 
144
48
  ```bash
145
- deveco auth logout
146
- ```
147
-
148
- ## 模型配置
149
-
150
- 登录后可使用 DevEco Code 提供的免费模型通道。
49
+ # YOLO
50
+ curl -fsSL https://opencode.ai/install | bash
151
51
 
152
- 在 DevEco Code 中输入 `/models` 可进入模型配置界面。当前免费提供 `GLM-5.1` 模型,单账号默认每分钟 50 次请求。也可以通过 `/connect` 进入 Provider 选择界面,配置支持的第三方模型。
153
-
154
- 内置免费模型通道在登录后自动可用,无需在配置文件中手动配置。如需接入其他模型服务,可以通过 `deveco.jsonc` 配置第三方 Provider(以下字段均为占位符,请替换为你的服务商信息):
155
-
156
- ```jsonc
157
- {
158
- "$schema": "https://opencode.ai/config.json",
159
- "provider": {
160
- // Provider ID,自定义命名即可,其他配置中通过 "<provider-id>/<model-id>" 引用模型
161
- "myprovider": {
162
- // 可选,缺省即为 openai-compatible;非 OpenAI 兼容的服务商才需要指定
163
- "npm": "@ai-sdk/openai-compatible",
164
- // 显示名称,可自定义
165
- "name": "My Provider",
166
- "models": {
167
- // 替换为服务商提供的模型 ID
168
- "<your-model-id>": {
169
- "tool_call": true,
170
- "limit": {
171
- "context": 200000,
172
- "output": 8192
173
- }
174
- }
175
- },
176
- "options": {
177
- // 替换为服务商的 API 地址
178
- "baseURL": "https://<your-endpoint>/v1",
179
- // 替换为你的 API Key
180
- "apiKey": "<your-api-key>"
181
- }
182
- }
183
- }
184
- }
52
+ # Package managers
53
+ npm i -g opencode-ai@latest # or bun/pnpm/yarn
54
+ scoop install opencode # Windows
55
+ choco install opencode # Windows
56
+ brew install anomalyco/tap/opencode # macOS and Linux (recommended, always up to date)
57
+ brew install opencode # macOS and Linux (official brew formula, updated less)
58
+ sudo pacman -S opencode # Arch Linux (Stable)
59
+ paru -S opencode-bin # Arch Linux (Latest from AUR)
60
+ mise use -g opencode # Any OS
61
+ nix run nixpkgs#opencode # or github:anomalyco/opencode for latest dev branch
185
62
  ```
186
63
 
187
- **UI 检查配置**
188
-
189
- UI 检查是功能验证阶段的可选能力,用于验证界面是否符合需求描述。
64
+ > [!TIP]
65
+ > Remove versions older than 0.1.x before installing.
190
66
 
191
- 该功能需调用多模态模型(仅用于 UI 检查,不作为主对话模型):已登录账号时默认使用内置 Qwen3-VL 模型,未登录时则跳过 UI 检查。
67
+ ### Desktop App (BETA)
192
68
 
193
- 如需配置第三方多模态模型(仅支持 Qwen 系列),可在 `deveco.jsonc` 的 `agent` 中指定,以 qwen3-vl-plus 为例:
194
-
195
- ```jsonc
196
- {
197
- "$schema": "https://opencode.ai/config.json",
198
- "provider": {
199
- "myprovider": {
200
- "npm": "@ai-sdk/openai-compatible",
201
- "name": "alibaba",
202
- "options": {
203
- "baseURL": "https://dashscope.aliyuncs.com/compatible-mode/v1",
204
- "apiKey": "<your-api-key>",
205
- },
206
- "models": {
207
- "qwen3-vl-plus": {
208
- "modalities": {
209
- "input": ["text", "image"],
210
- "output": ["text"],
211
- },
212
- },
213
- },
214
- },
215
- },
216
- "agent": {
217
- "ui_verification": {
218
- "mode": "subagent",
219
- "model": "myprovider/qwen3-vl-plus", // 格式为 <provider-id>/<model-id>
220
- "hidden": true,
221
- },
222
- },
223
- }
224
- ```
69
+ OpenCode is also available as a desktop application. Download directly from the [releases page](https://github.com/anomalyco/opencode/releases) or [opencode.ai/download](https://opencode.ai/download).
225
70
 
226
- 配置文件读取优先级:
227
-
228
- 1. 项目目录下 `.deveco/deveco.jsonc`
229
- 2. 项目目录下 `deveco.jsonc`
230
- 3. 用户目录下 `.config/deveco/deveco.jsonc`
231
-
232
- ## Agent 配置
233
-
234
- DevEco Code 面向 HarmonyOS 开发提供以下 Agent 配置(按 `Tab` 键切换):
235
-
236
- - `Build`:默认模式,适合工程生成、代码生成、配置修正、测试执行、推包运行和发布执行
237
- - `Plan`:适合需求拆解、技术方案、发布规划、测试规划和文档生成
238
- - `Goal`:适合 SDD 五阶段从需求到实现与构建验证的端到端特性交付
239
-
240
- ## HarmonyOS 场景能力
241
-
242
- DevEco Code 集成了常用 HarmonyOS 开发工具能力:
243
-
244
- | 工具 | 说明 |
245
- | ------------------------ | -------------------- |
246
- | `build_project` | 执行编译构建并导出构建产物 |
247
- | `start_app` | 在模拟器或真机上运行应用 |
248
- | `hdc_log` | 收集/清理设备日志/查看连接模拟器 |
249
- | `verify_ui` | 执行 UI 操作验证功能是否正确 |
250
- | `switch_cwd` | 切换构建项目路径 |
251
-
252
- 常见场景包括:从零到一创建 HarmonyOS 工程、增量开发页面、修复编译报错、真机调试。
253
-
254
- ## 扩展能力
255
-
256
- DevEco Code 兼容 OpenCode 的 Skill、MCP 和 Plugin 扩展方式。
257
-
258
- > 新增或修改 Skill、MCP、Plugin 配置后,需退出并重新执行 `deveco` 启动后才会生效。
259
-
260
- ### Skills
71
+ | Platform | Download |
72
+ | --------------------- | ---------------------------------- |
73
+ | macOS (Apple Silicon) | `opencode-desktop-mac-arm64.dmg` |
74
+ | macOS (Intel) | `opencode-desktop-mac-x64.dmg` |
75
+ | Windows | `opencode-desktop-windows-x64.exe` |
76
+ | Linux | `.deb`, `.rpm`, or `.AppImage` |
261
77
 
262
78
  ```bash
263
- npx skills add vercel-labs/agent-skills
79
+ # macOS (Homebrew)
80
+ brew install --cask opencode-desktop
81
+ # Windows (Scoop)
82
+ scoop bucket add extras; scoop install extras/opencode-desktop
264
83
  ```
265
84
 
266
- 也可以把 Skill 放到 `~/.config/deveco/skills` 目录。
267
-
268
- ### MCP
85
+ #### Installation Directory
269
86
 
270
- 可在 `~/.config/deveco/deveco.jsonc` 中配置 MCP:
87
+ The install script respects the following priority order for the installation path:
271
88
 
272
- ```jsonc
273
- {
274
- "$schema": "https://opencode.ai/config.json",
275
- "mcp": {
276
- "playwright": {
277
- "type": "local",
278
- "command": ["npx", "@playwright/mcp@latest"],
279
- "enabled": true
280
- }
281
- }
282
- }
283
- ```
284
-
285
- ### Plugins
89
+ 1. `$OPENCODE_INSTALL_DIR` - Custom installation directory
90
+ 2. `$XDG_BIN_DIR` - XDG Base Directory Specification compliant path
91
+ 3. `$HOME/bin` - Standard user binary directory (if it exists or can be created)
92
+ 4. `$HOME/.opencode/bin` - Default fallback
286
93
 
287
94
  ```bash
288
- npm install -g oh-my-opencode
289
- ```
290
-
291
- 然后在 `deveco.jsonc` 中配置插件入口:
292
-
293
- ```jsonc
294
- {
295
- "plugin": [
296
- "node_modules/oh-my-opencode/dist/index.js"
297
- ]
298
- }
95
+ # Examples
96
+ OPENCODE_INSTALL_DIR=/usr/local/bin curl -fsSL https://opencode.ai/install | bash
97
+ XDG_BIN_DIR=$HOME/.local/bin curl -fsSL https://opencode.ai/install | bash
299
98
  ```
300
99
 
301
- ## 从 OpenCode 迁移
100
+ ### Agents
302
101
 
303
- 如果需要从 OpenCode 迁移到 DevEco Code,请将配置文件迁移到 DevEco Code 目录。主配置文件可参考:
102
+ OpenCode includes two built-in agents you can switch between with the `Tab` key.
304
103
 
305
- ```powershell
306
- # Windows PowerShell
307
- Copy-Item -Force "{源路径}\opencode.jsonc" "~\.config\deveco\deveco.jsonc"
308
- ```
104
+ - **build** - Default, full-access agent for development work
105
+ - **plan** - Read-only agent for analysis and code exploration
106
+ - Denies file edits by default
107
+ - Asks permission before running bash commands
108
+ - Ideal for exploring unfamiliar codebases or planning changes
309
109
 
310
- ```bash
311
- # macOS
312
- cp {源路径}/opencode.jsonc ~/.config/deveco/deveco.jsonc
313
- ```
110
+ Also included is a **general** subagent for complex searches and multistep tasks.
111
+ This is used internally and can be invoked using `@general` in messages.
314
112
 
315
- Skills、Agents、Plugins 也可以迁移到 `~/.config/deveco` 下的对应目录;MCP 配置项可迁移到 `deveco.jsonc` 中。
113
+ Learn more about [agents](https://opencode.ai/docs/agents).
316
114
 
317
- ## 参与贡献
115
+ ### Documentation
318
116
 
319
- 欢迎贡献!请在提交 Pull Request 前阅读 [CONTRIBUTING.md](CONTRIBUTING.md)。
117
+ For more info on how to configure OpenCode, [**head over to our docs**](https://opencode.ai/docs).
320
118
 
321
- ## 帮助与支持
119
+ ### Contributing
322
120
 
323
- - 完整文档请参阅 [DevEco Code 使用文档](docs/deveco-code-docs.html)(需下载到本地后打开),也可在线阅读 [OpenCode TUI 文档](https://opencode.ai/docs/zh-cn/tui/)
324
- - 常见问题请参阅 [FAQ 文档](https://gitcode.com/openharmony-sig/deveco-code/wiki/FAQ.md)
325
- - 反馈与交流 [GitCode Issue](https://gitcode.com/openharmony-sig/deveco-code/issues)
121
+ If you're interested in contributing to OpenCode, please read our [contributing docs](./CONTRIBUTING.md) before submitting a pull request.
326
122
 
327
- ## 开源许可
123
+ ### Building on OpenCode
328
124
 
329
- [MIT License](LICENSE)
125
+ If you are working on a project that's related to OpenCode and is using "opencode" as part of its name, for example "opencode-dashboard" or "opencode-mobile", please add a note to your README to clarify that it is not built by the OpenCode team and is not affiliated with us in any way.
330
126
 
331
- ## 基于 OpenCode 构建的声明
127
+ ---
332
128
 
333
- 本项目基于开源项目 [OpenCode](https://opencode.ai) 扩展开发。DevEco Code **并非** OpenCode 团队出品,也与 OpenCode 团队无任何附属或关联关系。如有与 DevEco Code 相关的问题,请通过 [GitCode Issue](https://gitcode.com/openharmony-sig/deveco-code/issues) 反馈,而非联系 OpenCode 社区。
129
+ **Join our community** [Discord](https://discord.gg/opencode) | [X.com](https://x.com/opencode)
package/bin/deveco.exe ADDED
@@ -0,0 +1,5 @@
1
+ echo "Error: @deveco-test/deveco-code's postinstall script was not run." >&2
2
+ echo "" >&2
3
+ echo "This occurs when installation scripts are disabled." >&2
4
+ echo "Run the package postinstall script or reinstall with scripts enabled."
5
+ exit 1
package/package.json CHANGED
@@ -1,13 +1,23 @@
1
1
  {
2
2
  "name": "@deveco-test/deveco-code",
3
3
  "bin": {
4
- "deveco": "./bin/deveco"
4
+ "deveco": "./bin/deveco.exe"
5
5
  },
6
6
  "scripts": {
7
- "postinstall": "bun ./postinstall.mjs || node ./postinstall.mjs"
7
+ "postinstall": "node ./postinstall.mjs"
8
8
  },
9
- "version": "0.3.0-4.2",
9
+ "version": "1.0.0",
10
10
  "license": "MIT",
11
+ "os": [
12
+ "darwin",
13
+ "linux",
14
+ "win32",
15
+ "openharmony"
16
+ ],
17
+ "cpu": [
18
+ "arm64",
19
+ "x64"
20
+ ],
11
21
  "files": [
12
22
  "bin/**/*",
13
23
  "postinstall.mjs",
@@ -16,12 +26,10 @@
16
26
  "CHANGELOG.md"
17
27
  ],
18
28
  "optionalDependencies": {
19
- "@deveco-test/deveco-code-darwin-arm64": "0.3.0-4.2",
20
- "@deveco-test/deveco-code-darwin-x64": "0.3.0-4.2",
21
- "@deveco-test/deveco-code-windows-x64-baseline": "0.3.0-4.2",
22
- "@deveco-test/deveco-code-windows-x64": "0.3.0-4.2"
23
- },
24
- "dependencies": {
25
- "@deveco/deveco-cli": "1.3.4"
29
+ "@deveco-test/deveco-code": "1.0.0",
30
+ "@deveco-test/deveco-windows-x64": "1.0.0",
31
+ "@deveco-test/deveco-darwin-x64": "1.0.0",
32
+ "@deveco-test/deveco-darwin-arm64": "1.0.0",
33
+ "@deveco-test/deveco-code-openharmony-arm64": "1.0.0"
26
34
  }
27
35
  }
package/postinstall.mjs CHANGED
@@ -1,53 +1,29 @@
1
1
  #!/usr/bin/env node
2
2
 
3
- import childProcess from "child_process"
4
- import fs from "fs"
5
- import os from "os"
6
- import path from "path"
7
- import { createRequire } from "module"
8
- import { fileURLToPath } from "url"
9
-
10
- const __dirname = path.dirname(fileURLToPath(import.meta.url))
3
+ import childProcess from "node:child_process"
4
+ import fs from "node:fs"
5
+ import os from "node:os"
6
+ import path from "node:path"
7
+ import { createRequire } from "node:module"
8
+ import { fileURLToPath } from "node:url"
9
+
10
+ const directory = path.dirname(fileURLToPath(import.meta.url))
11
11
  const require = createRequire(import.meta.url)
12
- const packageJson = JSON.parse(fs.readFileSync(path.join(__dirname, "package.json"), "utf8"))
13
-
14
- const platformMap = {
15
- darwin: "darwin",
16
- linux: "linux",
17
- win32: "windows",
18
- }
19
- const archMap = {
20
- x64: "x64",
21
- arm64: "arm64",
22
- arm: "arm",
23
- }
24
-
25
- const platform = platformMap[os.platform()] ?? os.platform()
26
- const arch = archMap[os.arch()] ?? os.arch()
27
- const scope = packageJson.name && packageJson.name.includes("/") ? packageJson.name.split("/")[0] : "@deveco"
28
- const base = `${scope}/deveco-code-${platform}-${arch}`
29
- const sourceBinary = platform === "windows" ? "deveco.exe" : "deveco"
30
- const targetBinary = path.join(__dirname, "bin", "deveco.exe")
31
- const devecoCliPackageName = "@deveco/deveco-cli"
32
-
33
- function resolveLocalDevecoCliEntry() {
34
- const packageJsonPath = require.resolve(`${devecoCliPackageName}/package.json`)
35
- const root = path.dirname(packageJsonPath)
36
- const pkg = JSON.parse(fs.readFileSync(packageJsonPath, "utf8"))
37
- const entry = path.join(root, pkg.bin?.devecocli ?? "dist/cli.js")
38
- if (fs.existsSync(entry)) return entry
39
- throw new Error(`Local dependency "${devecoCliPackageName}" has no CLI entry at ${entry}.`)
40
- }
41
-
42
- function writeDevecoCliEntryMarker(installRoot) {
43
- const marker = path.join(installRoot, "vendor", ".deveco-cli-entry")
44
- fs.mkdirSync(path.dirname(marker), { recursive: true })
45
- fs.writeFileSync(marker, `${resolveLocalDevecoCliEntry()}\n`, "utf8")
46
- }
12
+ const packageJson = JSON.parse(fs.readFileSync(path.join(directory, "package.json"), "utf8"))
13
+ const command = Object.keys(packageJson.bin ?? {})[0]
14
+ if (!command) throw new Error("OpenCode package does not declare a binary")
15
+ const sourceCommand = packageJson.opencodeSourceBinary ?? command
16
+
17
+ const platform = { darwin: "darwin", linux: "linux", win32: "windows" }[os.platform()] ?? os.platform()
18
+ const arch = { x64: "x64", arm64: "arm64", arm: "arm" }[os.arch()] ?? os.arch()
19
+ const sourceBinary = platform === "windows" ? `${sourceCommand}.exe` : sourceCommand
20
+ const targetBinary = path.resolve(directory, packageJson.bin[command])
21
+ const dependencies = packageJson.optionalDependencies ?? {}
22
+ const base = Object.keys(dependencies).find((name) => name.endsWith(`-${platform}-${arch}`))
23
+ if (!base) throw new Error(`OpenCode does not provide a binary for ${platform}-${arch}`)
47
24
 
48
25
  function supportsAvx2() {
49
26
  if (arch !== "x64") return false
50
-
51
27
  if (platform === "linux") {
52
28
  try {
53
29
  return /(^|\s)avx2(\s|$)/i.test(fs.readFileSync("/proc/cpuinfo", "utf8"))
@@ -55,27 +31,23 @@ function supportsAvx2() {
55
31
  return false
56
32
  }
57
33
  }
58
-
59
34
  if (platform === "darwin") {
60
35
  try {
61
36
  const result = childProcess.spawnSync("sysctl", ["-n", "hw.optional.avx2_0"], {
62
37
  encoding: "utf8",
63
38
  timeout: 1500,
64
39
  })
65
- if (result.status !== 0) return false
66
- return (result.stdout || "").trim() === "1"
40
+ return result.status === 0 && (result.stdout || "").trim() === "1"
67
41
  } catch {
68
42
  return false
69
43
  }
70
44
  }
71
-
72
45
  if (platform === "windows") {
73
- const command =
46
+ const script =
74
47
  '(Add-Type -MemberDefinition "[DllImport(""kernel32.dll"")] public static extern bool IsProcessorFeaturePresent(int ProcessorFeature);" -Name Kernel32 -Namespace Win32 -PassThru)::IsProcessorFeaturePresent(40)'
75
-
76
48
  for (const executable of ["powershell.exe", "pwsh.exe", "pwsh", "powershell"]) {
77
49
  try {
78
- const result = childProcess.spawnSync(executable, ["-NoProfile", "-NonInteractive", "-Command", command], {
50
+ const result = childProcess.spawnSync(executable, ["-NoProfile", "-NonInteractive", "-Command", script], {
79
51
  encoding: "utf8",
80
52
  timeout: 3000,
81
53
  windowsHide: true,
@@ -89,20 +61,13 @@ function supportsAvx2() {
89
61
  }
90
62
  }
91
63
  }
92
-
93
64
  return false
94
65
  }
95
66
 
96
67
  function isMusl() {
97
68
  if (platform !== "linux") return false
98
-
99
69
  try {
100
70
  if (fs.existsSync("/etc/alpine-release")) return true
101
- } catch {
102
- // Ignore filesystem probes that are blocked by the host.
103
- }
104
-
105
- try {
106
71
  const result = childProcess.spawnSync("ldd", ["--version"], { encoding: "utf8" })
107
72
  return `${result.stdout || ""}${result.stderr || ""}`.toLowerCase().includes("musl")
108
73
  } catch {
@@ -112,148 +77,90 @@ function isMusl() {
112
77
 
113
78
  function packageNames() {
114
79
  const baseline = arch === "x64" && !supportsAvx2()
115
-
116
- if (platform === "linux") {
117
- if (isMusl()) {
118
- if (arch === "x64")
119
- return baseline
120
- ? [`${base}-baseline-musl`, `${base}-musl`, `${base}-baseline`, base]
121
- : [`${base}-musl`, `${base}-baseline-musl`, base, `${base}-baseline`]
122
- return [`${base}-musl`, base]
123
- }
124
-
125
- if (arch === "x64")
126
- return baseline
127
- ? [`${base}-baseline`, base, `${base}-baseline-musl`, `${base}-musl`]
128
- : [base, `${base}-baseline`, `${base}-musl`, `${base}-baseline-musl`]
129
- return [base, `${base}-musl`]
130
- }
131
-
132
- if (arch === "x64") return baseline ? [`${base}-baseline`, base] : [base, `${base}-baseline`]
133
- return [base]
134
- }
135
-
136
- function resolvePackageDir(name) {
137
- const packageJsonPath = require.resolve(`${name}/package.json`)
138
- return path.dirname(packageJsonPath)
139
- }
140
-
141
- function resolveBinary(name) {
142
- const binaryPath = path.join(resolvePackageDir(name), "bin", sourceBinary)
143
- if (!fs.existsSync(binaryPath)) throw new Error(`Binary not found at ${binaryPath}`)
144
- return binaryPath
145
- }
146
-
147
- function copyDir(src, dst) {
148
- if (!fs.existsSync(dst)) fs.mkdirSync(dst, { recursive: true })
149
- for (const entry of fs.readdirSync(src, { withFileTypes: true })) {
150
- const srcPath = path.join(src, entry.name)
151
- const dstPath = path.join(dst, entry.name)
152
- if (entry.isDirectory()) {
153
- copyDir(srcPath, dstPath)
154
- } else {
155
- fs.copyFileSync(srcPath, dstPath)
156
- if (process.platform !== "win32") {
157
- fs.chmodSync(dstPath, fs.statSync(srcPath).mode)
158
- }
159
- }
80
+ const names =
81
+ platform === "linux"
82
+ ? isMusl()
83
+ ? arch === "x64"
84
+ ? baseline
85
+ ? [`${base}-baseline-musl`, `${base}-musl`, `${base}-baseline`, base]
86
+ : [`${base}-musl`, `${base}-baseline-musl`, base, `${base}-baseline`]
87
+ : [`${base}-musl`, base]
88
+ : arch === "x64"
89
+ ? baseline
90
+ ? [`${base}-baseline`, base, `${base}-baseline-musl`, `${base}-musl`]
91
+ : [base, `${base}-baseline`, `${base}-musl`, `${base}-baseline-musl`]
92
+ : [base, `${base}-musl`]
93
+ : arch === "x64"
94
+ ? baseline
95
+ ? [`${base}-baseline`, base]
96
+ : [base, `${base}-baseline`]
97
+ : [base]
98
+ return names.filter((name) => dependencies[name])
99
+ }
100
+
101
+ function copyBinary(source) {
102
+ if (!fs.existsSync(source)) throw new Error(`Binary not found at ${source}`)
103
+ fs.mkdirSync(path.dirname(targetBinary), { recursive: true })
104
+ if (fs.existsSync(targetBinary)) {
105
+ try {
106
+ fs.unlinkSync(targetBinary)
107
+ } catch {}
160
108
  }
161
- }
162
-
163
- function copyVendor(packageDir) {
164
- const vendorSrc = path.join(packageDir, "vendor")
165
- const vendorDst = path.join(__dirname, "vendor")
166
- if (fs.existsSync(vendorSrc)) {
167
- copyDir(vendorSrc, vendorDst)
168
- // Windows packs often drop Unix +x; force it back on macOS/Linux install.
169
- ensureVendorExecutables(vendorDst)
170
- ensureVendorExecutables(path.join(packageDir, "vendor"))
109
+ try {
110
+ fs.linkSync(source, targetBinary)
111
+ } catch {
112
+ fs.copyFileSync(source, targetBinary)
171
113
  }
114
+ fs.chmodSync(targetBinary, 0o755)
172
115
  }
173
116
 
174
- /** Restore execute bits lost when packages are built/published from Windows. */
175
- function ensureVendorExecutables(vendorRoot) {
176
- if (process.platform === "win32" || !fs.existsSync(vendorRoot)) return
177
-
178
- const stack = [vendorRoot]
179
- while (stack.length > 0) {
180
- const dir = stack.pop()
181
- let entries
182
- try {
183
- entries = fs.readdirSync(dir, { withFileTypes: true })
184
- } catch {
185
- continue
186
- }
187
- for (const entry of entries) {
188
- const full = path.join(dir, entry.name)
189
- if (entry.isDirectory()) {
190
- stack.push(full)
191
- continue
192
- }
193
- if (!entry.isFile()) continue
194
- // Top-level vendor/ripgrep/rg and nested @vscode/ripgrep*/**/rg
195
- if (entry.name === "rg") {
196
- try {
197
- fs.chmodSync(full, 0o755)
198
- } catch {
199
- // Best-effort; ignore files we cannot chmod.
200
- }
201
- }
202
- }
203
- }
117
+ function resolveBinary(name) {
118
+ const packagePath = require.resolve(`${name}/package.json`)
119
+ // Package managers keep an older platform package when the matching version is not yet on the registry,
120
+ // which would silently install the previous release under the new launcher.
121
+ const version = JSON.parse(fs.readFileSync(packagePath, "utf8")).version
122
+ if (version !== dependencies[name]) throw new Error(`${name} is ${version}, expected ${dependencies[name]}`)
123
+ return path.join(path.dirname(packagePath), "bin", sourceBinary)
204
124
  }
205
125
 
206
126
  function installPackage(name) {
207
- const version = packageJson.optionalDependencies?.[name]
208
- if (!version) return
209
-
210
127
  const temp = fs.mkdtempSync(path.join(os.tmpdir(), "opencode-install-"))
211
128
  try {
212
129
  const result = childProcess.spawnSync(
213
130
  "npm",
214
- ["install", "--ignore-scripts", "--no-save", "--loglevel=error", "--prefix", temp, `${name}@${version}`],
131
+ [
132
+ "install",
133
+ "--ignore-scripts",
134
+ "--no-save",
135
+ "--loglevel=error",
136
+ "--prefix",
137
+ temp,
138
+ `${name}@${dependencies[name]}`,
139
+ ],
215
140
  { stdio: "inherit", windowsHide: true },
216
141
  )
217
- if (result.status !== 0) return
218
- const packageDir = path.join(temp, "node_modules", name)
219
- copyBinary(path.join(packageDir, "bin", sourceBinary), targetBinary)
220
- copyVendor(packageDir)
142
+ if (result.status !== 0) return false
143
+ copyBinary(path.join(temp, "node_modules", name, "bin", sourceBinary))
221
144
  return true
222
145
  } finally {
223
146
  fs.rmSync(temp, { recursive: true, force: true })
224
147
  }
225
148
  }
226
149
 
227
- function copyBinary(source, target) {
228
- if (!fs.existsSync(source)) throw new Error(`Binary not found at ${source}`)
229
- fs.mkdirSync(path.dirname(target), { recursive: true })
230
- if (fs.existsSync(target)) fs.unlinkSync(target)
231
- try {
232
- fs.linkSync(source, target)
233
- } catch {
234
- fs.copyFileSync(source, target)
235
- }
236
- fs.chmodSync(target, 0o755)
237
- }
238
-
239
150
  function verifyBinary() {
240
- const result = childProcess.spawnSync(targetBinary, ["--version"], {
241
- encoding: "utf8",
242
- stdio: "ignore",
243
- windowsHide: true,
244
- })
245
- return result.status === 0
151
+ return (
152
+ childProcess.spawnSync(targetBinary, ["--version"], {
153
+ stdio: "ignore",
154
+ windowsHide: true,
155
+ }).status === 0
156
+ )
246
157
  }
247
158
 
248
159
  function main() {
249
- writeDevecoCliEntryMarker(__dirname)
250
-
251
- for (const name of packageNames()) {
160
+ const names = packageNames()
161
+ for (const name of names) {
252
162
  try {
253
- const packageDir = resolvePackageDir(name)
254
- copyBinary(resolveBinary(name), targetBinary)
255
- copyVendor(packageDir)
256
- writeDevecoCliEntryMarker(packageDir)
163
+ copyBinary(resolveBinary(name))
257
164
  if (verifyBinary()) return
258
165
  } catch {
259
166
  if (installPackage(name) && verifyBinary()) return
@@ -261,15 +168,13 @@ function main() {
261
168
  }
262
169
 
263
170
  throw new Error(
264
- `It seems your package manager failed to install the right deveco-code package. Try manually installing ${packageNames()
265
- .map((name) => JSON.stringify(name))
266
- .join(" or ")}.`,
171
+ `Failed to install OpenCode. Try manually installing ${names.map((name) => JSON.stringify(name)).join(" or ")}.`,
267
172
  )
268
173
  }
269
174
 
270
175
  try {
271
176
  main()
272
177
  } catch (error) {
273
- console.error(error.message)
178
+ console.error(error instanceof Error ? error.message : String(error))
274
179
  process.exit(1)
275
180
  }
package/bin/deveco DELETED
@@ -1,206 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- const childProcess = require("child_process")
4
- const fs = require("fs")
5
- const path = require("path")
6
- const os = require("os")
7
-
8
- const forwardedSignals = ["SIGINT", "SIGTERM", "SIGHUP"]
9
-
10
- function run(target) {
11
- const child = childProcess.spawn(target, process.argv.slice(2), {
12
- stdio: "inherit",
13
- })
14
-
15
- child.on("error", (error) => {
16
- console.error(error.message)
17
- process.exit(1)
18
- })
19
-
20
- const forwarders = {}
21
- for (const signal of forwardedSignals) {
22
- forwarders[signal] = () => {
23
- try {
24
- child.kill(signal)
25
- } catch {
26
- // The child may have already exited.
27
- }
28
- }
29
- process.on(signal, forwarders[signal])
30
- }
31
-
32
- child.on("exit", (code, signal) => {
33
- for (const forwardedSignal of forwardedSignals) {
34
- process.removeListener(forwardedSignal, forwarders[forwardedSignal])
35
- }
36
-
37
- if (signal) {
38
- process.kill(process.pid, signal)
39
- return
40
- }
41
-
42
- process.exit(typeof code === "number" ? code : 0)
43
- })
44
- }
45
-
46
- const envPath = process.env.DEVECO_BIN_PATH
47
-
48
- const scriptPath = fs.realpathSync(__filename)
49
- const scriptDir = path.dirname(scriptPath)
50
-
51
- //
52
- const cached = path.join(scriptDir, ".deveco")
53
-
54
- const platformMap = {
55
- darwin: "darwin",
56
- linux: "linux",
57
- win32: "windows",
58
- }
59
- const archMap = {
60
- x64: "x64",
61
- arm64: "arm64",
62
- arm: "arm",
63
- }
64
-
65
- let platform = platformMap[os.platform()]
66
- if (!platform) {
67
- platform = os.platform()
68
- }
69
- let arch = archMap[os.arch()]
70
- if (!arch) {
71
- arch = os.arch()
72
- }
73
- let mainPkg = {}
74
- try {
75
- mainPkg = JSON.parse(fs.readFileSync(path.join(scriptDir, "..", "package.json"), "utf8"))
76
- } catch {
77
- // dev mode or missing package.json
78
- }
79
- const scope = mainPkg.name && mainPkg.name.includes("/") ? mainPkg.name.split("/")[0] : "@deveco"
80
- const base = scope + "/deveco-code-" + platform + "-" + arch
81
- const binary = platform === "windows" ? "deveco.exe" : "deveco"
82
-
83
- function supportsAvx2() {
84
- if (arch !== "x64") return false
85
-
86
- if (platform === "linux") {
87
- try {
88
- return /(^|\s)avx2(\s|$)/i.test(fs.readFileSync("/proc/cpuinfo", "utf8"))
89
- } catch {
90
- return false
91
- }
92
- }
93
-
94
- if (platform === "darwin") {
95
- try {
96
- const result = childProcess.spawnSync("sysctl", ["-n", "hw.optional.avx2_0"], {
97
- encoding: "utf8",
98
- timeout: 1500,
99
- })
100
- if (result.status !== 0) return false
101
- return (result.stdout || "").trim() === "1"
102
- } catch {
103
- return false
104
- }
105
- }
106
-
107
- if (platform === "windows") {
108
- const cmd =
109
- '(Add-Type -MemberDefinition "[DllImport(""kernel32.dll"")] public static extern bool IsProcessorFeaturePresent(int ProcessorFeature);" -Name Kernel32 -Namespace Win32 -PassThru)::IsProcessorFeaturePresent(40)'
110
-
111
- for (const exe of ["powershell.exe", "pwsh.exe", "pwsh", "powershell"]) {
112
- try {
113
- const result = childProcess.spawnSync(exe, ["-NoProfile", "-NonInteractive", "-Command", cmd], {
114
- encoding: "utf8",
115
- timeout: 3000,
116
- windowsHide: true,
117
- })
118
- if (result.status !== 0) continue
119
- const out = (result.stdout || "").trim().toLowerCase()
120
- if (out === "true" || out === "1") return true
121
- if (out === "false" || out === "0") return false
122
- } catch {
123
- continue
124
- }
125
- }
126
-
127
- return false
128
- }
129
-
130
- return false
131
- }
132
-
133
- const names = (() => {
134
- const avx2 = supportsAvx2()
135
- const baseline = arch === "x64" && !avx2
136
-
137
- if (platform === "linux") {
138
- const musl = (() => {
139
- try {
140
- if (fs.existsSync("/etc/alpine-release")) return true
141
- } catch {
142
- // ignore
143
- }
144
-
145
- try {
146
- const result = childProcess.spawnSync("ldd", ["--version"], { encoding: "utf8" })
147
- const text = ((result.stdout || "") + (result.stderr || "")).toLowerCase()
148
- if (text.includes("musl")) return true
149
- } catch {
150
- // ignore
151
- }
152
-
153
- return false
154
- })()
155
-
156
- if (musl) {
157
- if (arch === "x64") {
158
- if (baseline) return [`${base}-baseline-musl`, `${base}-musl`, `${base}-baseline`, base]
159
- return [`${base}-musl`, `${base}-baseline-musl`, base, `${base}-baseline`]
160
- }
161
- return [`${base}-musl`, base]
162
- }
163
-
164
- if (arch === "x64") {
165
- if (baseline) return [`${base}-baseline`, base, `${base}-baseline-musl`, `${base}-musl`]
166
- return [base, `${base}-baseline`, `${base}-musl`, `${base}-baseline-musl`]
167
- }
168
- return [base, `${base}-musl`]
169
- }
170
-
171
- if (arch === "x64") {
172
- if (baseline) return [`${base}-baseline`, base]
173
- return [base, `${base}-baseline`]
174
- }
175
- return [base]
176
- })()
177
-
178
- function findBinary(startDir) {
179
- let current = startDir
180
- for (;;) {
181
- const modules = path.join(current, "node_modules")
182
- if (fs.existsSync(modules)) {
183
- for (const name of names) {
184
- const candidate = path.join(modules, name, "bin", binary)
185
- if (fs.existsSync(candidate)) return candidate
186
- }
187
- }
188
- const parent = path.dirname(current)
189
- if (parent === current) {
190
- return
191
- }
192
- current = parent
193
- }
194
- }
195
-
196
- const resolved = envPath || (fs.existsSync(cached) ? cached : findBinary(scriptDir))
197
- if (!resolved) {
198
- console.error(
199
- "It seems that your package manager failed to install the right version of the deveco CLI for your platform. You can try manually installing " +
200
- names.map((n) => `\"${n}\"`).join(" or ") +
201
- " package",
202
- )
203
- process.exit(1)
204
- }
205
-
206
- run(resolved)