droid-patch 0.2.1 → 0.4.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/README.md +49 -1
- package/README.zh-CN.md +49 -1
- package/dist/{alias-C9LRaTwF.js → alias-UwlvAO5o.js} +99 -3
- package/dist/alias-UwlvAO5o.js.map +1 -0
- package/dist/cli.js +220 -9
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/package.json +1 -1
- package/dist/alias-C9LRaTwF.js.map +0 -1
package/dist/cli.js
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { createAlias, createAliasForWrapper, listAliases, patchDroid, removeAlias } from "./alias-
|
|
2
|
+
import { createAlias, createAliasForWrapper, createMetadata, formatPatches, listAliases, listAllMetadata, loadAliasMetadata, patchDroid, removeAlias, saveAliasMetadata } from "./alias-UwlvAO5o.js";
|
|
3
3
|
import bin from "tiny-bin";
|
|
4
4
|
import { styleText } from "node:util";
|
|
5
5
|
import { existsSync, readFileSync } from "node:fs";
|
|
6
6
|
import { dirname, join } from "node:path";
|
|
7
7
|
import { homedir } from "node:os";
|
|
8
8
|
import { fileURLToPath } from "node:url";
|
|
9
|
+
import { execSync } from "node:child_process";
|
|
9
10
|
import { chmod, mkdir, writeFile } from "node:fs/promises";
|
|
10
11
|
|
|
11
12
|
//#region src/websearch-patch.ts
|
|
@@ -674,20 +675,34 @@ function getVersion() {
|
|
|
674
675
|
const version = getVersion();
|
|
675
676
|
function findDefaultDroidPath() {
|
|
676
677
|
const home = homedir();
|
|
678
|
+
try {
|
|
679
|
+
const result = execSync("which droid", {
|
|
680
|
+
encoding: "utf-8",
|
|
681
|
+
stdio: [
|
|
682
|
+
"pipe",
|
|
683
|
+
"pipe",
|
|
684
|
+
"pipe"
|
|
685
|
+
]
|
|
686
|
+
}).trim();
|
|
687
|
+
if (result && existsSync(result)) return result;
|
|
688
|
+
} catch {}
|
|
677
689
|
const paths = [
|
|
678
|
-
join(home, ".droid
|
|
690
|
+
join(home, ".droid", "bin", "droid"),
|
|
691
|
+
"/opt/homebrew/bin/droid",
|
|
679
692
|
"/usr/local/bin/droid",
|
|
693
|
+
"/usr/bin/droid",
|
|
680
694
|
"./droid"
|
|
681
695
|
];
|
|
682
696
|
for (const p of paths) if (existsSync(p)) return p;
|
|
683
|
-
return join(home, ".droid
|
|
697
|
+
return join(home, ".droid", "bin", "droid");
|
|
684
698
|
}
|
|
685
|
-
bin("droid-patch", "CLI tool to patch droid binary with various modifications").package("droid-patch", version).option("--is-custom", "Patch isCustom:!0 to isCustom:!1 (enable context compression for custom models)").option("--skip-login", "Inject a fake FACTORY_API_KEY to bypass login requirement (no real key needed)").option("--api-base <url>", "Replace Factory API base URL (https://api.factory.ai) with custom URL").option("--websearch", "Enable local WebSearch via fetch hook (Google PSE + DuckDuckGo fallback)").option("--dry-run", "Verify patches without actually modifying the binary").option("-p, --path <path>", "Path to the droid binary").option("-o, --output <dir>", "Output directory for patched binary").option("--no-backup", "Do not create backup of original binary").option("-v, --verbose", "Enable verbose output").argument("[alias]", "Alias name for the patched binary").action(async (options, args) => {
|
|
699
|
+
bin("droid-patch", "CLI tool to patch droid binary with various modifications").package("droid-patch", version).option("--is-custom", "Patch isCustom:!0 to isCustom:!1 (enable context compression for custom models)").option("--skip-login", "Inject a fake FACTORY_API_KEY to bypass login requirement (no real key needed)").option("--api-base <url>", "Replace Factory API base URL (https://api.factory.ai) with custom URL").option("--websearch", "Enable local WebSearch via fetch hook (Google PSE + DuckDuckGo fallback)").option("--reasoning-effort", "Enable reasoning effort for custom models (set to high, enable UI selector)").option("--dry-run", "Verify patches without actually modifying the binary").option("-p, --path <path>", "Path to the droid binary").option("-o, --output <dir>", "Output directory for patched binary").option("--no-backup", "Do not create backup of original binary").option("-v, --verbose", "Enable verbose output").argument("[alias]", "Alias name for the patched binary").action(async (options, args) => {
|
|
686
700
|
const alias = args?.[0];
|
|
687
701
|
const isCustom = options["is-custom"];
|
|
688
702
|
const skipLogin = options["skip-login"];
|
|
689
703
|
const apiBase = options["api-base"];
|
|
690
704
|
const webSearch = options["websearch"];
|
|
705
|
+
const reasoningEffort = options["reasoning-effort"];
|
|
691
706
|
const dryRun = options["dry-run"];
|
|
692
707
|
const path = options.path || findDefaultDroidPath();
|
|
693
708
|
const outputDir = options.output;
|
|
@@ -707,6 +722,14 @@ bin("droid-patch", "CLI tool to patch droid binary with various modifications").
|
|
|
707
722
|
const websearchDir = join(homedir(), ".droid-patch", "websearch");
|
|
708
723
|
const { wrapperScript } = await createWebSearchUnifiedFiles(websearchDir, path, alias);
|
|
709
724
|
await createAliasForWrapper(wrapperScript, alias, verbose);
|
|
725
|
+
const metadata = createMetadata(alias, path, {
|
|
726
|
+
isCustom: false,
|
|
727
|
+
skipLogin: false,
|
|
728
|
+
apiBase: null,
|
|
729
|
+
websearch: true,
|
|
730
|
+
reasoningEffort: false
|
|
731
|
+
});
|
|
732
|
+
await saveAliasMetadata(metadata);
|
|
710
733
|
console.log();
|
|
711
734
|
console.log(styleText("green", "═".repeat(60)));
|
|
712
735
|
console.log(styleText(["green", "bold"], " WebSearch Ready!"));
|
|
@@ -732,12 +755,13 @@ bin("droid-patch", "CLI tool to patch droid binary with various modifications").
|
|
|
732
755
|
console.log(styleText("gray", " export DROID_SEARCH_DEBUG=1"));
|
|
733
756
|
return;
|
|
734
757
|
}
|
|
735
|
-
if (!isCustom && !skipLogin && !apiBase && !webSearch) {
|
|
758
|
+
if (!isCustom && !skipLogin && !apiBase && !webSearch && !reasoningEffort) {
|
|
736
759
|
console.log(styleText("yellow", "No patch flags specified. Available patches:"));
|
|
737
|
-
console.log(styleText("gray", " --is-custom
|
|
738
|
-
console.log(styleText("gray", " --skip-login
|
|
739
|
-
console.log(styleText("gray", " --api-base
|
|
740
|
-
console.log(styleText("gray", " --websearch
|
|
760
|
+
console.log(styleText("gray", " --is-custom Patch isCustom for custom models"));
|
|
761
|
+
console.log(styleText("gray", " --skip-login Bypass login by injecting a fake API key"));
|
|
762
|
+
console.log(styleText("gray", " --api-base Replace Factory API URL with custom server"));
|
|
763
|
+
console.log(styleText("gray", " --websearch Enable local WebSearch (Google PSE + DuckDuckGo)"));
|
|
764
|
+
console.log(styleText("gray", " --reasoning-effort Set reasoning effort level for custom models"));
|
|
741
765
|
console.log();
|
|
742
766
|
console.log("Usage examples:");
|
|
743
767
|
console.log(styleText("cyan", " npx droid-patch --is-custom droid-custom"));
|
|
@@ -746,6 +770,7 @@ bin("droid-patch", "CLI tool to patch droid binary with various modifications").
|
|
|
746
770
|
console.log(styleText("cyan", " npx droid-patch --skip-login -o . my-droid"));
|
|
747
771
|
console.log(styleText("cyan", " npx droid-patch --api-base http://localhost:3000 droid-local"));
|
|
748
772
|
console.log(styleText("cyan", " npx droid-patch --websearch droid-search"));
|
|
773
|
+
console.log(styleText("cyan", " npx droid-patch --reasoning-effort high droid-reasoning"));
|
|
749
774
|
process.exit(1);
|
|
750
775
|
}
|
|
751
776
|
if (!alias && !dryRun) {
|
|
@@ -793,6 +818,32 @@ bin("droid-patch", "CLI tool to patch droid binary with various modifications").
|
|
|
793
818
|
replacement: Buffer.from(paddedUrl)
|
|
794
819
|
});
|
|
795
820
|
}
|
|
821
|
+
if (reasoningEffort) {
|
|
822
|
+
patches.push({
|
|
823
|
+
name: "reasoningEffortSupported",
|
|
824
|
+
description: "Change supportedReasoningEfforts:[\"none\"] to [\"high\"]",
|
|
825
|
+
pattern: Buffer.from("supportedReasoningEfforts:[\"none\"]"),
|
|
826
|
+
replacement: Buffer.from("supportedReasoningEfforts:[\"high\"]")
|
|
827
|
+
});
|
|
828
|
+
patches.push({
|
|
829
|
+
name: "reasoningEffortDefault",
|
|
830
|
+
description: "Change defaultReasoningEffort:\"none\" to \"high\"",
|
|
831
|
+
pattern: Buffer.from("defaultReasoningEffort:\"none\""),
|
|
832
|
+
replacement: Buffer.from("defaultReasoningEffort:\"high\"")
|
|
833
|
+
});
|
|
834
|
+
patches.push({
|
|
835
|
+
name: "reasoningEffortUIShow",
|
|
836
|
+
description: "Change supportedReasoningEfforts.length>1 to length>0",
|
|
837
|
+
pattern: Buffer.from("supportedReasoningEfforts.length>1"),
|
|
838
|
+
replacement: Buffer.from("supportedReasoningEfforts.length>0")
|
|
839
|
+
});
|
|
840
|
+
patches.push({
|
|
841
|
+
name: "reasoningEffortUIEnable",
|
|
842
|
+
description: "Change supportedReasoningEfforts.length<=1 to length<=0",
|
|
843
|
+
pattern: Buffer.from("supportedReasoningEfforts.length<=1"),
|
|
844
|
+
replacement: Buffer.from("supportedReasoningEfforts.length<=0")
|
|
845
|
+
});
|
|
846
|
+
}
|
|
796
847
|
try {
|
|
797
848
|
const result = await patchDroid({
|
|
798
849
|
inputPath: path,
|
|
@@ -839,6 +890,14 @@ bin("droid-patch", "CLI tool to patch droid binary with various modifications").
|
|
|
839
890
|
console.log();
|
|
840
891
|
console.log(styleText("gray", " See README for all providers and setup guides"));
|
|
841
892
|
} else await createAlias(result.outputPath, alias, verbose);
|
|
893
|
+
const metadata = createMetadata(alias, path, {
|
|
894
|
+
isCustom: !!isCustom,
|
|
895
|
+
skipLogin: !!skipLogin,
|
|
896
|
+
apiBase: apiBase || null,
|
|
897
|
+
websearch: !!webSearch,
|
|
898
|
+
reasoningEffort: !!reasoningEffort
|
|
899
|
+
});
|
|
900
|
+
await saveAliasMetadata(metadata);
|
|
842
901
|
}
|
|
843
902
|
if (result.success) {
|
|
844
903
|
console.log();
|
|
@@ -948,6 +1007,158 @@ bin("droid-patch", "CLI tool to patch droid binary with various modifications").
|
|
|
948
1007
|
console.log(styleText("cyan", "═".repeat(60)));
|
|
949
1008
|
console.log();
|
|
950
1009
|
console.log(lines.join("\n"));
|
|
1010
|
+
}).command("update", "Update aliases with latest droid binary").argument("[alias]", "Specific alias to update (optional, updates all if not specified)").option("--dry-run", "Preview without making changes").option("-p, --path <path>", "Path to new droid binary").option("-v, --verbose", "Enable verbose output").action(async (options, args) => {
|
|
1011
|
+
const aliasName = args?.[0];
|
|
1012
|
+
const dryRun = options["dry-run"];
|
|
1013
|
+
const newBinaryPath = options.path || findDefaultDroidPath();
|
|
1014
|
+
const verbose = options.verbose;
|
|
1015
|
+
console.log(styleText("cyan", "═".repeat(60)));
|
|
1016
|
+
console.log(styleText(["cyan", "bold"], " Droid-Patch Update"));
|
|
1017
|
+
console.log(styleText("cyan", "═".repeat(60)));
|
|
1018
|
+
console.log();
|
|
1019
|
+
if (!existsSync(newBinaryPath)) {
|
|
1020
|
+
console.log(styleText("red", `Error: Droid binary not found at ${newBinaryPath}`));
|
|
1021
|
+
console.log(styleText("gray", "Use -p to specify a different path"));
|
|
1022
|
+
process.exit(1);
|
|
1023
|
+
}
|
|
1024
|
+
let metaList;
|
|
1025
|
+
if (aliasName) {
|
|
1026
|
+
const meta = await loadAliasMetadata(aliasName);
|
|
1027
|
+
if (!meta) {
|
|
1028
|
+
console.log(styleText("red", `Error: No metadata found for alias "${aliasName}"`));
|
|
1029
|
+
console.log(styleText("gray", "This alias may have been created before update tracking was added."));
|
|
1030
|
+
console.log(styleText("gray", "Remove and recreate the alias to enable update support."));
|
|
1031
|
+
process.exit(1);
|
|
1032
|
+
}
|
|
1033
|
+
metaList = [meta];
|
|
1034
|
+
} else {
|
|
1035
|
+
metaList = await listAllMetadata();
|
|
1036
|
+
if (metaList.length === 0) {
|
|
1037
|
+
console.log(styleText("yellow", "No aliases with metadata found."));
|
|
1038
|
+
console.log(styleText("gray", "Create aliases with droid-patch to enable update support."));
|
|
1039
|
+
process.exit(0);
|
|
1040
|
+
}
|
|
1041
|
+
}
|
|
1042
|
+
console.log(styleText("white", `Using droid binary: ${newBinaryPath}`));
|
|
1043
|
+
console.log(styleText("white", `Found ${metaList.length} alias(es) to update`));
|
|
1044
|
+
if (dryRun) console.log(styleText("blue", "(DRY RUN - no changes will be made)"));
|
|
1045
|
+
console.log();
|
|
1046
|
+
let successCount = 0;
|
|
1047
|
+
let failCount = 0;
|
|
1048
|
+
for (const meta of metaList) {
|
|
1049
|
+
if (!meta) continue;
|
|
1050
|
+
console.log(styleText("cyan", `─`.repeat(40)));
|
|
1051
|
+
console.log(styleText("white", `Updating: ${styleText(["cyan", "bold"], meta.name)}`));
|
|
1052
|
+
console.log(styleText("gray", ` Patches: ${formatPatches(meta.patches)}`));
|
|
1053
|
+
if (dryRun) {
|
|
1054
|
+
console.log(styleText("blue", ` [DRY RUN] Would re-apply patches`));
|
|
1055
|
+
successCount++;
|
|
1056
|
+
continue;
|
|
1057
|
+
}
|
|
1058
|
+
try {
|
|
1059
|
+
const patches = [];
|
|
1060
|
+
if (meta.patches.isCustom) patches.push({
|
|
1061
|
+
name: "isCustom",
|
|
1062
|
+
description: "Change isCustom:!0 to isCustom:!1",
|
|
1063
|
+
pattern: Buffer.from("isCustom:!0"),
|
|
1064
|
+
replacement: Buffer.from("isCustom:!1")
|
|
1065
|
+
});
|
|
1066
|
+
if (meta.patches.skipLogin) patches.push({
|
|
1067
|
+
name: "skipLogin",
|
|
1068
|
+
description: "Replace process.env.FACTORY_API_KEY with fake key",
|
|
1069
|
+
pattern: Buffer.from("process.env.FACTORY_API_KEY"),
|
|
1070
|
+
replacement: Buffer.from("\"fk-droid-patch-skip-00000\"")
|
|
1071
|
+
});
|
|
1072
|
+
if (meta.patches.apiBase) {
|
|
1073
|
+
const originalUrl = "https://api.factory.ai";
|
|
1074
|
+
const paddedUrl = meta.patches.apiBase.padEnd(originalUrl.length, " ");
|
|
1075
|
+
patches.push({
|
|
1076
|
+
name: "apiBase",
|
|
1077
|
+
description: `Replace Factory API URL with "${meta.patches.apiBase}"`,
|
|
1078
|
+
pattern: Buffer.from(originalUrl),
|
|
1079
|
+
replacement: Buffer.from(paddedUrl)
|
|
1080
|
+
});
|
|
1081
|
+
}
|
|
1082
|
+
if (meta.patches.reasoningEffort) {
|
|
1083
|
+
patches.push({
|
|
1084
|
+
name: "reasoningEffortSupported",
|
|
1085
|
+
description: "Change supportedReasoningEfforts:[\"none\"] to [\"high\"]",
|
|
1086
|
+
pattern: Buffer.from("supportedReasoningEfforts:[\"none\"]"),
|
|
1087
|
+
replacement: Buffer.from("supportedReasoningEfforts:[\"high\"]")
|
|
1088
|
+
});
|
|
1089
|
+
patches.push({
|
|
1090
|
+
name: "reasoningEffortDefault",
|
|
1091
|
+
description: "Change defaultReasoningEffort:\"none\" to \"high\"",
|
|
1092
|
+
pattern: Buffer.from("defaultReasoningEffort:\"none\""),
|
|
1093
|
+
replacement: Buffer.from("defaultReasoningEffort:\"high\"")
|
|
1094
|
+
});
|
|
1095
|
+
patches.push({
|
|
1096
|
+
name: "reasoningEffortUIShow",
|
|
1097
|
+
description: "Change supportedReasoningEfforts.length>1 to length>0",
|
|
1098
|
+
pattern: Buffer.from("supportedReasoningEfforts.length>1"),
|
|
1099
|
+
replacement: Buffer.from("supportedReasoningEfforts.length>0")
|
|
1100
|
+
});
|
|
1101
|
+
patches.push({
|
|
1102
|
+
name: "reasoningEffortUIEnable",
|
|
1103
|
+
description: "Change supportedReasoningEfforts.length<=1 to length<=0",
|
|
1104
|
+
pattern: Buffer.from("supportedReasoningEfforts.length<=1"),
|
|
1105
|
+
replacement: Buffer.from("supportedReasoningEfforts.length<=0")
|
|
1106
|
+
});
|
|
1107
|
+
}
|
|
1108
|
+
const binsDir = join(homedir(), ".droid-patch", "bins");
|
|
1109
|
+
const outputPath = join(binsDir, `${meta.name}-patched`);
|
|
1110
|
+
if (patches.length > 0) {
|
|
1111
|
+
const result = await patchDroid({
|
|
1112
|
+
inputPath: newBinaryPath,
|
|
1113
|
+
outputPath,
|
|
1114
|
+
patches,
|
|
1115
|
+
dryRun: false,
|
|
1116
|
+
backup: false,
|
|
1117
|
+
verbose
|
|
1118
|
+
});
|
|
1119
|
+
if (!result.success) {
|
|
1120
|
+
console.log(styleText("red", ` ✗ Failed to apply patches`));
|
|
1121
|
+
failCount++;
|
|
1122
|
+
continue;
|
|
1123
|
+
}
|
|
1124
|
+
if (process.platform === "darwin") try {
|
|
1125
|
+
const { execSync: execSync$1 } = await import("node:child_process");
|
|
1126
|
+
execSync$1(`codesign --force --deep --sign - "${outputPath}"`, { stdio: "pipe" });
|
|
1127
|
+
if (verbose) console.log(styleText("gray", ` Re-signed binary`));
|
|
1128
|
+
} catch {
|
|
1129
|
+
console.log(styleText("yellow", ` [!] Could not re-sign binary`));
|
|
1130
|
+
}
|
|
1131
|
+
}
|
|
1132
|
+
if (meta.patches.websearch) {
|
|
1133
|
+
const websearchDir = join(homedir(), ".droid-patch", "websearch");
|
|
1134
|
+
const targetBinaryPath = patches.length > 0 ? outputPath : newBinaryPath;
|
|
1135
|
+
await createWebSearchUnifiedFiles(websearchDir, targetBinaryPath, meta.name);
|
|
1136
|
+
if (verbose) console.log(styleText("gray", ` Regenerated websearch wrapper`));
|
|
1137
|
+
}
|
|
1138
|
+
meta.updatedAt = new Date().toISOString();
|
|
1139
|
+
meta.originalBinaryPath = newBinaryPath;
|
|
1140
|
+
await saveAliasMetadata(meta);
|
|
1141
|
+
console.log(styleText("green", ` ✓ Updated successfully`));
|
|
1142
|
+
successCount++;
|
|
1143
|
+
} catch (error) {
|
|
1144
|
+
console.log(styleText("red", ` ✗ Error: ${error.message}`));
|
|
1145
|
+
if (verbose) console.error(error.stack);
|
|
1146
|
+
failCount++;
|
|
1147
|
+
}
|
|
1148
|
+
}
|
|
1149
|
+
console.log();
|
|
1150
|
+
console.log(styleText("cyan", "═".repeat(60)));
|
|
1151
|
+
if (dryRun) {
|
|
1152
|
+
console.log(styleText(["blue", "bold"], " DRY RUN COMPLETE"));
|
|
1153
|
+
console.log(styleText("gray", ` Would update ${successCount} alias(es)`));
|
|
1154
|
+
} else if (failCount === 0) {
|
|
1155
|
+
console.log(styleText(["green", "bold"], " UPDATE COMPLETE"));
|
|
1156
|
+
console.log(styleText("gray", ` Updated ${successCount} alias(es)`));
|
|
1157
|
+
} else {
|
|
1158
|
+
console.log(styleText(["yellow", "bold"], " UPDATE FINISHED WITH ERRORS"));
|
|
1159
|
+
console.log(styleText("gray", ` Success: ${successCount}, Failed: ${failCount}`));
|
|
1160
|
+
}
|
|
1161
|
+
console.log(styleText("cyan", "═".repeat(60)));
|
|
951
1162
|
}).run().catch((err) => {
|
|
952
1163
|
console.error(err);
|
|
953
1164
|
process.exit(1);
|