droid-patch 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +83 -0
- package/dist/alias-kOmb9bCi.js +555 -0
- package/dist/alias-kOmb9bCi.js.map +1 -0
- package/dist/cli.d.ts +1 -0
- package/dist/cli.js +98 -0
- package/dist/cli.js.map +1 -0
- package/dist/index.d.ts +52 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +3 -0
- package/package.json +55 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Kingsword
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
# droid-patch
|
|
2
|
+
|
|
3
|
+
CLI tool to patch the droid binary with various modifications.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install -g droid-patch
|
|
9
|
+
# or use directly with npx
|
|
10
|
+
npx droid-patch --help
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Usage
|
|
14
|
+
|
|
15
|
+
### Patch and create an alias
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
# Patch the default droid binary and create an alias
|
|
19
|
+
npx droid-patch --is-custom droid
|
|
20
|
+
|
|
21
|
+
# Specify a custom path to the droid binary
|
|
22
|
+
npx droid-patch --is-custom -p /path/to/droid my-droid
|
|
23
|
+
|
|
24
|
+
# Dry run - verify patches without actually applying them
|
|
25
|
+
npx droid-patch --is-custom --dry-run droid
|
|
26
|
+
|
|
27
|
+
# Verbose output
|
|
28
|
+
npx droid-patch --is-custom -v droid
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
### Available Options
|
|
32
|
+
|
|
33
|
+
| Option | Description |
|
|
34
|
+
|--------|-------------|
|
|
35
|
+
| `--is-custom` | Patch `isCustom:!0` to `isCustom:!1` (enables context compression for custom models) |
|
|
36
|
+
| `--dry-run` | Verify patches without actually modifying the binary |
|
|
37
|
+
| `-p, --path <path>` | Path to the droid binary (default: `~/.droid/bin/droid`) |
|
|
38
|
+
| `-o, --output <path>` | Output path for patched binary (default: `<path>.patched`) |
|
|
39
|
+
| `--no-backup` | Skip creating backup of original binary |
|
|
40
|
+
| `-v, --verbose` | Enable verbose output |
|
|
41
|
+
|
|
42
|
+
### Manage Aliases
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
# List all aliases
|
|
46
|
+
npx droid-patch list
|
|
47
|
+
|
|
48
|
+
# Remove an alias
|
|
49
|
+
npx droid-patch remove <alias-name>
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
## PATH Configuration
|
|
53
|
+
|
|
54
|
+
After creating an alias, you need to add the aliases directory to your PATH:
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
# Add to your shell config (~/.zshrc, ~/.bashrc, etc.)
|
|
58
|
+
export PATH="$HOME/.droid-patch/aliases:$PATH"
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
Or run the quick setup command shown after patching.
|
|
62
|
+
|
|
63
|
+
## How It Works
|
|
64
|
+
|
|
65
|
+
1. **Patching**: The tool searches for specific byte patterns in the droid binary and replaces them
|
|
66
|
+
2. **Alias Creation**:
|
|
67
|
+
- Copies the patched binary to `~/.droid-patch/bins/`
|
|
68
|
+
- Creates a symlink in `~/.droid-patch/aliases/`
|
|
69
|
+
- On macOS, automatically re-signs the binary with `codesign`
|
|
70
|
+
|
|
71
|
+
## Available Patches
|
|
72
|
+
|
|
73
|
+
### `--is-custom`
|
|
74
|
+
|
|
75
|
+
Changes `isCustom:!0` (true) to `isCustom:!1` (false) for custom models.
|
|
76
|
+
|
|
77
|
+
**Purpose**: This may enable context compression (auto-summarization) for custom models, which is normally only available for official models.
|
|
78
|
+
|
|
79
|
+
**Note**: Side effects are unknown - test thoroughly before production use.
|
|
80
|
+
|
|
81
|
+
## License
|
|
82
|
+
|
|
83
|
+
MIT
|
|
@@ -0,0 +1,555 @@
|
|
|
1
|
+
import { styleText } from "node:util";
|
|
2
|
+
import { appendFileSync, existsSync, lstatSync, mkdirSync, readFileSync, readdirSync, unlinkSync, writeFileSync } from "node:fs";
|
|
3
|
+
import { basename, dirname, join } from "node:path";
|
|
4
|
+
import { homedir } from "node:os";
|
|
5
|
+
import { chmod, copyFile, readFile, readlink, stat, symlink, unlink, writeFile } from "node:fs/promises";
|
|
6
|
+
import { execSync } from "node:child_process";
|
|
7
|
+
|
|
8
|
+
//#region src/patcher.ts
|
|
9
|
+
async function patchDroid(options) {
|
|
10
|
+
const { inputPath, outputPath, patches, dryRun = false, backup = true, verbose = false } = options;
|
|
11
|
+
const finalOutputPath = outputPath || `${inputPath}.patched`;
|
|
12
|
+
if (!existsSync(inputPath)) throw new Error(`Binary not found: ${inputPath}`);
|
|
13
|
+
const stats = await stat(inputPath);
|
|
14
|
+
const fileSizeMB = (stats.size / (1024 * 1024)).toFixed(2);
|
|
15
|
+
console.log(styleText("white", `[*] Reading binary: ${styleText("cyan", inputPath)}`));
|
|
16
|
+
console.log(styleText("white", `[*] File size: ${styleText("cyan", fileSizeMB)} MB`));
|
|
17
|
+
console.log();
|
|
18
|
+
const data = await readFile(inputPath);
|
|
19
|
+
const buffer = Buffer.from(data);
|
|
20
|
+
const results = [];
|
|
21
|
+
for (const patch of patches) {
|
|
22
|
+
console.log(styleText("white", `[*] Checking patch: ${styleText("yellow", patch.name)}`));
|
|
23
|
+
console.log(styleText("gray", ` ${patch.description}`));
|
|
24
|
+
const positions = findAllPositions(buffer, patch.pattern);
|
|
25
|
+
if (positions.length === 0) {
|
|
26
|
+
console.log(styleText("yellow", ` ! Pattern not found - may already be patched`));
|
|
27
|
+
results.push({
|
|
28
|
+
name: patch.name,
|
|
29
|
+
found: 0,
|
|
30
|
+
success: false,
|
|
31
|
+
alreadyPatched: buffer.includes(patch.replacement)
|
|
32
|
+
});
|
|
33
|
+
const replacementPositions = findAllPositions(buffer, patch.replacement);
|
|
34
|
+
if (replacementPositions.length > 0) {
|
|
35
|
+
console.log(styleText("blue", ` ✓ Found ${replacementPositions.length} occurrences of patched pattern`));
|
|
36
|
+
console.log(styleText("blue", ` ✓ Binary appears to be already patched`));
|
|
37
|
+
results[results.length - 1].alreadyPatched = true;
|
|
38
|
+
results[results.length - 1].success = true;
|
|
39
|
+
}
|
|
40
|
+
continue;
|
|
41
|
+
}
|
|
42
|
+
console.log(styleText("green", ` ✓ Found ${positions.length} occurrences`));
|
|
43
|
+
if (verbose) {
|
|
44
|
+
for (const pos of positions.slice(0, 5)) {
|
|
45
|
+
const context = getContext(buffer, pos, patch.pattern.length, 25);
|
|
46
|
+
console.log(styleText("gray", ` @ 0x${pos.toString(16).padStart(8, "0")}: ...${context}...`));
|
|
47
|
+
}
|
|
48
|
+
if (positions.length > 5) console.log(styleText("gray", ` ... and ${positions.length - 5} more`));
|
|
49
|
+
}
|
|
50
|
+
results.push({
|
|
51
|
+
name: patch.name,
|
|
52
|
+
found: positions.length,
|
|
53
|
+
positions,
|
|
54
|
+
success: true
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
console.log();
|
|
58
|
+
if (dryRun) {
|
|
59
|
+
console.log(styleText("blue", "─".repeat(60)));
|
|
60
|
+
console.log(styleText(["blue", "bold"], " DRY RUN RESULTS"));
|
|
61
|
+
console.log(styleText("blue", "─".repeat(60)));
|
|
62
|
+
console.log();
|
|
63
|
+
for (const result of results) if (result.alreadyPatched) console.log(styleText("blue", ` [✓] ${result.name}: Already patched`));
|
|
64
|
+
else if (result.found > 0) console.log(styleText("green", ` [✓] ${result.name}: ${result.found} occurrences will be patched`));
|
|
65
|
+
else console.log(styleText("yellow", ` [!] ${result.name}: Pattern not found`));
|
|
66
|
+
return {
|
|
67
|
+
success: results.every((r) => r.success || r.alreadyPatched),
|
|
68
|
+
dryRun: true,
|
|
69
|
+
results
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
const patchesNeeded = results.filter((r) => r.found > 0 && !r.alreadyPatched);
|
|
73
|
+
if (patchesNeeded.length === 0) {
|
|
74
|
+
const allPatched = results.every((r) => r.alreadyPatched);
|
|
75
|
+
if (allPatched) {
|
|
76
|
+
console.log(styleText("blue", "[*] All patches already applied. Binary is up to date."));
|
|
77
|
+
return {
|
|
78
|
+
success: true,
|
|
79
|
+
outputPath: inputPath,
|
|
80
|
+
results,
|
|
81
|
+
noPatchNeeded: true
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
console.log(styleText("yellow", "[!] No patches could be applied."));
|
|
85
|
+
return {
|
|
86
|
+
success: false,
|
|
87
|
+
results
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
if (backup) {
|
|
91
|
+
const backupPath = `${inputPath}.backup`;
|
|
92
|
+
if (!existsSync(backupPath)) {
|
|
93
|
+
await copyFile(inputPath, backupPath);
|
|
94
|
+
console.log(styleText("white", `[*] Created backup: ${styleText("cyan", backupPath)}`));
|
|
95
|
+
} else console.log(styleText("gray", `[*] Backup already exists: ${backupPath}`));
|
|
96
|
+
}
|
|
97
|
+
console.log(styleText("white", "[*] Applying patches..."));
|
|
98
|
+
const patchedBuffer = Buffer.from(buffer);
|
|
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
|
+
}
|
|
108
|
+
console.log(styleText("green", `[*] Applied ${totalPatched} patches`));
|
|
109
|
+
await writeFile(finalOutputPath, patchedBuffer);
|
|
110
|
+
console.log(styleText("white", `[*] Patched binary saved: ${styleText("cyan", finalOutputPath)}`));
|
|
111
|
+
await chmod(finalOutputPath, 493);
|
|
112
|
+
console.log(styleText("gray", "[*] Set executable permission"));
|
|
113
|
+
console.log();
|
|
114
|
+
console.log(styleText("white", "[*] Verifying patches..."));
|
|
115
|
+
const verifyBuffer = await readFile(finalOutputPath);
|
|
116
|
+
let allVerified = true;
|
|
117
|
+
for (const patch of patches) {
|
|
118
|
+
const oldCount = findAllPositions(verifyBuffer, patch.pattern).length;
|
|
119
|
+
const newCount = findAllPositions(verifyBuffer, patch.replacement).length;
|
|
120
|
+
if (oldCount === 0) console.log(styleText("green", ` ✓ ${patch.name}: Verified (${newCount} patched)`));
|
|
121
|
+
else {
|
|
122
|
+
console.log(styleText("red", ` ✗ ${patch.name}: ${oldCount} occurrences not patched`));
|
|
123
|
+
allVerified = false;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
if (allVerified) {
|
|
127
|
+
console.log();
|
|
128
|
+
console.log(styleText("green", "[+] All patches verified successfully!"));
|
|
129
|
+
}
|
|
130
|
+
if (process.platform === "darwin") {
|
|
131
|
+
console.log();
|
|
132
|
+
console.log(styleText("yellow", "Note for macOS:"));
|
|
133
|
+
console.log(styleText("gray", ` You may need to re-sign: codesign --force --deep --sign - ${finalOutputPath}`));
|
|
134
|
+
console.log(styleText("gray", ` Or remove quarantine: xattr -cr ${finalOutputPath}`));
|
|
135
|
+
}
|
|
136
|
+
return {
|
|
137
|
+
success: allVerified,
|
|
138
|
+
outputPath: finalOutputPath,
|
|
139
|
+
results,
|
|
140
|
+
patchedCount: totalPatched
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
function findAllPositions(buffer, pattern) {
|
|
144
|
+
const positions = [];
|
|
145
|
+
let pos = 0;
|
|
146
|
+
while (true) {
|
|
147
|
+
pos = buffer.indexOf(pattern, pos);
|
|
148
|
+
if (pos === -1) break;
|
|
149
|
+
positions.push(pos);
|
|
150
|
+
pos += pattern.length;
|
|
151
|
+
}
|
|
152
|
+
return positions;
|
|
153
|
+
}
|
|
154
|
+
function getContext(buffer, position, patternLength, contextSize) {
|
|
155
|
+
const start = Math.max(0, position - contextSize);
|
|
156
|
+
const end = Math.min(buffer.length, position + patternLength + contextSize);
|
|
157
|
+
const slice = buffer.slice(start, end);
|
|
158
|
+
let str = "";
|
|
159
|
+
for (let i = 0; i < slice.length; i++) {
|
|
160
|
+
const c = slice[i];
|
|
161
|
+
if (c >= 32 && c < 127) str += String.fromCharCode(c);
|
|
162
|
+
else str += ".";
|
|
163
|
+
}
|
|
164
|
+
return str;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
//#endregion
|
|
168
|
+
//#region src/alias.ts
|
|
169
|
+
const DROID_PATCH_DIR = join(homedir(), ".droid-patch");
|
|
170
|
+
const ALIASES_DIR = join(DROID_PATCH_DIR, "aliases");
|
|
171
|
+
const BINS_DIR = join(DROID_PATCH_DIR, "bins");
|
|
172
|
+
const COMMON_PATH_DIRS = [
|
|
173
|
+
join(homedir(), ".local/bin"),
|
|
174
|
+
join(homedir(), "bin"),
|
|
175
|
+
join(homedir(), ".bin"),
|
|
176
|
+
"/opt/homebrew/bin",
|
|
177
|
+
"/usr/local/bin",
|
|
178
|
+
join(homedir(), ".npm-global/bin"),
|
|
179
|
+
join(homedir(), ".npm/bin"),
|
|
180
|
+
join(homedir(), ".pnpm-global/bin"),
|
|
181
|
+
join(homedir(), ".yarn/bin"),
|
|
182
|
+
join(homedir(), ".config/yarn/global/node_modules/.bin"),
|
|
183
|
+
join(homedir(), ".cargo/bin"),
|
|
184
|
+
join(homedir(), "go/bin"),
|
|
185
|
+
join(homedir(), ".deno/bin"),
|
|
186
|
+
join(homedir(), ".bun/bin"),
|
|
187
|
+
join(homedir(), ".local/share/mise/shims"),
|
|
188
|
+
join(homedir(), ".asdf/shims"),
|
|
189
|
+
join(homedir(), ".nvm/current/bin"),
|
|
190
|
+
join(homedir(), ".volta/bin"),
|
|
191
|
+
join(homedir(), ".fnm/current/bin")
|
|
192
|
+
];
|
|
193
|
+
function ensureDirectories() {
|
|
194
|
+
if (!existsSync(DROID_PATCH_DIR)) mkdirSync(DROID_PATCH_DIR, { recursive: true });
|
|
195
|
+
if (!existsSync(ALIASES_DIR)) mkdirSync(ALIASES_DIR, { recursive: true });
|
|
196
|
+
if (!existsSync(BINS_DIR)) mkdirSync(BINS_DIR, { recursive: true });
|
|
197
|
+
}
|
|
198
|
+
function checkPathInclusion() {
|
|
199
|
+
const pathEnv = process.env.PATH || "";
|
|
200
|
+
return pathEnv.split(":").includes(ALIASES_DIR);
|
|
201
|
+
}
|
|
202
|
+
function findWritablePathDir() {
|
|
203
|
+
const pathEnv = process.env.PATH || "";
|
|
204
|
+
const pathDirs = pathEnv.split(":");
|
|
205
|
+
for (const dir of COMMON_PATH_DIRS) if (pathDirs.includes(dir)) try {
|
|
206
|
+
if (!existsSync(dir)) mkdirSync(dir, { recursive: true });
|
|
207
|
+
const testFile = join(dir, `.droid-patch-test-${Date.now()}`);
|
|
208
|
+
writeFileSync(testFile, "");
|
|
209
|
+
unlinkSync(testFile);
|
|
210
|
+
return dir;
|
|
211
|
+
} catch {
|
|
212
|
+
continue;
|
|
213
|
+
}
|
|
214
|
+
return null;
|
|
215
|
+
}
|
|
216
|
+
function getShellConfigPath() {
|
|
217
|
+
const shell = process.env.SHELL || "/bin/bash";
|
|
218
|
+
const shellName = basename(shell);
|
|
219
|
+
switch (shellName) {
|
|
220
|
+
case "zsh": return join(homedir(), ".zshrc");
|
|
221
|
+
case "bash": {
|
|
222
|
+
const bashProfile = join(homedir(), ".bash_profile");
|
|
223
|
+
if (existsSync(bashProfile)) return bashProfile;
|
|
224
|
+
return join(homedir(), ".bashrc");
|
|
225
|
+
}
|
|
226
|
+
case "fish": return join(homedir(), ".config/fish/config.fish");
|
|
227
|
+
default: return join(homedir(), ".profile");
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
function isPathConfigured(shellConfigPath) {
|
|
231
|
+
if (!existsSync(shellConfigPath)) return false;
|
|
232
|
+
try {
|
|
233
|
+
const content = readFileSync(shellConfigPath, "utf-8");
|
|
234
|
+
return content.includes(".droid-patch/aliases") || content.includes("droid-patch/aliases");
|
|
235
|
+
} catch {
|
|
236
|
+
return false;
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
function addPathToShellConfig(shellConfigPath, verbose = false) {
|
|
240
|
+
const shell = process.env.SHELL || "/bin/bash";
|
|
241
|
+
const shellName = basename(shell);
|
|
242
|
+
let exportLine;
|
|
243
|
+
if (shellName === "fish") exportLine = `\n# Added by droid-patch\nfish_add_path "${ALIASES_DIR}"\n`;
|
|
244
|
+
else exportLine = `\n# Added by droid-patch\nexport PATH="${ALIASES_DIR}:$PATH"\n`;
|
|
245
|
+
try {
|
|
246
|
+
appendFileSync(shellConfigPath, exportLine);
|
|
247
|
+
if (verbose) console.log(styleText("gray", ` Added PATH export to: ${shellConfigPath}`));
|
|
248
|
+
return true;
|
|
249
|
+
} catch (error) {
|
|
250
|
+
console.log(styleText("yellow", `[!] Could not write to ${shellConfigPath}: ${error.message}`));
|
|
251
|
+
return false;
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
async function createAlias(patchedBinaryPath, aliasName, verbose = false) {
|
|
255
|
+
ensureDirectories();
|
|
256
|
+
console.log(styleText("white", `[*] Creating alias: ${styleText("cyan", aliasName)}`));
|
|
257
|
+
const writablePathDir = findWritablePathDir();
|
|
258
|
+
if (writablePathDir) {
|
|
259
|
+
const targetPath = join(writablePathDir, aliasName);
|
|
260
|
+
const binaryDest$1 = join(BINS_DIR, `${aliasName}-patched`);
|
|
261
|
+
await copyFile(patchedBinaryPath, binaryDest$1);
|
|
262
|
+
await chmod(binaryDest$1, 493);
|
|
263
|
+
if (verbose) console.log(styleText("gray", ` Stored binary: ${binaryDest$1}`));
|
|
264
|
+
if (existsSync(targetPath)) {
|
|
265
|
+
await unlink(targetPath);
|
|
266
|
+
if (verbose) console.log(styleText("gray", ` Removed existing: ${targetPath}`));
|
|
267
|
+
}
|
|
268
|
+
await symlink(binaryDest$1, targetPath);
|
|
269
|
+
if (process.platform === "darwin") {
|
|
270
|
+
try {
|
|
271
|
+
console.log(styleText("gray", "[*] Re-signing binary for macOS..."));
|
|
272
|
+
execSync(`codesign --force --deep --sign - "${binaryDest$1}"`, { stdio: "pipe" });
|
|
273
|
+
console.log(styleText("green", "[*] Binary re-signed successfully"));
|
|
274
|
+
} catch {
|
|
275
|
+
console.log(styleText("yellow", "[!] Could not re-sign binary"));
|
|
276
|
+
}
|
|
277
|
+
try {
|
|
278
|
+
execSync(`xattr -cr "${binaryDest$1}"`, { stdio: "pipe" });
|
|
279
|
+
} catch {}
|
|
280
|
+
}
|
|
281
|
+
console.log(styleText("green", `[*] Created: ${targetPath} -> ${binaryDest$1}`));
|
|
282
|
+
console.log();
|
|
283
|
+
console.log(styleText("green", "─".repeat(60)));
|
|
284
|
+
console.log(styleText(["green", "bold"], " ALIAS READY - NO ACTION REQUIRED!"));
|
|
285
|
+
console.log(styleText("green", "─".repeat(60)));
|
|
286
|
+
console.log();
|
|
287
|
+
console.log(styleText("white", `The alias "${styleText(["cyan", "bold"], aliasName)}" is now available in ALL terminals.`));
|
|
288
|
+
console.log(styleText("gray", `(Installed to: ${writablePathDir})`));
|
|
289
|
+
return {
|
|
290
|
+
aliasPath: targetPath,
|
|
291
|
+
binaryPath: binaryDest$1,
|
|
292
|
+
immediate: true
|
|
293
|
+
};
|
|
294
|
+
}
|
|
295
|
+
console.log(styleText("yellow", "[*] No writable PATH directory found, using fallback..."));
|
|
296
|
+
const binaryDest = join(BINS_DIR, `${aliasName}-patched`);
|
|
297
|
+
await copyFile(patchedBinaryPath, binaryDest);
|
|
298
|
+
await chmod(binaryDest, 493);
|
|
299
|
+
if (verbose) console.log(styleText("gray", ` Copied binary to: ${binaryDest}`));
|
|
300
|
+
if (process.platform === "darwin") {
|
|
301
|
+
try {
|
|
302
|
+
console.log(styleText("gray", "[*] Re-signing binary for macOS..."));
|
|
303
|
+
execSync(`codesign --force --deep --sign - "${binaryDest}"`, { stdio: "pipe" });
|
|
304
|
+
console.log(styleText("green", "[*] Binary re-signed successfully"));
|
|
305
|
+
} catch {
|
|
306
|
+
console.log(styleText("yellow", "[!] Could not re-sign binary. You may need to do this manually:"));
|
|
307
|
+
console.log(styleText("gray", ` codesign --force --deep --sign - "${binaryDest}"`));
|
|
308
|
+
}
|
|
309
|
+
try {
|
|
310
|
+
execSync(`xattr -cr "${binaryDest}"`, { stdio: "pipe" });
|
|
311
|
+
} catch {}
|
|
312
|
+
}
|
|
313
|
+
const symlinkPath = join(ALIASES_DIR, aliasName);
|
|
314
|
+
if (existsSync(symlinkPath)) {
|
|
315
|
+
await unlink(symlinkPath);
|
|
316
|
+
if (verbose) console.log(styleText("gray", ` Removed existing symlink`));
|
|
317
|
+
}
|
|
318
|
+
await symlink(binaryDest, symlinkPath);
|
|
319
|
+
await chmod(symlinkPath, 493);
|
|
320
|
+
console.log(styleText("green", `[*] Created symlink: ${symlinkPath} -> ${binaryDest}`));
|
|
321
|
+
const shellConfig = getShellConfigPath();
|
|
322
|
+
if (!checkPathInclusion()) if (!isPathConfigured(shellConfig)) {
|
|
323
|
+
console.log(styleText("white", `[*] Configuring PATH in ${shellConfig}...`));
|
|
324
|
+
if (addPathToShellConfig(shellConfig, verbose)) {
|
|
325
|
+
console.log(styleText("green", `[*] PATH configured successfully!`));
|
|
326
|
+
console.log();
|
|
327
|
+
console.log(styleText("yellow", "─".repeat(60)));
|
|
328
|
+
console.log(styleText(["yellow", "bold"], " ACTION REQUIRED"));
|
|
329
|
+
console.log(styleText("yellow", "─".repeat(60)));
|
|
330
|
+
console.log();
|
|
331
|
+
console.log(styleText("white", "To use the alias in this terminal, run:"));
|
|
332
|
+
console.log();
|
|
333
|
+
console.log(styleText("cyan", ` source ${shellConfig}`));
|
|
334
|
+
console.log();
|
|
335
|
+
console.log(styleText("gray", "Or simply open a new terminal window."));
|
|
336
|
+
console.log(styleText("yellow", "─".repeat(60)));
|
|
337
|
+
} else {
|
|
338
|
+
const exportLine = `export PATH="${ALIASES_DIR}:$PATH"`;
|
|
339
|
+
console.log();
|
|
340
|
+
console.log(styleText("yellow", "─".repeat(60)));
|
|
341
|
+
console.log(styleText(["yellow", "bold"], " Manual PATH Configuration Required"));
|
|
342
|
+
console.log(styleText("yellow", "─".repeat(60)));
|
|
343
|
+
console.log();
|
|
344
|
+
console.log(styleText("white", "Add this line to your shell config:"));
|
|
345
|
+
console.log(styleText("cyan", ` ${exportLine}`));
|
|
346
|
+
console.log();
|
|
347
|
+
console.log(styleText("gray", `Shell config file: ${shellConfig}`));
|
|
348
|
+
console.log(styleText("yellow", "─".repeat(60)));
|
|
349
|
+
}
|
|
350
|
+
} else {
|
|
351
|
+
console.log(styleText("green", `[*] PATH already configured in ${shellConfig}`));
|
|
352
|
+
console.log();
|
|
353
|
+
console.log(styleText("yellow", `Note: Run \`source ${shellConfig}\` or open a new terminal to use the alias.`));
|
|
354
|
+
}
|
|
355
|
+
else {
|
|
356
|
+
console.log(styleText("green", `[*] PATH already includes aliases directory`));
|
|
357
|
+
console.log();
|
|
358
|
+
console.log(styleText("green", `You can now use "${styleText(["cyan", "bold"], aliasName)}" command directly!`));
|
|
359
|
+
}
|
|
360
|
+
return {
|
|
361
|
+
aliasPath: symlinkPath,
|
|
362
|
+
binaryPath: binaryDest
|
|
363
|
+
};
|
|
364
|
+
}
|
|
365
|
+
async function removeAlias(aliasName) {
|
|
366
|
+
console.log(styleText("white", `[*] Removing alias: ${styleText("cyan", aliasName)}`));
|
|
367
|
+
let removed = false;
|
|
368
|
+
for (const pathDir of COMMON_PATH_DIRS) {
|
|
369
|
+
const pathSymlink = join(pathDir, aliasName);
|
|
370
|
+
if (existsSync(pathSymlink)) try {
|
|
371
|
+
const stats = lstatSync(pathSymlink);
|
|
372
|
+
if (stats.isSymbolicLink()) {
|
|
373
|
+
const target = await readlink(pathSymlink);
|
|
374
|
+
if (target.includes(".droid-patch/bins")) {
|
|
375
|
+
await unlink(pathSymlink);
|
|
376
|
+
console.log(styleText("green", ` Removed: ${pathSymlink}`));
|
|
377
|
+
removed = true;
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
} catch {}
|
|
381
|
+
}
|
|
382
|
+
const symlinkPath = join(ALIASES_DIR, aliasName);
|
|
383
|
+
if (existsSync(symlinkPath)) {
|
|
384
|
+
await unlink(symlinkPath);
|
|
385
|
+
console.log(styleText("green", ` Removed: ${symlinkPath}`));
|
|
386
|
+
removed = true;
|
|
387
|
+
}
|
|
388
|
+
const binaryPath = join(BINS_DIR, `${aliasName}-patched`);
|
|
389
|
+
if (existsSync(binaryPath)) {
|
|
390
|
+
await unlink(binaryPath);
|
|
391
|
+
console.log(styleText("green", ` Removed binary: ${binaryPath}`));
|
|
392
|
+
removed = true;
|
|
393
|
+
}
|
|
394
|
+
if (!removed) console.log(styleText("yellow", ` Alias "${aliasName}" not found`));
|
|
395
|
+
else console.log(styleText("green", `[*] Alias "${aliasName}" removed successfully`));
|
|
396
|
+
}
|
|
397
|
+
async function listAliases() {
|
|
398
|
+
ensureDirectories();
|
|
399
|
+
console.log(styleText("cyan", "═".repeat(60)));
|
|
400
|
+
console.log(styleText(["cyan", "bold"], " Droid-Patch Aliases"));
|
|
401
|
+
console.log(styleText("cyan", "═".repeat(60)));
|
|
402
|
+
console.log();
|
|
403
|
+
const aliases = [];
|
|
404
|
+
for (const pathDir of COMMON_PATH_DIRS) {
|
|
405
|
+
if (!existsSync(pathDir)) continue;
|
|
406
|
+
try {
|
|
407
|
+
const files = readdirSync(pathDir);
|
|
408
|
+
for (const file of files) {
|
|
409
|
+
const fullPath = join(pathDir, file);
|
|
410
|
+
try {
|
|
411
|
+
const stats = lstatSync(fullPath);
|
|
412
|
+
if (stats.isSymbolicLink()) {
|
|
413
|
+
const target = await readlink(fullPath);
|
|
414
|
+
if (target.includes(".droid-patch/bins")) aliases.push({
|
|
415
|
+
name: file,
|
|
416
|
+
target,
|
|
417
|
+
location: pathDir,
|
|
418
|
+
immediate: true
|
|
419
|
+
});
|
|
420
|
+
}
|
|
421
|
+
} catch {}
|
|
422
|
+
}
|
|
423
|
+
} catch {}
|
|
424
|
+
}
|
|
425
|
+
try {
|
|
426
|
+
const files = readdirSync(ALIASES_DIR);
|
|
427
|
+
for (const file of files) {
|
|
428
|
+
const fullPath = join(ALIASES_DIR, file);
|
|
429
|
+
try {
|
|
430
|
+
const stats = lstatSync(fullPath);
|
|
431
|
+
if (stats.isSymbolicLink()) {
|
|
432
|
+
const target = await readlink(fullPath);
|
|
433
|
+
if (!aliases.find((a) => a.name === file)) aliases.push({
|
|
434
|
+
name: file,
|
|
435
|
+
target,
|
|
436
|
+
location: ALIASES_DIR,
|
|
437
|
+
immediate: false
|
|
438
|
+
});
|
|
439
|
+
}
|
|
440
|
+
} catch {}
|
|
441
|
+
}
|
|
442
|
+
} catch {}
|
|
443
|
+
if (aliases.length === 0) {
|
|
444
|
+
console.log(styleText("gray", " No aliases configured."));
|
|
445
|
+
console.log();
|
|
446
|
+
console.log(styleText("gray", " Create one with: npx droid-patch --is-custom <alias-name>"));
|
|
447
|
+
} else {
|
|
448
|
+
console.log(styleText("white", ` Found ${aliases.length} alias(es):`));
|
|
449
|
+
console.log();
|
|
450
|
+
for (const alias of aliases) {
|
|
451
|
+
const status = alias.immediate ? styleText("green", "✓ immediate") : styleText("yellow", "requires source");
|
|
452
|
+
console.log(styleText("green", ` • ${styleText(["cyan", "bold"], alias.name)} [${status}]`));
|
|
453
|
+
console.log(styleText("gray", ` → ${alias.target}`));
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
console.log();
|
|
457
|
+
console.log(styleText("gray", ` Aliases directory: ${ALIASES_DIR}`));
|
|
458
|
+
console.log(styleText("gray", ` PATH configured: ${checkPathInclusion() ? styleText("green", "Yes") : styleText("yellow", "No")}`));
|
|
459
|
+
console.log();
|
|
460
|
+
}
|
|
461
|
+
async function replaceOriginal(patchedBinaryPath, originalPath, verbose = false) {
|
|
462
|
+
ensureDirectories();
|
|
463
|
+
console.log(styleText("white", `[*] Replacing original binary: ${styleText("cyan", originalPath)}`));
|
|
464
|
+
const latestBackupPath = join(BINS_DIR, "droid-original-latest");
|
|
465
|
+
if (!existsSync(latestBackupPath)) {
|
|
466
|
+
await copyFile(originalPath, latestBackupPath);
|
|
467
|
+
console.log(styleText("green", `[*] Created backup: ${latestBackupPath}`));
|
|
468
|
+
} else if (verbose) console.log(styleText("gray", ` Backup already exists: ${latestBackupPath}`));
|
|
469
|
+
await copyFile(patchedBinaryPath, originalPath);
|
|
470
|
+
await chmod(originalPath, 493);
|
|
471
|
+
console.log(styleText("green", `[*] Replaced: ${originalPath}`));
|
|
472
|
+
if (process.platform === "darwin") {
|
|
473
|
+
try {
|
|
474
|
+
console.log(styleText("gray", "[*] Re-signing binary for macOS..."));
|
|
475
|
+
execSync(`codesign --force --deep --sign - "${originalPath}"`, { stdio: "pipe" });
|
|
476
|
+
console.log(styleText("green", "[*] Binary re-signed successfully"));
|
|
477
|
+
} catch {
|
|
478
|
+
console.log(styleText("yellow", "[!] Could not re-sign binary. You may need to run:"));
|
|
479
|
+
console.log(styleText("gray", ` codesign --force --deep --sign - "${originalPath}"`));
|
|
480
|
+
}
|
|
481
|
+
try {
|
|
482
|
+
execSync(`xattr -cr "${originalPath}"`, { stdio: "pipe" });
|
|
483
|
+
} catch {}
|
|
484
|
+
}
|
|
485
|
+
console.log();
|
|
486
|
+
console.log(styleText("green", "─".repeat(60)));
|
|
487
|
+
console.log(styleText(["green", "bold"], " REPLACEMENT COMPLETE"));
|
|
488
|
+
console.log(styleText("green", "─".repeat(60)));
|
|
489
|
+
console.log();
|
|
490
|
+
console.log(styleText("white", "The patched binary is now active in all terminals."));
|
|
491
|
+
console.log(styleText("white", "No need to restart or source anything!"));
|
|
492
|
+
console.log();
|
|
493
|
+
console.log(styleText("gray", `To restore the original, run:`));
|
|
494
|
+
console.log(styleText("cyan", ` npx droid-patch restore`));
|
|
495
|
+
return {
|
|
496
|
+
originalPath,
|
|
497
|
+
backupPath: latestBackupPath
|
|
498
|
+
};
|
|
499
|
+
}
|
|
500
|
+
async function restoreOriginal(originalPath) {
|
|
501
|
+
ensureDirectories();
|
|
502
|
+
const latestBackupPath = join(BINS_DIR, "droid-original-latest");
|
|
503
|
+
console.log(styleText("cyan", "═".repeat(60)));
|
|
504
|
+
console.log(styleText(["cyan", "bold"], " Restore Original Droid"));
|
|
505
|
+
console.log(styleText("cyan", "═".repeat(60)));
|
|
506
|
+
console.log();
|
|
507
|
+
if (!existsSync(latestBackupPath)) {
|
|
508
|
+
const localBackup = `${originalPath}.backup`;
|
|
509
|
+
if (existsSync(localBackup)) {
|
|
510
|
+
console.log(styleText("white", `[*] Found local backup: ${localBackup}`));
|
|
511
|
+
console.log(styleText("white", `[*] Restoring to: ${originalPath}`));
|
|
512
|
+
await copyFile(localBackup, originalPath);
|
|
513
|
+
await chmod(originalPath, 493);
|
|
514
|
+
if (process.platform === "darwin") try {
|
|
515
|
+
execSync(`codesign --force --deep --sign - "${originalPath}"`, { stdio: "pipe" });
|
|
516
|
+
execSync(`xattr -cr "${originalPath}"`, { stdio: "pipe" });
|
|
517
|
+
} catch {}
|
|
518
|
+
console.log();
|
|
519
|
+
console.log(styleText("green", "═".repeat(60)));
|
|
520
|
+
console.log(styleText(["green", "bold"], " RESTORE COMPLETE"));
|
|
521
|
+
console.log(styleText("green", "═".repeat(60)));
|
|
522
|
+
console.log();
|
|
523
|
+
console.log(styleText("green", "Original droid binary has been restored from local backup."));
|
|
524
|
+
return;
|
|
525
|
+
}
|
|
526
|
+
console.log(styleText("red", "[!] No backup found."));
|
|
527
|
+
console.log(styleText("gray", ` Checked: ${latestBackupPath}`));
|
|
528
|
+
console.log(styleText("gray", ` Checked: ${localBackup}`));
|
|
529
|
+
console.log();
|
|
530
|
+
console.log(styleText("gray", "If you have a manual backup, restore it with:"));
|
|
531
|
+
console.log(styleText("cyan", ` cp /path/to/backup ${originalPath}`));
|
|
532
|
+
return;
|
|
533
|
+
}
|
|
534
|
+
console.log(styleText("white", `[*] Restoring from: ${latestBackupPath}`));
|
|
535
|
+
console.log(styleText("white", `[*] Restoring to: ${originalPath}`));
|
|
536
|
+
const targetDir = dirname(originalPath);
|
|
537
|
+
if (!existsSync(targetDir)) mkdirSync(targetDir, { recursive: true });
|
|
538
|
+
await copyFile(latestBackupPath, originalPath);
|
|
539
|
+
await chmod(originalPath, 493);
|
|
540
|
+
if (process.platform === "darwin") try {
|
|
541
|
+
execSync(`codesign --force --deep --sign - "${originalPath}"`, { stdio: "pipe" });
|
|
542
|
+
execSync(`xattr -cr "${originalPath}"`, { stdio: "pipe" });
|
|
543
|
+
} catch {}
|
|
544
|
+
console.log();
|
|
545
|
+
console.log(styleText("green", "═".repeat(60)));
|
|
546
|
+
console.log(styleText(["green", "bold"], " RESTORE COMPLETE"));
|
|
547
|
+
console.log(styleText("green", "═".repeat(60)));
|
|
548
|
+
console.log();
|
|
549
|
+
console.log(styleText("green", "Original droid binary has been restored."));
|
|
550
|
+
console.log(styleText("green", "All terminals will now use the original version."));
|
|
551
|
+
}
|
|
552
|
+
|
|
553
|
+
//#endregion
|
|
554
|
+
export { createAlias, listAliases, patchDroid, removeAlias, replaceOriginal, restoreOriginal };
|
|
555
|
+
//# sourceMappingURL=alias-kOmb9bCi.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"alias-kOmb9bCi.js","names":["options: PatchOptions","results: PatchResult[]","buffer: Buffer","pattern: Buffer","positions: number[]","position: number","patternLength: number","contextSize: number","shellConfigPath: string","exportLine: string","patchedBinaryPath: string","aliasName: string","aliases: AliasInfo[]","originalPath: string"],"sources":["../src/patcher.ts","../src/alias.ts"],"sourcesContent":["import { readFile, writeFile, copyFile, chmod, stat } from \"node:fs/promises\";\nimport { existsSync } from \"node:fs\";\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 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 const positions = findAllPositions(buffer, 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: buffer.includes(patch.replacement),\n });\n\n const replacementPositions = findAllPositions(buffer, patch.replacement);\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(buffer, pos, patch.pattern.length, 25);\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 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 const patchedBuffer = Buffer.from(buffer);\n\n let totalPatched = 0;\n for (const patch of patches) {\n const result = results.find((r) => r.name === patch.name);\n if (!result || !result.positions) continue;\n\n for (const pos of result.positions) {\n patch.replacement.copy(patchedBuffer, pos);\n totalPatched++;\n }\n }\n\n console.log(styleText(\"green\", `[*] Applied ${totalPatched} patches`));\n\n await writeFile(finalOutputPath, patchedBuffer);\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 console.log(styleText(\"yellow\", \"Note for macOS:\"));\n console.log(\n styleText(\n \"gray\",\n ` You may need to re-sign: codesign --force --deep --sign - ${finalOutputPath}`,\n ),\n );\n console.log(\n styleText(\"gray\", ` Or remove quarantine: xattr -cr ${finalOutputPath}`),\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","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\";\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\nfunction 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 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 if (target.includes(\".droid-patch/bins\")) {\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 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 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 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 if (target.includes(\".droid-patch/bins\")) {\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\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.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { };
|
package/dist/cli.js
ADDED
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { createAlias, listAliases, patchDroid, removeAlias } from "./alias-kOmb9bCi.js";
|
|
3
|
+
import bin from "tiny-bin";
|
|
4
|
+
import { styleText } from "node:util";
|
|
5
|
+
import { existsSync } from "node:fs";
|
|
6
|
+
import { join } from "node:path";
|
|
7
|
+
import { homedir } from "node:os";
|
|
8
|
+
|
|
9
|
+
//#region src/cli.ts
|
|
10
|
+
const version = "0.1.0";
|
|
11
|
+
function findDefaultDroidPath() {
|
|
12
|
+
const home = homedir();
|
|
13
|
+
const paths = [
|
|
14
|
+
join(home, ".droid/bin/droid"),
|
|
15
|
+
"/usr/local/bin/droid",
|
|
16
|
+
"./droid"
|
|
17
|
+
];
|
|
18
|
+
for (const p of paths) if (existsSync(p)) return p;
|
|
19
|
+
return join(home, ".droid/bin/droid");
|
|
20
|
+
}
|
|
21
|
+
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("--dry-run", "Verify patches without actually modifying the binary").option("-p, --path <path>", "Path to the droid binary").option("-o, --output <path>", "Output path 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 ({ args, options }) => {
|
|
22
|
+
const alias = args[0];
|
|
23
|
+
const isCustom = options["is-custom"];
|
|
24
|
+
const dryRun = options["dry-run"];
|
|
25
|
+
const path = options.path || findDefaultDroidPath();
|
|
26
|
+
const output = options.output;
|
|
27
|
+
const backup = options.backup !== false;
|
|
28
|
+
const verbose = options.verbose;
|
|
29
|
+
if (!isCustom) {
|
|
30
|
+
console.log(styleText("yellow", "No patch flags specified. Available patches:"));
|
|
31
|
+
console.log(styleText("gray", " --is-custom Patch isCustom for custom models"));
|
|
32
|
+
console.log();
|
|
33
|
+
console.log("Usage examples:");
|
|
34
|
+
console.log(styleText("cyan", " npx droid-patch --is-custom droid-custom"));
|
|
35
|
+
process.exit(1);
|
|
36
|
+
}
|
|
37
|
+
if (!alias && !dryRun) {
|
|
38
|
+
console.log(styleText("red", "Error: alias name is required"));
|
|
39
|
+
console.log(styleText("gray", "Usage: droid-patch --is-custom <alias-name>"));
|
|
40
|
+
process.exit(1);
|
|
41
|
+
}
|
|
42
|
+
console.log(styleText("cyan", "═".repeat(60)));
|
|
43
|
+
console.log(styleText(["cyan", "bold"], " Droid Binary Patcher"));
|
|
44
|
+
console.log(styleText("cyan", "═".repeat(60)));
|
|
45
|
+
console.log();
|
|
46
|
+
const patches = [];
|
|
47
|
+
if (isCustom) patches.push({
|
|
48
|
+
name: "isCustom",
|
|
49
|
+
description: "Change isCustom:!0 to isCustom:!1",
|
|
50
|
+
pattern: Buffer.from("isCustom:!0"),
|
|
51
|
+
replacement: Buffer.from("isCustom:!1")
|
|
52
|
+
});
|
|
53
|
+
try {
|
|
54
|
+
const result = await patchDroid({
|
|
55
|
+
inputPath: path,
|
|
56
|
+
outputPath: output,
|
|
57
|
+
patches,
|
|
58
|
+
dryRun,
|
|
59
|
+
backup,
|
|
60
|
+
verbose
|
|
61
|
+
});
|
|
62
|
+
if (dryRun) {
|
|
63
|
+
console.log();
|
|
64
|
+
console.log(styleText("blue", "═".repeat(60)));
|
|
65
|
+
console.log(styleText(["blue", "bold"], " DRY RUN COMPLETE"));
|
|
66
|
+
console.log(styleText("blue", "═".repeat(60)));
|
|
67
|
+
console.log();
|
|
68
|
+
console.log(styleText("gray", "To apply the patches, run without --dry-run:"));
|
|
69
|
+
console.log(styleText("cyan", ` npx droid-patch --is-custom ${alias || "<alias-name>"}`));
|
|
70
|
+
process.exit(0);
|
|
71
|
+
}
|
|
72
|
+
if (result.success && result.outputPath && alias) {
|
|
73
|
+
console.log();
|
|
74
|
+
await createAlias(result.outputPath, alias, verbose);
|
|
75
|
+
}
|
|
76
|
+
if (result.success) {
|
|
77
|
+
console.log();
|
|
78
|
+
console.log(styleText("green", "═".repeat(60)));
|
|
79
|
+
console.log(styleText(["green", "bold"], " PATCH SUCCESSFUL"));
|
|
80
|
+
console.log(styleText("green", "═".repeat(60)));
|
|
81
|
+
}
|
|
82
|
+
process.exit(result.success ? 0 : 1);
|
|
83
|
+
} catch (error) {
|
|
84
|
+
console.error(styleText("red", `Error: ${error.message}`));
|
|
85
|
+
if (verbose) console.error(error.stack);
|
|
86
|
+
process.exit(1);
|
|
87
|
+
}
|
|
88
|
+
}).command("list", "List all droid-patch aliases").action(async () => {
|
|
89
|
+
await listAliases();
|
|
90
|
+
}).command("remove", "Remove a droid-patch alias").argument("<alias>", "Alias name to remove").action(async ({ args }) => {
|
|
91
|
+
await removeAlias(args[0]);
|
|
92
|
+
}).run().catch((err) => {
|
|
93
|
+
console.error(err);
|
|
94
|
+
process.exit(1);
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
//#endregion
|
|
98
|
+
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","names":["patches: Patch[]","err: Error"],"sources":["../src/cli.ts"],"sourcesContent":["import bin from \"tiny-bin\";\nimport { styleText } from \"node:util\";\nimport { existsSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { homedir } from \"node:os\";\nimport { patchDroid, type Patch } from \"./patcher.ts\";\nimport { createAlias, removeAlias, listAliases } from \"./alias.ts\";\n\nconst version = \"0.1.0\";\n\nfunction findDefaultDroidPath(): string {\n const home = homedir();\n const paths = [\n join(home, \".droid/bin/droid\"),\n \"/usr/local/bin/droid\",\n \"./droid\",\n ];\n for (const p of paths) {\n if (existsSync(p)) return p;\n }\n return join(home, \".droid/bin/droid\");\n}\n\nbin(\"droid-patch\", \"CLI tool to patch droid binary with various modifications\")\n .package(\"droid-patch\", version)\n .option(\n \"--is-custom\",\n \"Patch isCustom:!0 to isCustom:!1 (enable context compression for custom models)\",\n )\n .option(\"--dry-run\", \"Verify patches without actually modifying the binary\")\n .option(\"-p, --path <path>\", \"Path to the droid binary\")\n .option(\"-o, --output <path>\", \"Output path for patched binary\")\n .option(\"--no-backup\", \"Do not create backup of original binary\")\n .option(\"-v, --verbose\", \"Enable verbose output\")\n .argument(\"[alias]\", \"Alias name for the patched binary\")\n .action(async ({ args, options }) => {\n const alias = args[0] as string | undefined;\n const isCustom = options[\"is-custom\"] as boolean;\n const dryRun = options[\"dry-run\"] as boolean;\n const path = (options.path as string) || findDefaultDroidPath();\n const output = options.output as string | undefined;\n const backup = options.backup !== false;\n const verbose = options.verbose as boolean;\n\n if (!isCustom) {\n console.log(\n styleText(\"yellow\", \"No patch flags specified. Available patches:\"),\n );\n console.log(\n styleText(\"gray\", \" --is-custom Patch isCustom for custom models\"),\n );\n console.log();\n console.log(\"Usage examples:\");\n console.log(\n styleText(\"cyan\", \" npx droid-patch --is-custom droid-custom\"),\n );\n process.exit(1);\n }\n\n if (!alias && !dryRun) {\n console.log(styleText(\"red\", \"Error: alias name is required\"));\n console.log(\n styleText(\"gray\", \"Usage: droid-patch --is-custom <alias-name>\"),\n );\n process.exit(1);\n }\n\n console.log(styleText(\"cyan\", \"═\".repeat(60)));\n console.log(styleText([\"cyan\", \"bold\"], \" Droid Binary Patcher\"));\n console.log(styleText(\"cyan\", \"═\".repeat(60)));\n console.log();\n\n const patches: Patch[] = [];\n if (isCustom) {\n patches.push({\n name: \"isCustom\",\n description: \"Change isCustom:!0 to isCustom:!1\",\n pattern: Buffer.from(\"isCustom:!0\"),\n replacement: Buffer.from(\"isCustom:!1\"),\n });\n }\n\n try {\n const result = await patchDroid({\n inputPath: path,\n outputPath: output,\n patches,\n dryRun,\n backup,\n verbose,\n });\n\n if (dryRun) {\n console.log();\n console.log(styleText(\"blue\", \"═\".repeat(60)));\n console.log(styleText([\"blue\", \"bold\"], \" DRY RUN COMPLETE\"));\n console.log(styleText(\"blue\", \"═\".repeat(60)));\n console.log();\n console.log(\n styleText(\"gray\", \"To apply the patches, run without --dry-run:\"),\n );\n console.log(\n styleText(\n \"cyan\",\n ` npx droid-patch --is-custom ${alias || \"<alias-name>\"}`,\n ),\n );\n process.exit(0);\n }\n\n if (result.success && result.outputPath && alias) {\n console.log();\n await createAlias(result.outputPath, alias, verbose);\n }\n\n if (result.success) {\n console.log();\n console.log(styleText(\"green\", \"═\".repeat(60)));\n console.log(styleText([\"green\", \"bold\"], \" PATCH SUCCESSFUL\"));\n console.log(styleText(\"green\", \"═\".repeat(60)));\n }\n\n process.exit(result.success ? 0 : 1);\n } catch (error) {\n console.error(styleText(\"red\", `Error: ${(error as Error).message}`));\n if (verbose) console.error((error as Error).stack);\n process.exit(1);\n }\n })\n .command(\"list\", \"List all droid-patch aliases\")\n .action(async () => {\n await listAliases();\n })\n .command(\"remove\", \"Remove a droid-patch alias\")\n .argument(\"<alias>\", \"Alias name to remove\")\n .action(async ({ args }) => {\n await removeAlias(args[0] as string);\n })\n .run()\n .catch((err: Error) => {\n console.error(err);\n process.exit(1);\n });\n"],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
//#region src/patcher.d.ts
|
|
2
|
+
interface Patch {
|
|
3
|
+
name: string;
|
|
4
|
+
description: string;
|
|
5
|
+
pattern: Buffer;
|
|
6
|
+
replacement: Buffer;
|
|
7
|
+
}
|
|
8
|
+
interface PatchOptions {
|
|
9
|
+
inputPath: string;
|
|
10
|
+
outputPath?: string;
|
|
11
|
+
patches: Patch[];
|
|
12
|
+
dryRun?: boolean;
|
|
13
|
+
backup?: boolean;
|
|
14
|
+
verbose?: boolean;
|
|
15
|
+
}
|
|
16
|
+
interface PatchResult {
|
|
17
|
+
name: string;
|
|
18
|
+
found: number;
|
|
19
|
+
positions?: number[];
|
|
20
|
+
success: boolean;
|
|
21
|
+
alreadyPatched?: boolean;
|
|
22
|
+
}
|
|
23
|
+
interface PatchDroidResult {
|
|
24
|
+
success: boolean;
|
|
25
|
+
dryRun?: boolean;
|
|
26
|
+
results: PatchResult[];
|
|
27
|
+
outputPath?: string;
|
|
28
|
+
noPatchNeeded?: boolean;
|
|
29
|
+
patchedCount?: number;
|
|
30
|
+
}
|
|
31
|
+
declare function patchDroid(options: PatchOptions): Promise<PatchDroidResult>; //#endregion
|
|
32
|
+
//#region src/alias.d.ts
|
|
33
|
+
interface CreateAliasResult {
|
|
34
|
+
aliasPath: string;
|
|
35
|
+
binaryPath: string;
|
|
36
|
+
immediate?: boolean;
|
|
37
|
+
}
|
|
38
|
+
declare function createAlias(patchedBinaryPath: string, aliasName: string, verbose?: boolean): Promise<CreateAliasResult>;
|
|
39
|
+
declare function removeAlias(aliasName: string): Promise<void>;
|
|
40
|
+
declare function listAliases(): Promise<void>;
|
|
41
|
+
interface ReplaceOriginalResult {
|
|
42
|
+
originalPath: string;
|
|
43
|
+
backupPath: string;
|
|
44
|
+
}
|
|
45
|
+
declare function replaceOriginal(patchedBinaryPath: string, originalPath: string, verbose?: boolean): Promise<ReplaceOriginalResult>;
|
|
46
|
+
declare function restoreOriginal(originalPath: string): Promise<void>;
|
|
47
|
+
|
|
48
|
+
//#endregion
|
|
49
|
+
//# sourceMappingURL=alias.d.ts.map
|
|
50
|
+
|
|
51
|
+
export { CreateAliasResult, Patch, PatchDroidResult, PatchOptions, ReplaceOriginalResult, createAlias, listAliases, patchDroid, removeAlias, replaceOriginal, restoreOriginal };
|
|
52
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","names":[],"sources":["../src/patcher.ts","../src/alias.ts"],"sourcesContent":null,"mappings":";UAIiB,KAAA;EAAA,IAAA,EAAA,MAAK;EAAA,WAAA,EAAA,MAAA;EAAA,OAGX,EAAA,MAAA;EAAM,WACF,EAAA,MAAA;AAAM;AAGJ,UAAA,YAAA,CAGN;EAMD,SAAA,EAAA,MAAW;EAQJ,UAAA,CAAA,EAAA,MAAgB;EASX,OAAA,EAvBX,KAuBqB,EAAA;EAAA,MAAA,CAAA,EAAA,OAAA;EAAA,MACrB,CAAA,EAAA,OAAA;EAAY,OACZ,CAAA,EAAA,OAAA;;AAAD,UAnBA,WAAA,CAmBA;;;;EC+GO,OAAA,EAAA,OAAA;EAMK,cAAW,CAAA,EAAA,OAAA;;AAItB,UDpIM,gBAAA,CCoIN;EAAiB,OAAzB,EAAA,OAAA;EAAO,MAAA,CAAA,EAAA,OAAA;EAwMY,OAAA,EDzUX,WCyUsB,EAAA;EAiDX,UAAA,CAAA,EAAA,MAAW;EA6GhB,aAAA,CAAA,EAAA,OAAA;EAKK,YAAA,CAAA,EAAA,MAAe;;AAI1B,iBD1eW,UAAA,CC0eX,OAAA,EDzeA,YCyeA,CAAA,EDxeR,OCweQ,CDxeA,gBCweA,CAAA,CAAA;;UAzXM,iBAAA;EDlJA,SAAK,EAAA,MAAA;EAAA,UAAA,EAAA,MAAA;EAAA,SAGX,CAAA,EAAA,OAAA;;AACU,iBCoJC,WAAA,CDpJD,iBAAA,EAAA,MAAA,EAAA,SAAA,EAAA,MAAA,EAAA,OAAA,CAAA,EAAA,OAAA,CAAA,ECwJlB,ODxJkB,CCwJV,iBDxJU,CAAA;AAGJ,iBC6VK,WAAA,CD1VN,SAAA,EAAA,MAAA,CAAA,EC0VsC,OD1VtC,CAAA,IAAA,CAAA;AAMN,iBCqYY,WAAA,CAAA,CDrYD,ECqYgB,ODrYhB,CAAA,IAAA,CAAA;AAQJ,UC0eA,qBAAA,CDveN;EAMW,YAAA,EAAU,MAAA;EAAA,UAAA,EAAA,MAAA;;AAErB,iBCoeW,eAAA,CDpeX,iBAAA,EAAA,MAAA,EAAA,YAAA,EAAA,MAAA,EAAA,OAAA,CAAA,EAAA,OAAA,CAAA,ECweR,ODxeQ,CCweA,qBDxeA,CAAA;AAAR,iBCmjBmB,eAAA,CDnjBnB,YAAA,EAAA,MAAA,CAAA,ECmjB0D,ODnjB1D,CAAA,IAAA,CAAA;;;AAAO"}
|
package/dist/index.js
ADDED
package/package.json
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "droid-patch",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "CLI tool to patch droid binary with various modifications",
|
|
5
|
+
"homepage": "https://github.com/kingsword09/droid-patch#readme",
|
|
6
|
+
"bugs": {
|
|
7
|
+
"url": "https://github.com/kingsword09/droid-patch/issues"
|
|
8
|
+
},
|
|
9
|
+
"repository": {
|
|
10
|
+
"type": "git",
|
|
11
|
+
"url": "git+https://github.com/kingsword09/droid-patch.git"
|
|
12
|
+
},
|
|
13
|
+
"type": "module",
|
|
14
|
+
"main": "dist/index.js",
|
|
15
|
+
"types": "dist/index.d.ts",
|
|
16
|
+
"bin": {
|
|
17
|
+
"droid-patch": "./dist/cli.js"
|
|
18
|
+
},
|
|
19
|
+
"files": [
|
|
20
|
+
"dist"
|
|
21
|
+
],
|
|
22
|
+
"scripts": {
|
|
23
|
+
"build": "npx tsdown",
|
|
24
|
+
"dev": "npx tsdown --watch",
|
|
25
|
+
"start": "node dist/cli.js",
|
|
26
|
+
"test": "node dist/cli.js --help",
|
|
27
|
+
"lint": "oxlint --type-aware --type-check",
|
|
28
|
+
"lint:fix": "oxlint --fix",
|
|
29
|
+
"format": "oxfmt",
|
|
30
|
+
"format:check": "oxfmt --check",
|
|
31
|
+
"prepublishOnly": "npm run build"
|
|
32
|
+
},
|
|
33
|
+
"keywords": [
|
|
34
|
+
"droid",
|
|
35
|
+
"patch",
|
|
36
|
+
"binary",
|
|
37
|
+
"cli"
|
|
38
|
+
],
|
|
39
|
+
"author": "Kingsword kingsword09 <kingsword09@gmail.com>",
|
|
40
|
+
"license": "MIT",
|
|
41
|
+
"dependencies": {
|
|
42
|
+
"tiny-bin": "^1.11.3"
|
|
43
|
+
},
|
|
44
|
+
"devDependencies": {
|
|
45
|
+
"@types/node": "^22.10.2",
|
|
46
|
+
"oxfmt": "^0.13.0",
|
|
47
|
+
"oxlint": "^1.32.0",
|
|
48
|
+
"oxlint-tsgolint": "^0.8.5",
|
|
49
|
+
"tsdown": "^0.9.3",
|
|
50
|
+
"typescript": "^5.7.2"
|
|
51
|
+
},
|
|
52
|
+
"engines": {
|
|
53
|
+
"node": ">=22.0.0"
|
|
54
|
+
}
|
|
55
|
+
}
|