droid-patch 0.14.0 → 0.15.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/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-jucBZXia.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-DgX_0sGe.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";
@@ -1042,6 +1042,56 @@ function getDroidVersion(droidPath) {
1042
1042
  return;
1043
1043
  }
1044
1044
  }
1045
+ function parseSemver(versionText) {
1046
+ const match = versionText.match(/^(\d+)\.(\d+)\.(\d+)$/);
1047
+ if (!match) return null;
1048
+ return [
1049
+ Number(match[1]),
1050
+ Number(match[2]),
1051
+ Number(match[3])
1052
+ ];
1053
+ }
1054
+ function compareSemver(left, right) {
1055
+ const l = parseSemver(left);
1056
+ const r = parseSemver(right);
1057
+ if (!l || !r) throw new Error(`Invalid semver comparison: "${left}" vs "${right}"`);
1058
+ for (let i = 0; i < 3; i++) {
1059
+ if (l[i] > r[i]) return 1;
1060
+ if (l[i] < r[i]) return -1;
1061
+ }
1062
+ return 0;
1063
+ }
1064
+ function matchesVersionRule(droidVersion, rule) {
1065
+ if (rule.minVersion && compareSemver(droidVersion, rule.minVersion) < 0) return false;
1066
+ if (rule.maxVersion && compareSemver(droidVersion, rule.maxVersion) >= 0) return false;
1067
+ return true;
1068
+ }
1069
+ function resolveVersionedPatches(featureName, droidVersion, rules) {
1070
+ if (!droidVersion) throw new Error(`Unable to detect droid version for ${featureName}`);
1071
+ if (!parseSemver(droidVersion)) throw new Error(`Unsupported droid version format "${droidVersion}" for ${featureName}`);
1072
+ const matchedRule = rules.find((rule) => matchesVersionRule(droidVersion, rule));
1073
+ if (!matchedRule) throw new Error(`No patch rule matched ${featureName} on droid ${droidVersion}`);
1074
+ return matchedRule.buildPatches();
1075
+ }
1076
+ const SKIP_LOGIN_PATCH_RULES = [{
1077
+ id: "skip-login-legacy",
1078
+ maxVersion: "0.68.0",
1079
+ buildPatches: () => [{
1080
+ name: "skipLogin",
1081
+ description: "Replace process.env.FACTORY_API_KEY with \"fk-droid-patch-skip-00000\"",
1082
+ pattern: Buffer.from("process.env.FACTORY_API_KEY"),
1083
+ replacement: Buffer.from("\"fk-droid-patch-skip-00000\"")
1084
+ }]
1085
+ }, {
1086
+ id: "skip-login-v068-plus",
1087
+ minVersion: "0.68.0",
1088
+ buildPatches: () => [{
1089
+ name: "factoryApiKeyLookupV068",
1090
+ description: "Replace process.env[__.FACTORY_API_KEY]?.trim() with \"fk-droid-patch-skip-00000000000000000\"",
1091
+ pattern: Buffer.from("process.env[__.FACTORY_API_KEY]?.trim()"),
1092
+ replacement: Buffer.from("\"fk-droid-patch-skip-00000000000000000\"")
1093
+ }]
1094
+ }];
1045
1095
  function findDefaultDroidPath() {
1046
1096
  const home = homedir();
1047
1097
  if (IS_WINDOWS) {
@@ -1102,6 +1152,7 @@ bin("droid-patch", "CLI tool to patch droid binary with various modifications").
1102
1152
  const outputDir = options.output;
1103
1153
  const backup = options.backup !== false;
1104
1154
  const verbose = options.verbose;
1155
+ const droidVersion = getDroidVersion(path);
1105
1156
  const outputPath = outputDir && alias ? join(outputDir, alias) : void 0;
1106
1157
  const needsBinaryPatch = !!isCustom || !!skipLogin || !!reasoningEffort || !!noTelemetry || !!apiBase && !websearch && !websearchProxy;
1107
1158
  if (websearch && websearchProxy) {
@@ -1136,7 +1187,6 @@ bin("droid-patch", "CLI tool to patch droid binary with various modifications").
1136
1187
  const { wrapperScript } = await createWebSearchUnifiedFiles(join(homedir(), ".droid-patch", "proxy"), execTargetPath, alias, websearchProxy ? void 0 : websearchTarget, standalone, websearchProxy);
1137
1188
  execTargetPath = wrapperScript;
1138
1189
  const aliasResult = await createAliasForWrapper(execTargetPath, alias, verbose);
1139
- const droidVersion = getDroidVersion(path);
1140
1190
  await saveAliasMetadata(createMetadata(alias, path, {
1141
1191
  isCustom: false,
1142
1192
  skipLogin: false,
@@ -1230,12 +1280,13 @@ bin("droid-patch", "CLI tool to patch droid binary with various modifications").
1230
1280
  pattern: Buffer.from("isCustom:!0"),
1231
1281
  replacement: Buffer.from("isCustom:!1")
1232
1282
  });
1233
- if (skipLogin) patches.push({
1234
- name: "skipLogin",
1235
- description: "Replace process.env.FACTORY_API_KEY with \"fk-droid-patch-skip-00000\"",
1236
- pattern: Buffer.from("process.env.FACTORY_API_KEY"),
1237
- replacement: Buffer.from("\"fk-droid-patch-skip-00000\"")
1238
- });
1283
+ if (skipLogin) try {
1284
+ patches.push(...resolveVersionedPatches("--skip-login", droidVersion, SKIP_LOGIN_PATCH_RULES));
1285
+ } catch (error) {
1286
+ console.log(styleText("red", `Error: ${error.message}`));
1287
+ if (!droidVersion) console.log(styleText("gray", "Please use -p to point to a runnable droid binary."));
1288
+ process.exit(1);
1289
+ }
1239
1290
  if (apiBase && !websearch) {
1240
1291
  const originalUrl = "https://api.factory.ai";
1241
1292
  const originalLength = 22;
@@ -1261,23 +1312,45 @@ bin("droid-patch", "CLI tool to patch droid binary with various modifications").
1261
1312
  }
1262
1313
  if (reasoningEffort) {
1263
1314
  patches.push({
1264
- name: "reasoningEffortSupportedXHighList",
1265
- description: "Enable [\"high\",\"max\",\"xhigh\"] in UI for custom model list",
1315
+ name: "reasoningEffortSupportedXHighListLegacy",
1316
+ description: "Enable [\"high\",\"max\",\"xhigh\"] in UI for custom model list (legacy)",
1266
1317
  pattern: Buffer.from(""),
1267
1318
  replacement: Buffer.from(""),
1319
+ suppressCheckUnlessFound: true,
1268
1320
  regexPattern: /id:([A-Za-z$_])\.id,displayName:\1\.displayName,shortDisplayName:\1\.(?:displayName|id),modelProvider:\1\.provider\s*,supportedReasoningEfforts:\[(?:"(?:none|high)"(?:,"xhigh")?|"low","high","xhigh")\],defaultReasoningEffort:"(?:none|high)",isCustom:!([01]),noImageSupport:(?:\1\.noImageSupport|!1)/g,
1269
1321
  regexReplacement: "id:$1.id,displayName:$1.displayName,shortDisplayName:$1.displayName,modelProvider:$1.provider,supportedReasoningEfforts:[\"high\",\"max\",\"xhigh\"],defaultReasoningEffort:\"high\",isCustom:!$2,noImageSupport:!1",
1270
1322
  alreadyPatchedRegexPattern: /id:([A-Za-z$_])\.id,displayName:\1\.displayName,shortDisplayName:\1\.displayName,modelProvider:\1\.provider,supportedReasoningEfforts:\["high","max","xhigh"\],defaultReasoningEffort:"high",isCustom:!([01]),noImageSupport:!1/g
1271
1323
  });
1272
1324
  patches.push({
1273
- name: "reasoningEffortSupportedXHighResolver",
1274
- description: "Enable [\"high\",\"max\",\"xhigh\"] in UI for custom model config resolver",
1325
+ name: "reasoningEffortSupportedXHighResolverLegacy",
1326
+ description: "Enable [\"high\",\"max\",\"xhigh\"] in UI for custom model config resolver (legacy)",
1275
1327
  pattern: Buffer.from(""),
1276
1328
  replacement: Buffer.from(""),
1329
+ suppressCheckUnlessFound: true,
1277
1330
  regexPattern: /id:([A-Za-z$_])\.model,modelProvider:\1\.provider\s*,displayName:([A-Za-z$_]),shortDisplayName:\2,supportedReasoningEfforts:\[(?:"(?:none|high)"(?:,"xhigh")?|"low","high","xhigh")\],defaultReasoningEffort:"(?:none|high)",isCustom:!([01]),noImageSupport:(?:\1\.noImageSupport|!1)/g,
1278
1331
  regexReplacement: "id:$1.model,modelProvider:$1.provider,displayName:$2,shortDisplayName:$2,supportedReasoningEfforts:[\"high\",\"max\",\"xhigh\"],defaultReasoningEffort:\"high\",isCustom:!$3,noImageSupport:!1",
1279
1332
  alreadyPatchedRegexPattern: /id:([A-Za-z$_])\.model,modelProvider:\1\.provider,displayName:([A-Za-z$_]),shortDisplayName:\2,supportedReasoningEfforts:\["high","max","xhigh"\],defaultReasoningEffort:"high",isCustom:!([01]),noImageSupport:!1/g
1280
1333
  });
1334
+ patches.push({
1335
+ name: "reasoningEffortSupportedXHighList",
1336
+ description: "Enable [\"high\",\"max\",\"xhigh\"] in UI for custom model list",
1337
+ pattern: Buffer.from(""),
1338
+ replacement: Buffer.from(""),
1339
+ skipIfAnySucceeded: ["reasoningEffortSupportedXHighListLegacy"],
1340
+ regexPattern: /id:([A-Za-z$_])\.id,displayName:\1\.displayName,shortDisplayName:\1\.displayName,modelProvider:\1\.provider,supportedReasoningEfforts:[A-Za-z$_]\?\["off","low","medium","high"\]:\["none"\],defaultReasoningEffort:\1\.reasoningEffort\?\?"none",isCustom:!([01]),noImageSupport:\1\.noImageSupport/g,
1341
+ regexReplacement: "id:$1.id,displayName:$1.displayName,shortDisplayName:$1.displayName,modelProvider:$1.provider,supportedReasoningEfforts:1?[\"high\",\"max\",\"xhigh\",\"none\"]:[\"high\"],defaultReasoningEffort:$1.reasoningEffort??\"high\",isCustom:!$2,noImageSupport:$1.noImageSupport",
1342
+ alreadyPatchedRegexPattern: /id:([A-Za-z$_])\.id,displayName:\1\.displayName,shortDisplayName:\1\.displayName,modelProvider:\1\.provider,supportedReasoningEfforts:1\?\["high","max","xhigh"(?:,"none")?\]\s{0,7}:\["high"\],defaultReasoningEffort:\1\.reasoningEffort\?\?"high",isCustom:!([01]),noImageSupport:\1\.noImageSupport/g
1343
+ });
1344
+ patches.push({
1345
+ name: "reasoningEffortSupportedXHighResolver",
1346
+ description: "Enable [\"high\",\"max\",\"xhigh\"] in UI for custom model config resolver",
1347
+ pattern: Buffer.from(""),
1348
+ replacement: Buffer.from(""),
1349
+ skipIfAnySucceeded: ["reasoningEffortSupportedXHighResolverLegacy"],
1350
+ regexPattern: /id:([A-Za-z$_])\.model,modelProvider:\1\.provider,displayName:([A-Za-z$_]),shortDisplayName:\2,supportedReasoningEfforts:[A-Za-z$_]\?\["off","low","medium","high"\]:\["none"\],defaultReasoningEffort:\1\.reasoningEffort\?\?"none",isCustom:!([01]),noImageSupport:\1\.noImageSupport/g,
1351
+ regexReplacement: "id:$1.model,modelProvider:$1.provider,displayName:$2,shortDisplayName:$2,supportedReasoningEfforts:1?[\"high\",\"max\",\"xhigh\",\"none\"]:[\"high\"],defaultReasoningEffort:$1.reasoningEffort??\"high\",isCustom:!$3,noImageSupport:$1.noImageSupport",
1352
+ alreadyPatchedRegexPattern: /id:([A-Za-z$_])\.model,modelProvider:\1\.provider,displayName:([A-Za-z$_]),shortDisplayName:\2,supportedReasoningEfforts:1\?\["high","max","xhigh"(?:,"none")?\]\s{0,7}:\["high"\],defaultReasoningEffort:\1\.reasoningEffort\?\?"high",isCustom:!([01]),noImageSupport:\1\.noImageSupport/g
1353
+ });
1281
1354
  patches.push({
1282
1355
  name: "reasoningEffortSupported",
1283
1356
  description: "Fallback: Change supportedReasoningEfforts:[\"none\"] to [\"high\"] (for legacy/custom: configs)",
@@ -1380,7 +1453,6 @@ bin("droid-patch", "CLI tool to patch droid binary with various modifications").
1380
1453
  let aliasResult;
1381
1454
  if (websearch || websearchProxy) aliasResult = await createAliasForWrapper(execTargetPath, alias, verbose);
1382
1455
  else aliasResult = await createAlias(result.outputPath, alias, verbose);
1383
- const droidVersion = getDroidVersion(path);
1384
1456
  await saveAliasMetadata(createMetadata(alias, path, {
1385
1457
  isCustom: !!isCustom,
1386
1458
  skipLogin: !!skipLogin,
@@ -1493,6 +1565,11 @@ bin("droid-patch", "CLI tool to patch droid binary with various modifications").
1493
1565
  }
1494
1566
  console.log(styleText("white", `Using droid binary: ${newBinaryPath}`));
1495
1567
  console.log(styleText("white", `Found ${metaList.length} alias(es) to update`));
1568
+ const newDroidVersion = getDroidVersion(newBinaryPath);
1569
+ if (!newDroidVersion) {
1570
+ console.log(styleText("yellow", "[!] Warning: Could not detect droid version from the new binary"));
1571
+ console.log(styleText("gray", " skip-login aliases may fail to update"));
1572
+ }
1496
1573
  if (dryRun) console.log(styleText("blue", "(DRY RUN - no changes will be made)"));
1497
1574
  console.log();
1498
1575
  let successCount = 0;
@@ -1515,12 +1592,7 @@ bin("droid-patch", "CLI tool to patch droid binary with various modifications").
1515
1592
  pattern: Buffer.from("isCustom:!0"),
1516
1593
  replacement: Buffer.from("isCustom:!1")
1517
1594
  });
1518
- if (meta.patches.skipLogin) patches.push({
1519
- name: "skipLogin",
1520
- description: "Replace process.env.FACTORY_API_KEY with fake key",
1521
- pattern: Buffer.from("process.env.FACTORY_API_KEY"),
1522
- replacement: Buffer.from("\"fk-droid-patch-skip-00000\"")
1523
- });
1595
+ if (meta.patches.skipLogin) patches.push(...resolveVersionedPatches("skip-login", newDroidVersion, SKIP_LOGIN_PATCH_RULES));
1524
1596
  if (meta.patches.apiBase && !meta.patches.websearch) {
1525
1597
  const originalUrl = "https://api.factory.ai";
1526
1598
  const paddedUrl = meta.patches.apiBase.padEnd(22, " ");
@@ -1533,23 +1605,45 @@ bin("droid-patch", "CLI tool to patch droid binary with various modifications").
1533
1605
  }
1534
1606
  if (meta.patches.reasoningEffort) {
1535
1607
  patches.push({
1536
- name: "reasoningEffortSupportedXHighList",
1537
- description: "Enable [\"high\",\"max\",\"xhigh\"] in UI for custom model list",
1608
+ name: "reasoningEffortSupportedXHighListLegacy",
1609
+ description: "Enable [\"high\",\"max\",\"xhigh\"] in UI for custom model list (legacy)",
1538
1610
  pattern: Buffer.from(""),
1539
1611
  replacement: Buffer.from(""),
1612
+ suppressCheckUnlessFound: true,
1540
1613
  regexPattern: /id:([A-Za-z$_])\.id,displayName:\1\.displayName,shortDisplayName:\1\.(?:displayName|id),modelProvider:\1\.provider\s*,supportedReasoningEfforts:\[(?:"(?:none|high)"(?:,"xhigh")?|"low","high","xhigh")\],defaultReasoningEffort:"(?:none|high)",isCustom:!([01]),noImageSupport:(?:\1\.noImageSupport|!1)/g,
1541
1614
  regexReplacement: "id:$1.id,displayName:$1.displayName,shortDisplayName:$1.displayName,modelProvider:$1.provider,supportedReasoningEfforts:[\"high\",\"max\",\"xhigh\"],defaultReasoningEffort:\"high\",isCustom:!$2,noImageSupport:!1",
1542
1615
  alreadyPatchedRegexPattern: /id:([A-Za-z$_])\.id,displayName:\1\.displayName,shortDisplayName:\1\.displayName,modelProvider:\1\.provider,supportedReasoningEfforts:\["high","max","xhigh"\],defaultReasoningEffort:"high",isCustom:!([01]),noImageSupport:!1/g
1543
1616
  });
1544
1617
  patches.push({
1545
- name: "reasoningEffortSupportedXHighResolver",
1546
- description: "Enable [\"high\",\"max\",\"xhigh\"] in UI for custom model config resolver",
1618
+ name: "reasoningEffortSupportedXHighResolverLegacy",
1619
+ description: "Enable [\"high\",\"max\",\"xhigh\"] in UI for custom model config resolver (legacy)",
1547
1620
  pattern: Buffer.from(""),
1548
1621
  replacement: Buffer.from(""),
1622
+ suppressCheckUnlessFound: true,
1549
1623
  regexPattern: /id:([A-Za-z$_])\.model,modelProvider:\1\.provider\s*,displayName:([A-Za-z$_]),shortDisplayName:\2,supportedReasoningEfforts:\[(?:"(?:none|high)"(?:,"xhigh")?|"low","high","xhigh")\],defaultReasoningEffort:"(?:none|high)",isCustom:!([01]),noImageSupport:(?:\1\.noImageSupport|!1)/g,
1550
1624
  regexReplacement: "id:$1.model,modelProvider:$1.provider,displayName:$2,shortDisplayName:$2,supportedReasoningEfforts:[\"high\",\"max\",\"xhigh\"],defaultReasoningEffort:\"high\",isCustom:!$3,noImageSupport:!1",
1551
1625
  alreadyPatchedRegexPattern: /id:([A-Za-z$_])\.model,modelProvider:\1\.provider,displayName:([A-Za-z$_]),shortDisplayName:\2,supportedReasoningEfforts:\["high","max","xhigh"\],defaultReasoningEffort:"high",isCustom:!([01]),noImageSupport:!1/g
1552
1626
  });
1627
+ patches.push({
1628
+ name: "reasoningEffortSupportedXHighList",
1629
+ description: "Enable [\"high\",\"max\",\"xhigh\"] in UI for custom model list",
1630
+ pattern: Buffer.from(""),
1631
+ replacement: Buffer.from(""),
1632
+ skipIfAnySucceeded: ["reasoningEffortSupportedXHighListLegacy"],
1633
+ regexPattern: /id:([A-Za-z$_])\.id,displayName:\1\.displayName,shortDisplayName:\1\.displayName,modelProvider:\1\.provider,supportedReasoningEfforts:[A-Za-z$_]\?\["off","low","medium","high"\]:\["none"\],defaultReasoningEffort:\1\.reasoningEffort\?\?"none",isCustom:!([01]),noImageSupport:\1\.noImageSupport/g,
1634
+ regexReplacement: "id:$1.id,displayName:$1.displayName,shortDisplayName:$1.displayName,modelProvider:$1.provider,supportedReasoningEfforts:1?[\"high\",\"max\",\"xhigh\",\"none\"]:[\"high\"],defaultReasoningEffort:$1.reasoningEffort??\"high\",isCustom:!$2,noImageSupport:$1.noImageSupport",
1635
+ alreadyPatchedRegexPattern: /id:([A-Za-z$_])\.id,displayName:\1\.displayName,shortDisplayName:\1\.displayName,modelProvider:\1\.provider,supportedReasoningEfforts:1\?\["high","max","xhigh"(?:,"none")?\]\s{0,7}:\["high"\],defaultReasoningEffort:\1\.reasoningEffort\?\?"high",isCustom:!([01]),noImageSupport:\1\.noImageSupport/g
1636
+ });
1637
+ patches.push({
1638
+ name: "reasoningEffortSupportedXHighResolver",
1639
+ description: "Enable [\"high\",\"max\",\"xhigh\"] in UI for custom model config resolver",
1640
+ pattern: Buffer.from(""),
1641
+ replacement: Buffer.from(""),
1642
+ skipIfAnySucceeded: ["reasoningEffortSupportedXHighResolverLegacy"],
1643
+ regexPattern: /id:([A-Za-z$_])\.model,modelProvider:\1\.provider,displayName:([A-Za-z$_]),shortDisplayName:\2,supportedReasoningEfforts:[A-Za-z$_]\?\["off","low","medium","high"\]:\["none"\],defaultReasoningEffort:\1\.reasoningEffort\?\?"none",isCustom:!([01]),noImageSupport:\1\.noImageSupport/g,
1644
+ regexReplacement: "id:$1.model,modelProvider:$1.provider,displayName:$2,shortDisplayName:$2,supportedReasoningEfforts:1?[\"high\",\"max\",\"xhigh\",\"none\"]:[\"high\"],defaultReasoningEffort:$1.reasoningEffort??\"high\",isCustom:!$3,noImageSupport:$1.noImageSupport",
1645
+ alreadyPatchedRegexPattern: /id:([A-Za-z$_])\.model,modelProvider:\1\.provider,displayName:([A-Za-z$_]),shortDisplayName:\2,supportedReasoningEfforts:1\?\["high","max","xhigh"(?:,"none")?\]\s{0,7}:\["high"\],defaultReasoningEffort:\1\.reasoningEffort\?\?"high",isCustom:!([01]),noImageSupport:\1\.noImageSupport/g
1646
+ });
1553
1647
  patches.push({
1554
1648
  name: "reasoningEffortSupported",
1555
1649
  description: "Fallback: Change supportedReasoningEfforts:[\"none\"] to [\"high\"] (for legacy/custom: configs)",
@@ -1685,7 +1779,7 @@ bin("droid-patch", "CLI tool to patch droid binary with various modifications").
1685
1779
  }
1686
1780
  meta.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
1687
1781
  meta.originalBinaryPath = newBinaryPath;
1688
- meta.droidVersion = getDroidVersion(newBinaryPath);
1782
+ meta.droidVersion = newDroidVersion;
1689
1783
  meta.droidPatchVersion = version;
1690
1784
  await saveAliasMetadata(meta);
1691
1785
  console.log(styleText("green", ` ✓ Updated successfully`));