droid-patch 0.13.1 → 0.13.3

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
@@ -62,7 +62,7 @@ npx droid-patch --skip-login -o /path/to/dir my-droid
62
62
  | `--is-custom` | Patch `isCustom:!0` to `isCustom:!1` (enables context compression for custom models) |
63
63
  | `--skip-login` | Bypass login by injecting a fake `FACTORY_API_KEY` into the binary |
64
64
  | `--api-base <url>` | Replace API URL (standalone: binary patch, max 22 chars; with `--websearch`: proxy forward target, no limit) |
65
- | `--websearch` | External providers mode: Smithery, Google PSE, Serper, Brave, SearXNG, DuckDuckGo |
65
+ | `--websearch` | External providers mode: Smithery, Google PSE, Tavily, Serper, Brave, SearXNG, DuckDuckGo |
66
66
  | `--websearch-proxy` | Native provider mode: use model's built-in web_search (requires proxy plugin) |
67
67
  | `--standalone` | Standalone mode: mock non-LLM Factory APIs (use with `--websearch` or `--websearch-proxy`) |
68
68
  | `--reasoning-effort` | Enable reasoning effort UI selector for custom models (set to high) |
@@ -247,7 +247,7 @@ Enables WebSearch via **external search providers** through a local proxy server
247
247
 
248
248
  **Features**:
249
249
 
250
- - **Multiple search providers** with automatic fallback (Smithery > Google PSE > Serper > Brave > SearXNG > DuckDuckGo)
250
+ - **Multiple search providers** with automatic fallback (Smithery > Google PSE > Tavily > Serper > Brave > SearXNG > DuckDuckGo)
251
251
  - **Per-instance proxy**: Each droid instance runs its own proxy on an auto-assigned port
252
252
  - **Auto-cleanup**: Proxy automatically stops when droid exits
253
253
  - **Forward target**: Use `--api-base` with `--websearch` to forward non-search requests to a custom backend
@@ -448,10 +448,11 @@ The proxy tries providers in this order and uses the first one that succeeds:
448
448
  | -------- | ------------ | --------- | --------------------- | ---------------- |
449
449
  | 1 | Smithery Exa | Excellent | Free (via Smithery) | Easy |
450
450
  | 2 | Google PSE | Very Good | 10,000/day | Medium |
451
- | 3 | Serper | Very Good | 2,500 free credits | Easy |
452
- | 4 | Brave Search | Good | 2,000/month | Easy |
453
- | 5 | SearXNG | Good | Unlimited (self-host) | Hard |
454
- | 6 | DuckDuckGo | Basic | Unlimited | None |
451
+ | 3 | Tavily | Very Good | Free credits (varies) | Easy |
452
+ | 4 | Serper | Very Good | 2,500 free credits | Easy |
453
+ | 5 | Brave Search | Good | 2,000/month | Easy |
454
+ | 6 | SearXNG | Good | Unlimited (self-host) | Hard |
455
+ | 7 | DuckDuckGo | Basic | Unlimited | None |
455
456
 
456
457
  ---
457
458
 
@@ -533,7 +534,29 @@ export GOOGLE_PSE_CX="017576662512468239146:omuauf_lfve" # Your Search engine I
533
534
 
534
535
  ---
535
536
 
536
- ## 3. Serper
537
+ ## 3. Tavily
538
+
539
+ [Tavily](https://tavily.com/) provides an easy-to-use web search API.
540
+
541
+ ### Setup Steps
542
+
543
+ 1. **Create an Account**
544
+ - Go to [tavily.com](https://tavily.com/)
545
+ - Sign up for an account
546
+
547
+ 2. **Get Your API Key**
548
+ - Navigate to your dashboard / API settings
549
+ - Copy your API key
550
+
551
+ 3. **Configure Environment Variable**
552
+ ```bash
553
+ # Add to ~/.zshrc or ~/.bashrc
554
+ export TAVILY_API_KEY="your_api_key_here"
555
+ ```
556
+
557
+ ---
558
+
559
+ ## 4. Serper
537
560
 
538
561
  [Serper](https://serper.dev) provides Google search results through an easy-to-use API.
539
562
 
@@ -561,7 +584,7 @@ export GOOGLE_PSE_CX="017576662512468239146:omuauf_lfve" # Your Search engine I
561
584
 
562
585
  ---
563
586
 
564
- ## 4. Brave Search
587
+ ## 5. Brave Search
565
588
 
566
589
  [Brave Search API](https://brave.com/search/api/) provides privacy-focused search results.
567
590
 
@@ -593,7 +616,7 @@ export GOOGLE_PSE_CX="017576662512468239146:omuauf_lfve" # Your Search engine I
593
616
 
594
617
  ---
595
618
 
596
- ## 5. SearXNG (Self-Hosted)
619
+ ## 6. SearXNG (Self-Hosted)
597
620
 
598
621
  [SearXNG](https://github.com/searxng/searxng) is a free, privacy-respecting metasearch engine you can self-host.
599
622
 
@@ -642,7 +665,7 @@ Find public instances at [searx.space](https://searx.space/)
642
665
 
643
666
  ---
644
667
 
645
- ## 6. DuckDuckGo (Default Fallback)
668
+ ## 7. DuckDuckGo (Default Fallback)
646
669
 
647
670
  DuckDuckGo is used automatically as the final fallback when no other providers are configured or available.
648
671
 
@@ -690,10 +713,13 @@ export GOOGLE_PSE_CX="your_search_engine_id"
690
713
  export GOOGLE_PSE_API_KEY="your_google_key"
691
714
  export GOOGLE_PSE_CX="your_search_engine_id"
692
715
 
693
- # Option 2: Serper (2,500 free credits)
716
+ # Option 2: Tavily (free credits vary)
717
+ export TAVILY_API_KEY="your_tavily_key"
718
+
719
+ # Option 3: Serper (2,500 free credits)
694
720
  export SERPER_API_KEY="your_serper_key"
695
721
 
696
- # Option 3: Brave (2,000/month free)
722
+ # Option 4: Brave (2,000/month free)
697
723
  export BRAVE_API_KEY="your_brave_key"
698
724
 
699
725
  # DuckDuckGo is always available as final fallback
package/README.zh-CN.md CHANGED
@@ -62,7 +62,7 @@ npx droid-patch --skip-login -o /path/to/dir my-droid
62
62
  | `--is-custom` | 将 `isCustom:!0` 修改为 `isCustom:!1`(为自定义模型启用上下文压缩) |
63
63
  | `--skip-login` | 通过注入假的 `FACTORY_API_KEY` 跳过登录验证 |
64
64
  | `--api-base <url>` | 替换 API URL(单独使用:二进制补丁,最多 22 字符;与 `--websearch` 配合:代理转发目标,无限制) |
65
- | `--websearch` | 外部搜索模式:使用 Smithery、Google PSE、Serper、Brave、SearXNG、DuckDuckGo |
65
+ | `--websearch` | 外部搜索模式:使用 Smithery、Google PSE、Tavily、Serper、Brave、SearXNG、DuckDuckGo |
66
66
  | `--websearch-proxy` | 原生搜索模式:使用模型内置的 web_search 能力(需要 proxy 插件) |
67
67
  | `--standalone` | 独立模式:mock 非 LLM 的 Factory API(与 `--websearch` 或 `--websearch-proxy` 配合使用) |
68
68
  | `--reasoning-effort` | 为自定义模型启用推理强度 UI 选择器(设置为 high) |
@@ -247,7 +247,7 @@ npx droid-patch --websearch --api-base "http://my-proxy.example.com:3000" droid-
247
247
 
248
248
  **特性**:
249
249
 
250
- - **多搜索提供商**:自动降级(Smithery > Google PSE > Serper > Brave > SearXNG > DuckDuckGo)
250
+ - **多搜索提供商**:自动降级(Smithery > Google PSE > Tavily > Serper > Brave > SearXNG > DuckDuckGo)
251
251
  - **每实例独立代理**:每个 droid 实例运行自己的代理,自动分配端口
252
252
  - **自动清理**:droid 退出时代理自动停止
253
253
  - **转发目标**:使用 `--api-base` 配合 `--websearch` 可将非搜索请求转发到自定义后端
@@ -442,10 +442,11 @@ npx droid-patch --is-custom --skip-login --disable-telemetry droid-private
442
442
  | ------ | ------------ | ---- | --------------------- | -------- |
443
443
  | 1 | Smithery Exa | 优秀 | 免费(通过 Smithery) | 简单 |
444
444
  | 2 | Google PSE | 很好 | 10,000 次/天 | 中等 |
445
- | 3 | Serper | 很好 | 2,500 免费额度 | 简单 |
446
- | 4 | Brave Search | 好 | 2,000 次/月 | 简单 |
447
- | 5 | SearXNG | 好 | 无限(自托管) | 较难 |
448
- | 6 | DuckDuckGo | 基本 | 无限 | 无需配置 |
445
+ | 3 | Tavily | 很好 | 免费额度(不固定) | 简单 |
446
+ | 4 | Serper | 很好 | 2,500 免费额度 | 简单 |
447
+ | 5 | Brave Search | 好 | 2,000 次/月 | 简单 |
448
+ | 6 | SearXNG | | 无限(自托管) | 较难 |
449
+ | 7 | DuckDuckGo | 基本 | 无限 | 无需配置 |
449
450
 
450
451
  ---
451
452
 
@@ -527,7 +528,28 @@ export GOOGLE_PSE_CX="017576662512468239146:omuauf_lfve" # 你的搜索引擎 I
527
528
 
528
529
  ---
529
530
 
530
- ## 3. Serper
531
+ ## 3. Tavily
532
+
533
+ [Tavily](https://tavily.com/) 提供简单易用的 Web 搜索 API。
534
+
535
+ ### 设置步骤
536
+
537
+ 1. **创建账号**
538
+ - 访问 [tavily.com](https://tavily.com/)
539
+ - 注册账号
540
+
541
+ 2. **获取 API Key**
542
+ - 在控制台/API 设置中找到并复制 API key
543
+
544
+ 3. **配置环境变量**
545
+ ```bash
546
+ # 添加到 ~/.zshrc 或 ~/.bashrc
547
+ export TAVILY_API_KEY="your_api_key_here"
548
+ ```
549
+
550
+ ---
551
+
552
+ ## 4. Serper
531
553
 
532
554
  [Serper](https://serper.dev) 通过易用的 API 提供 Google 搜索结果。
533
555
 
@@ -555,7 +577,7 @@ export GOOGLE_PSE_CX="017576662512468239146:omuauf_lfve" # 你的搜索引擎 I
555
577
 
556
578
  ---
557
579
 
558
- ## 4. Brave Search
580
+ ## 5. Brave Search
559
581
 
560
582
  [Brave Search API](https://brave.com/search/api/) 提供注重隐私的搜索结果。
561
583
 
@@ -587,7 +609,7 @@ export GOOGLE_PSE_CX="017576662512468239146:omuauf_lfve" # 你的搜索引擎 I
587
609
 
588
610
  ---
589
611
 
590
- ## 5. SearXNG(自托管)
612
+ ## 6. SearXNG(自托管)
591
613
 
592
614
  [SearXNG](https://github.com/searxng/searxng) 是一个免费、注重隐私的元搜索引擎,可以自托管。
593
615
 
@@ -636,7 +658,7 @@ export SEARXNG_URL="https://searx.be"
636
658
 
637
659
  ---
638
660
 
639
- ## 6. DuckDuckGo(默认备用)
661
+ ## 7. DuckDuckGo(默认备用)
640
662
 
641
663
  当没有配置其他提供商或其他提供商不可用时,自动使用 DuckDuckGo 作为最终备用。
642
664
 
@@ -684,10 +706,13 @@ export GOOGLE_PSE_CX="your_search_engine_id"
684
706
  export GOOGLE_PSE_API_KEY="your_google_key"
685
707
  export GOOGLE_PSE_CX="your_search_engine_id"
686
708
 
687
- # 选项 2:Serper(2,500 免费额度)
709
+ # 选项 2:Tavily(免费额度不固定)
710
+ export TAVILY_API_KEY="your_tavily_key"
711
+
712
+ # 选项 3:Serper(2,500 免费额度)
688
713
  export SERPER_API_KEY="your_serper_key"
689
714
 
690
- # 选项 3:Brave(每月 2,000 次免费)
715
+ # 选项 4:Brave(每月 2,000 次免费)
691
716
  export BRAVE_API_KEY="your_brave_key"
692
717
 
693
718
  # DuckDuckGo 始终作为最终备用可用
@@ -37,8 +37,12 @@ async function patchDroid(options) {
37
37
  }
38
38
  if (matches.length === 0) {
39
39
  console.log(styleText("yellow", ` ! Pattern not found - may already be patched`));
40
- const sampleReplacement = patch.regexReplacement.replace(/\$\d+/g, "X");
41
- const alreadyPatched = content.includes(sampleReplacement.slice(0, 20));
40
+ let alreadyPatched = false;
41
+ if (patch.alreadyPatchedRegexPattern) alreadyPatched = new RegExp(patch.alreadyPatchedRegexPattern.source, "g").test(content);
42
+ else {
43
+ const sampleReplacement = patch.regexReplacement.replace(/\$\d+/g, "X");
44
+ alreadyPatched = content.includes(sampleReplacement.slice(0, 20));
45
+ }
42
46
  results.push({
43
47
  name: patch.name,
44
48
  found: 0,
@@ -1296,4 +1300,4 @@ async function clearAllAliases() {
1296
1300
 
1297
1301
  //#endregion
1298
1302
  export { removeAlias as a, restoreOriginal as c, listAllMetadata as d, loadAliasMetadata as f, listAliases as i, createMetadata as l, patchDroid as m, createAlias as n, removeAliasesByFilter as o, saveAliasMetadata as p, createAliasForWrapper as r, replaceOriginal as s, clearAllAliases as t, formatPatches as u };
1299
- //# sourceMappingURL=alias-12JqnRQZ.mjs.map
1303
+ //# sourceMappingURL=alias-DTf8YAYU.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"alias-DTf8YAYU.mjs","names":["IS_WINDOWS","results: PatchResult[]","matches: Array<{ charIndex: number; match: string; replacement: string }>","match","positions: number[]","matchedVariant: (typeof variants)[number] | undefined","metaList: AliasMetadata[]","applied: string[]","exportLine: string","binaryDest","aliases: AliasInfo[]","matchingAliases: 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\";\nimport { platform } from \"node:os\";\n\nconst IS_WINDOWS = platform() === \"win32\";\n\nexport interface Patch {\n name: string;\n description: string;\n pattern: Buffer;\n replacement: Buffer;\n variants?: Array<{\n pattern: Buffer;\n replacement: Buffer;\n }>;\n // Regex-based matching: use $1, $2, etc. in regexReplacement for capture groups\n regexPattern?: RegExp;\n regexReplacement?: string;\n // Optional regex to detect already-patched binaries when regexPattern is not found.\n alreadyPatchedRegexPattern?: RegExp;\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(options: PatchOptions): 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(styleText(\"white\", `[*] Reading binary: ${styleText(\"cyan\", inputPath)}`));\n console.log(styleText(\"white\", `[*] File size: ${styleText(\"cyan\", fileSizeMB)} MB`));\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(styleText(\"white\", `[*] Checking patch: ${styleText(\"yellow\", patch.name)}`));\n console.log(styleText(\"gray\", ` ${patch.description}`));\n\n // Handle regex-based matching\n // For binary files, convert pattern/replacement to Buffer and use findAllPositions\n if (patch.regexPattern && patch.regexReplacement) {\n const content = workingBuffer.toString(\"utf-8\");\n const regex = new RegExp(patch.regexPattern.source, \"g\");\n const matches: Array<{ charIndex: number; match: string; replacement: string }> = [];\n\n let match;\n while ((match = regex.exec(content)) !== null) {\n const replacement = match[0].replace(\n new RegExp(patch.regexPattern.source),\n patch.regexReplacement,\n );\n matches.push({\n charIndex: match.index,\n match: match[0],\n replacement,\n });\n }\n\n if (matches.length === 0) {\n console.log(styleText(\"yellow\", ` ! Pattern not found - may already be patched`));\n let alreadyPatched = false;\n if (patch.alreadyPatchedRegexPattern) {\n const alreadyPatchedRegex = new RegExp(patch.alreadyPatchedRegexPattern.source, \"g\");\n alreadyPatched = alreadyPatchedRegex.test(content);\n } else {\n // Fallback: look for a sample replacement pattern (best-effort heuristic).\n const sampleReplacement = patch.regexReplacement.replace(/\\$\\d+/g, \"X\");\n alreadyPatched = content.includes(sampleReplacement.slice(0, 20));\n }\n results.push({\n name: patch.name,\n found: 0,\n success: alreadyPatched,\n alreadyPatched,\n });\n if (alreadyPatched) {\n console.log(styleText(\"blue\", ` ✓ Binary appears to be already patched`));\n }\n continue;\n }\n\n console.log(styleText(\"green\", ` ✓ Found ${matches.length} occurrences (regex)`));\n\n if (!dryRun) {\n // Apply regex replacement using Buffer.indexOf for accurate byte positions\n for (const { match, replacement } of matches) {\n const matchBuffer = Buffer.from(match, \"utf-8\");\n const replacementBuffer = Buffer.from(replacement, \"utf-8\");\n\n if (matchBuffer.length !== replacementBuffer.length) {\n console.log(\n styleText(\n \"yellow\",\n ` ! Warning: Length mismatch: ${matchBuffer.length} vs ${replacementBuffer.length}`,\n ),\n );\n }\n\n // Find the actual byte position in the buffer\n const bytePos = workingBuffer.indexOf(matchBuffer);\n if (bytePos !== -1) {\n replacementBuffer.copy(workingBuffer, bytePos, 0, replacementBuffer.length);\n }\n }\n }\n\n results.push({\n name: patch.name,\n found: matches.length,\n positions: matches.map((m) => m.charIndex),\n success: true,\n });\n continue;\n }\n\n const variants = [\n { pattern: patch.pattern, replacement: patch.replacement },\n ...(patch.variants || []),\n ];\n\n // Search in the working buffer (which may have earlier patches applied)\n let positions: number[] = [];\n let matchedVariant: (typeof variants)[number] | undefined;\n for (const variant of variants) {\n positions = findAllPositions(workingBuffer, variant.pattern);\n if (positions.length > 0) {\n matchedVariant = variant;\n break;\n }\n }\n\n if (positions.length === 0) {\n console.log(styleText(\"yellow\", ` ! Pattern not found - may already be patched`));\n results.push({\n name: patch.name,\n found: 0,\n success: false,\n alreadyPatched: variants.some((v) => workingBuffer.includes(v.replacement)),\n });\n\n let totalReplacementPositions = 0;\n for (const variant of variants) {\n totalReplacementPositions += findAllPositions(workingBuffer, variant.replacement).length;\n }\n if (totalReplacementPositions > 0) {\n console.log(\n styleText(\n \"blue\",\n ` ✓ Found ${totalReplacementPositions} occurrences of patched pattern`,\n ),\n );\n console.log(styleText(\"blue\", ` ✓ Binary appears to be already patched`));\n results[results.length - 1].alreadyPatched = true;\n results[results.length - 1].success = true;\n }\n continue;\n }\n\n if (!matchedVariant) {\n throw new Error(`Internal error: matchedVariant not set for patch ${patch.name}`);\n }\n\n console.log(styleText(\"green\", ` ✓ Found ${positions.length} occurrences`));\n\n if (verbose) {\n for (const pos of positions.slice(0, 5)) {\n const context = getContext(workingBuffer, pos, matchedVariant.pattern.length, 25);\n console.log(\n styleText(\"gray\", ` @ 0x${pos.toString(16).padStart(8, \"0\")}: ...${context}...`),\n );\n }\n if (positions.length > 5) {\n console.log(styleText(\"gray\", ` ... and ${positions.length - 5} more`));\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 matchedVariant.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(\"green\", ` [✓] ${result.name}: ${result.found} occurrences will be patched`),\n );\n } else {\n console.log(styleText(\"yellow\", ` [!] ${result.name}: Pattern not found`));\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(styleText(\"blue\", \"[*] All patches already applied. Binary is up to date.\"));\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(styleText(\"white\", `[*] Created backup: ${styleText(\"cyan\", backupPath)}`));\n } else {\n console.log(styleText(\"gray\", `[*] Backup already exists: ${backupPath}`));\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((sum, r) => sum + (r.positions?.length || 0), 0);\n\n console.log(styleText(\"green\", `[*] Applied ${totalPatched} patches`));\n\n // Handle Windows file locking - if file is locked, use a new filename\n let actualOutputPath = finalOutputPath;\n try {\n await writeFile(finalOutputPath, workingBuffer);\n } catch (error) {\n const err = error as NodeJS.ErrnoException;\n if (err.code === \"EBUSY\" && IS_WINDOWS) {\n // File is locked, generate new filename with timestamp\n const timestamp = Date.now();\n const ext = finalOutputPath.endsWith(\".exe\") ? \".exe\" : \"\";\n const basePath = finalOutputPath\n .replace(/\\.exe$/, \"\")\n .replace(/\\.patched$/, \"\")\n .replace(/-\\d+$/, \"\");\n actualOutputPath = `${basePath}-${timestamp}${ext ? ext : \".patched\"}`;\n console.log(styleText(\"yellow\", `[!] Original file locked, saving to: ${actualOutputPath}`));\n await writeFile(actualOutputPath, workingBuffer);\n } else {\n throw error;\n }\n }\n console.log(\n styleText(\"white\", `[*] Patched binary saved: ${styleText(\"cyan\", actualOutputPath)}`),\n );\n\n await chmod(actualOutputPath, 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(actualOutputPath);\n\n let allVerified = true;\n for (const patch of patches) {\n // Handle regex-based patches\n if (patch.regexPattern && patch.regexReplacement) {\n const content = verifyBuffer.toString(\"utf-8\");\n const oldMatches = [...content.matchAll(new RegExp(patch.regexPattern.source, \"g\"))];\n // For verification, just check that the original pattern is no longer present\n if (oldMatches.length === 0) {\n console.log(styleText(\"green\", ` ✓ ${patch.name}: Verified (regex)`));\n } else {\n console.log(\n styleText(\"red\", ` ✗ ${patch.name}: ${oldMatches.length} occurrences not patched`),\n );\n allVerified = false;\n }\n continue;\n }\n\n const variants = [\n { pattern: patch.pattern, replacement: patch.replacement },\n ...(patch.variants || []),\n ];\n\n let oldCount = 0;\n let newCount = 0;\n for (const variant of variants) {\n if (variant.pattern.length > 0) {\n oldCount += findAllPositions(verifyBuffer, variant.pattern).length;\n }\n if (variant.replacement.length > 0) {\n newCount += findAllPositions(verifyBuffer, variant.replacement).length;\n }\n }\n\n if (oldCount === 0) {\n console.log(styleText(\"green\", ` ✓ ${patch.name}: Verified (${newCount} patched)`));\n } else {\n console.log(styleText(\"red\", ` ✗ ${patch.name}: ${oldCount} occurrences not patched`));\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: actualOutputPath,\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 /** Path where the alias symlink was created */\n aliasPath?: string;\n /** droid-patch version used to create this alias */\n droidPatchVersion?: string;\n /** droid binary version */\n droidVersion?: string;\n /** Patches that were applied */\n patches: {\n isCustom: boolean;\n skipLogin: boolean;\n /** API base URL for binary patching or websearch forward target */\n apiBase: string | null;\n /** Whether websearch is enabled (external providers mode) */\n websearch: boolean;\n /** Whether websearch-proxy is enabled (native provider mode) */\n websearchProxy?: boolean;\n /** @deprecated Old proxy field, kept for backward compatibility */\n proxy?: string | null;\n reasoningEffort: boolean;\n /** Whether telemetry/Sentry is disabled */\n noTelemetry?: boolean;\n /** Standalone mode: mock non-LLM Factory APIs */\n standalone?: 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(aliasName: string): 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 options?: {\n droidPatchVersion?: string;\n droidVersion?: string;\n aliasPath?: string;\n },\n): AliasMetadata {\n const now = new Date().toISOString();\n return {\n name,\n createdAt: now,\n updatedAt: now,\n originalBinaryPath,\n aliasPath: options?.aliasPath,\n droidPatchVersion: options?.droidPatchVersion,\n droidVersion: options?.droidVersion,\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 // Show apiBase only when not using websearch (binary patch mode)\n if (patches.apiBase && !patches.websearch && !patches.websearchProxy)\n applied.push(`apiBase(${patches.apiBase})`);\n // Show websearch with optional custom target (external providers mode)\n if (patches.websearch) {\n const target = patches.apiBase || \"api.factory.ai\";\n applied.push(`websearch(${target})`);\n }\n // Show websearchProxy (native provider mode)\n if (patches.websearchProxy) {\n applied.push(\"websearchProxy(native)\");\n }\n // Support old proxy field for backward compatibility\n if (patches.proxy && !patches.websearch && !patches.websearchProxy)\n applied.push(`websearch(${patches.proxy})`);\n if (patches.reasoningEffort) applied.push(\"reasoningEffort\");\n if (patches.noTelemetry) applied.push(\"noTelemetry\");\n if (patches.standalone) applied.push(\"standalone\");\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, delimiter } from \"node:path\";\nimport { homedir, platform } from \"node:os\";\nimport { execSync } from \"node:child_process\";\nimport { styleText } from \"node:util\";\nimport { removeAliasMetadata, loadAliasMetadata, formatPatches } from \"./metadata.ts\";\n\nconst IS_WINDOWS = platform() === \"win32\";\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\n// Unix common PATH directories\nconst UNIX_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\n// Windows common PATH directories\nconst WINDOWS_PATH_DIRS = [\n join(homedir(), \".droid-patch\", \"bin\"),\n join(homedir(), \"scoop\", \"shims\"),\n join(homedir(), \"AppData\", \"Local\", \"Programs\", \"bin\"),\n];\n\nconst COMMON_PATH_DIRS = IS_WINDOWS ? WINDOWS_PATH_DIRS : UNIX_PATH_DIRS;\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(delimiter).some((p) => p.toLowerCase() === ALIASES_DIR.toLowerCase());\n}\n\nexport function findWritablePathDir(): string | null {\n const pathEnv = process.env.PATH || \"\";\n const pathDirs = pathEnv.split(delimiter);\n\n for (const dir of COMMON_PATH_DIRS) {\n // Case-insensitive comparison for Windows\n const isInPath = pathDirs.some((p) => p.toLowerCase() === dir.toLowerCase());\n if (isInPath) {\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 if (IS_WINDOWS) {\n // Windows doesn't use shell config files for PATH\n return \"\";\n }\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 (IS_WINDOWS || !shellConfigPath) {\n return false;\n }\n\n if (!existsSync(shellConfigPath)) {\n return false;\n }\n\n try {\n const content = readFileSync(shellConfigPath, \"utf-8\");\n return content.includes(\".droid-patch/aliases\") || content.includes(\"droid-patch/aliases\");\n } catch {\n return false;\n }\n}\n\n/**\n * Add directory to Windows user PATH using setx command\n * This modifies the user's PATH permanently (requires terminal restart)\n */\nfunction addToWindowsUserPath(dir: string): boolean {\n try {\n // Get current user PATH from registry\n let existingPath = \"\";\n try {\n const result = execSync('reg query \"HKCU\\\\Environment\" /v Path 2>nul', {\n encoding: \"utf-8\",\n stdio: [\"pipe\", \"pipe\", \"pipe\"],\n });\n const match = result.match(/Path\\s+REG_(?:EXPAND_)?SZ\\s+(.+)/);\n existingPath = match ? match[1].trim() : \"\";\n } catch {\n // PATH not set yet, that's fine\n }\n\n // Check if already in PATH (case-insensitive)\n const paths = existingPath.split(\";\").map((p) => p.toLowerCase().trim());\n if (paths.includes(dir.toLowerCase())) {\n return true; // Already in PATH\n }\n\n // Add to PATH\n const newPath = existingPath ? `${existingPath};${dir}` : dir;\n execSync(`setx PATH \"${newPath}\"`, { stdio: \"pipe\" });\n return true;\n } catch {\n return false;\n }\n}\n\n/**\n * Generate Windows .cmd launcher script\n */\nfunction generateWindowsLauncher(targetPath: string): string {\n return `@echo off\\r\\n\"${targetPath}\" %*\\r\\n`;\n}\n\nfunction addPathToShellConfig(shellConfigPath: string, verbose = false): 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(styleText(\"gray\", ` Added PATH export to: ${shellConfigPath}`));\n }\n return true;\n } catch (error) {\n console.log(\n styleText(\"yellow\", `[!] Could not write to ${shellConfigPath}: ${(error as Error).message}`),\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(styleText(\"white\", `[*] Creating alias: ${styleText(\"cyan\", aliasName)}`));\n\n // Windows: use .cmd launcher instead of symlink\n if (IS_WINDOWS) {\n return createWindowsAlias(patchedBinaryPath, aliasName, verbose);\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(styleText(\"green\", `[*] Created: ${targetPath} -> ${binaryDest}`));\n console.log();\n console.log(styleText(\"green\", \"─\".repeat(60)));\n console.log(styleText([\"green\", \"bold\"], \" ALIAS READY - NO ACTION REQUIRED!\"));\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(styleText(\"yellow\", \"[*] No writable PATH directory found, using fallback...\"));\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(\"yellow\", \"[!] Could not re-sign binary. You may need to do this manually:\"),\n );\n console.log(styleText(\"gray\", ` codesign --force --deep --sign - \"${binaryDest}\"`));\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(styleText(\"green\", `[*] Created symlink: ${symlinkPath} -> ${binaryDest}`));\n\n const shellConfig = getShellConfigPath();\n\n if (!checkPathInclusion()) {\n if (!isPathConfigured(shellConfig)) {\n console.log(styleText(\"white\", `[*] Configuring PATH in ${shellConfig}...`));\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(styleText(\"white\", \"To use the alias in this terminal, run:\"));\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(styleText([\"yellow\", \"bold\"], \" Manual PATH Configuration Required\"));\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(styleText(\"green\", `[*] PATH already configured in ${shellConfig}`));\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(styleText(\"green\", `[*] PATH already includes aliases directory`));\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\n/**\n * Create alias on Windows using .cmd launcher and setx for PATH\n */\n/**\n * Try to copy file, handling Windows file locking\n * If target is locked, use a new filename with timestamp\n */\nasync function copyFileWithLockHandling(\n src: string,\n dest: string,\n verbose = false,\n): Promise<string> {\n try {\n await copyFile(src, dest);\n return dest;\n } catch (error) {\n const err = error as NodeJS.ErrnoException;\n // EBUSY = file is locked/in use (Windows)\n if (err.code === \"EBUSY\" && IS_WINDOWS) {\n // Generate new filename with timestamp\n const timestamp = Date.now();\n const ext = dest.endsWith(\".exe\") ? \".exe\" : \"\";\n const baseName = dest.replace(/\\.exe$/, \"\").replace(/-\\d+$/, \"\"); // Remove old timestamp if any\n const newDest = `${baseName}-${timestamp}${ext}`;\n\n if (verbose) {\n console.log(styleText(\"yellow\", ` [!] File locked, using new path: ${newDest}`));\n }\n\n await copyFile(src, newDest);\n return newDest;\n }\n throw error;\n }\n}\n\nasync function createWindowsAlias(\n patchedBinaryPath: string,\n aliasName: string,\n verbose = false,\n): Promise<CreateAliasResult> {\n const binDir = join(DROID_PATCH_DIR, \"bin\");\n if (!existsSync(binDir)) {\n mkdirSync(binDir, { recursive: true });\n }\n\n // Copy binary to bins directory, handling file locking\n const targetPath = join(BINS_DIR, `${aliasName}-patched.exe`);\n const binaryDest = await copyFileWithLockHandling(patchedBinaryPath, targetPath, verbose);\n\n if (verbose) {\n console.log(styleText(\"gray\", ` Stored binary: ${binaryDest}`));\n }\n\n // Create .cmd launcher in bin directory\n const cmdPath = join(binDir, `${aliasName}.cmd`);\n const cmdContent = generateWindowsLauncher(binaryDest);\n writeFileSync(cmdPath, cmdContent);\n\n if (verbose) {\n console.log(styleText(\"gray\", ` Created launcher: ${cmdPath}`));\n }\n\n // Try to add bin directory to user PATH\n const pathAdded = addToWindowsUserPath(binDir);\n\n console.log(styleText(\"green\", `[*] Created: ${cmdPath}`));\n console.log();\n\n if (pathAdded) {\n if (checkPathInclusion()) {\n console.log(styleText(\"green\", \"─\".repeat(60)));\n console.log(styleText([\"green\", \"bold\"], \" ALIAS READY!\"));\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.`,\n ),\n );\n console.log(styleText(\"gray\", `(Installed to: ${binDir})`));\n\n return {\n aliasPath: cmdPath,\n binaryPath: binaryDest,\n immediate: true,\n };\n }\n\n console.log(styleText(\"yellow\", \"─\".repeat(60)));\n console.log(styleText([\"yellow\", \"bold\"], \" PATH Updated - Restart Terminal\"));\n console.log(styleText(\"yellow\", \"─\".repeat(60)));\n console.log();\n console.log(styleText(\"white\", \"PATH has been updated. Please restart your terminal.\"));\n console.log(\n styleText(\n \"white\",\n `Then you can use \"${styleText([\"cyan\", \"bold\"], aliasName)}\" command directly.`,\n ),\n );\n console.log();\n console.log(styleText(\"gray\", `Installed to: ${binDir}`));\n } else {\n console.log(styleText(\"yellow\", \"─\".repeat(60)));\n console.log(styleText([\"yellow\", \"bold\"], \" Manual PATH Configuration Required\"));\n console.log(styleText(\"yellow\", \"─\".repeat(60)));\n console.log();\n console.log(styleText(\"white\", \"Add this directory to your PATH:\"));\n console.log(styleText(\"cyan\", ` ${binDir}`));\n console.log();\n console.log(styleText(\"gray\", \"Or run directly:\"));\n console.log(styleText(\"cyan\", ` \"${cmdPath}\"`));\n }\n\n return {\n aliasPath: cmdPath,\n binaryPath: binaryDest,\n immediate: false,\n };\n}\n\nexport async function removeAlias(aliasName: string): Promise<void> {\n console.log(styleText(\"white\", `[*] Removing alias: ${styleText(\"cyan\", aliasName)}`));\n\n let removed = false;\n\n // Windows: check for .cmd launcher\n if (IS_WINDOWS) {\n const binDir = join(DROID_PATCH_DIR, \"bin\");\n const cmdPath = join(binDir, `${aliasName}.cmd`);\n if (existsSync(cmdPath)) {\n await unlink(cmdPath);\n console.log(styleText(\"green\", ` Removed: ${cmdPath}`));\n removed = true;\n }\n\n // Remove Windows binary (.exe)\n const exePath = join(BINS_DIR, `${aliasName}-patched.exe`);\n if (existsSync(exePath)) {\n await unlink(exePath);\n console.log(styleText(\"green\", ` Removed binary: ${exePath}`));\n removed = true;\n }\n\n // Also check for wrapper .cmd in proxy directory\n const proxyDir = join(DROID_PATCH_DIR, \"proxy\");\n const proxyWrapperCmd = join(proxyDir, `${aliasName}.cmd`);\n if (existsSync(proxyWrapperCmd)) {\n await unlink(proxyWrapperCmd);\n console.log(styleText(\"green\", ` Removed wrapper: ${proxyWrapperCmd}`));\n removed = true;\n }\n }\n\n // Check common PATH directories for symlinks (Unix)\n if (!IS_WINDOWS) {\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 regular aliases, old websearch wrappers, and new proxy wrappers\n if (\n target.includes(\".droid-patch/bins\") ||\n target.includes(\".droid-patch/websearch\") ||\n target.includes(\".droid-patch/proxy\") ||\n target.includes(\".droid-patch/statusline\")\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\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 (Unix style without .exe)\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 new proxy wrapper and related files if exist\n const proxyDir = join(DROID_PATCH_DIR, \"proxy\");\n const proxyWrapperPath = join(proxyDir, aliasName);\n const proxyScriptPath = join(proxyDir, `${aliasName}-proxy.js`);\n\n if (existsSync(proxyWrapperPath)) {\n await unlink(proxyWrapperPath);\n console.log(styleText(\"green\", ` Removed wrapper: ${proxyWrapperPath}`));\n removed = true;\n }\n\n if (existsSync(proxyScriptPath)) {\n await unlink(proxyScriptPath);\n console.log(styleText(\"green\", ` Removed proxy script: ${proxyScriptPath}`));\n removed = true;\n }\n\n // Remove old websearch wrapper and related files if exist (backward compatibility)\n const websearchDir = join(DROID_PATCH_DIR, \"websearch\");\n const wrapperPath = join(websearchDir, aliasName);\n const oldProxyPath = 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 legacy wrapper: ${wrapperPath}`));\n removed = true;\n }\n\n if (existsSync(oldProxyPath)) {\n await unlink(oldProxyPath);\n console.log(styleText(\"green\", ` Removed legacy proxy: ${oldProxyPath}`));\n removed = true;\n }\n\n if (existsSync(preloadPath)) {\n await unlink(preloadPath);\n console.log(styleText(\"green\", ` Removed legacy preload: ${preloadPath}`));\n removed = true;\n }\n\n // Remove statusline wrapper and monitor script if exist\n const statuslineDir = join(DROID_PATCH_DIR, \"statusline\");\n const statuslineWrapperPath = join(statuslineDir, aliasName);\n const statuslineMonitorPath = join(statuslineDir, `${aliasName}-statusline.js`);\n const statuslineSessionsPath = join(statuslineDir, `${aliasName}-sessions.js`);\n\n if (existsSync(statuslineWrapperPath)) {\n await unlink(statuslineWrapperPath);\n console.log(styleText(\"green\", ` Removed statusline wrapper: ${statuslineWrapperPath}`));\n removed = true;\n }\n\n if (existsSync(statuslineMonitorPath)) {\n await unlink(statuslineMonitorPath);\n console.log(styleText(\"green\", ` Removed statusline monitor: ${statuslineMonitorPath}`));\n removed = true;\n }\n\n if (existsSync(statuslineSessionsPath)) {\n await unlink(statuslineSessionsPath);\n console.log(styleText(\"green\", ` Removed sessions browser: ${statuslineSessionsPath}`));\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(styleText(\"green\", `[*] Alias \"${aliasName}\" removed successfully`));\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 // Windows: check for .cmd launchers in bin directory\n if (IS_WINDOWS) {\n const binDir = join(DROID_PATCH_DIR, \"bin\");\n if (existsSync(binDir)) {\n try {\n const files = readdirSync(binDir);\n for (const file of files) {\n if (file.endsWith(\".cmd\")) {\n const aliasName = file.replace(/\\.cmd$/, \"\");\n const fullPath = join(binDir, file);\n // Read .cmd to find target\n try {\n const content = readFileSync(fullPath, \"utf-8\");\n const match = content.match(/\"([^\"]+)\"/);\n const target = match ? match[1] : fullPath;\n aliases.push({\n name: aliasName,\n target,\n location: binDir,\n immediate: checkPathInclusion(),\n });\n } catch {\n aliases.push({\n name: aliasName,\n target: fullPath,\n location: binDir,\n immediate: false,\n });\n }\n }\n }\n } catch {\n // Directory can't be read\n }\n }\n\n // Also check proxy directory for wrapper .cmd files\n const proxyDir = join(DROID_PATCH_DIR, \"proxy\");\n if (existsSync(proxyDir)) {\n try {\n const files = readdirSync(proxyDir);\n for (const file of files) {\n if (file.endsWith(\".cmd\")) {\n const aliasName = file.replace(/\\.cmd$/, \"\");\n if (!aliases.find((a) => a.name === aliasName)) {\n const fullPath = join(proxyDir, file);\n aliases.push({\n name: aliasName,\n target: fullPath,\n location: proxyDir,\n immediate: false,\n });\n }\n }\n }\n } catch {\n // Ignore\n }\n }\n } else {\n // Unix: check for symlinks\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 regular aliases, old websearch wrappers, and new proxy wrappers\n if (\n target.includes(\".droid-patch/bins\") ||\n target.includes(\".droid-patch/websearch\") ||\n target.includes(\".droid-patch/proxy\") ||\n target.includes(\".droid-patch/statusline\")\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\n if (aliases.length === 0) {\n console.log(styleText(\"gray\", \" No aliases configured.\"));\n console.log();\n console.log(styleText(\"gray\", \" Create one with: npx droid-patch --is-custom <alias-name>\"));\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(styleText(\"green\", ` • ${styleText([\"cyan\", \"bold\"], alias.name)} [${status}]`));\n console.log(styleText(\"gray\", ` → ${alias.target}`));\n\n // Load and display metadata\n const meta = await loadAliasMetadata(alias.name);\n if (meta) {\n // Version info\n const patchVer = meta.droidPatchVersion\n ? `droid-patch@${meta.droidPatchVersion}`\n : \"unknown\";\n const droidVer = meta.droidVersion ? `droid@${meta.droidVersion}` : \"unknown\";\n console.log(styleText(\"gray\", ` Versions: ${patchVer}, ${droidVer}`));\n\n // Flags/patches\n const flags = formatPatches(meta.patches);\n console.log(styleText(\"gray\", ` Flags: ${flags}`));\n\n // Created time\n if (meta.createdAt) {\n const date = new Date(meta.createdAt).toLocaleString();\n console.log(styleText(\"gray\", ` Created: ${date}`));\n }\n } else {\n console.log(styleText(\"yellow\", ` (no metadata - created by older version)`));\n }\n console.log();\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(\"white\", `[*] Replacing original binary: ${styleText(\"cyan\", originalPath)}`),\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(styleText(\"gray\", ` Backup already exists: ${latestBackupPath}`));\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(styleText(\"yellow\", \"[!] Could not re-sign binary. You may need to run:\"));\n console.log(styleText(\"gray\", ` codesign --force --deep --sign - \"${originalPath}\"`));\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(styleText(\"white\", \"The patched binary is now active in all terminals.\"));\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(styleText(\"white\", `[*] Creating alias: ${styleText(\"cyan\", aliasName)}`));\n\n // Windows: create .cmd launcher pointing to wrapper\n if (IS_WINDOWS) {\n return createWindowsWrapperAlias(wrapperPath, aliasName, verbose);\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(styleText(\"green\", `[*] Created: ${targetPath} -> ${wrapperPath}`));\n console.log();\n console.log(styleText(\"green\", \"─\".repeat(60)));\n console.log(styleText([\"green\", \"bold\"], \" ALIAS READY - NO ACTION REQUIRED!\"));\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(styleText(\"yellow\", \"[*] No writable PATH directory found, using fallback...\"));\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(styleText(\"green\", `[*] Created symlink: ${symlinkPath} -> ${wrapperPath}`));\n\n const shellConfig = getShellConfigPath();\n\n if (!checkPathInclusion()) {\n if (!isPathConfigured(shellConfig)) {\n console.log(styleText(\"white\", `[*] Configuring PATH in ${shellConfig}...`));\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(styleText(\"white\", \"To use the alias in this terminal, run:\"));\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(styleText([\"yellow\", \"bold\"], \" Manual PATH Configuration Required\"));\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(styleText(\"green\", `[*] PATH already configured in ${shellConfig}`));\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(styleText(\"green\", `[*] PATH already includes aliases directory`));\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\n/**\n * Create Windows alias for wrapper script (.cmd pointing to wrapper .cmd)\n */\nasync function createWindowsWrapperAlias(\n wrapperPath: string,\n aliasName: string,\n verbose = false,\n): Promise<CreateAliasResult> {\n const binDir = join(DROID_PATCH_DIR, \"bin\");\n if (!existsSync(binDir)) {\n mkdirSync(binDir, { recursive: true });\n }\n\n if (verbose) {\n console.log(styleText(\"gray\", ` Wrapper: ${wrapperPath}`));\n }\n\n // Create .cmd launcher in bin directory that calls the wrapper\n const cmdPath = join(binDir, `${aliasName}.cmd`);\n const cmdContent = generateWindowsLauncher(wrapperPath);\n writeFileSync(cmdPath, cmdContent);\n\n if (verbose) {\n console.log(styleText(\"gray\", ` Created launcher: ${cmdPath}`));\n }\n\n // Try to add bin directory to user PATH\n const pathAdded = addToWindowsUserPath(binDir);\n\n console.log(styleText(\"green\", `[*] Created: ${cmdPath}`));\n console.log();\n\n if (pathAdded) {\n if (checkPathInclusion()) {\n console.log(styleText(\"green\", \"─\".repeat(60)));\n console.log(styleText([\"green\", \"bold\"], \" ALIAS READY!\"));\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.`,\n ),\n );\n console.log(styleText(\"gray\", `(Installed to: ${binDir})`));\n\n return {\n aliasPath: cmdPath,\n binaryPath: wrapperPath,\n immediate: true,\n };\n }\n\n console.log(styleText(\"yellow\", \"─\".repeat(60)));\n console.log(styleText([\"yellow\", \"bold\"], \" PATH Updated - Restart Terminal\"));\n console.log(styleText(\"yellow\", \"─\".repeat(60)));\n console.log();\n console.log(styleText(\"white\", \"PATH has been updated. Please restart your terminal.\"));\n console.log(\n styleText(\n \"white\",\n `Then you can use \"${styleText([\"cyan\", \"bold\"], aliasName)}\" command directly.`,\n ),\n );\n console.log();\n console.log(styleText(\"gray\", `Installed to: ${binDir}`));\n } else {\n console.log(styleText(\"yellow\", \"─\".repeat(60)));\n console.log(styleText([\"yellow\", \"bold\"], \" Manual PATH Configuration Required\"));\n console.log(styleText(\"yellow\", \"─\".repeat(60)));\n console.log();\n console.log(styleText(\"white\", \"Add this directory to your PATH:\"));\n console.log(styleText(\"cyan\", ` ${binDir}`));\n console.log();\n console.log(styleText(\"gray\", \"Or run directly:\"));\n console.log(styleText(\"cyan\", ` \"${cmdPath}\"`));\n }\n\n return {\n aliasPath: cmdPath,\n binaryPath: wrapperPath,\n immediate: false,\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(styleText(\"green\", \"Original droid binary has been restored from local backup.\"));\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(styleText(\"gray\", \"If you have a manual backup, restore it with:\"));\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(styleText(\"green\", \"All terminals will now use the original version.\"));\n}\n\n/**\n * Filter options for removing aliases\n * Uses the same names as CLI options for consistency\n */\nexport type FilterFlag =\n | \"is-custom\"\n | \"skip-login\"\n | \"websearch\"\n | \"api-base\"\n | \"reasoning-effort\"\n | \"disable-telemetry\"\n | \"standalone\";\n\nexport interface RemoveFilterOptions {\n /** Remove aliases created by this droid-patch version */\n patchVersion?: string;\n /** Remove aliases for this droid version */\n droidVersion?: string;\n /** Remove aliases that have these flags enabled (all must match) */\n flags?: FilterFlag[];\n}\n\n/**\n * Remove aliases matching filter criteria\n */\nexport async function removeAliasesByFilter(filter: RemoveFilterOptions): Promise<void> {\n console.log(styleText(\"cyan\", \"═\".repeat(60)));\n console.log(styleText([\"cyan\", \"bold\"], \" Remove Aliases by Filter\"));\n console.log(styleText(\"cyan\", \"═\".repeat(60)));\n console.log();\n\n // Show filter criteria\n if (filter.patchVersion) {\n console.log(styleText(\"white\", ` Filter: droid-patch version = ${filter.patchVersion}`));\n }\n if (filter.droidVersion) {\n console.log(styleText(\"white\", ` Filter: droid version = ${filter.droidVersion}`));\n }\n if (filter.flags && filter.flags.length > 0) {\n console.log(styleText(\"white\", ` Filter: flags = ${filter.flags.join(\", \")}`));\n }\n console.log();\n\n // Collect all alias names\n const aliasNames = new Set<string>();\n\n // Check common PATH directories for symlinks\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 if (\n target.includes(\".droid-patch/bins\") ||\n target.includes(\".droid-patch/websearch\") ||\n target.includes(\".droid-patch/proxy\") ||\n target.includes(\".droid-patch/statusline\")\n ) {\n aliasNames.add(file);\n }\n }\n } catch {\n // Ignore\n }\n }\n } catch {\n // Directory can't be read\n }\n }\n\n // Check aliases directory\n if (existsSync(ALIASES_DIR)) {\n try {\n const files = readdirSync(ALIASES_DIR);\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 aliasNames.add(file);\n }\n } catch {\n // Ignore\n }\n }\n } catch {\n // Directory can't be read\n }\n }\n\n // Filter aliases by metadata\n const matchingAliases: string[] = [];\n\n for (const aliasName of aliasNames) {\n const meta = await loadAliasMetadata(aliasName);\n\n // If no metadata, skip (can't filter without metadata)\n if (!meta) {\n continue;\n }\n\n let matches = true;\n\n // Check droid-patch version\n if (filter.patchVersion && meta.droidPatchVersion !== filter.patchVersion) {\n matches = false;\n }\n\n // Check droid version\n if (filter.droidVersion && meta.droidVersion !== filter.droidVersion) {\n matches = false;\n }\n\n // Check flags (all specified flags must match)\n if (filter.flags && filter.flags.length > 0) {\n const patches = meta.patches;\n for (const flag of filter.flags) {\n switch (flag) {\n case \"is-custom\":\n if (!patches.isCustom) matches = false;\n break;\n case \"skip-login\":\n if (!patches.skipLogin) matches = false;\n break;\n case \"websearch\":\n if (!patches.websearch) matches = false;\n break;\n case \"reasoning-effort\":\n if (!patches.reasoningEffort) matches = false;\n break;\n case \"api-base\":\n if (!patches.apiBase) matches = false;\n break;\n case \"disable-telemetry\":\n if (!patches.noTelemetry) matches = false;\n break;\n case \"standalone\":\n if (!patches.standalone) matches = false;\n break;\n }\n if (!matches) break;\n }\n }\n\n if (matches) {\n matchingAliases.push(aliasName);\n }\n }\n\n if (matchingAliases.length === 0) {\n console.log(styleText(\"yellow\", \" No aliases match the filter criteria.\"));\n console.log();\n return;\n }\n\n console.log(styleText(\"white\", ` Found ${matchingAliases.length} matching alias(es):`));\n for (const name of matchingAliases) {\n console.log(styleText(\"gray\", ` • ${name}`));\n }\n console.log();\n\n // Remove each matching alias\n for (const aliasName of matchingAliases) {\n await removeAlias(aliasName);\n console.log();\n }\n\n console.log(styleText(\"green\", `[*] Removed ${matchingAliases.length} alias(es)`));\n}\n\n/**\n * Clear all droid-patch aliases and related files\n */\nexport async function clearAllAliases(): Promise<void> {\n console.log(styleText(\"cyan\", \"═\".repeat(60)));\n console.log(styleText([\"cyan\", \"bold\"], \" Clearing All Droid-Patch Data\"));\n console.log(styleText(\"cyan\", \"═\".repeat(60)));\n console.log();\n\n // Collect all alias names\n const aliasNames = new Set<string>();\n\n // Check common PATH directories for symlinks\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 if (\n target.includes(\".droid-patch/bins\") ||\n target.includes(\".droid-patch/websearch\") ||\n target.includes(\".droid-patch/proxy\") ||\n target.includes(\".droid-patch/statusline\")\n ) {\n aliasNames.add(file);\n }\n }\n } catch {\n // Ignore\n }\n }\n } catch {\n // Directory can't be read\n }\n }\n\n // Check aliases directory\n if (existsSync(ALIASES_DIR)) {\n try {\n const files = readdirSync(ALIASES_DIR);\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 aliasNames.add(file);\n }\n } catch {\n // Ignore\n }\n }\n } catch {\n // Directory can't be read\n }\n }\n\n if (aliasNames.size === 0) {\n console.log(styleText(\"yellow\", \" No aliases found.\"));\n } else {\n console.log(styleText(\"white\", ` Found ${aliasNames.size} alias(es) to remove:`));\n for (const name of aliasNames) {\n console.log(styleText(\"gray\", ` • ${name}`));\n }\n console.log();\n\n // Remove each alias\n for (const aliasName of aliasNames) {\n await removeAlias(aliasName);\n console.log();\n }\n }\n\n // Clean up directories (including legacy files)\n console.log(styleText(\"white\", \" Cleaning up directories...\"));\n const dirsToClean = [\n join(DROID_PATCH_DIR, \"bins\"),\n join(DROID_PATCH_DIR, \"aliases\"),\n join(DROID_PATCH_DIR, \"proxy\"),\n join(DROID_PATCH_DIR, \"websearch\"),\n join(DROID_PATCH_DIR, \"statusline\"),\n ];\n\n for (const dir of dirsToClean) {\n if (existsSync(dir)) {\n try {\n const files = readdirSync(dir);\n for (const file of files) {\n const fullPath = join(dir, file);\n try {\n await unlink(fullPath);\n console.log(styleText(\"green\", ` Removed: ${fullPath}`));\n } catch {\n // Ignore\n }\n }\n } catch {\n // Ignore\n }\n }\n }\n\n // Clean up legacy temp files from old versions\n const legacyTempFiles = [\"/tmp/droid-search-proxy.pid\", \"/tmp/droid-search-proxy.log\"];\n\n for (const tempFile of legacyTempFiles) {\n if (existsSync(tempFile)) {\n try {\n await unlink(tempFile);\n console.log(styleText(\"green\", ` Removed legacy: ${tempFile}`));\n } catch {\n // Ignore\n }\n }\n }\n\n // Clean up temp port files (pattern: /tmp/droid-websearch-*.port)\n try {\n const tmpFiles = readdirSync(\"/tmp\");\n for (const file of tmpFiles) {\n if (file.startsWith(\"droid-websearch-\") && file.endsWith(\".port\")) {\n const fullPath = join(\"/tmp\", file);\n try {\n await unlink(fullPath);\n console.log(styleText(\"green\", ` Removed temp: ${fullPath}`));\n } catch {\n // Ignore\n }\n }\n // Also clean old droid-search-proxy-*.port files\n if (file.startsWith(\"droid-search-proxy-\") && file.endsWith(\".port\")) {\n const fullPath = join(\"/tmp\", file);\n try {\n await unlink(fullPath);\n console.log(styleText(\"green\", ` Removed legacy temp: ${fullPath}`));\n } catch {\n // Ignore\n }\n }\n }\n } catch {\n // Ignore\n }\n\n // Clean up metadata file\n const metadataFile = join(DROID_PATCH_DIR, \"metadata.json\");\n if (existsSync(metadataFile)) {\n try {\n await unlink(metadataFile);\n console.log(styleText(\"green\", ` Removed: ${metadataFile}`));\n } catch {\n // Ignore\n }\n }\n\n console.log();\n console.log(styleText(\"green\", \"[*] All droid-patch data cleared successfully\"));\n}\n"],"mappings":"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"}
package/dist/cli.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { a as removeAlias, d as listAllMetadata, f as loadAliasMetadata, i as listAliases, l as createMetadata, m as patchDroid, n as createAlias, o as removeAliasesByFilter, p as saveAliasMetadata, r as createAliasForWrapper, t as clearAllAliases, u as formatPatches } from "./alias-12JqnRQZ.mjs";
2
+ import { a as removeAlias, d as listAllMetadata, f as loadAliasMetadata, i as listAliases, l as createMetadata, m as patchDroid, n as createAlias, o as removeAliasesByFilter, p as saveAliasMetadata, r as createAliasForWrapper, t as clearAllAliases, u as formatPatches } from "./alias-DTf8YAYU.mjs";
3
3
  import bin from "tiny-bin";
4
4
  import { styleText } from "node:util";
5
5
  import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
@@ -14,12 +14,12 @@ import { createInterface } from "node:readline/promises";
14
14
  /**
15
15
  * WebSearch External Providers Mode (--websearch)
16
16
  *
17
- * Priority: Smithery Exa > Google PSE > Serper > Brave > SearXNG > DuckDuckGo
17
+ * Priority: Smithery Exa > Google PSE > Tavily > Serper > Brave > SearXNG > DuckDuckGo
18
18
  */
19
19
  function generateSearchProxyServerCode() {
20
20
  return `#!/usr/bin/env node
21
21
  // Droid WebSearch Proxy Server (External Providers Mode)
22
- // Priority: Smithery Exa > Google PSE > Serper > Brave > SearXNG > DuckDuckGo
22
+ // Priority: Smithery Exa > Google PSE > Tavily > Serper > Brave > SearXNG > DuckDuckGo
23
23
 
24
24
  const http = require('http');
25
25
  const https = require('https');
@@ -75,6 +75,30 @@ async function searchGooglePSE(query, numResults) {
75
75
  return null;
76
76
  }
77
77
 
78
+ async function searchTavily(query, numResults) {
79
+ const apiKey = process.env.TAVILY_API_KEY;
80
+ if (!apiKey) return null;
81
+ try {
82
+ const bodyStr = JSON.stringify({
83
+ api_key: apiKey,
84
+ query: query,
85
+ max_results: numResults,
86
+ search_depth: 'basic',
87
+ include_answer: false,
88
+ include_images: false,
89
+ include_raw_content: false
90
+ }).replace(/'/g, "'\\\\''");
91
+ const curlCmd = 'curl -s "https://api.tavily.com/search" -H "Content-Type: application/json" -d \\'' + bodyStr + "\\'";
92
+ const data = JSON.parse(execSync(curlCmd, { encoding: 'utf-8', timeout: 15000 }));
93
+ if (data && Array.isArray(data.results) && data.results.length > 0) {
94
+ return data.results.slice(0, numResults).map(function(item) {
95
+ return { title: item.title || '', url: item.url || '', content: item.content || item.snippet || item.raw_content || '' };
96
+ });
97
+ }
98
+ } catch (e) { log('Tavily failed:', e.message); }
99
+ return null;
100
+ }
101
+
78
102
  async function searchSerper(query, numResults) {
79
103
  const apiKey = process.env.SERPER_API_KEY;
80
104
  if (!apiKey) return null;
@@ -144,13 +168,16 @@ async function search(query, numResults) {
144
168
  numResults = numResults || 10;
145
169
  log('Search:', query);
146
170
 
147
- // Priority: Smithery > Google PSE > Serper > Brave > SearXNG > DuckDuckGo
171
+ // Priority: Smithery > Google PSE > Tavily > Serper > Brave > SearXNG > DuckDuckGo
148
172
  var results = await searchSmitheryExa(query, numResults);
149
173
  if (results && results.length > 0) return { results: results, source: 'smithery-exa' };
150
174
 
151
175
  results = await searchGooglePSE(query, numResults);
152
176
  if (results && results.length > 0) return { results: results, source: 'google-pse' };
153
177
 
178
+ results = await searchTavily(query, numResults);
179
+ if (results && results.length > 0) return { results: results, source: 'tavily' };
180
+
154
181
  results = await searchSerper(query, numResults);
155
182
  if (results && results.length > 0) return { results: results, source: 'serper' };
156
183
 
@@ -1156,7 +1183,9 @@ bin("droid-patch", "CLI tool to patch droid binary with various modifications").
1156
1183
  console.log(styleText("gray", " 2. Google PSE:"));
1157
1184
  console.log(styleText("gray", " export GOOGLE_PSE_API_KEY=your_api_key"));
1158
1185
  console.log(styleText("gray", " export GOOGLE_PSE_CX=your_search_engine_id"));
1159
- console.log(styleText("gray", " 3-6. Serper, Brave, SearXNG, DuckDuckGo (fallbacks)"));
1186
+ console.log(styleText("gray", " 3. Tavily:"));
1187
+ console.log(styleText("gray", " export TAVILY_API_KEY=your_api_key"));
1188
+ console.log(styleText("gray", " 4-7. Serper, Brave, SearXNG, DuckDuckGo (fallbacks)"));
1160
1189
  console.log();
1161
1190
  console.log("Debug mode:");
1162
1191
  console.log(styleText("gray", " export DROID_SEARCH_DEBUG=1"));
@@ -1258,8 +1287,9 @@ bin("droid-patch", "CLI tool to patch droid binary with various modifications").
1258
1287
  description: "Bypass reasoning effort validation (allows xhigh in settings.json)",
1259
1288
  pattern: Buffer.from(""),
1260
1289
  replacement: Buffer.from(""),
1261
- regexPattern: /T!=="none"&&T!=="off"&&!([A-Z])\.(supportedReasoningEfforts|reasoningEffort\.supported)\.includes\(T\)/g,
1262
- regexReplacement: "T!=\"none\"&&T!=\"off\"&&0&&$1.$2.includes(T)"
1290
+ regexPattern: /([A-Z])!=="none"&&\1!=="off"&&!([A-Z])\.(supportedReasoningEfforts|reasoningEffort\.supported)\.includes\(\1\)/g,
1291
+ regexReplacement: "$1!=\"none\"&&$1!=\"off\"&&0&&$2.$3.includes($1)",
1292
+ alreadyPatchedRegexPattern: /([A-Z])!="none"&&\1!="off"&&0&&([A-Z])\.(supportedReasoningEfforts|reasoningEffort\.supported)\.includes\(\1\)/g
1263
1293
  });
1264
1294
  }
1265
1295
  if (noTelemetry) {
@@ -1511,8 +1541,9 @@ bin("droid-patch", "CLI tool to patch droid binary with various modifications").
1511
1541
  description: "Bypass reasoning effort validation (allows xhigh in settings.json)",
1512
1542
  pattern: Buffer.from(""),
1513
1543
  replacement: Buffer.from(""),
1514
- regexPattern: /T!=="none"&&T!=="off"&&!([A-Z])\.(supportedReasoningEfforts|reasoningEffort\.supported)\.includes\(T\)/g,
1515
- regexReplacement: "T!=\"none\"&&T!=\"off\"&&0&&$1.$2.includes(T)"
1544
+ regexPattern: /([A-Z])!=="none"&&\1!=="off"&&!([A-Z])\.(supportedReasoningEfforts|reasoningEffort\.supported)\.includes\(\1\)/g,
1545
+ regexReplacement: "$1!=\"none\"&&$1!=\"off\"&&0&&$2.$3.includes($1)",
1546
+ alreadyPatchedRegexPattern: /([A-Z])!="none"&&\1!="off"&&0&&([A-Z])\.(supportedReasoningEfforts|reasoningEffort\.supported)\.includes\(\1\)/g
1516
1547
  });
1517
1548
  }
1518
1549
  if (meta.patches.noTelemetry) {