impel-cli 0.17.3 → 0.17.5
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/package.json +1 -1
- package/src/apps.js +143 -83
- package/src/windowsApps.js +39 -3
package/package.json
CHANGED
package/src/apps.js
CHANGED
|
@@ -42,33 +42,33 @@ const APP_DEFINITIONS = {
|
|
|
42
42
|
// with its compatibility patches. Updating a pin requires a new CLI release.
|
|
43
43
|
export const PINNED_VENDOR_APPS = Object.freeze({
|
|
44
44
|
claude: Object.freeze({
|
|
45
|
-
version: "1.
|
|
46
|
-
claudeCodeVersion: "2.1.
|
|
47
|
-
claudeCodeCommit: "
|
|
45
|
+
version: "1.22209.3",
|
|
46
|
+
claudeCodeVersion: "2.1.215",
|
|
47
|
+
claudeCodeCommit: "316ce99628e89900bf0b1328fed3b8fec0c0c92d",
|
|
48
48
|
bundleName: "Claude.app",
|
|
49
49
|
downloads: Object.freeze({
|
|
50
50
|
arm64: Object.freeze({
|
|
51
|
-
url: "https://downloads.claude.ai/releases/darwin/universal/1.
|
|
52
|
-
sha256: "
|
|
51
|
+
url: "https://downloads.claude.ai/releases/darwin/universal/1.22209.3/Claude-babe11577dfefe3e209c06bd674628d862f0dbae.zip",
|
|
52
|
+
sha256: "b110e0fdb7b2601d80dfdd7893f7811de382de84c4586113e7873e28f17680fc",
|
|
53
53
|
}),
|
|
54
54
|
x64: Object.freeze({
|
|
55
|
-
url: "https://downloads.claude.ai/releases/darwin/universal/1.
|
|
56
|
-
sha256: "
|
|
55
|
+
url: "https://downloads.claude.ai/releases/darwin/universal/1.22209.3/Claude-babe11577dfefe3e209c06bd674628d862f0dbae.zip",
|
|
56
|
+
sha256: "b110e0fdb7b2601d80dfdd7893f7811de382de84c4586113e7873e28f17680fc",
|
|
57
57
|
}),
|
|
58
58
|
}),
|
|
59
59
|
}),
|
|
60
60
|
chatgpt: Object.freeze({
|
|
61
|
-
version: "26.
|
|
62
|
-
codexVersion: "0.
|
|
61
|
+
version: "26.715.31925",
|
|
62
|
+
codexVersion: "0.145.0-alpha.18",
|
|
63
63
|
bundleName: "ChatGPT.app",
|
|
64
64
|
downloads: Object.freeze({
|
|
65
65
|
arm64: Object.freeze({
|
|
66
|
-
url: "https://persistent.oaistatic.com/codex-app-prod/ChatGPT-darwin-arm64-26.
|
|
67
|
-
sha256: "
|
|
66
|
+
url: "https://persistent.oaistatic.com/codex-app-prod/ChatGPT-darwin-arm64-26.715.31925.zip",
|
|
67
|
+
sha256: "a0cded116975c71c723dc8601c07402533b5ff23881d15e52cfb6dc71413e45b",
|
|
68
68
|
}),
|
|
69
69
|
x64: Object.freeze({
|
|
70
|
-
url: "https://persistent.oaistatic.com/codex-app-prod/ChatGPT-darwin-x64-26.
|
|
71
|
-
sha256: "
|
|
70
|
+
url: "https://persistent.oaistatic.com/codex-app-prod/ChatGPT-darwin-x64-26.715.31925.zip",
|
|
71
|
+
sha256: "f18972b893207ff5cbf047599369ce96768c2ace25128a09315058ef0a5cfdcb",
|
|
72
72
|
}),
|
|
73
73
|
}),
|
|
74
74
|
}),
|
|
@@ -85,16 +85,22 @@ const ULTRA_REASONING_LEVEL = { effort: "ultra", description: "Maximum reasoning
|
|
|
85
85
|
const FAST_SERVICE_TIER = { id: "priority", name: "Fast", description: "1.5x speed, increased usage" };
|
|
86
86
|
const FAST_MODE_AUTH_GATE = /([A-Za-z_$][\w$]*)=([A-Za-z_$][\w$]*)&&!([A-Za-z_$][\w$]*)&&([A-Za-z_$][\w$]*)!=null&&\4\?\.requirements\?\.featureRequirements\?\.fast_mode!==!1/gu;
|
|
87
87
|
const CHATGPT_RESOURCE_ROOT = "linked_vendor_resources_with_patched_asar";
|
|
88
|
-
const CLAUDE_PLAN_USAGE_GUARD = "if(!
|
|
89
|
-
const IMPEL_CLAUDE_PLAN_USAGE_GUARD =
|
|
90
|
-
const
|
|
91
|
-
const
|
|
92
|
-
const CLAUDE_DRAFT_AGENT_MENTIONS = 'agentMentionsEnabled:"draft"===Be&&s';
|
|
93
|
-
const IMPEL_CLAUDE_BOUND_AGENT_MENTIONS = 'agentMentionsEnabled:"draft"===Be?s:Le?.agent??!1';
|
|
88
|
+
const CLAUDE_PLAN_USAGE_GUARD = "if(!Vve()){f8();return}if(!et().hasOrgPolicyBackend())return;if((r=yr())";
|
|
89
|
+
const IMPEL_CLAUDE_PLAN_USAGE_GUARD = `if(!Vve()){f8();return}${"".padEnd("if(!et().hasOrgPolicyBackend())return;".length, " ")}if((r=yr())`;
|
|
90
|
+
const CLAUDE_DRAFT_AGENT_MENTIONS = 'agentMentionsEnabled:"draft"===He&&s';
|
|
91
|
+
const IMPEL_CLAUDE_BOUND_AGENT_MENTIONS = 'agentMentionsEnabled:"draft"===He?s:Le?.agent??!1';
|
|
94
92
|
const CLAUDE_AGENT_MENTION_FILTER = 'return e.filter(e=>"user"===e.source&&(!s||e.name.toLowerCase().includes(s))).slice(0,10)';
|
|
95
93
|
const IMPEL_CLAUDE_BOUND_AGENT_MENTION_FILTER = 'return e.filter(e=>"user"===e.source&&(!s||e.name.toLowerCase().includes(s))&&("string"!=typeof y||e.name===y)).slice(0,10)';
|
|
96
94
|
const CLAUDE_AGENT_MENTION_SELECT = 'onSelect:t=>(e(String(t)),Promise.resolve(null))';
|
|
97
95
|
const IMPEL_CLAUDE_BOUND_AGENT_MENTION_SELECT = 'onSelect:t=>"string"==typeof y?Promise.resolve({chipText:String(t)}):(e(String(t)),Promise.resolve(null))';
|
|
96
|
+
// Claude's Code-disabled screens link Back to "/", but the root router honors
|
|
97
|
+
// its separately persisted last Code mode and immediately returns to the same
|
|
98
|
+
// disabled screen. Route directly to the pinned build's canonical Chat page;
|
|
99
|
+
// its normal mode effect then reconciles both renderer and desktop preference.
|
|
100
|
+
const CLAUDE_CODE_DISABLED_BACK_LINK = 'function Fi(){return e.jsxs("a",{href:"/",className:"inline-flex items-center text-sm text-text-400 hover:text-text-300 outline-none"';
|
|
101
|
+
const IMPEL_CLAUDE_CODE_DISABLED_BACK_LINK = 'function Fi(){return e.jsxs("a",{href:"/chat/new",className:"inline-flex items-center text-sm text-text-400 hover:text-text-300 outline-none"';
|
|
102
|
+
const CLAUDE_CODE_NO_SEAT_BACK_LINK = 'b.jsx(D,{variant:"ghost",href:"/",icon:"ArrowLeft",children:b.jsx(A,{defaultMessage:"Back to Claude",id:"e4M0bJ/pZc"})})';
|
|
103
|
+
const IMPEL_CLAUDE_CODE_NO_SEAT_BACK_LINK = 'b.jsx(D,{variant:"ghost",href:"/chat/new",icon:"ArrowLeft",children:b.jsx(A,{defaultMessage:"Back to Claude",id:"e4M0bJ/pZc"})})';
|
|
98
104
|
const LEGACY_CLAUDE_SAFE_STORAGE_NAME = "Claude";
|
|
99
105
|
const CLAUDE_SAFE_STORAGE_METADATA = "safe-storage.json";
|
|
100
106
|
|
|
@@ -176,7 +182,7 @@ export const CURRENT_CONFIG_VERSION = 16;
|
|
|
176
182
|
// — which is what made every `impel update` re-trigger macOS permission
|
|
177
183
|
// prompts. Bump this ONLY when a code change alters the bytes of a built
|
|
178
184
|
// bundle; leave it alone for changes that don't touch bundle contents.
|
|
179
|
-
export const BUNDLE_BUILD_FINGERPRINT = "bundle-2026-07-
|
|
185
|
+
export const BUNDLE_BUILD_FINGERPRINT = "bundle-2026-07-20.2";
|
|
180
186
|
|
|
181
187
|
/** Parse the tenant's install manifest, or null when absent/corrupt. */
|
|
182
188
|
export function readTenantManifest(homeDir = os.homedir(), tenantId = null) {
|
|
@@ -247,6 +253,8 @@ export function bundleIsCurrent(status, {
|
|
|
247
253
|
compatibility.patches?.followupBoundAgentEnable === 1
|
|
248
254
|
&& compatibility.patches?.followupBoundAgentFilter === 1
|
|
249
255
|
&& compatibility.patches?.followupBoundAgentChip === 1
|
|
256
|
+
&& compatibility.patches?.codeDisabledBack === 1
|
|
257
|
+
&& compatibility.patches?.codeNoSeatBack === 1
|
|
250
258
|
&& managedClaudeRendererMatchesCompatibility(status, compatibility)
|
|
251
259
|
))
|
|
252
260
|
&& (status.target !== "chatgpt" || (
|
|
@@ -282,12 +290,19 @@ function wrapperLaunchesOnTahoe(status) {
|
|
|
282
290
|
|
|
283
291
|
function managedClaudeRendererMatchesCompatibility(status, compatibility) {
|
|
284
292
|
try {
|
|
285
|
-
const
|
|
286
|
-
|
|
293
|
+
const groups = [
|
|
294
|
+
compatibility.rendererAssets?.agentMentions,
|
|
295
|
+
compatibility.rendererAssets?.codeDisabledBack,
|
|
296
|
+
];
|
|
297
|
+
if (groups.some((renderers) => !Array.isArray(renderers) || renderers.length === 0)) return false;
|
|
298
|
+
const renderers = groups.flat();
|
|
287
299
|
const root = path.resolve(status.launcher, "Contents", "Resources", "ion-dist");
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
300
|
+
return renderers.every((renderer) => {
|
|
301
|
+
if (!renderer?.path || !renderer.sha256 || path.isAbsolute(renderer.path)) return false;
|
|
302
|
+
const target = path.resolve(root, renderer.path);
|
|
303
|
+
if (!target.startsWith(`${root}${path.sep}`)) return false;
|
|
304
|
+
return sha256(fs.readFileSync(target)) === renderer.sha256;
|
|
305
|
+
});
|
|
291
306
|
} catch {
|
|
292
307
|
return false;
|
|
293
308
|
}
|
|
@@ -1364,6 +1379,7 @@ function writeVendoredClaudeBundle(paths, vendorPath, gatewayUrl, safeStorageNam
|
|
|
1364
1379
|
}
|
|
1365
1380
|
|
|
1366
1381
|
const agentMentionPatches = patchClaudeFollowupAgentMentions(staging);
|
|
1382
|
+
const codeDisabledBackPatches = patchClaudeCodeDisabledBackRouting(staging);
|
|
1367
1383
|
const oldAsarHash = asarHeaderHash(asarPath);
|
|
1368
1384
|
let planUsageGuardPatchCount = 0;
|
|
1369
1385
|
let planUsageRequestPatchCount = 0;
|
|
@@ -1406,7 +1422,7 @@ function writeVendoredClaudeBundle(paths, vendorPath, gatewayUrl, safeStorageNam
|
|
|
1406
1422
|
const vendorExecutable = path.join(macos, executableName);
|
|
1407
1423
|
const signingIdentity = resolveVendoredAppSigningIdentity(vendorExecutable);
|
|
1408
1424
|
writeAtomic(path.join(staging, "Contents", "Resources", "impel-compatibility.json"), JSON.stringify({
|
|
1409
|
-
schemaVersion:
|
|
1425
|
+
schemaVersion: 6,
|
|
1410
1426
|
cliVersion: CLI_VERSION,
|
|
1411
1427
|
bundleFingerprint: BUNDLE_BUILD_FINGERPRINT,
|
|
1412
1428
|
signingMode: signingModeForIdentity(signingIdentity),
|
|
@@ -1425,12 +1441,12 @@ function writeVendoredClaudeBundle(paths, vendorPath, gatewayUrl, safeStorageNam
|
|
|
1425
1441
|
followupBoundAgentEnable: agentMentionPatches.enable,
|
|
1426
1442
|
followupBoundAgentFilter: agentMentionPatches.filter,
|
|
1427
1443
|
followupBoundAgentChip: agentMentionPatches.chip,
|
|
1444
|
+
codeDisabledBack: codeDisabledBackPatches.disabled,
|
|
1445
|
+
codeNoSeatBack: codeDisabledBackPatches.noSeat,
|
|
1428
1446
|
},
|
|
1429
1447
|
rendererAssets: {
|
|
1430
|
-
agentMentions:
|
|
1431
|
-
|
|
1432
|
-
sha256: agentMentionPatches.sha256,
|
|
1433
|
-
},
|
|
1448
|
+
agentMentions: agentMentionPatches.assets,
|
|
1449
|
+
codeDisabledBack: codeDisabledBackPatches.assets,
|
|
1434
1450
|
},
|
|
1435
1451
|
asarHeaderSha256: newAsarHash,
|
|
1436
1452
|
}, null, 2) + "\n", 0o644);
|
|
@@ -1567,52 +1583,109 @@ function linkVendoredChatGPTResources(bundle, vendorBundleName) {
|
|
|
1567
1583
|
}
|
|
1568
1584
|
|
|
1569
1585
|
function patchClaudeFollowupAgentMentions(bundle) {
|
|
1586
|
+
const assets = patchClaudeRendererContracts(bundle, {
|
|
1587
|
+
supportLabel: "follow-up agent mentions",
|
|
1588
|
+
patchLabel: "follow-up agent-mention",
|
|
1589
|
+
contracts: [
|
|
1590
|
+
{
|
|
1591
|
+
key: "enable",
|
|
1592
|
+
original: CLAUDE_DRAFT_AGENT_MENTIONS,
|
|
1593
|
+
replacement: IMPEL_CLAUDE_BOUND_AGENT_MENTIONS,
|
|
1594
|
+
},
|
|
1595
|
+
{
|
|
1596
|
+
key: "filter",
|
|
1597
|
+
original: CLAUDE_AGENT_MENTION_FILTER,
|
|
1598
|
+
replacement: IMPEL_CLAUDE_BOUND_AGENT_MENTION_FILTER,
|
|
1599
|
+
},
|
|
1600
|
+
{
|
|
1601
|
+
key: "chip",
|
|
1602
|
+
original: CLAUDE_AGENT_MENTION_SELECT,
|
|
1603
|
+
replacement: IMPEL_CLAUDE_BOUND_AGENT_MENTION_SELECT,
|
|
1604
|
+
},
|
|
1605
|
+
],
|
|
1606
|
+
});
|
|
1607
|
+
return {
|
|
1608
|
+
enable: 1,
|
|
1609
|
+
filter: 1,
|
|
1610
|
+
chip: 1,
|
|
1611
|
+
assets,
|
|
1612
|
+
};
|
|
1613
|
+
}
|
|
1614
|
+
|
|
1615
|
+
function patchClaudeCodeDisabledBackRouting(bundle) {
|
|
1616
|
+
const assets = patchClaudeRendererContracts(bundle, {
|
|
1617
|
+
supportLabel: "Code-disabled Back routing",
|
|
1618
|
+
patchLabel: "Code-disabled Back routing",
|
|
1619
|
+
contracts: [
|
|
1620
|
+
{
|
|
1621
|
+
key: "disabled",
|
|
1622
|
+
original: CLAUDE_CODE_DISABLED_BACK_LINK,
|
|
1623
|
+
replacement: IMPEL_CLAUDE_CODE_DISABLED_BACK_LINK,
|
|
1624
|
+
},
|
|
1625
|
+
{
|
|
1626
|
+
key: "noSeat",
|
|
1627
|
+
original: CLAUDE_CODE_NO_SEAT_BACK_LINK,
|
|
1628
|
+
replacement: IMPEL_CLAUDE_CODE_NO_SEAT_BACK_LINK,
|
|
1629
|
+
},
|
|
1630
|
+
],
|
|
1631
|
+
});
|
|
1632
|
+
return {
|
|
1633
|
+
disabled: 1,
|
|
1634
|
+
noSeat: 1,
|
|
1635
|
+
assets,
|
|
1636
|
+
};
|
|
1637
|
+
}
|
|
1638
|
+
|
|
1639
|
+
function patchClaudeRendererContracts(bundle, {
|
|
1640
|
+
supportLabel,
|
|
1641
|
+
patchLabel,
|
|
1642
|
+
contracts,
|
|
1643
|
+
}) {
|
|
1570
1644
|
const version = bundleVersion(bundle);
|
|
1571
1645
|
if (version !== PINNED_VENDOR_APPS.claude.version) {
|
|
1572
1646
|
throw new Error(
|
|
1573
|
-
`Claude
|
|
1647
|
+
`Claude ${supportLabel} support is pinned to ${PINNED_VENDOR_APPS.claude.version}; found ${version || "unknown"}`,
|
|
1574
1648
|
);
|
|
1575
1649
|
}
|
|
1576
1650
|
|
|
1577
1651
|
const ionDist = path.join(bundle, "Contents", "Resources", "ion-dist");
|
|
1578
|
-
const
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
|
|
1582
|
-
];
|
|
1583
|
-
const
|
|
1584
|
-
const
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
|
|
1588
|
-
throw new Error(
|
|
1589
|
-
`Claude follow-up agent-mention renderer expected 1 matching asset, found ${candidates.length}; update impel-cli before installing this desktop app version`,
|
|
1590
|
-
);
|
|
1652
|
+
const sources = new Map(listJavaScriptFiles(ionDist).map((candidate) => [
|
|
1653
|
+
candidate,
|
|
1654
|
+
fs.readFileSync(candidate, "utf8"),
|
|
1655
|
+
]));
|
|
1656
|
+
const matches = new Map(contracts.map(({ key }) => [key, []]));
|
|
1657
|
+
for (const [candidate, source] of sources) {
|
|
1658
|
+
for (const contract of contracts) {
|
|
1659
|
+
const count = exactTextMatchCount(source, contract.original);
|
|
1660
|
+
if (count > 0) matches.get(contract.key).push({ candidate, count });
|
|
1661
|
+
}
|
|
1591
1662
|
}
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
let source = fs.readFileSync(renderer, "utf8");
|
|
1595
|
-
const enable = exactTextMatchCount(source, CLAUDE_DRAFT_AGENT_MENTIONS);
|
|
1596
|
-
const filter = exactTextMatchCount(source, CLAUDE_AGENT_MENTION_FILTER);
|
|
1597
|
-
const chip = exactTextMatchCount(source, CLAUDE_AGENT_MENTION_SELECT);
|
|
1598
|
-
for (const [label, count] of [["enable", enable], ["filter", filter], ["chip", chip]]) {
|
|
1663
|
+
for (const contract of contracts) {
|
|
1664
|
+
const count = matches.get(contract.key).reduce((total, match) => total + match.count, 0);
|
|
1599
1665
|
if (count !== 1) {
|
|
1600
|
-
throw new Error(`Claude
|
|
1666
|
+
throw new Error(`Claude ${patchLabel} ${contract.key} patch expected 1 match, found ${count}`);
|
|
1601
1667
|
}
|
|
1602
1668
|
}
|
|
1603
1669
|
|
|
1604
|
-
|
|
1605
|
-
|
|
1606
|
-
.
|
|
1607
|
-
|
|
1608
|
-
|
|
1609
|
-
|
|
1610
|
-
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
|
|
1614
|
-
|
|
1615
|
-
|
|
1670
|
+
const assets = [];
|
|
1671
|
+
for (const candidate of [...new Set(
|
|
1672
|
+
[...matches.values()].flatMap((entries) => entries.map(({ candidate: file }) => file)),
|
|
1673
|
+
)].sort()) {
|
|
1674
|
+
const source = fs.readFileSync(candidate, "utf8");
|
|
1675
|
+
const applicable = contracts.filter((contract) => source.includes(contract.original));
|
|
1676
|
+
let patched = source;
|
|
1677
|
+
for (const contract of applicable) {
|
|
1678
|
+
patched = patched.replace(contract.original, contract.replacement);
|
|
1679
|
+
}
|
|
1680
|
+
writeAtomic(candidate, patched, fs.statSync(candidate).mode & 0o777);
|
|
1681
|
+
assets.push({
|
|
1682
|
+
path: path.relative(ionDist, candidate).split(path.sep).join("/"),
|
|
1683
|
+
sha256: sha256(Buffer.from(patched, "utf8")),
|
|
1684
|
+
patches: applicable.map(({ key }) => key),
|
|
1685
|
+
});
|
|
1686
|
+
}
|
|
1687
|
+
|
|
1688
|
+
return assets;
|
|
1616
1689
|
}
|
|
1617
1690
|
|
|
1618
1691
|
function listJavaScriptFiles(root) {
|
|
@@ -1661,23 +1734,6 @@ function patchFixedWidthAsarString(asarPath, original, replacement, label) {
|
|
|
1661
1734
|
function patchClaudePlanUsageRequest(asarPath) {
|
|
1662
1735
|
const archive = fs.readFileSync(asarPath);
|
|
1663
1736
|
const source = archive.toString("latin1");
|
|
1664
|
-
const legacyPatches = [];
|
|
1665
|
-
for (
|
|
1666
|
-
let offset = source.indexOf(CLAUDE_PLAN_USAGE_REQUEST);
|
|
1667
|
-
offset !== -1;
|
|
1668
|
-
offset = source.indexOf(CLAUDE_PLAN_USAGE_REQUEST, offset + CLAUDE_PLAN_USAGE_REQUEST.length)
|
|
1669
|
-
) {
|
|
1670
|
-
legacyPatches.push({
|
|
1671
|
-
offset,
|
|
1672
|
-
original: CLAUDE_PLAN_USAGE_REQUEST,
|
|
1673
|
-
replacement: IMPEL_CLAUDE_PLAN_USAGE_REQUEST,
|
|
1674
|
-
});
|
|
1675
|
-
}
|
|
1676
|
-
if (legacyPatches.length > 0) {
|
|
1677
|
-
return applyFixedWidthAsarPatches(
|
|
1678
|
-
asarPath, archive, legacyPatches, "Claude plan-usage gateway request",
|
|
1679
|
-
);
|
|
1680
|
-
}
|
|
1681
1737
|
const credentialAccessor = source.match(
|
|
1682
1738
|
/function ([A-Za-z_$][\w$]*)\(e\)\{var t;return [\s\S]{0,500}?\[custom-3p\] Credentials loaded from managed config/u,
|
|
1683
1739
|
)?.[1];
|
|
@@ -1693,10 +1749,10 @@ function patchClaudePlanUsageRequest(asarPath) {
|
|
|
1693
1749
|
return applyFixedWidthAsarPatches(asarPath, archive, [], "Claude plan-usage gateway request");
|
|
1694
1750
|
}
|
|
1695
1751
|
|
|
1696
|
-
const requestPattern = /([A-Za-z_$][\w$]*)
|
|
1752
|
+
const requestPattern = /const ([A-Za-z_$][\w$]*)=`\$\{[A-Za-z_$][\w$]*\(\)\}\/api\/organizations\/\$\{[A-Za-z_$][\w$]*\}\/usage\$\{[A-Za-z_$][\w$]*\?"\?skip_spend=1":""\}`,([A-Za-z_$][\w$]*)=await ([A-Za-z_$][\w$]*)\.net\.fetch\(\1,\{signal:AbortSignal\.timeout\([A-Za-z_$][\w$]*\)\}\)/gu;
|
|
1697
1753
|
const patches = [...source.matchAll(requestPattern)].map((match) => {
|
|
1698
1754
|
const original = match[0];
|
|
1699
|
-
const replacement =
|
|
1755
|
+
const replacement = `const ${match[1]}="https://gateway.useimpel.com/ui/a/u",${match[2]}=await ${match[3]}.net.fetch(${match[1]},{headers:{key:${credentialAccessor}(${configAccessor}()).apiKey}})`;
|
|
1700
1756
|
if (replacement.length > original.length) {
|
|
1701
1757
|
throw new Error("Claude plan-usage gateway request replacement no longer fits the vendor ASAR contract");
|
|
1702
1758
|
}
|
|
@@ -1997,7 +2053,11 @@ function vendoredChatGPTWrapperPlist(vendorPath, asarHash, identity, executableN
|
|
|
1997
2053
|
<key>CFBundleShortVersionString</key><string>${xmlEscape(bundleVersion(vendorPath) || "1")}</string>
|
|
1998
2054
|
<key>ElectronAsarIntegrity</key><dict><key>Resources/app.asar</key><dict><key>algorithm</key><string>SHA256</string><key>hash</key><string>${xmlEscape(asarHash)}</string></dict></dict>
|
|
1999
2055
|
<key>LSMinimumSystemVersion</key><string>12.0</string>
|
|
2056
|
+
<key>NSCalendarsFullAccessUsageDescription</key><string>Allow access so that ChatGPT can read and update your calendar events when you ask.</string>
|
|
2057
|
+
<key>NSCalendarsUsageDescription</key><string>Allow access so that ChatGPT can read and update your calendar events when you ask.</string>
|
|
2000
2058
|
<key>NSHighResolutionCapable</key><true/>
|
|
2059
|
+
<key>NSRemindersFullAccessUsageDescription</key><string>Allow access so that ChatGPT can read and update your reminders when you ask.</string>
|
|
2060
|
+
<key>NSRemindersUsageDescription</key><string>Allow access so that ChatGPT can read and update your reminders when you ask.</string>
|
|
2001
2061
|
</dict></plist>
|
|
2002
2062
|
`;
|
|
2003
2063
|
}
|
package/src/windowsApps.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { spawn, spawnSync } from "node:child_process";
|
|
2
|
+
import crypto from "node:crypto";
|
|
2
3
|
import fs from "node:fs";
|
|
3
4
|
import os from "node:os";
|
|
4
5
|
import path from "node:path";
|
|
@@ -251,14 +252,47 @@ export function findManagedWindowsChatGPTApp(appsRoot, dependencies = {}) {
|
|
|
251
252
|
return null;
|
|
252
253
|
}
|
|
253
254
|
|
|
255
|
+
function sha256File(file) {
|
|
256
|
+
const hash = crypto.createHash("sha256");
|
|
257
|
+
const buffer = Buffer.allocUnsafe(1024 * 1024);
|
|
258
|
+
const descriptor = fs.openSync(file, "r");
|
|
259
|
+
try {
|
|
260
|
+
for (let offset = 0; ; offset += buffer.length) {
|
|
261
|
+
const bytesRead = fs.readSync(descriptor, buffer, 0, buffer.length, offset);
|
|
262
|
+
if (bytesRead === 0) break;
|
|
263
|
+
hash.update(buffer.subarray(0, bytesRead));
|
|
264
|
+
}
|
|
265
|
+
return hash.digest("hex");
|
|
266
|
+
} finally {
|
|
267
|
+
fs.closeSync(descriptor);
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
function windowsChatGPTSourceIdentity(binary) {
|
|
272
|
+
const sourceRoot = path.dirname(binary);
|
|
273
|
+
const files = {
|
|
274
|
+
executable: binary,
|
|
275
|
+
appAsar: path.join(sourceRoot, "resources", "app.asar"),
|
|
276
|
+
codex: path.join(sourceRoot, "resources", "codex.exe"),
|
|
277
|
+
};
|
|
278
|
+
return {
|
|
279
|
+
executableName: path.basename(binary),
|
|
280
|
+
sha256: Object.fromEntries(
|
|
281
|
+
Object.entries(files).map(([name, file]) => [name, sha256File(file)]),
|
|
282
|
+
),
|
|
283
|
+
};
|
|
284
|
+
}
|
|
285
|
+
|
|
254
286
|
export function windowsChatGPTStageIsCurrent(binary, appsRoot) {
|
|
255
287
|
if (!binary || !findManagedWindowsChatGPTApp(appsRoot)) return false;
|
|
256
288
|
try {
|
|
257
289
|
const record = JSON.parse(
|
|
258
290
|
fs.readFileSync(path.join(windowsChatGPTCacheRoot(appsRoot), "source.json"), "utf8"),
|
|
259
291
|
);
|
|
260
|
-
return
|
|
261
|
-
|
|
292
|
+
return record.schemaVersion === 2
|
|
293
|
+
&& path.win32.normalize(record.sourceBinary || "").toLowerCase()
|
|
294
|
+
=== path.win32.normalize(binary).toLowerCase()
|
|
295
|
+
&& JSON.stringify(record.sourceIdentity) === JSON.stringify(windowsChatGPTSourceIdentity(binary));
|
|
262
296
|
} catch {
|
|
263
297
|
return false;
|
|
264
298
|
}
|
|
@@ -288,6 +322,7 @@ export function stageWindowsChatGPTApp(binary, appsRoot, dependencies = {}) {
|
|
|
288
322
|
if (!io.isFile(binary) || !io.isFile(sourceAsar) || !io.isFile(sourceCodex)) {
|
|
289
323
|
throw new Error(`unsupported ChatGPT/Codex Windows app layout at ${sourceRoot}`);
|
|
290
324
|
}
|
|
325
|
+
const sourceIdentity = windowsChatGPTSourceIdentity(binary);
|
|
291
326
|
|
|
292
327
|
const cacheRoot = windowsChatGPTCacheRoot(appsRoot);
|
|
293
328
|
const destination = windowsManagedChatGPTRoot(appsRoot);
|
|
@@ -309,8 +344,9 @@ export function stageWindowsChatGPTApp(binary, appsRoot, dependencies = {}) {
|
|
|
309
344
|
try {
|
|
310
345
|
io.rename(staging, destination);
|
|
311
346
|
fs.writeFileSync(path.join(cacheRoot, "source.json"), `${JSON.stringify({
|
|
312
|
-
schemaVersion:
|
|
347
|
+
schemaVersion: 2,
|
|
313
348
|
sourceBinary: path.win32.normalize(binary),
|
|
349
|
+
sourceIdentity,
|
|
314
350
|
stagedAt: new Date().toISOString(),
|
|
315
351
|
}, null, 2)}\n`, { mode: 0o600 });
|
|
316
352
|
io.remove(backup);
|