droid-patch 0.3.0 → 0.4.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/README.md +53 -1
- package/README.zh-CN.md +53 -1
- package/dist/{alias-Ols294ja.js → alias-BGsm9wXL.js} +11 -17
- package/dist/alias-BGsm9wXL.js.map +1 -0
- package/dist/cli.js +96 -13
- package/dist/cli.js.map +1 -1
- package/dist/index.js +1 -1
- package/package.json +1 -1
- package/dist/alias-Ols294ja.js.map +0 -1
package/README.md
CHANGED
|
@@ -26,8 +26,11 @@ npx droid-patch --skip-login droid-nologin
|
|
|
26
26
|
# Patch with --websearch to enable local search proxy
|
|
27
27
|
npx droid-patch --websearch droid-search
|
|
28
28
|
|
|
29
|
+
# Patch with --reasoning-effort to enable reasoning for custom models
|
|
30
|
+
npx droid-patch --reasoning-effort droid-reasoning
|
|
31
|
+
|
|
29
32
|
# Combine multiple patches
|
|
30
|
-
npx droid-patch --is-custom --skip-login --websearch droid-full
|
|
33
|
+
npx droid-patch --is-custom --skip-login --websearch --reasoning-effort droid-full
|
|
31
34
|
|
|
32
35
|
# Specify a custom path to the droid binary
|
|
33
36
|
npx droid-patch --skip-login -p /path/to/droid my-droid
|
|
@@ -57,6 +60,7 @@ npx droid-patch --skip-login -o /path/to/dir my-droid
|
|
|
57
60
|
| `--skip-login` | Bypass login by injecting a fake `FACTORY_API_KEY` into the binary |
|
|
58
61
|
| `--api-base <url>` | Replace Factory API URL with a custom server (max 22 chars) |
|
|
59
62
|
| `--websearch` | Inject local WebSearch proxy with multiple search providers |
|
|
63
|
+
| `--reasoning-effort` | Enable reasoning effort UI selector for custom models (set to high) |
|
|
60
64
|
| `--dry-run` | Verify patches without actually modifying the binary |
|
|
61
65
|
| `-p, --path <path>` | Path to the droid binary (default: `~/.droid/bin/droid`) |
|
|
62
66
|
| `-o, --output <dir>` | Output directory for patched binary (creates file without alias) |
|
|
@@ -186,6 +190,54 @@ npx droid-patch --websearch droid-search
|
|
|
186
190
|
droid-search
|
|
187
191
|
```
|
|
188
192
|
|
|
193
|
+
### `--reasoning-effort`
|
|
194
|
+
|
|
195
|
+
Enables reasoning effort control for custom models by patching the binary to:
|
|
196
|
+
1. Set `supportedReasoningEfforts` from `["none"]` to `["high"]`
|
|
197
|
+
2. Set `defaultReasoningEffort` from `"none"` to `"high"`
|
|
198
|
+
3. Enable the reasoning effort UI selector (normally hidden for custom models)
|
|
199
|
+
4. Bypass validation to allow `xhigh` via settings.json
|
|
200
|
+
|
|
201
|
+
**Purpose**: Allow custom models to use reasoning effort features that are normally only available for official models.
|
|
202
|
+
|
|
203
|
+
**How it works**:
|
|
204
|
+
- The droid UI shows a reasoning effort selector when `supportedReasoningEfforts.length > 1`
|
|
205
|
+
- Custom models are hardcoded with `["none"]`, hiding the selector
|
|
206
|
+
- This patch changes the value to `["high"]` and modifies the UI condition to show the selector
|
|
207
|
+
- The reasoning effort setting will be sent to your custom model's API
|
|
208
|
+
|
|
209
|
+
**Usage**:
|
|
210
|
+
```bash
|
|
211
|
+
# Enable reasoning effort for custom models
|
|
212
|
+
npx droid-patch --reasoning-effort droid-reasoning
|
|
213
|
+
|
|
214
|
+
# Combine with other patches
|
|
215
|
+
npx droid-patch --is-custom --reasoning-effort droid-full
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
**Configuring `xhigh` Reasoning Effort**:
|
|
219
|
+
|
|
220
|
+
The default reasoning effort is `high`. To use `xhigh` (extra high), edit your settings file:
|
|
221
|
+
|
|
222
|
+
```bash
|
|
223
|
+
# Edit ~/.factory/settings.json
|
|
224
|
+
{
|
|
225
|
+
"model": "custom:Your-Model-0",
|
|
226
|
+
"reasoningEffort": "xhigh",
|
|
227
|
+
// ... other settings
|
|
228
|
+
}
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
Available values:
|
|
232
|
+
| Value | Description |
|
|
233
|
+
|-------|-------------|
|
|
234
|
+
| `high` | High reasoning effort (default after patching) |
|
|
235
|
+
| `xhigh` | Extra high reasoning effort |
|
|
236
|
+
| `medium` | Medium reasoning effort |
|
|
237
|
+
| `low` | Low reasoning effort |
|
|
238
|
+
|
|
239
|
+
**Note**: The `xhigh` value bypasses validation and is sent directly to your API. Make sure your custom model/proxy supports this parameter.
|
|
240
|
+
|
|
189
241
|
---
|
|
190
242
|
|
|
191
243
|
## WebSearch Configuration Guide
|
package/README.zh-CN.md
CHANGED
|
@@ -26,8 +26,11 @@ npx droid-patch --skip-login droid-nologin
|
|
|
26
26
|
# 使用 --websearch 启用本地搜索代理
|
|
27
27
|
npx droid-patch --websearch droid-search
|
|
28
28
|
|
|
29
|
+
# 使用 --reasoning-effort 为自定义模型启用推理功能
|
|
30
|
+
npx droid-patch --reasoning-effort droid-reasoning
|
|
31
|
+
|
|
29
32
|
# 组合多个修补选项
|
|
30
|
-
npx droid-patch --is-custom --skip-login --websearch droid-full
|
|
33
|
+
npx droid-patch --is-custom --skip-login --websearch --reasoning-effort droid-full
|
|
31
34
|
|
|
32
35
|
# 指定 droid 二进制文件路径
|
|
33
36
|
npx droid-patch --skip-login -p /path/to/droid my-droid
|
|
@@ -57,6 +60,7 @@ npx droid-patch --skip-login -o /path/to/dir my-droid
|
|
|
57
60
|
| `--skip-login` | 通过注入假的 `FACTORY_API_KEY` 跳过登录验证 |
|
|
58
61
|
| `--api-base <url>` | 将 Factory API URL 替换为自定义服务器(最多 22 个字符) |
|
|
59
62
|
| `--websearch` | 注入本地 WebSearch 代理,支持多个搜索提供商 |
|
|
63
|
+
| `--reasoning-effort` | 为自定义模型启用推理强度 UI 选择器(设置为 high) |
|
|
60
64
|
| `--dry-run` | 验证修补但不实际修改二进制文件 |
|
|
61
65
|
| `-p, --path <path>` | droid 二进制文件路径(默认:`~/.droid/bin/droid`) |
|
|
62
66
|
| `-o, --output <dir>` | 修补后二进制文件的输出目录(直接创建文件,不创建别名) |
|
|
@@ -186,6 +190,54 @@ npx droid-patch --websearch droid-search
|
|
|
186
190
|
droid-search
|
|
187
191
|
```
|
|
188
192
|
|
|
193
|
+
### `--reasoning-effort`
|
|
194
|
+
|
|
195
|
+
通过修补二进制文件为自定义模型启用推理强度控制:
|
|
196
|
+
1. 将 `supportedReasoningEfforts` 从 `["none"]` 改为 `["high"]`
|
|
197
|
+
2. 将 `defaultReasoningEffort` 从 `"none"` 改为 `"high"`
|
|
198
|
+
3. 启用推理强度 UI 选择器(通常对自定义模型隐藏)
|
|
199
|
+
4. 绕过验证以允许通过 settings.json 设置 `xhigh`
|
|
200
|
+
|
|
201
|
+
**用途**:允许自定义模型使用通常仅对官方模型可用的推理强度功能。
|
|
202
|
+
|
|
203
|
+
**工作原理**:
|
|
204
|
+
- 当 `supportedReasoningEfforts.length > 1` 时,droid UI 会显示推理强度选择器
|
|
205
|
+
- 自定义模型硬编码为 `["none"]`,隐藏了选择器
|
|
206
|
+
- 此补丁将值改为 `["high"]` 并修改 UI 条件以显示选择器
|
|
207
|
+
- 推理强度设置将发送到您的自定义模型 API
|
|
208
|
+
|
|
209
|
+
**使用方法**:
|
|
210
|
+
```bash
|
|
211
|
+
# 为自定义模型启用推理强度
|
|
212
|
+
npx droid-patch --reasoning-effort droid-reasoning
|
|
213
|
+
|
|
214
|
+
# 与其他补丁组合使用
|
|
215
|
+
npx droid-patch --is-custom --reasoning-effort droid-full
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
**配置 `xhigh` 推理强度**:
|
|
219
|
+
|
|
220
|
+
默认推理强度为 `high`。要使用 `xhigh`(超高),请编辑设置文件:
|
|
221
|
+
|
|
222
|
+
```bash
|
|
223
|
+
# 编辑 ~/.factory/settings.json
|
|
224
|
+
{
|
|
225
|
+
"model": "custom:Your-Model-0",
|
|
226
|
+
"reasoningEffort": "xhigh",
|
|
227
|
+
// ... 其他设置
|
|
228
|
+
}
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
可用的值:
|
|
232
|
+
| 值 | 描述 |
|
|
233
|
+
|-------|-------------|
|
|
234
|
+
| `high` | 高推理强度(补丁后的默认值) |
|
|
235
|
+
| `xhigh` | 超高推理强度 |
|
|
236
|
+
| `medium` | 中等推理强度 |
|
|
237
|
+
| `low` | 低推理强度 |
|
|
238
|
+
|
|
239
|
+
**注意**:`xhigh` 值会绕过验证直接发送到 API。请确保您的自定义模型/代理支持此参数。
|
|
240
|
+
|
|
189
241
|
---
|
|
190
242
|
|
|
191
243
|
## WebSearch 配置指南
|
|
@@ -2,8 +2,8 @@ import { styleText } from "node:util";
|
|
|
2
2
|
import { appendFileSync, existsSync, lstatSync, mkdirSync, readFileSync, readdirSync, unlinkSync, writeFileSync } from "node:fs";
|
|
3
3
|
import { basename, dirname, join } from "node:path";
|
|
4
4
|
import { homedir } from "node:os";
|
|
5
|
-
import { chmod, copyFile, mkdir, readFile, readdir, readlink, stat, symlink, unlink, writeFile } from "node:fs/promises";
|
|
6
5
|
import { execSync } from "node:child_process";
|
|
6
|
+
import { chmod, copyFile, mkdir, readFile, readdir, readlink, stat, symlink, unlink, writeFile } from "node:fs/promises";
|
|
7
7
|
|
|
8
8
|
//#region src/patcher.ts
|
|
9
9
|
async function patchDroid(options) {
|
|
@@ -17,20 +17,21 @@ async function patchDroid(options) {
|
|
|
17
17
|
console.log();
|
|
18
18
|
const data = await readFile(inputPath);
|
|
19
19
|
const buffer = Buffer.from(data);
|
|
20
|
+
const workingBuffer = Buffer.from(buffer);
|
|
20
21
|
const results = [];
|
|
21
22
|
for (const patch of patches) {
|
|
22
23
|
console.log(styleText("white", `[*] Checking patch: ${styleText("yellow", patch.name)}`));
|
|
23
24
|
console.log(styleText("gray", ` ${patch.description}`));
|
|
24
|
-
const positions = findAllPositions(
|
|
25
|
+
const positions = findAllPositions(workingBuffer, patch.pattern);
|
|
25
26
|
if (positions.length === 0) {
|
|
26
27
|
console.log(styleText("yellow", ` ! Pattern not found - may already be patched`));
|
|
27
28
|
results.push({
|
|
28
29
|
name: patch.name,
|
|
29
30
|
found: 0,
|
|
30
31
|
success: false,
|
|
31
|
-
alreadyPatched:
|
|
32
|
+
alreadyPatched: workingBuffer.includes(patch.replacement)
|
|
32
33
|
});
|
|
33
|
-
const replacementPositions = findAllPositions(
|
|
34
|
+
const replacementPositions = findAllPositions(workingBuffer, patch.replacement);
|
|
34
35
|
if (replacementPositions.length > 0) {
|
|
35
36
|
console.log(styleText("blue", ` ✓ Found ${replacementPositions.length} occurrences of patched pattern`));
|
|
36
37
|
console.log(styleText("blue", ` ✓ Binary appears to be already patched`));
|
|
@@ -42,11 +43,12 @@ async function patchDroid(options) {
|
|
|
42
43
|
console.log(styleText("green", ` ✓ Found ${positions.length} occurrences`));
|
|
43
44
|
if (verbose) {
|
|
44
45
|
for (const pos of positions.slice(0, 5)) {
|
|
45
|
-
const context = getContext(
|
|
46
|
+
const context = getContext(workingBuffer, pos, patch.pattern.length, 25);
|
|
46
47
|
console.log(styleText("gray", ` @ 0x${pos.toString(16).padStart(8, "0")}: ...${context}...`));
|
|
47
48
|
}
|
|
48
49
|
if (positions.length > 5) console.log(styleText("gray", ` ... and ${positions.length - 5} more`));
|
|
49
50
|
}
|
|
51
|
+
if (!dryRun) for (const pos of positions) patch.replacement.copy(workingBuffer, pos);
|
|
50
52
|
results.push({
|
|
51
53
|
name: patch.name,
|
|
52
54
|
found: positions.length,
|
|
@@ -95,18 +97,9 @@ async function patchDroid(options) {
|
|
|
95
97
|
} else console.log(styleText("gray", `[*] Backup already exists: ${backupPath}`));
|
|
96
98
|
}
|
|
97
99
|
console.log(styleText("white", "[*] Applying patches..."));
|
|
98
|
-
const
|
|
99
|
-
let totalPatched = 0;
|
|
100
|
-
for (const patch of patches) {
|
|
101
|
-
const result = results.find((r) => r.name === patch.name);
|
|
102
|
-
if (!result || !result.positions) continue;
|
|
103
|
-
for (const pos of result.positions) {
|
|
104
|
-
patch.replacement.copy(patchedBuffer, pos);
|
|
105
|
-
totalPatched++;
|
|
106
|
-
}
|
|
107
|
-
}
|
|
100
|
+
const totalPatched = results.reduce((sum, r) => sum + (r.positions?.length || 0), 0);
|
|
108
101
|
console.log(styleText("green", `[*] Applied ${totalPatched} patches`));
|
|
109
|
-
await writeFile(finalOutputPath,
|
|
102
|
+
await writeFile(finalOutputPath, workingBuffer);
|
|
110
103
|
console.log(styleText("white", `[*] Patched binary saved: ${styleText("cyan", finalOutputPath)}`));
|
|
111
104
|
await chmod(finalOutputPath, 493);
|
|
112
105
|
console.log(styleText("gray", "[*] Set executable permission"));
|
|
@@ -259,6 +252,7 @@ function formatPatches(patches) {
|
|
|
259
252
|
if (patches.skipLogin) applied.push("skipLogin");
|
|
260
253
|
if (patches.apiBase) applied.push(`apiBase(${patches.apiBase})`);
|
|
261
254
|
if (patches.websearch) applied.push("websearch");
|
|
255
|
+
if (patches.reasoningEffort) applied.push("reasoningEffort");
|
|
262
256
|
return applied.length > 0 ? applied.join(", ") : "(none)";
|
|
263
257
|
}
|
|
264
258
|
|
|
@@ -757,4 +751,4 @@ async function restoreOriginal(originalPath) {
|
|
|
757
751
|
|
|
758
752
|
//#endregion
|
|
759
753
|
export { createAlias, createAliasForWrapper, createMetadata, formatPatches, listAliases, listAllMetadata, loadAliasMetadata, patchDroid, removeAlias, replaceOriginal, restoreOriginal, saveAliasMetadata };
|
|
760
|
-
//# sourceMappingURL=alias-
|
|
754
|
+
//# sourceMappingURL=alias-BGsm9wXL.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"alias-BGsm9wXL.js","names":["options: PatchOptions","results: PatchResult[]","buffer: Buffer","pattern: Buffer","positions: number[]","position: number","patternLength: number","contextSize: number","aliasName: string","meta: AliasMetadata","metaList: AliasMetadata[]","name: string","originalBinaryPath: string","patches: AliasMetadata[\"patches\"]","applied: string[]","shellConfigPath: string","exportLine: string","patchedBinaryPath: string","aliasName: string","aliases: AliasInfo[]","originalPath: string","wrapperPath: string"],"sources":["../src/patcher.ts","../src/metadata.ts","../src/alias.ts"],"sourcesContent":["import { readFile, writeFile, copyFile, chmod, stat } from \"node:fs/promises\";\nimport { existsSync } from \"node:fs\";\nimport { execSync } from \"node:child_process\";\nimport { styleText } from \"node:util\";\n\nexport interface Patch {\n name: string;\n description: string;\n pattern: Buffer;\n replacement: Buffer;\n}\n\nexport interface PatchOptions {\n inputPath: string;\n outputPath?: string;\n patches: Patch[];\n dryRun?: boolean;\n backup?: boolean;\n verbose?: boolean;\n}\n\ninterface PatchResult {\n name: string;\n found: number;\n positions?: number[];\n success: boolean;\n alreadyPatched?: boolean;\n}\n\nexport interface PatchDroidResult {\n success: boolean;\n dryRun?: boolean;\n results: PatchResult[];\n outputPath?: string;\n noPatchNeeded?: boolean;\n patchedCount?: number;\n}\n\nexport async function patchDroid(\n options: PatchOptions,\n): Promise<PatchDroidResult> {\n const {\n inputPath,\n outputPath,\n patches,\n dryRun = false,\n backup = true,\n verbose = false,\n } = options;\n\n const finalOutputPath = outputPath || `${inputPath}.patched`;\n\n if (!existsSync(inputPath)) {\n throw new Error(`Binary not found: ${inputPath}`);\n }\n\n const stats = await stat(inputPath);\n const fileSizeMB = (stats.size / (1024 * 1024)).toFixed(2);\n\n console.log(\n styleText(\"white\", `[*] Reading binary: ${styleText(\"cyan\", inputPath)}`),\n );\n console.log(\n styleText(\"white\", `[*] File size: ${styleText(\"cyan\", fileSizeMB)} MB`),\n );\n console.log();\n\n const data = await readFile(inputPath);\n const buffer = Buffer.from(data);\n\n // Use a working buffer that gets updated after each patch application\n // This ensures later patches search against the already-patched content\n const workingBuffer = Buffer.from(buffer);\n\n const results: PatchResult[] = [];\n\n for (const patch of patches) {\n console.log(\n styleText(\n \"white\",\n `[*] Checking patch: ${styleText(\"yellow\", patch.name)}`,\n ),\n );\n console.log(styleText(\"gray\", ` ${patch.description}`));\n\n // Search in the working buffer (which may have earlier patches applied)\n const positions = findAllPositions(workingBuffer, patch.pattern);\n\n if (positions.length === 0) {\n console.log(\n styleText(\"yellow\", ` ! Pattern not found - may already be patched`),\n );\n results.push({\n name: patch.name,\n found: 0,\n success: false,\n alreadyPatched: workingBuffer.includes(patch.replacement),\n });\n\n const replacementPositions = findAllPositions(\n workingBuffer,\n patch.replacement,\n );\n if (replacementPositions.length > 0) {\n console.log(\n styleText(\n \"blue\",\n ` ✓ Found ${replacementPositions.length} occurrences of patched pattern`,\n ),\n );\n console.log(\n styleText(\"blue\", ` ✓ Binary appears to be already patched`),\n );\n results[results.length - 1].alreadyPatched = true;\n results[results.length - 1].success = true;\n }\n continue;\n }\n\n console.log(\n styleText(\"green\", ` ✓ Found ${positions.length} occurrences`),\n );\n\n if (verbose) {\n for (const pos of positions.slice(0, 5)) {\n const context = getContext(\n workingBuffer,\n pos,\n patch.pattern.length,\n 25,\n );\n console.log(\n styleText(\n \"gray\",\n ` @ 0x${pos.toString(16).padStart(8, \"0\")}: ...${context}...`,\n ),\n );\n }\n if (positions.length > 5) {\n console.log(\n styleText(\"gray\", ` ... and ${positions.length - 5} more`),\n );\n }\n }\n\n // Apply patch immediately to working buffer so later patches see updated content\n if (!dryRun) {\n for (const pos of positions) {\n patch.replacement.copy(workingBuffer, pos);\n }\n }\n\n results.push({\n name: patch.name,\n found: positions.length,\n positions,\n success: true,\n });\n }\n\n console.log();\n\n if (dryRun) {\n console.log(styleText(\"blue\", \"─\".repeat(60)));\n console.log(styleText([\"blue\", \"bold\"], \" DRY RUN RESULTS\"));\n console.log(styleText(\"blue\", \"─\".repeat(60)));\n console.log();\n\n for (const result of results) {\n if (result.alreadyPatched) {\n console.log(styleText(\"blue\", ` [✓] ${result.name}: Already patched`));\n } else if (result.found > 0) {\n console.log(\n styleText(\n \"green\",\n ` [✓] ${result.name}: ${result.found} occurrences will be patched`,\n ),\n );\n } else {\n console.log(\n styleText(\"yellow\", ` [!] ${result.name}: Pattern not found`),\n );\n }\n }\n\n return {\n success: results.every((r) => r.success || r.alreadyPatched),\n dryRun: true,\n results,\n };\n }\n\n const patchesNeeded = results.filter((r) => r.found > 0 && !r.alreadyPatched);\n\n if (patchesNeeded.length === 0) {\n const allPatched = results.every((r) => r.alreadyPatched);\n if (allPatched) {\n console.log(\n styleText(\n \"blue\",\n \"[*] All patches already applied. Binary is up to date.\",\n ),\n );\n return {\n success: true,\n outputPath: inputPath,\n results,\n noPatchNeeded: true,\n };\n }\n console.log(styleText(\"yellow\", \"[!] No patches could be applied.\"));\n return { success: false, results };\n }\n\n if (backup) {\n const backupPath = `${inputPath}.backup`;\n if (!existsSync(backupPath)) {\n await copyFile(inputPath, backupPath);\n console.log(\n styleText(\n \"white\",\n `[*] Created backup: ${styleText(\"cyan\", backupPath)}`,\n ),\n );\n } else {\n console.log(\n styleText(\"gray\", `[*] Backup already exists: ${backupPath}`),\n );\n }\n }\n\n console.log(styleText(\"white\", \"[*] Applying patches...\"));\n // Patches have already been applied to workingBuffer during the check phase\n // Count total patches applied\n const totalPatched = results.reduce(\n (sum, r) => sum + (r.positions?.length || 0),\n 0,\n );\n\n console.log(styleText(\"green\", `[*] Applied ${totalPatched} patches`));\n\n await writeFile(finalOutputPath, workingBuffer);\n console.log(\n styleText(\n \"white\",\n `[*] Patched binary saved: ${styleText(\"cyan\", finalOutputPath)}`,\n ),\n );\n\n await chmod(finalOutputPath, 0o755);\n console.log(styleText(\"gray\", \"[*] Set executable permission\"));\n\n console.log();\n console.log(styleText(\"white\", \"[*] Verifying patches...\"));\n const verifyBuffer = await readFile(finalOutputPath);\n\n let allVerified = true;\n for (const patch of patches) {\n const oldCount = findAllPositions(verifyBuffer, patch.pattern).length;\n const newCount = findAllPositions(verifyBuffer, patch.replacement).length;\n\n if (oldCount === 0) {\n console.log(\n styleText(\n \"green\",\n ` ✓ ${patch.name}: Verified (${newCount} patched)`,\n ),\n );\n } else {\n console.log(\n styleText(\n \"red\",\n ` ✗ ${patch.name}: ${oldCount} occurrences not patched`,\n ),\n );\n allVerified = false;\n }\n }\n\n if (allVerified) {\n console.log();\n console.log(styleText(\"green\", \"[+] All patches verified successfully!\"));\n }\n\n if (process.platform === \"darwin\") {\n console.log();\n try {\n console.log(styleText(\"gray\", \"[*] Re-signing binary for macOS...\"));\n execSync(`codesign --force --deep --sign - \"${finalOutputPath}\"`, {\n stdio: \"pipe\",\n });\n console.log(styleText(\"green\", \"[*] Binary re-signed successfully\"));\n } catch {\n console.log(styleText(\"yellow\", \"[!] Could not re-sign binary\"));\n console.log(\n styleText(\n \"gray\",\n ` You may need to run: codesign --force --deep --sign - ${finalOutputPath}`,\n ),\n );\n }\n\n try {\n execSync(`xattr -cr \"${finalOutputPath}\"`, { stdio: \"pipe\" });\n } catch {\n // Ignore\n }\n }\n\n return {\n success: allVerified,\n outputPath: finalOutputPath,\n results,\n patchedCount: totalPatched,\n };\n}\n\nfunction findAllPositions(buffer: Buffer, pattern: Buffer): number[] {\n const positions: number[] = [];\n let pos = 0;\n\n while (true) {\n pos = buffer.indexOf(pattern, pos);\n if (pos === -1) break;\n positions.push(pos);\n pos += pattern.length;\n }\n\n return positions;\n}\n\nfunction getContext(\n buffer: Buffer,\n position: number,\n patternLength: number,\n contextSize: number,\n): string {\n const start = Math.max(0, position - contextSize);\n const end = Math.min(buffer.length, position + patternLength + contextSize);\n const slice = buffer.slice(start, end);\n\n let str = \"\";\n for (let i = 0; i < slice.length; i++) {\n const c = slice[i];\n if (c >= 32 && c < 127) {\n str += String.fromCharCode(c);\n } else {\n str += \".\";\n }\n }\n return str;\n}\n","/**\n * Alias Metadata Management\n *\n * Stores and retrieves metadata about created aliases, including\n * which patches were applied. This enables the `update` command\n * to re-apply the same patches when the original droid binary is updated.\n */\n\nimport { existsSync } from \"node:fs\";\nimport { mkdir, readdir, readFile, unlink, writeFile } from \"node:fs/promises\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\n\n/**\n * Metadata structure for an alias\n */\nexport interface AliasMetadata {\n /** Alias name */\n name: string;\n /** ISO timestamp when created */\n createdAt: string;\n /** ISO timestamp when last updated */\n updatedAt: string;\n /** Path to the original droid binary used for patching */\n originalBinaryPath: string;\n /** Patches that were applied */\n patches: {\n isCustom: boolean;\n skipLogin: boolean;\n apiBase: string | null;\n websearch: boolean;\n reasoningEffort: boolean;\n };\n}\n\n// Directory for storing metadata files\nconst META_DIR = join(homedir(), \".droid-patch\", \"meta\");\n\n/**\n * Ensure metadata directory exists\n */\nasync function ensureMetaDir(): Promise<void> {\n if (!existsSync(META_DIR)) {\n await mkdir(META_DIR, { recursive: true });\n }\n}\n\n/**\n * Get the path to a metadata file for an alias\n */\nfunction getMetaPath(aliasName: string): string {\n return join(META_DIR, `${aliasName}.json`);\n}\n\n/**\n * Save alias metadata to disk\n */\nexport async function saveAliasMetadata(meta: AliasMetadata): Promise<void> {\n await ensureMetaDir();\n const metaPath = getMetaPath(meta.name);\n await writeFile(metaPath, JSON.stringify(meta, null, 2));\n}\n\n/**\n * Load alias metadata from disk\n * Returns null if metadata doesn't exist\n */\nexport async function loadAliasMetadata(\n aliasName: string,\n): Promise<AliasMetadata | null> {\n const metaPath = getMetaPath(aliasName);\n if (!existsSync(metaPath)) {\n return null;\n }\n try {\n const content = await readFile(metaPath, \"utf-8\");\n return JSON.parse(content) as AliasMetadata;\n } catch {\n return null;\n }\n}\n\n/**\n * List all alias metadata\n */\nexport async function listAllMetadata(): Promise<AliasMetadata[]> {\n await ensureMetaDir();\n\n const files = await readdir(META_DIR);\n const metaList: AliasMetadata[] = [];\n\n for (const file of files) {\n if (!file.endsWith(\".json\")) continue;\n\n const aliasName = file.replace(/\\.json$/, \"\");\n const meta = await loadAliasMetadata(aliasName);\n if (meta) {\n metaList.push(meta);\n }\n }\n\n return metaList;\n}\n\n/**\n * Remove alias metadata\n */\nexport async function removeAliasMetadata(aliasName: string): Promise<boolean> {\n const metaPath = getMetaPath(aliasName);\n if (!existsSync(metaPath)) {\n return false;\n }\n try {\n await unlink(metaPath);\n return true;\n } catch {\n return false;\n }\n}\n\n/**\n * Create a new metadata object with current timestamp\n */\nexport function createMetadata(\n name: string,\n originalBinaryPath: string,\n patches: AliasMetadata[\"patches\"],\n): AliasMetadata {\n const now = new Date().toISOString();\n return {\n name,\n createdAt: now,\n updatedAt: now,\n originalBinaryPath,\n patches,\n };\n}\n\n/**\n * Format patches for display\n */\nexport function formatPatches(patches: AliasMetadata[\"patches\"]): string {\n const applied: string[] = [];\n if (patches.isCustom) applied.push(\"isCustom\");\n if (patches.skipLogin) applied.push(\"skipLogin\");\n if (patches.apiBase) applied.push(`apiBase(${patches.apiBase})`);\n if (patches.websearch) applied.push(\"websearch\");\n if (patches.reasoningEffort) applied.push(\"reasoningEffort\");\n return applied.length > 0 ? applied.join(\", \") : \"(none)\";\n}\n","import {\n existsSync,\n mkdirSync,\n readdirSync,\n unlinkSync,\n lstatSync,\n readFileSync,\n appendFileSync,\n writeFileSync,\n} from \"node:fs\";\nimport { symlink, readlink, unlink, copyFile, chmod } from \"node:fs/promises\";\nimport { join, basename, dirname } from \"node:path\";\nimport { homedir } from \"node:os\";\nimport { execSync } from \"node:child_process\";\nimport { styleText } from \"node:util\";\nimport { removeAliasMetadata } from \"./metadata.ts\";\n\nconst DROID_PATCH_DIR = join(homedir(), \".droid-patch\");\nconst ALIASES_DIR = join(DROID_PATCH_DIR, \"aliases\");\nconst BINS_DIR = join(DROID_PATCH_DIR, \"bins\");\n\nconst COMMON_PATH_DIRS = [\n join(homedir(), \".local/bin\"),\n join(homedir(), \"bin\"),\n join(homedir(), \".bin\"),\n \"/opt/homebrew/bin\",\n \"/usr/local/bin\",\n join(homedir(), \".npm-global/bin\"),\n join(homedir(), \".npm/bin\"),\n join(homedir(), \".pnpm-global/bin\"),\n join(homedir(), \".yarn/bin\"),\n join(homedir(), \".config/yarn/global/node_modules/.bin\"),\n join(homedir(), \".cargo/bin\"),\n join(homedir(), \"go/bin\"),\n join(homedir(), \".deno/bin\"),\n join(homedir(), \".bun/bin\"),\n join(homedir(), \".local/share/mise/shims\"),\n join(homedir(), \".asdf/shims\"),\n join(homedir(), \".nvm/current/bin\"),\n join(homedir(), \".volta/bin\"),\n join(homedir(), \".fnm/current/bin\"),\n];\n\nfunction ensureDirectories(): void {\n if (!existsSync(DROID_PATCH_DIR)) {\n mkdirSync(DROID_PATCH_DIR, { recursive: true });\n }\n if (!existsSync(ALIASES_DIR)) {\n mkdirSync(ALIASES_DIR, { recursive: true });\n }\n if (!existsSync(BINS_DIR)) {\n mkdirSync(BINS_DIR, { recursive: true });\n }\n}\n\nfunction checkPathInclusion(): boolean {\n const pathEnv = process.env.PATH || \"\";\n return pathEnv.split(\":\").includes(ALIASES_DIR);\n}\n\nexport function findWritablePathDir(): string | null {\n const pathEnv = process.env.PATH || \"\";\n const pathDirs = pathEnv.split(\":\");\n\n for (const dir of COMMON_PATH_DIRS) {\n if (pathDirs.includes(dir)) {\n try {\n if (!existsSync(dir)) {\n mkdirSync(dir, { recursive: true });\n }\n const testFile = join(dir, `.droid-patch-test-${Date.now()}`);\n writeFileSync(testFile, \"\");\n unlinkSync(testFile);\n return dir;\n } catch {\n continue;\n }\n }\n }\n\n return null;\n}\n\nfunction getShellConfigPath(): string {\n const shell = process.env.SHELL || \"/bin/bash\";\n const shellName = basename(shell);\n\n switch (shellName) {\n case \"zsh\":\n return join(homedir(), \".zshrc\");\n case \"bash\": {\n const bashProfile = join(homedir(), \".bash_profile\");\n if (existsSync(bashProfile)) return bashProfile;\n return join(homedir(), \".bashrc\");\n }\n case \"fish\":\n return join(homedir(), \".config/fish/config.fish\");\n default:\n return join(homedir(), \".profile\");\n }\n}\n\nfunction isPathConfigured(shellConfigPath: string): boolean {\n if (!existsSync(shellConfigPath)) {\n return false;\n }\n\n try {\n const content = readFileSync(shellConfigPath, \"utf-8\");\n return (\n content.includes(\".droid-patch/aliases\") ||\n content.includes(\"droid-patch/aliases\")\n );\n } catch {\n return false;\n }\n}\n\nfunction addPathToShellConfig(\n shellConfigPath: string,\n verbose = false,\n): boolean {\n const shell = process.env.SHELL || \"/bin/bash\";\n const shellName = basename(shell);\n\n let exportLine: string;\n if (shellName === \"fish\") {\n exportLine = `\\n# Added by droid-patch\\nfish_add_path \"${ALIASES_DIR}\"\\n`;\n } else {\n exportLine = `\\n# Added by droid-patch\\nexport PATH=\"${ALIASES_DIR}:$PATH\"\\n`;\n }\n\n try {\n appendFileSync(shellConfigPath, exportLine);\n if (verbose) {\n console.log(\n styleText(\"gray\", ` Added PATH export to: ${shellConfigPath}`),\n );\n }\n return true;\n } catch (error) {\n console.log(\n styleText(\n \"yellow\",\n `[!] Could not write to ${shellConfigPath}: ${(error as Error).message}`,\n ),\n );\n return false;\n }\n}\n\nexport interface CreateAliasResult {\n aliasPath: string;\n binaryPath: string;\n immediate?: boolean;\n}\n\nexport async function createAlias(\n patchedBinaryPath: string,\n aliasName: string,\n verbose = false,\n): Promise<CreateAliasResult> {\n ensureDirectories();\n\n console.log(\n styleText(\"white\", `[*] Creating alias: ${styleText(\"cyan\", aliasName)}`),\n );\n\n const writablePathDir = findWritablePathDir();\n\n if (writablePathDir) {\n const targetPath = join(writablePathDir, aliasName);\n const binaryDest = join(BINS_DIR, `${aliasName}-patched`);\n await copyFile(patchedBinaryPath, binaryDest);\n await chmod(binaryDest, 0o755);\n\n if (verbose) {\n console.log(styleText(\"gray\", ` Stored binary: ${binaryDest}`));\n }\n\n if (existsSync(targetPath)) {\n await unlink(targetPath);\n if (verbose) {\n console.log(styleText(\"gray\", ` Removed existing: ${targetPath}`));\n }\n }\n\n await symlink(binaryDest, targetPath);\n\n if (process.platform === \"darwin\") {\n try {\n console.log(styleText(\"gray\", \"[*] Re-signing binary for macOS...\"));\n execSync(`codesign --force --deep --sign - \"${binaryDest}\"`, {\n stdio: \"pipe\",\n });\n console.log(styleText(\"green\", \"[*] Binary re-signed successfully\"));\n } catch {\n console.log(styleText(\"yellow\", \"[!] Could not re-sign binary\"));\n }\n\n try {\n execSync(`xattr -cr \"${binaryDest}\"`, { stdio: \"pipe\" });\n } catch {\n // Ignore\n }\n }\n\n console.log(\n styleText(\"green\", `[*] Created: ${targetPath} -> ${binaryDest}`),\n );\n console.log();\n console.log(styleText(\"green\", \"─\".repeat(60)));\n console.log(\n styleText([\"green\", \"bold\"], \" ALIAS READY - NO ACTION REQUIRED!\"),\n );\n console.log(styleText(\"green\", \"─\".repeat(60)));\n console.log();\n console.log(\n styleText(\n \"white\",\n `The alias \"${styleText([\"cyan\", \"bold\"], aliasName)}\" is now available in ALL terminals.`,\n ),\n );\n console.log(styleText(\"gray\", `(Installed to: ${writablePathDir})`));\n\n return {\n aliasPath: targetPath,\n binaryPath: binaryDest,\n immediate: true,\n };\n }\n\n console.log(\n styleText(\n \"yellow\",\n \"[*] No writable PATH directory found, using fallback...\",\n ),\n );\n\n const binaryDest = join(BINS_DIR, `${aliasName}-patched`);\n await copyFile(patchedBinaryPath, binaryDest);\n await chmod(binaryDest, 0o755);\n\n if (verbose) {\n console.log(styleText(\"gray\", ` Copied binary to: ${binaryDest}`));\n }\n\n if (process.platform === \"darwin\") {\n try {\n console.log(styleText(\"gray\", \"[*] Re-signing binary for macOS...\"));\n execSync(`codesign --force --deep --sign - \"${binaryDest}\"`, {\n stdio: \"pipe\",\n });\n console.log(styleText(\"green\", \"[*] Binary re-signed successfully\"));\n } catch {\n console.log(\n styleText(\n \"yellow\",\n \"[!] Could not re-sign binary. You may need to do this manually:\",\n ),\n );\n console.log(\n styleText(\n \"gray\",\n ` codesign --force --deep --sign - \"${binaryDest}\"`,\n ),\n );\n }\n\n try {\n execSync(`xattr -cr \"${binaryDest}\"`, { stdio: \"pipe\" });\n } catch {\n // Ignore\n }\n }\n\n const symlinkPath = join(ALIASES_DIR, aliasName);\n\n if (existsSync(symlinkPath)) {\n await unlink(symlinkPath);\n if (verbose) {\n console.log(styleText(\"gray\", ` Removed existing symlink`));\n }\n }\n\n await symlink(binaryDest, symlinkPath);\n await chmod(symlinkPath, 0o755);\n\n console.log(\n styleText(\"green\", `[*] Created symlink: ${symlinkPath} -> ${binaryDest}`),\n );\n\n const shellConfig = getShellConfigPath();\n\n if (!checkPathInclusion()) {\n if (!isPathConfigured(shellConfig)) {\n console.log(\n styleText(\"white\", `[*] Configuring PATH in ${shellConfig}...`),\n );\n\n if (addPathToShellConfig(shellConfig, verbose)) {\n console.log(styleText(\"green\", `[*] PATH configured successfully!`));\n console.log();\n console.log(styleText(\"yellow\", \"─\".repeat(60)));\n console.log(styleText([\"yellow\", \"bold\"], \" ACTION REQUIRED\"));\n console.log(styleText(\"yellow\", \"─\".repeat(60)));\n console.log();\n console.log(\n styleText(\"white\", \"To use the alias in this terminal, run:\"),\n );\n console.log();\n console.log(styleText(\"cyan\", ` source ${shellConfig}`));\n console.log();\n console.log(styleText(\"gray\", \"Or simply open a new terminal window.\"));\n console.log(styleText(\"yellow\", \"─\".repeat(60)));\n } else {\n const exportLine = `export PATH=\"${ALIASES_DIR}:$PATH\"`;\n console.log();\n console.log(styleText(\"yellow\", \"─\".repeat(60)));\n console.log(\n styleText([\"yellow\", \"bold\"], \" Manual PATH Configuration Required\"),\n );\n console.log(styleText(\"yellow\", \"─\".repeat(60)));\n console.log();\n console.log(styleText(\"white\", \"Add this line to your shell config:\"));\n console.log(styleText(\"cyan\", ` ${exportLine}`));\n console.log();\n console.log(styleText(\"gray\", `Shell config file: ${shellConfig}`));\n console.log(styleText(\"yellow\", \"─\".repeat(60)));\n }\n } else {\n console.log(\n styleText(\"green\", `[*] PATH already configured in ${shellConfig}`),\n );\n console.log();\n console.log(\n styleText(\n \"yellow\",\n `Note: Run \\`source ${shellConfig}\\` or open a new terminal to use the alias.`,\n ),\n );\n }\n } else {\n console.log(\n styleText(\"green\", `[*] PATH already includes aliases directory`),\n );\n console.log();\n console.log(\n styleText(\n \"green\",\n `You can now use \"${styleText([\"cyan\", \"bold\"], aliasName)}\" command directly!`,\n ),\n );\n }\n\n return {\n aliasPath: symlinkPath,\n binaryPath: binaryDest,\n };\n}\n\nexport async function removeAlias(aliasName: string): Promise<void> {\n console.log(\n styleText(\"white\", `[*] Removing alias: ${styleText(\"cyan\", aliasName)}`),\n );\n\n let removed = false;\n\n // Check common PATH directories for symlinks\n for (const pathDir of COMMON_PATH_DIRS) {\n const pathSymlink = join(pathDir, aliasName);\n if (existsSync(pathSymlink)) {\n try {\n const stats = lstatSync(pathSymlink);\n if (stats.isSymbolicLink()) {\n const target = await readlink(pathSymlink);\n // Support both regular aliases (.droid-patch/bins) and websearch wrappers (.droid-patch/websearch)\n if (\n target.includes(\".droid-patch/bins\") ||\n target.includes(\".droid-patch/websearch\")\n ) {\n await unlink(pathSymlink);\n console.log(styleText(\"green\", ` Removed: ${pathSymlink}`));\n removed = true;\n }\n }\n } catch {\n // Ignore\n }\n }\n }\n\n // Check aliases directory\n const symlinkPath = join(ALIASES_DIR, aliasName);\n if (existsSync(symlinkPath)) {\n await unlink(symlinkPath);\n console.log(styleText(\"green\", ` Removed: ${symlinkPath}`));\n removed = true;\n }\n\n // Remove binary if exists\n const binaryPath = join(BINS_DIR, `${aliasName}-patched`);\n if (existsSync(binaryPath)) {\n await unlink(binaryPath);\n console.log(styleText(\"green\", ` Removed binary: ${binaryPath}`));\n removed = true;\n }\n\n // Remove websearch wrapper and related files if exist\n const websearchDir = join(DROID_PATCH_DIR, \"websearch\");\n const wrapperPath = join(websearchDir, aliasName);\n const proxyPath = join(websearchDir, `${aliasName}-proxy.js`);\n const preloadPath = join(websearchDir, `${aliasName}-preload.js`);\n\n if (existsSync(wrapperPath)) {\n await unlink(wrapperPath);\n console.log(styleText(\"green\", ` Removed wrapper: ${wrapperPath}`));\n removed = true;\n }\n\n if (existsSync(proxyPath)) {\n await unlink(proxyPath);\n console.log(styleText(\"green\", ` Removed proxy: ${proxyPath}`));\n removed = true;\n }\n\n if (existsSync(preloadPath)) {\n await unlink(preloadPath);\n console.log(styleText(\"green\", ` Removed preload: ${preloadPath}`));\n removed = true;\n }\n\n // Remove metadata\n const metaRemoved = await removeAliasMetadata(aliasName);\n if (metaRemoved) {\n console.log(styleText(\"green\", ` Removed metadata`));\n removed = true;\n }\n\n if (!removed) {\n console.log(styleText(\"yellow\", ` Alias \"${aliasName}\" not found`));\n } else {\n console.log(\n styleText(\"green\", `[*] Alias \"${aliasName}\" removed successfully`),\n );\n }\n}\n\nexport async function listAliases(): Promise<void> {\n ensureDirectories();\n\n console.log(styleText(\"cyan\", \"═\".repeat(60)));\n console.log(styleText([\"cyan\", \"bold\"], \" Droid-Patch Aliases\"));\n console.log(styleText(\"cyan\", \"═\".repeat(60)));\n console.log();\n\n interface AliasInfo {\n name: string;\n target: string;\n location: string;\n immediate: boolean;\n }\n\n const aliases: AliasInfo[] = [];\n\n for (const pathDir of COMMON_PATH_DIRS) {\n if (!existsSync(pathDir)) continue;\n\n try {\n const files = readdirSync(pathDir);\n for (const file of files) {\n const fullPath = join(pathDir, file);\n try {\n const stats = lstatSync(fullPath);\n if (stats.isSymbolicLink()) {\n const target = await readlink(fullPath);\n // Support both regular aliases and websearch wrappers\n if (\n target.includes(\".droid-patch/bins\") ||\n target.includes(\".droid-patch/websearch\")\n ) {\n aliases.push({\n name: file,\n target,\n location: pathDir,\n immediate: true,\n });\n }\n }\n } catch {\n // Ignore\n }\n }\n } catch {\n // Directory can't be read\n }\n }\n\n try {\n const files = readdirSync(ALIASES_DIR);\n\n for (const file of files) {\n const fullPath = join(ALIASES_DIR, file);\n try {\n const stats = lstatSync(fullPath);\n if (stats.isSymbolicLink()) {\n const target = await readlink(fullPath);\n if (!aliases.find((a) => a.name === file)) {\n aliases.push({\n name: file,\n target,\n location: ALIASES_DIR,\n immediate: false,\n });\n }\n }\n } catch {\n // Ignore\n }\n }\n } catch {\n // Directory doesn't exist or can't be read\n }\n\n if (aliases.length === 0) {\n console.log(styleText(\"gray\", \" No aliases configured.\"));\n console.log();\n console.log(\n styleText(\n \"gray\",\n \" Create one with: npx droid-patch --is-custom <alias-name>\",\n ),\n );\n } else {\n console.log(styleText(\"white\", ` Found ${aliases.length} alias(es):`));\n console.log();\n for (const alias of aliases) {\n const status = alias.immediate\n ? styleText(\"green\", \"✓ immediate\")\n : styleText(\"yellow\", \"requires source\");\n console.log(\n styleText(\n \"green\",\n ` • ${styleText([\"cyan\", \"bold\"], alias.name)} [${status}]`,\n ),\n );\n console.log(styleText(\"gray\", ` → ${alias.target}`));\n }\n }\n\n console.log();\n console.log(styleText(\"gray\", ` Aliases directory: ${ALIASES_DIR}`));\n console.log(\n styleText(\n \"gray\",\n ` PATH configured: ${checkPathInclusion() ? styleText(\"green\", \"Yes\") : styleText(\"yellow\", \"No\")}`,\n ),\n );\n console.log();\n}\n\nexport interface ReplaceOriginalResult {\n originalPath: string;\n backupPath: string;\n}\n\nexport async function replaceOriginal(\n patchedBinaryPath: string,\n originalPath: string,\n verbose = false,\n): Promise<ReplaceOriginalResult> {\n ensureDirectories();\n\n console.log(\n styleText(\n \"white\",\n `[*] Replacing original binary: ${styleText(\"cyan\", originalPath)}`,\n ),\n );\n\n const latestBackupPath = join(BINS_DIR, \"droid-original-latest\");\n\n if (!existsSync(latestBackupPath)) {\n await copyFile(originalPath, latestBackupPath);\n console.log(styleText(\"green\", `[*] Created backup: ${latestBackupPath}`));\n } else {\n if (verbose) {\n console.log(\n styleText(\"gray\", ` Backup already exists: ${latestBackupPath}`),\n );\n }\n }\n\n await copyFile(patchedBinaryPath, originalPath);\n await chmod(originalPath, 0o755);\n console.log(styleText(\"green\", `[*] Replaced: ${originalPath}`));\n\n if (process.platform === \"darwin\") {\n try {\n console.log(styleText(\"gray\", \"[*] Re-signing binary for macOS...\"));\n execSync(`codesign --force --deep --sign - \"${originalPath}\"`, {\n stdio: \"pipe\",\n });\n console.log(styleText(\"green\", \"[*] Binary re-signed successfully\"));\n } catch {\n console.log(\n styleText(\n \"yellow\",\n \"[!] Could not re-sign binary. You may need to run:\",\n ),\n );\n console.log(\n styleText(\n \"gray\",\n ` codesign --force --deep --sign - \"${originalPath}\"`,\n ),\n );\n }\n\n try {\n execSync(`xattr -cr \"${originalPath}\"`, { stdio: \"pipe\" });\n } catch {\n // Ignore\n }\n }\n\n console.log();\n console.log(styleText(\"green\", \"─\".repeat(60)));\n console.log(styleText([\"green\", \"bold\"], \" REPLACEMENT COMPLETE\"));\n console.log(styleText(\"green\", \"─\".repeat(60)));\n console.log();\n console.log(\n styleText(\"white\", \"The patched binary is now active in all terminals.\"),\n );\n console.log(styleText(\"white\", \"No need to restart or source anything!\"));\n console.log();\n console.log(styleText(\"gray\", `To restore the original, run:`));\n console.log(styleText(\"cyan\", ` npx droid-patch restore`));\n\n return {\n originalPath,\n backupPath: latestBackupPath,\n };\n}\n\n/**\n * Create alias for wrapper script\n * Unlike createAlias, this function creates symlink pointing to wrapper script\n * Used for features like websearch that require preprocessing\n */\nexport async function createAliasForWrapper(\n wrapperPath: string,\n aliasName: string,\n verbose = false,\n): Promise<CreateAliasResult> {\n ensureDirectories();\n\n console.log(\n styleText(\"white\", `[*] Creating alias: ${styleText(\"cyan\", aliasName)}`),\n );\n\n const writablePathDir = findWritablePathDir();\n\n if (writablePathDir) {\n const targetPath = join(writablePathDir, aliasName);\n\n if (verbose) {\n console.log(styleText(\"gray\", ` Wrapper: ${wrapperPath}`));\n }\n\n if (existsSync(targetPath)) {\n await unlink(targetPath);\n if (verbose) {\n console.log(styleText(\"gray\", ` Removed existing: ${targetPath}`));\n }\n }\n\n await symlink(wrapperPath, targetPath);\n\n console.log(\n styleText(\"green\", `[*] Created: ${targetPath} -> ${wrapperPath}`),\n );\n console.log();\n console.log(styleText(\"green\", \"─\".repeat(60)));\n console.log(\n styleText([\"green\", \"bold\"], \" ALIAS READY - NO ACTION REQUIRED!\"),\n );\n console.log(styleText(\"green\", \"─\".repeat(60)));\n console.log();\n console.log(\n styleText(\n \"white\",\n `The alias \"${styleText([\"cyan\", \"bold\"], aliasName)}\" is now available in ALL terminals.`,\n ),\n );\n console.log(styleText(\"gray\", `(Installed to: ${writablePathDir})`));\n\n return {\n aliasPath: targetPath,\n binaryPath: wrapperPath,\n immediate: true,\n };\n }\n\n // Fallback: use ~/.droid-patch/aliases\n console.log(\n styleText(\n \"yellow\",\n \"[*] No writable PATH directory found, using fallback...\",\n ),\n );\n\n const symlinkPath = join(ALIASES_DIR, aliasName);\n\n if (existsSync(symlinkPath)) {\n await unlink(symlinkPath);\n if (verbose) {\n console.log(styleText(\"gray\", ` Removed existing symlink`));\n }\n }\n\n await symlink(wrapperPath, symlinkPath);\n\n console.log(\n styleText(\"green\", `[*] Created symlink: ${symlinkPath} -> ${wrapperPath}`),\n );\n\n const shellConfig = getShellConfigPath();\n\n if (!checkPathInclusion()) {\n if (!isPathConfigured(shellConfig)) {\n console.log(\n styleText(\"white\", `[*] Configuring PATH in ${shellConfig}...`),\n );\n\n if (addPathToShellConfig(shellConfig, verbose)) {\n console.log(styleText(\"green\", `[*] PATH configured successfully!`));\n console.log();\n console.log(styleText(\"yellow\", \"─\".repeat(60)));\n console.log(styleText([\"yellow\", \"bold\"], \" ACTION REQUIRED\"));\n console.log(styleText(\"yellow\", \"─\".repeat(60)));\n console.log();\n console.log(\n styleText(\"white\", \"To use the alias in this terminal, run:\"),\n );\n console.log();\n console.log(styleText(\"cyan\", ` source ${shellConfig}`));\n console.log();\n console.log(styleText(\"gray\", \"Or simply open a new terminal window.\"));\n console.log(styleText(\"yellow\", \"─\".repeat(60)));\n } else {\n const exportLine = `export PATH=\"${ALIASES_DIR}:$PATH\"`;\n console.log();\n console.log(styleText(\"yellow\", \"─\".repeat(60)));\n console.log(\n styleText([\"yellow\", \"bold\"], \" Manual PATH Configuration Required\"),\n );\n console.log(styleText(\"yellow\", \"─\".repeat(60)));\n console.log();\n console.log(styleText(\"white\", \"Add this line to your shell config:\"));\n console.log(styleText(\"cyan\", ` ${exportLine}`));\n console.log();\n console.log(styleText(\"gray\", `Shell config file: ${shellConfig}`));\n console.log(styleText(\"yellow\", \"─\".repeat(60)));\n }\n } else {\n console.log(\n styleText(\"green\", `[*] PATH already configured in ${shellConfig}`),\n );\n console.log();\n console.log(\n styleText(\n \"yellow\",\n `Note: Run \\`source ${shellConfig}\\` or open a new terminal to use the alias.`,\n ),\n );\n }\n } else {\n console.log(\n styleText(\"green\", `[*] PATH already includes aliases directory`),\n );\n console.log();\n console.log(\n styleText(\n \"green\",\n `You can now use \"${styleText([\"cyan\", \"bold\"], aliasName)}\" command directly!`,\n ),\n );\n }\n\n return {\n aliasPath: symlinkPath,\n binaryPath: wrapperPath,\n };\n}\n\nexport async function restoreOriginal(originalPath: string): Promise<void> {\n ensureDirectories();\n\n const latestBackupPath = join(BINS_DIR, \"droid-original-latest\");\n\n console.log(styleText(\"cyan\", \"═\".repeat(60)));\n console.log(styleText([\"cyan\", \"bold\"], \" Restore Original Droid\"));\n console.log(styleText(\"cyan\", \"═\".repeat(60)));\n console.log();\n\n if (!existsSync(latestBackupPath)) {\n const localBackup = `${originalPath}.backup`;\n if (existsSync(localBackup)) {\n console.log(styleText(\"white\", `[*] Found local backup: ${localBackup}`));\n console.log(styleText(\"white\", `[*] Restoring to: ${originalPath}`));\n\n await copyFile(localBackup, originalPath);\n await chmod(originalPath, 0o755);\n\n if (process.platform === \"darwin\") {\n try {\n execSync(`codesign --force --deep --sign - \"${originalPath}\"`, {\n stdio: \"pipe\",\n });\n execSync(`xattr -cr \"${originalPath}\"`, { stdio: \"pipe\" });\n } catch {\n // Ignore\n }\n }\n\n console.log();\n console.log(styleText(\"green\", \"═\".repeat(60)));\n console.log(styleText([\"green\", \"bold\"], \" RESTORE COMPLETE\"));\n console.log(styleText(\"green\", \"═\".repeat(60)));\n console.log();\n console.log(\n styleText(\n \"green\",\n \"Original droid binary has been restored from local backup.\",\n ),\n );\n return;\n }\n\n console.log(styleText(\"red\", \"[!] No backup found.\"));\n console.log(styleText(\"gray\", ` Checked: ${latestBackupPath}`));\n console.log(styleText(\"gray\", ` Checked: ${localBackup}`));\n console.log();\n console.log(\n styleText(\"gray\", \"If you have a manual backup, restore it with:\"),\n );\n console.log(styleText(\"cyan\", ` cp /path/to/backup ${originalPath}`));\n return;\n }\n\n console.log(styleText(\"white\", `[*] Restoring from: ${latestBackupPath}`));\n console.log(styleText(\"white\", `[*] Restoring to: ${originalPath}`));\n\n const targetDir = dirname(originalPath);\n if (!existsSync(targetDir)) {\n mkdirSync(targetDir, { recursive: true });\n }\n\n await copyFile(latestBackupPath, originalPath);\n await chmod(originalPath, 0o755);\n\n if (process.platform === \"darwin\") {\n try {\n execSync(`codesign --force --deep --sign - \"${originalPath}\"`, {\n stdio: \"pipe\",\n });\n execSync(`xattr -cr \"${originalPath}\"`, { stdio: \"pipe\" });\n } catch {\n // Ignore\n }\n }\n\n console.log();\n console.log(styleText(\"green\", \"═\".repeat(60)));\n console.log(styleText([\"green\", \"bold\"], \" RESTORE COMPLETE\"));\n console.log(styleText(\"green\", \"═\".repeat(60)));\n console.log();\n console.log(styleText(\"green\", \"Original droid binary has been restored.\"));\n console.log(\n styleText(\"green\", \"All terminals will now use the original version.\"),\n );\n}\n"],"mappings":"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"}
|
package/dist/cli.js
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { createAlias, createAliasForWrapper, createMetadata, formatPatches, listAliases, listAllMetadata, loadAliasMetadata, patchDroid, removeAlias, saveAliasMetadata } from "./alias-
|
|
2
|
+
import { createAlias, createAliasForWrapper, createMetadata, formatPatches, listAliases, listAllMetadata, loadAliasMetadata, patchDroid, removeAlias, saveAliasMetadata } from "./alias-BGsm9wXL.js";
|
|
3
3
|
import bin from "tiny-bin";
|
|
4
4
|
import { styleText } from "node:util";
|
|
5
5
|
import { existsSync, readFileSync } from "node:fs";
|
|
6
6
|
import { dirname, join } from "node:path";
|
|
7
7
|
import { homedir } from "node:os";
|
|
8
8
|
import { fileURLToPath } from "node:url";
|
|
9
|
+
import { execSync } from "node:child_process";
|
|
9
10
|
import { chmod, mkdir, writeFile } from "node:fs/promises";
|
|
10
11
|
|
|
11
12
|
//#region src/websearch-patch.ts
|
|
@@ -674,20 +675,34 @@ function getVersion() {
|
|
|
674
675
|
const version = getVersion();
|
|
675
676
|
function findDefaultDroidPath() {
|
|
676
677
|
const home = homedir();
|
|
678
|
+
try {
|
|
679
|
+
const result = execSync("which droid", {
|
|
680
|
+
encoding: "utf-8",
|
|
681
|
+
stdio: [
|
|
682
|
+
"pipe",
|
|
683
|
+
"pipe",
|
|
684
|
+
"pipe"
|
|
685
|
+
]
|
|
686
|
+
}).trim();
|
|
687
|
+
if (result && existsSync(result)) return result;
|
|
688
|
+
} catch {}
|
|
677
689
|
const paths = [
|
|
678
|
-
join(home, ".droid
|
|
690
|
+
join(home, ".droid", "bin", "droid"),
|
|
691
|
+
"/opt/homebrew/bin/droid",
|
|
679
692
|
"/usr/local/bin/droid",
|
|
693
|
+
"/usr/bin/droid",
|
|
680
694
|
"./droid"
|
|
681
695
|
];
|
|
682
696
|
for (const p of paths) if (existsSync(p)) return p;
|
|
683
|
-
return join(home, ".droid
|
|
697
|
+
return join(home, ".droid", "bin", "droid");
|
|
684
698
|
}
|
|
685
|
-
bin("droid-patch", "CLI tool to patch droid binary with various modifications").package("droid-patch", version).option("--is-custom", "Patch isCustom:!0 to isCustom:!1 (enable context compression for custom models)").option("--skip-login", "Inject a fake FACTORY_API_KEY to bypass login requirement (no real key needed)").option("--api-base <url>", "Replace Factory API base URL (https://api.factory.ai) with custom URL").option("--websearch", "Enable local WebSearch via fetch hook (Google PSE + DuckDuckGo fallback)").option("--dry-run", "Verify patches without actually modifying the binary").option("-p, --path <path>", "Path to the droid binary").option("-o, --output <dir>", "Output directory for patched binary").option("--no-backup", "Do not create backup of original binary").option("-v, --verbose", "Enable verbose output").argument("[alias]", "Alias name for the patched binary").action(async (options, args) => {
|
|
699
|
+
bin("droid-patch", "CLI tool to patch droid binary with various modifications").package("droid-patch", version).option("--is-custom", "Patch isCustom:!0 to isCustom:!1 (enable context compression for custom models)").option("--skip-login", "Inject a fake FACTORY_API_KEY to bypass login requirement (no real key needed)").option("--api-base <url>", "Replace Factory API base URL (https://api.factory.ai) with custom URL").option("--websearch", "Enable local WebSearch via fetch hook (Google PSE + DuckDuckGo fallback)").option("--reasoning-effort", "Enable reasoning effort for custom models (set to high, enable UI selector)").option("--dry-run", "Verify patches without actually modifying the binary").option("-p, --path <path>", "Path to the droid binary").option("-o, --output <dir>", "Output directory for patched binary").option("--no-backup", "Do not create backup of original binary").option("-v, --verbose", "Enable verbose output").argument("[alias]", "Alias name for the patched binary").action(async (options, args) => {
|
|
686
700
|
const alias = args?.[0];
|
|
687
701
|
const isCustom = options["is-custom"];
|
|
688
702
|
const skipLogin = options["skip-login"];
|
|
689
703
|
const apiBase = options["api-base"];
|
|
690
704
|
const webSearch = options["websearch"];
|
|
705
|
+
const reasoningEffort = options["reasoning-effort"];
|
|
691
706
|
const dryRun = options["dry-run"];
|
|
692
707
|
const path = options.path || findDefaultDroidPath();
|
|
693
708
|
const outputDir = options.output;
|
|
@@ -711,7 +726,8 @@ bin("droid-patch", "CLI tool to patch droid binary with various modifications").
|
|
|
711
726
|
isCustom: false,
|
|
712
727
|
skipLogin: false,
|
|
713
728
|
apiBase: null,
|
|
714
|
-
websearch: true
|
|
729
|
+
websearch: true,
|
|
730
|
+
reasoningEffort: false
|
|
715
731
|
});
|
|
716
732
|
await saveAliasMetadata(metadata);
|
|
717
733
|
console.log();
|
|
@@ -739,12 +755,13 @@ bin("droid-patch", "CLI tool to patch droid binary with various modifications").
|
|
|
739
755
|
console.log(styleText("gray", " export DROID_SEARCH_DEBUG=1"));
|
|
740
756
|
return;
|
|
741
757
|
}
|
|
742
|
-
if (!isCustom && !skipLogin && !apiBase && !webSearch) {
|
|
758
|
+
if (!isCustom && !skipLogin && !apiBase && !webSearch && !reasoningEffort) {
|
|
743
759
|
console.log(styleText("yellow", "No patch flags specified. Available patches:"));
|
|
744
|
-
console.log(styleText("gray", " --is-custom
|
|
745
|
-
console.log(styleText("gray", " --skip-login
|
|
746
|
-
console.log(styleText("gray", " --api-base
|
|
747
|
-
console.log(styleText("gray", " --websearch
|
|
760
|
+
console.log(styleText("gray", " --is-custom Patch isCustom for custom models"));
|
|
761
|
+
console.log(styleText("gray", " --skip-login Bypass login by injecting a fake API key"));
|
|
762
|
+
console.log(styleText("gray", " --api-base Replace Factory API URL with custom server"));
|
|
763
|
+
console.log(styleText("gray", " --websearch Enable local WebSearch (Google PSE + DuckDuckGo)"));
|
|
764
|
+
console.log(styleText("gray", " --reasoning-effort Set reasoning effort level for custom models"));
|
|
748
765
|
console.log();
|
|
749
766
|
console.log("Usage examples:");
|
|
750
767
|
console.log(styleText("cyan", " npx droid-patch --is-custom droid-custom"));
|
|
@@ -753,6 +770,7 @@ bin("droid-patch", "CLI tool to patch droid binary with various modifications").
|
|
|
753
770
|
console.log(styleText("cyan", " npx droid-patch --skip-login -o . my-droid"));
|
|
754
771
|
console.log(styleText("cyan", " npx droid-patch --api-base http://localhost:3000 droid-local"));
|
|
755
772
|
console.log(styleText("cyan", " npx droid-patch --websearch droid-search"));
|
|
773
|
+
console.log(styleText("cyan", " npx droid-patch --reasoning-effort high droid-reasoning"));
|
|
756
774
|
process.exit(1);
|
|
757
775
|
}
|
|
758
776
|
if (!alias && !dryRun) {
|
|
@@ -800,6 +818,38 @@ bin("droid-patch", "CLI tool to patch droid binary with various modifications").
|
|
|
800
818
|
replacement: Buffer.from(paddedUrl)
|
|
801
819
|
});
|
|
802
820
|
}
|
|
821
|
+
if (reasoningEffort) {
|
|
822
|
+
patches.push({
|
|
823
|
+
name: "reasoningEffortSupported",
|
|
824
|
+
description: "Change supportedReasoningEfforts:[\"none\"] to [\"high\"]",
|
|
825
|
+
pattern: Buffer.from("supportedReasoningEfforts:[\"none\"]"),
|
|
826
|
+
replacement: Buffer.from("supportedReasoningEfforts:[\"high\"]")
|
|
827
|
+
});
|
|
828
|
+
patches.push({
|
|
829
|
+
name: "reasoningEffortDefault",
|
|
830
|
+
description: "Change defaultReasoningEffort:\"none\" to \"high\"",
|
|
831
|
+
pattern: Buffer.from("defaultReasoningEffort:\"none\""),
|
|
832
|
+
replacement: Buffer.from("defaultReasoningEffort:\"high\"")
|
|
833
|
+
});
|
|
834
|
+
patches.push({
|
|
835
|
+
name: "reasoningEffortUIShow",
|
|
836
|
+
description: "Change supportedReasoningEfforts.length>1 to length>0",
|
|
837
|
+
pattern: Buffer.from("supportedReasoningEfforts.length>1"),
|
|
838
|
+
replacement: Buffer.from("supportedReasoningEfforts.length>0")
|
|
839
|
+
});
|
|
840
|
+
patches.push({
|
|
841
|
+
name: "reasoningEffortUIEnable",
|
|
842
|
+
description: "Change supportedReasoningEfforts.length<=1 to length<=0",
|
|
843
|
+
pattern: Buffer.from("supportedReasoningEfforts.length<=1"),
|
|
844
|
+
replacement: Buffer.from("supportedReasoningEfforts.length<=0")
|
|
845
|
+
});
|
|
846
|
+
patches.push({
|
|
847
|
+
name: "reasoningEffortValidationBypass",
|
|
848
|
+
description: "Bypass reasoning effort validation (allows xhigh in settings.json)",
|
|
849
|
+
pattern: Buffer.from("if(R&&!B.supportedReasoningEfforts.includes(R))"),
|
|
850
|
+
replacement: Buffer.from("if(0&&!B.supportedReasoningEfforts.includes(R))")
|
|
851
|
+
});
|
|
852
|
+
}
|
|
803
853
|
try {
|
|
804
854
|
const result = await patchDroid({
|
|
805
855
|
inputPath: path,
|
|
@@ -850,7 +900,8 @@ bin("droid-patch", "CLI tool to patch droid binary with various modifications").
|
|
|
850
900
|
isCustom: !!isCustom,
|
|
851
901
|
skipLogin: !!skipLogin,
|
|
852
902
|
apiBase: apiBase || null,
|
|
853
|
-
websearch: !!webSearch
|
|
903
|
+
websearch: !!webSearch,
|
|
904
|
+
reasoningEffort: !!reasoningEffort
|
|
854
905
|
});
|
|
855
906
|
await saveAliasMetadata(metadata);
|
|
856
907
|
}
|
|
@@ -1034,6 +1085,38 @@ bin("droid-patch", "CLI tool to patch droid binary with various modifications").
|
|
|
1034
1085
|
replacement: Buffer.from(paddedUrl)
|
|
1035
1086
|
});
|
|
1036
1087
|
}
|
|
1088
|
+
if (meta.patches.reasoningEffort) {
|
|
1089
|
+
patches.push({
|
|
1090
|
+
name: "reasoningEffortSupported",
|
|
1091
|
+
description: "Change supportedReasoningEfforts:[\"none\"] to [\"high\"]",
|
|
1092
|
+
pattern: Buffer.from("supportedReasoningEfforts:[\"none\"]"),
|
|
1093
|
+
replacement: Buffer.from("supportedReasoningEfforts:[\"high\"]")
|
|
1094
|
+
});
|
|
1095
|
+
patches.push({
|
|
1096
|
+
name: "reasoningEffortDefault",
|
|
1097
|
+
description: "Change defaultReasoningEffort:\"none\" to \"high\"",
|
|
1098
|
+
pattern: Buffer.from("defaultReasoningEffort:\"none\""),
|
|
1099
|
+
replacement: Buffer.from("defaultReasoningEffort:\"high\"")
|
|
1100
|
+
});
|
|
1101
|
+
patches.push({
|
|
1102
|
+
name: "reasoningEffortUIShow",
|
|
1103
|
+
description: "Change supportedReasoningEfforts.length>1 to length>0",
|
|
1104
|
+
pattern: Buffer.from("supportedReasoningEfforts.length>1"),
|
|
1105
|
+
replacement: Buffer.from("supportedReasoningEfforts.length>0")
|
|
1106
|
+
});
|
|
1107
|
+
patches.push({
|
|
1108
|
+
name: "reasoningEffortUIEnable",
|
|
1109
|
+
description: "Change supportedReasoningEfforts.length<=1 to length<=0",
|
|
1110
|
+
pattern: Buffer.from("supportedReasoningEfforts.length<=1"),
|
|
1111
|
+
replacement: Buffer.from("supportedReasoningEfforts.length<=0")
|
|
1112
|
+
});
|
|
1113
|
+
patches.push({
|
|
1114
|
+
name: "reasoningEffortValidationBypass",
|
|
1115
|
+
description: "Bypass reasoning effort validation (allows xhigh in settings.json)",
|
|
1116
|
+
pattern: Buffer.from("if(R&&!B.supportedReasoningEfforts.includes(R))"),
|
|
1117
|
+
replacement: Buffer.from("if(0&&!B.supportedReasoningEfforts.includes(R))")
|
|
1118
|
+
});
|
|
1119
|
+
}
|
|
1037
1120
|
const binsDir = join(homedir(), ".droid-patch", "bins");
|
|
1038
1121
|
const outputPath = join(binsDir, `${meta.name}-patched`);
|
|
1039
1122
|
if (patches.length > 0) {
|
|
@@ -1051,8 +1134,8 @@ bin("droid-patch", "CLI tool to patch droid binary with various modifications").
|
|
|
1051
1134
|
continue;
|
|
1052
1135
|
}
|
|
1053
1136
|
if (process.platform === "darwin") try {
|
|
1054
|
-
const { execSync } = await import("node:child_process");
|
|
1055
|
-
execSync(`codesign --force --deep --sign - "${outputPath}"`, { stdio: "pipe" });
|
|
1137
|
+
const { execSync: execSync$1 } = await import("node:child_process");
|
|
1138
|
+
execSync$1(`codesign --force --deep --sign - "${outputPath}"`, { stdio: "pipe" });
|
|
1056
1139
|
if (verbose) console.log(styleText("gray", ` Re-signed binary`));
|
|
1057
1140
|
} catch {
|
|
1058
1141
|
console.log(styleText("yellow", ` [!] Could not re-sign binary`));
|