@zyzheal/ola-cc 0.2.1 → 0.3.15

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 CHANGED
@@ -1,154 +1,163 @@
1
- # Claude Code
1
+ # Ola CC (Ola Claude Code)
2
2
 
3
3
  AI 编码助手,运行在你的终端中。
4
4
 
5
- ## 安装
5
+ ## 快速开始
6
+
7
+ ### 安装
6
8
 
7
9
  ```bash
8
- npm install claude
9
- # 或
10
- bun add claude
10
+ npm install -g @zyzheal/ola-cc
11
11
  ```
12
12
 
13
- ## 使用
13
+ 安装完成后,终端中运行 `ola-cc` 即可启动。
14
14
 
15
- ```bash
16
- # 启动交互式会话
17
- npx claude
15
+ ### 首次使用
18
16
 
19
- # 或全局安装
20
- npm install -g claude
21
- claude
22
- ```
17
+ 1. **配置 API 密钥** — 选择以下任一方式:
18
+
19
+ **方式 A:通过 session.json(推荐)**
20
+
21
+ 创建 `~/.claude/session.json`:
22
+
23
+ ```bash
24
+ mkdir -p ~/.claude
25
+ cat > ~/.claude/session.json << 'EOF'
26
+ {
27
+ "env": {
28
+ "OPENAI_API_KEY": "你的API密钥",
29
+ "OPENAI_BASE_URL": "https://api.openai.com/v1",
30
+ "OPENAI_MODEL": "gpt-4o"
31
+ }
32
+ }
33
+ EOF
34
+ ```
23
35
 
24
- ## 配置文件
36
+ **方式 B:通过环境变量**
25
37
 
26
- Claude Code 的配置存储在 `~/.claude/` 目录中。
38
+ ```bash
39
+ export OPENAI_API_KEY="你的API密钥"
40
+ export OPENAI_BASE_URL="https://api.openai.com/v1"
41
+ export OPENAI_MODEL="gpt-4o"
42
+ ola-cc
43
+ ```
44
+
45
+ 2. **启动 Ola CC**
46
+
47
+ ```bash
48
+ ola-cc
49
+ ```
50
+
51
+ ## 架构说明
52
+
53
+ 本项目采用 **包装器 + 原生二进制分发** 模式:
54
+
55
+ - **主包** `@zyzheal/ola-cc` — 包含安装脚本和 Node.js 兼容的 JS bundle,安装时自动下载对应平台的原生二进制(macOS/Linux)或 JS bundle(Windows)
56
+ - **平台子包** `@zyzheal/ola-cc-darwin-arm64` 等 — 每个平台一个独立包
57
+
58
+ ### 平台运行方式
59
+
60
+ | 平台 | 运行方式 | 说明 |
61
+ |------|----------|------|
62
+ | macOS | Bun 编译原生二进制 | 高性能,单进程 |
63
+ | Linux | Bun 编译原生二进制 | 高性能,单进程 |
64
+ | Windows | Node.js JS bundle | 稳定可靠,避免 Bun 编译二进制在 Windows 上的兼容性问题 |
65
+
66
+ ### 支持的平台
67
+
68
+ | 平台包名 | 操作系统 | CPU |
69
+ |----------|----------|-----|
70
+ | `@zyzheal/ola-cc-darwin-arm64` | macOS | Apple Silicon (M1/M2/M3/M4) |
71
+ | `@zyzheal/ola-cc-darwin-x64` | macOS | Intel |
72
+ | `@zyzheal/ola-cc-linux-x64` | Linux | x64 (glibc) |
73
+ | `@zyzheal/ola-cc-linux-arm64` | Linux | ARM64 (glibc) |
74
+ | `@zyzheal/ola-cc-linux-x64-musl` | Linux | x64 (musl/Alpine) |
75
+ | `@zyzheal/ola-cc-linux-arm64-musl` | Linux | ARM64 (musl/Alpine) |
76
+ | `@zyzheal/ola-cc-win32-x64` | Windows | x64 |
77
+ | `@zyzheal/ola-cc-win32-arm64` | Windows | ARM64 |
78
+
79
+ ## 配置文件详解
80
+
81
+ Ola CC 的配置存储在 `~/.claude/` 目录中。
27
82
 
28
83
  ### 配置目录结构
29
84
 
30
85
  ```
31
86
  ~/.claude/
32
87
  ├── settings.json # 用户设置(MCP 服务器、偏好等)
33
- ├── session.json # 会话级环境配置(API 密钥、模型、环境变量)
88
+ ├── session.json # 会话级环境配置(API 密钥、模型、环境变量等)
34
89
  ├── CLAUDE.md # 项目级指令文件
35
90
  └── chrome/ # Chrome 扩展原生主机文件
36
91
  ├── chrome-native-host # Unix: 包装脚本
37
92
  └── chrome-native-host.bat # Windows: 包装脚本
38
93
  ```
39
94
 
40
- ### 读取优先级
95
+ ### 配置读取优先级
41
96
 
42
- 配置文件的读取优先级如下(从高到低):
97
+ | 优先级 | 来源 | 说明 |
98
+ |--------|------|------|
99
+ | 1 | 命令行参数 | 启动时 `--` 传入的参数 |
100
+ | 2 | 环境变量 | 当前 shell 环境中的变量 |
101
+ | 3 | `~/.claude/session.json` | 会话级配置(API 密钥、模型、环境变量等) |
102
+ | 4 | `~/.claude/settings.json` | 用户级持久化设置(MCP 服务器、偏好设置等) |
103
+ | 5 | `.claude/CLAUDE.md` | 项目级指令(仅影响当前项目) |
43
104
 
44
- 1. **命令行参数** — 启动时传入的 `--` 参数,优先级最高
45
- 2. **环境变量** — 当前 shell 环境中设置的变量
46
- 3. **`~/.claude/session.json`** — 会话级配置,包含 API 密钥、模型选择、环境变量等
47
- 4. **`~/.claude/settings.json`** — 用户级持久化设置,包含 MCP 服务器、偏好设置等
48
- 5. **项目根目录 `.claude/CLAUDE.md`** — 项目级指令,仅影响当前项目的行为
105
+ > 高优先级的配置会覆盖低优先级的同名设置。
49
106
 
50
- > **注意**:`session.json` 中的配置会覆盖 `settings.json` 中的同名设置,但不会覆盖命令行参数和系统环境变量。
107
+ ### session.json 配置(会话级)
51
108
 
52
- ### session.json 配置详解
109
+ `~/.claude/session.json` 用于配置会话级别的环境变量和模型设置。
53
110
 
54
- `~/.claude/session.json` 用于配置会话级别的环境变量和模型设置。典型结构如下:
111
+ #### 完整示例
55
112
 
56
113
  ```json
57
114
  {
58
115
  "env": {
59
- "ANTHROPIC_API_KEY": "sk-ant-api03-xxxxx...xxxxx",
60
- "API_BASE_URL": "http://127.0.0.1:11434",
116
+ "OPENAI_API_KEY": "sk-xxx",
117
+ "OPENAI_BASE_URL": "https://api.openai.com/v1",
118
+ "OPENAI_MODEL": "gpt-4o",
61
119
  "CLAUDE_CODE_FORCE_FULL_LOGO": "true"
62
120
  },
63
121
  "model": {
64
- "name": "qwen/qwen3-235b-a22b",
122
+ "name": "gpt-4o",
65
123
  "provider": "openai"
66
124
  }
67
125
  }
68
126
  ```
69
127
 
70
- #### env 字段
128
+ #### env 字段 — 环境变量注入
71
129
 
72
130
  `env` 对象中的键值对会在会话启动时注入为环境变量。常用配置:
73
131
 
74
- | 变量 | 说明 |
75
- |------|------|
76
- | `ANTHROPIC_API_KEY` | API 密钥(必填),使用远程代理时填代理服务的 key |
77
- | `API_BASE_URL` | API 代理地址,使用本地模型时指向本地代理端口 |
78
- | `CLAUDE_CODE_ENABLE_CFC` | 启用 Chrome 集成(1=启用,0=禁用) |
79
- | `CLAUDE_CHROME_HTTP` | 启用 Chrome HTTP 桥接模式(1=启用) |
80
- | `CLAUDE_CHROME_HTTP_PORT` | HTTP 服务器端口(默认 12306) |
81
-
82
- #### model 字段
132
+ | 变量 | 说明 | 必填 |
133
+ |------|------|------|
134
+ | `OPENAI_API_KEY` | API 密钥 | |
135
+ | `OPENAI_BASE_URL` | API 基础 URL | 是 |
136
+ | `OPENAI_MODEL` | 模型名称 | 推荐 |
137
+ | `CLAUDE_CODE_USE_OPENAI` | 启用 OpenAI 协议(设为 `1`) | 是 |
138
+ | `CLAUDE_CODE_ENABLE_CFC` | 启用 Chrome 集成(1=启用,0=禁用) | 否 |
139
+ | `CLAUDE_CHROME_HTTP` | 启用 Chrome HTTP 桥接(1=启用) | 否 |
140
+ | `CLAUDE_CHROME_HTTP_PORT` | HTTP 桥接端口(默认 12306) | 否 |
83
141
 
84
- `model` 对象用于指定使用的模型。使用本地模型代理时的参考配置:
142
+ #### model 字段 — 模型选择
85
143
 
86
144
  ```json
87
145
  {
88
146
  "model": {
89
- "name": "qwen/qwen3-235b-a22b",
147
+ "name": "gpt-4o",
90
148
  "provider": "openai"
91
149
  }
92
150
  }
93
151
  ```
94
152
 
95
- - **name** — 模型名称,格式取决于代理服务的 API。本地 Ollama 代理通常为 `qwen/qwen3-235b-a22b` 或 `llama3.1`
96
- - **provider** — 提供商类型,本地 OpenAI 兼容代理填 `openai`,也支持 `bedrock`、`vertex` 等
97
-
98
- #### OpenAI 协议支持
153
+ - **name** — 模型名称,取决于你的 API 服务
154
+ - **provider** — 提供商类型:`openai`、`bedrock`、`vertex` 等
99
155
 
100
- 当设置 `OPENAI_BASE_URL` 或 `OPENAI_API_KEY` 时,CLI 会自动使用 OpenAI 兼容协议与 API 通信。
156
+ ### settings.json 配置(用户级)
101
157
 
102
- **必填环境变量:**
158
+ `~/.claude/settings.json` 用于持久化用户设置。
103
159
 
104
- | 环境变量 | 说明 |
105
- |----------|------|
106
- | `OPENAI_API_KEY` | API 密钥(必填) |
107
- | `OPENAI_BASE_URL` | API 基础 URL(必填) |
108
- | `OPENAI_MODEL` | 模型名称(推荐,作为 `settings.json` 中 `model` 字段的默认值) |
109
-
110
- **支持的端点示例:**
111
-
112
- | 服务 | OPENAI_BASE_URL | 说明 |
113
- |------|----------------|------|
114
- | 阿里云百炼 DashScope | `https://coding.dashscope.aliyuncs.com/v1` | 支持通义千问系列模型 |
115
- | OpenAI 官方 API | `https://api.openai.com/v1` | GPT-4o、o1 等 |
116
- | Ollama (本地) | `http://127.0.0.1:11434/v1` | 本地部署的开源模型 |
117
- | vLLM | `http://localhost:8000/v1` | 兼容 OpenAI API 格式的推理服务 |
118
-
119
- **使用方式:**
120
-
121
- ```bash
122
- # 命令行直接传入
123
- OPENAI_BASE_URL="https://coding.dashscope.aliyuncs.com/v1" \
124
- OPENAI_API_KEY="your-api-key" \
125
- OPENAI_MODEL="qwen3.6-plus" \
126
- claude
127
-
128
- # 或在 ~/.claude/session.json 中配置
129
- {
130
- "env": {
131
- "OPENAI_BASE_URL": "https://coding.dashscope.aliyuncs.com/v1",
132
- "OPENAI_API_KEY": "your-api-key",
133
- "OPENAI_MODEL": "qwen3.6-plus"
134
- }
135
- }
136
- ```
137
-
138
- **模型选择优先级:**
139
-
140
- 1. `/model` 命令(会话中动态切换)
141
- 2. `--model` 启动参数
142
- 3. `ANTHROPIC_MODEL` 环境变量
143
- 4. `OPENAI_MODEL` 环境变量
144
- 5. `~/.claude/settings.json` 中的 `model` 字段
145
- 6. 内置默认值
146
-
147
- **注意事项:**
148
- - 推荐设置 `OPENAI_MODEL` 环境变量,它会作为模型选择的主要来源之一
149
- - 支持流式和非流式响应
150
-
151
- ### settings.json 配置示例
160
+ #### MCP 服务器配置
152
161
 
153
162
  ```json
154
163
  {
@@ -165,84 +174,149 @@ claude
165
174
  }
166
175
  ```
167
176
 
168
- ## MCP 服务器配置
169
-
170
- 在 `~/.claude/settings.json` 的 `mcpServers` 中添加 MCP 服务器:
177
+ #### 宠物(SprocketDudot)配置
171
178
 
172
179
  ```json
173
180
  {
174
- "mcpServers": {
175
- "filesystem": {
176
- "command": "npx",
177
- "args": ["-y", "@modelcontextprotocol/server-filesystem", "/path/to/allowed/dir"]
178
- },
179
- "github": {
180
- "command": "npx",
181
- "args": ["-y", "@modelcontextprotocol/server-github"]
182
- }
181
+ "sprocketDudot": {
182
+ "enabled": true
183
183
  }
184
184
  }
185
185
  ```
186
186
 
187
- ## 环境变量
187
+ ### CLAUDE.md 配置(项目级)
188
188
 
189
- | 变量 | 说明 |
190
- |------|------|
191
- | `ANTHROPIC_API_KEY` | API 密钥 |
192
- | `CLAUDE_CODE_USE_OPENAI` | 启用 OpenAI 协议(1=启用) |
193
- | `OPENAI_API_KEY` | OpenAI API 密钥 |
194
- | `OPENAI_API_BASE` | OpenAI 兼容 API 基础 URL |
195
- | `CLAUDE_CODE_ENABLE_CFC` | 启用 Chrome 集成(1=启用,0=禁用) |
196
- | `CLAUDE_CHROME_HTTP` | 启用 Chrome HTTP 桥接模式(1=启用) |
197
- | `CLAUDE_CHROME_HTTP_PORT` | HTTP 服务器端口(默认 12306) |
198
- | `ENABLE_TOOL_SEARCH` | 工具搜索模式:`tst`(默认)、`tst-auto`、`standard` |
199
- | `CLAUDE_CODE_EXTRA_BODY` | API 请求的额外 body 参数 |
189
+ 在项目根目录创建 `.claude/CLAUDE.md`,用于定义项目特定的指令和行为:
200
190
 
201
- ## 开启"宠物"功能
191
+ ```markdown
192
+ # 项目指令
202
193
 
203
- "宠物"(SprocketDudot)是 Claude Code 的伴随功能。开启方式:
194
+ 你正在协助开发一个 Node.js 项目。请遵循以下规则:
204
195
 
205
- 1. **通过 session.json 配置**:
196
+ - 使用 TypeScript
197
+ - 遵循 ESLint 规范
198
+ - 编写单元测试
199
+ ```
206
200
 
207
- `~/.claude/session.json` 的 `env` 中添加:
201
+ ## OpenAI 协议支持
208
202
 
209
- ```json
210
- {
211
- "env": {
212
- "SPROCKET_DUDOT_ENABLED": "1"
213
- }
214
- }
215
- ```
203
+ 当设置 `CLAUDE_CODE_USE_OPENAI=1` 时,CLI 使用 OpenAI 兼容协议与 API 通信。
216
204
 
217
- 2. **通过环境变量**:
205
+ ### 支持的 API 端点
218
206
 
219
- 在启动 Claude Code 前设置环境变量:
207
+ | 服务 | OPENAI_BASE_URL | 说明 |
208
+ |------|----------------|------|
209
+ | OpenAI 官方 | `https://api.openai.com/v1` | GPT-4o、o1 等 |
210
+ | 阿里云百炼 DashScope | `https://coding.dashscope.aliyuncs.com/v1` | 通义千问系列 |
211
+ | Ollama (本地) | `http://127.0.0.1:11434/v1` | 本地开源模型 |
212
+ | vLLM | `http://localhost:8000/v1` | 兼容 OpenAI 格式 |
220
213
 
221
- ```bash
222
- export SPROCKET_DUDOT_ENABLED=1
223
- claude
224
- ```
214
+ ### 使用示例
225
215
 
226
- 3. **通过 settings.json 配置**:
216
+ ```bash
217
+ # OpenAI 官方 API
218
+ OPENAI_API_KEY="sk-xxx" OPENAI_BASE_URL="https://api.openai.com/v1" OPENAI_MODEL="gpt-4o" ola-cc
227
219
 
228
- `~/.claude/settings.json` 中添加:
220
+ # 阿里云百炼
221
+ OPENAI_API_KEY="your-key" OPENAI_BASE_URL="https://coding.dashscope.aliyuncs.com/v1" OPENAI_MODEL="qwen3.6-plus" ola-cc
229
222
 
230
- ```json
231
- {
232
- "sprocketDudot": {
233
- "enabled": true
234
- }
235
- }
236
- ```
223
+ # Ollama 本地模型
224
+ OPENAI_BASE_URL="http://127.0.0.1:11434/v1" OPENAI_MODEL="llama3.1" ola-cc
225
+ ```
226
+
227
+ ### 模型选择优先级
228
+
229
+ | 优先级 | 来源 |
230
+ |--------|------|
231
+ | 1 | `/model` 命令(会话中动态切换) |
232
+ | 2 | `--model` 启动参数 |
233
+ | 3 | `ANTHROPIC_MODEL` 环境变量 |
234
+ | 4 | `OPENAI_MODEL` 环境变量 |
235
+ | 5 | `~/.claude/settings.json` 中的 `model` 字段 |
236
+ | 6 | 内置默认值 |
237
+
238
+ ## 环境变量总览
239
+
240
+ | 变量 | 说明 |
241
+ |------|------|
242
+ | `OPENAI_API_KEY` | OpenAI API 密钥 |
243
+ | `OPENAI_BASE_URL` | OpenAI 兼容 API 基础 URL |
244
+ | `OPENAI_MODEL` | 模型名称 |
245
+ | `CLAUDE_CODE_USE_OPENAI` | 启用 OpenAI 协议(1=启用) |
246
+ | `ANTHROPIC_API_KEY` | Anthropic API 密钥(直连 Anthropic 时使用) |
247
+ | `CLAUDE_CODE_ENABLE_CFC` | 启用 Chrome 集成(1=启用) |
248
+ | `CLAUDE_CHROME_HTTP` | 启用 Chrome HTTP 桥接(1=启用) |
249
+ | `CLAUDE_CHROME_HTTP_PORT` | HTTP 桥接端口(默认 12306) |
250
+ | `CLAUDE_CODE_EXTRA_BODY` | API 请求的额外 body 参数 |
251
+ | `SPROCKET_DUDOT_ENABLED` | 开启宠物功能(1=启用) |
237
252
 
238
253
  ## Chrome 扩展(可选)
239
254
 
240
255
  浏览器自动化需要安装 Claude in Chrome 扩展:
241
256
 
242
- 1. Claude Code 会自动安装原生主机清单
257
+ 1. Ola CC 会自动安装原生主机清单
243
258
  2. 从 Chrome 应用商店安装扩展
244
259
  3. 设置 `CLAUDE_CODE_ENABLE_CFC=1` 或使用 `--chrome` 参数
245
260
 
261
+ ## 构建
262
+
263
+ ```bash
264
+ # 构建包装器包
265
+ bun run build:bin:wrapper
266
+
267
+ # 构建平台二进制包(当前平台)
268
+ bun run build:bin:platform
269
+
270
+ # 完整构建(包装器 + 当前平台二进制)
271
+ bun run build:bin
272
+ ```
273
+
274
+ > **注意**:Windows 平台构建会使用 Node.js JS bundle 而非 Bun 编译二进制,以确保稳定性。
275
+
276
+ ## 故障排除
277
+
278
+ ### Windows 安装问题
279
+
280
+ 如果 Windows 安装后运行 `ola-cc` 出现问题:
281
+
282
+ **方案 1:检查 Node.js 版本**
283
+
284
+ 确保 Node.js >= 18:
285
+
286
+ ```bash
287
+ node --version
288
+ ```
289
+
290
+ **方案 2:手动启动 JS bundle**
291
+
292
+ 绕过 npm bin shim,直接运行 JS bundle:
293
+
294
+ ```bash
295
+ node "%APPDATA%\npm\node_modules\@zyzheal\ola-cc\cli.mjs"
296
+ ```
297
+
298
+ 或本地安装时:
299
+
300
+ ```bash
301
+ node node_modules/@zyzheal/ola-cc/cli.mjs
302
+ ```
303
+
304
+ **方案 3:使用降级启动器**
305
+
306
+ ```bash
307
+ node node_modules/@zyzheal/ola-cc/cli-wrapper.cjs
308
+ ```
309
+
310
+ ### macOS/Linux 原生二进制问题
311
+
312
+ 如果原生二进制无法运行:
313
+
314
+ ```bash
315
+ # 手动重新安装
316
+ cd node_modules/@zyzheal/ola-cc
317
+ node install.cjs
318
+ ```
319
+
246
320
  ## 许可证
247
321
 
248
322
  详见 LICENSE.md。
package/bin/ola-cc.js ADDED
@@ -0,0 +1,31 @@
1
+ #!/usr/bin/env node
2
+ 'use strict'
3
+ var path = require('path')
4
+ var fs = require('fs')
5
+ var childProcess = require('child_process')
6
+ var pkgDir = path.dirname(__dirname)
7
+ var binDir = path.join(pkgDir, 'bin')
8
+ var nativeBin = process.platform === 'win32' ? path.join(binDir, 'ola-cc.exe') : path.join(binDir, 'ola-cc')
9
+ if (fs.existsSync(nativeBin)) {
10
+ try { childProcess.execFileSync(nativeBin, process.argv.slice(2), { stdio: 'inherit' }); process.exit(0) }
11
+ catch (err) { if (err.code !== 'ENOENT') process.exit(err.status || 1) }
12
+ }
13
+ // Try JS bundle in the same bin directory (for JS bundle platforms like darwin-x64)
14
+ var localJs = path.join(binDir, 'cli.mjs')
15
+ if (fs.existsSync(localJs)) { childProcess.execFileSync(process.execPath, [localJs].concat(process.argv.slice(2)), { stdio: 'inherit' }); process.exit(0) }
16
+ // Fall back to JS bundle from optionalDependencies platform package
17
+ try {
18
+ var platKey = process.platform + '-' + process.arch
19
+ var platPkgName = '@zyzheal/ola-cc-' + platKey
20
+ var platPkg = require.resolve(platPkgName + '/package.json')
21
+ var platDir = path.dirname(platPkg)
22
+ // Try native binary from platform package first (postinstall may not have run)
23
+ var platBinFile = process.platform === 'win32' ? 'ola-cc.exe' : 'ola-cc'
24
+ var platBin = path.join(platDir, platBinFile)
25
+ if (fs.existsSync(platBin)) { childProcess.execFileSync(platBin, process.argv.slice(2), { stdio: 'inherit' }); process.exit(0) }
26
+ // Then JS bundle
27
+ var js = path.join(platDir, 'cli.mjs')
28
+ if (fs.existsSync(js)) { childProcess.execFileSync(process.execPath, [js].concat(process.argv.slice(2)), { stdio: 'inherit' }); process.exit(0) }
29
+ } catch (_) {}
30
+ console.error('Error: ola-cc not installed for this platform.')
31
+ process.exit(1)
@@ -0,0 +1,30 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * CLI wrapper — fallback bin entry when native binary is not installed.
4
+ * Delegates to cli.mjs (Node.js bundle) if available, otherwise prints error.
5
+ */
6
+
7
+ const { execSync } = require('child_process')
8
+ const { existsSync } = require('fs')
9
+ const { join, dirname } = require('path')
10
+
11
+ const pkgDir = dirname(require.resolve('./package.json'))
12
+ const cliMjs = join(pkgDir, 'cli.mjs')
13
+
14
+ if (existsSync(cliMjs)) {
15
+ // Re-spawn under Node.js to handle the ESM bundle
16
+ const node = process.execPath
17
+ try {
18
+ require('child_process').execFileSync(node, [cliMjs, ...process.argv.slice(2)], {
19
+ stdio: 'inherit',
20
+ env: { ...process.env },
21
+ })
22
+ process.exit(0)
23
+ } catch (err) {
24
+ process.exit(err.status || 1)
25
+ }
26
+ } else {
27
+ console.error('Error: ola-cc CLI bundle not found.')
28
+ console.error('Ensure the package was installed correctly: npm install @zyzheal/ola-cc')
29
+ process.exit(1)
30
+ }
package/install.cjs ADDED
@@ -0,0 +1,134 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Postinstall script for the wrapper package.
4
+ *
5
+ * Detects the current platform and copies the native binary from the
6
+ * appropriate platform-specific optional dependency package.
7
+ *
8
+ * This is called automatically by npm during `npm install @zyzheal/ola-cc`.
9
+ */
10
+
11
+ const { existsSync, mkdirSync, cpSync, chmodSync } = require('fs')
12
+ const { join } = require('path')
13
+
14
+ const PACKAGE_NAME = '@zyzheal/ola-cc'
15
+
16
+ const PLATFORM_MAP = {
17
+ 'darwin-arm64': `${PACKAGE_NAME}-darwin-arm64`,
18
+ 'darwin-x64': `${PACKAGE_NAME}-darwin-x64`,
19
+ 'linux-x64': `${PACKAGE_NAME}-linux-x64`,
20
+ 'linux-arm64': `${PACKAGE_NAME}-linux-arm64`,
21
+ 'linux-x64-musl': `${PACKAGE_NAME}-linux-x64-musl`,
22
+ 'linux-arm64-musl': `${PACKAGE_NAME}-linux-arm64-musl`,
23
+ 'win32-x64': `${PACKAGE_NAME}-win32-x64`,
24
+ 'win32-arm64': `${PACKAGE_NAME}-win32-arm64`,
25
+ }
26
+
27
+ const pkgRoot = __dirname
28
+ // npm installs optionalDependencies inside the package's node_modules directory
29
+ // when using global install or certain package managers (pnpm, yarn).
30
+ // Check both locations to support all installation modes.
31
+ const nodeModulesNested = join(pkgRoot, 'node_modules') // npm global / pnpm / yarn
32
+ const nodeModulesTopLevel = join(pkgRoot, '..', '..') // npm local (legacy behavior)
33
+ const binDir = join(pkgRoot, 'bin')
34
+
35
+ function detectPlatform() {
36
+ const platform = process.platform
37
+ const arch = process.arch
38
+
39
+ let isMusl = false
40
+ if (platform === 'linux') {
41
+ try {
42
+ const report = typeof process.report?.getReport === 'function'
43
+ ? process.report.getReport()
44
+ : null
45
+ isMusl = report != null && report.header?.glibcVersionRuntime === undefined
46
+ } catch {
47
+ try {
48
+ const ldd = require('child_process').execSync('ldd --version 2>&1', { encoding: 'utf8' })
49
+ isMusl = ldd.toLowerCase().includes('musl')
50
+ } catch {
51
+ // Assume glibc if we can't determine
52
+ }
53
+ }
54
+ }
55
+
56
+ return platform === 'linux'
57
+ ? `${platform}-${arch}${isMusl ? '-musl' : ''}`
58
+ : `${platform}-${arch}`
59
+ }
60
+
61
+ function findPlatformPackage(depName) {
62
+ // Try nested location first (npm global, pnpm, yarn)
63
+ const nestedPath = join(nodeModulesNested, depName)
64
+ if (existsSync(nestedPath)) {
65
+ return nestedPath
66
+ }
67
+ // Try top-level location (npm local install legacy behavior)
68
+ const topLevelPath = join(nodeModulesTopLevel, depName)
69
+ if (existsSync(topLevelPath)) {
70
+ return topLevelPath
71
+ }
72
+ return null
73
+ }
74
+
75
+ function main() {
76
+ const platformKey = detectPlatform()
77
+ const depName = PLATFORM_MAP[platformKey]
78
+
79
+ if (!depName) {
80
+ console.warn(`ola-cc: Unsupported platform ${process.platform} ${process.arch}.`)
81
+ return
82
+ }
83
+
84
+ const depPath = findPlatformPackage(depName)
85
+
86
+ if (!depPath) {
87
+ console.warn(`ola-cc: Platform package ${depName} not installed.`)
88
+ return
89
+ }
90
+
91
+ const isWindows = process.platform === 'win32'
92
+ const binaryName = isWindows ? 'ola-cc.exe' : 'ola-cc'
93
+ const srcBinary = join(depPath, binaryName)
94
+
95
+ if (!existsSync(srcBinary)) {
96
+ // Fallback: JS bundle mode for platforms without native compilation (e.g. darwin-x64)
97
+ const jsBundle = join(depPath, 'cli.mjs')
98
+ if (existsSync(jsBundle)) {
99
+ mkdirSync(binDir, { recursive: true })
100
+ cpSync(jsBundle, join(binDir, 'cli.mjs'))
101
+ console.log(`ola-cc: Installed JS bundle (cli.mjs) for ${platformKey}`)
102
+ return
103
+ }
104
+ console.warn(`ola-cc: Binary not found at ${srcBinary}`)
105
+ return
106
+ }
107
+
108
+ mkdirSync(binDir, { recursive: true })
109
+ const destName = isWindows ? 'ola-cc.exe' : 'ola-cc'
110
+ const destBinary = join(binDir, destName)
111
+
112
+ cpSync(srcBinary, destBinary)
113
+ chmodSync(destBinary, 0o755)
114
+ console.log(`ola-cc: Installed native binary for ${platformKey}`)
115
+
116
+ // Copy vendor files if present (ripgrep, etc.)
117
+ const srcVendor = join(depPath, 'vendor')
118
+ if (existsSync(srcVendor)) {
119
+ const destVendor = join(pkgRoot, 'vendor')
120
+ try {
121
+ cpSync(srcVendor, destVendor, { recursive: true })
122
+ } catch {
123
+ // Best effort
124
+ }
125
+ }
126
+ }
127
+
128
+ try {
129
+ main()
130
+ } catch (err) {
131
+ console.error(`ola-cc postinstall error: ${err.message}`)
132
+ // Don't fail the install
133
+ process.exit(0)
134
+ }