impel-cli 0.20.29 → 0.20.31
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/RELEASE_NOTES.md +21 -0
- package/docs/native-agent-host-capability-matrix.md +5 -5
- package/package.json +1 -1
- package/src/apps.js +140 -46
- package/src/desktopTasks.js +21 -3
- package/src/vendorCliVersions.js +2 -2
package/RELEASE_NOTES.md
CHANGED
|
@@ -1,5 +1,26 @@
|
|
|
1
1
|
# Release notes
|
|
2
2
|
|
|
3
|
+
## 0.20.31 — Complete embedded Tasks controls
|
|
4
|
+
|
|
5
|
+
- Allows the guarded `delete_task` operation through the tenant desktop bridge
|
|
6
|
+
so the MCP App can complete the full task CRUD lifecycle.
|
|
7
|
+
- Keeps the embedded board below the macOS title-bar drag region so Board,
|
|
8
|
+
List, scope, refresh, create, and external-link controls receive pointer
|
|
9
|
+
input normally.
|
|
10
|
+
- Rebuilds managed Claude and ChatGPT bundles onto the corrected Tasks host
|
|
11
|
+
contract while preserving tenant profiles and app state.
|
|
12
|
+
|
|
13
|
+
## 0.20.30 — Stable Claude and Codex upgrades
|
|
14
|
+
|
|
15
|
+
- Updates the reviewed native CLI pins to Claude Code 2.1.220 and Codex
|
|
16
|
+
0.147.0 using the vendors' signed stable installers.
|
|
17
|
+
- Updates the managed Claude desktop pin to 1.26832.0 with its exact embedded
|
|
18
|
+
Claude Code 2.1.222 manifest and signed macOS and Windows artifacts.
|
|
19
|
+
- Updates the managed ChatGPT desktop pin to 26.803.41515 with embedded Codex
|
|
20
|
+
0.147.0-alpha.6.5, using the exact signed macOS production artifacts.
|
|
21
|
+
- Rebuilds tenant bundles only after both upgraded desktop contracts pass
|
|
22
|
+
validation.
|
|
23
|
+
|
|
3
24
|
## 0.20.28 — Exact opaque answer resumes
|
|
4
25
|
|
|
5
26
|
- Aligns generated Claude and Codex direct-answer adapters with the opaque
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
# Native-agent host capability matrix
|
|
2
2
|
|
|
3
|
-
Validated on 2026-08-
|
|
3
|
+
Validated on 2026-08-08 with isolated temporary homes and tenant profiles. The
|
|
4
4
|
matrix is intentionally pinned: a client upgrade must be re-qualified before it
|
|
5
5
|
is treated as an eager host.
|
|
6
6
|
|
|
7
7
|
| Surface | Pinned build | Exact selected tools | Selected path | Host behavior |
|
|
8
8
|
| --- | --- | --- | --- | --- |
|
|
9
|
-
| Claude Code | 2.1.
|
|
10
|
-
| Claude Desktop | 1.
|
|
11
|
-
| Codex CLI through `impel codex` | 0.
|
|
12
|
-
| ChatGPT desktop Codex | 26.
|
|
9
|
+
| Claude Code | 2.1.220 | Yes, agent frontmatter `tools` | Eager | The bound run/answer, resume, and recovery tools are direct child tools. No catalog discovery or code-cell polling is required. |
|
|
10
|
+
| Claude Desktop | 1.26832.0 (embedded Code 2.1.222) | Yes, agent frontmatter `tools` | Eager | Same direct-tool contract as Claude Code. |
|
|
11
|
+
| Codex CLI through `impel codex` | 0.147.0 | Yes, with `features.code_mode.direct_only_tool_namespaces = ["mcp__impel_agent"]` | Eager; optional single-thread profile | Existing `@Agent` children call the fixed MCP namespace directly. `impel codex --agent` also removes the parent spawn/wait/relay thread. |
|
|
12
|
+
| ChatGPT desktop Codex | 26.803.41515 (embedded Codex 0.147.0-alpha.6.5) | Yes, with the same exact native namespace | Eager child, compatible parent | Keeps the app's supported `@Agent` parent/child route, but the child no longer needs code cells or code-mode waits. |
|
|
13
13
|
|
|
14
14
|
## Qualified contract
|
|
15
15
|
|
package/package.json
CHANGED
package/src/apps.js
CHANGED
|
@@ -67,47 +67,45 @@ const portableBundleMutationLocks = new Set();
|
|
|
67
67
|
// CLI release therefore installs and accepts only the exact app builds tested
|
|
68
68
|
// with its compatibility patches. Updating a pin requires a new CLI release.
|
|
69
69
|
export const PINNED_VENDOR_APPS = Object.freeze({
|
|
70
|
-
//
|
|
71
|
-
//
|
|
72
|
-
//
|
|
73
|
-
//
|
|
74
|
-
// contract test asserts that source path directly so this regression cannot
|
|
75
|
-
// hide behind otherwise-valid configLibrary schema markers again.
|
|
70
|
+
// Keep the desktop build, its embedded Claude Code manifest, and every
|
|
71
|
+
// renderer patch on one exact reviewed release. The pinned contract test
|
|
72
|
+
// asserts the managed desktop-Code access path directly so that regression
|
|
73
|
+
// cannot hide behind otherwise-valid configLibrary schema markers.
|
|
76
74
|
claude: Object.freeze({
|
|
77
|
-
version: "1.
|
|
78
|
-
claudeCodeVersion: "2.1.
|
|
79
|
-
claudeCodeCommit: "
|
|
75
|
+
version: "1.26832.0",
|
|
76
|
+
claudeCodeVersion: "2.1.222",
|
|
77
|
+
claudeCodeCommit: "fbf49312c28437bf9c2546b9ace3bd7b34eb6ff6",
|
|
80
78
|
bundleName: "Claude.app",
|
|
81
79
|
windows: Object.freeze({
|
|
82
80
|
packageName: "Claude",
|
|
83
|
-
packageVersion: "1.
|
|
81
|
+
packageVersion: "1.26832.0.0",
|
|
84
82
|
publisher: 'CN="Anthropic, PBC", O="Anthropic, PBC", L=San Francisco, S=California, C=US, SERIALNUMBER=4860621, OID.2.5.4.15=Private Organization, OID.1.3.6.1.4.1.311.60.2.1.2=Delaware, OID.1.3.6.1.4.1.311.60.2.1.3=US',
|
|
85
83
|
executable: "app\\Claude.exe",
|
|
86
84
|
downloads: Object.freeze({
|
|
87
85
|
arm64: Object.freeze({
|
|
88
|
-
url: "https://downloads.claude.ai/releases/win32/arm64/1.
|
|
89
|
-
sha256: "
|
|
86
|
+
url: "https://downloads.claude.ai/releases/win32/arm64/1.26832.0/Claude-056ee2be623b207f6a4d24dfb1b2fb5a82db0ecf.msix",
|
|
87
|
+
sha256: "16f9f9b074b1ce1bbc67c7facfd2279825c6b15b6abee28ccf7fedffe3e23a23",
|
|
90
88
|
}),
|
|
91
89
|
x64: Object.freeze({
|
|
92
|
-
url: "https://downloads.claude.ai/releases/win32/x64/1.
|
|
93
|
-
sha256: "
|
|
90
|
+
url: "https://downloads.claude.ai/releases/win32/x64/1.26832.0/Claude-056ee2be623b207f6a4d24dfb1b2fb5a82db0ecf.msix",
|
|
91
|
+
sha256: "6dc210bca31b55c9fa307d11c6b13a42c7f3a3886ccc35ca2ecb7e9fceba0139",
|
|
94
92
|
}),
|
|
95
93
|
}),
|
|
96
94
|
}),
|
|
97
95
|
downloads: Object.freeze({
|
|
98
96
|
arm64: Object.freeze({
|
|
99
|
-
url: "https://downloads.claude.ai/releases/darwin/universal/1.
|
|
100
|
-
sha256: "
|
|
97
|
+
url: "https://downloads.claude.ai/releases/darwin/universal/1.26832.0/Claude-056ee2be623b207f6a4d24dfb1b2fb5a82db0ecf.zip",
|
|
98
|
+
sha256: "6b0f2c51c5e1c3f6db3885233ad96e48f92e61438b0bd9892c69f2ea11c54950",
|
|
101
99
|
}),
|
|
102
100
|
x64: Object.freeze({
|
|
103
|
-
url: "https://downloads.claude.ai/releases/darwin/universal/1.
|
|
104
|
-
sha256: "
|
|
101
|
+
url: "https://downloads.claude.ai/releases/darwin/universal/1.26832.0/Claude-056ee2be623b207f6a4d24dfb1b2fb5a82db0ecf.zip",
|
|
102
|
+
sha256: "6b0f2c51c5e1c3f6db3885233ad96e48f92e61438b0bd9892c69f2ea11c54950",
|
|
105
103
|
}),
|
|
106
104
|
}),
|
|
107
105
|
}),
|
|
108
106
|
chatgpt: Object.freeze({
|
|
109
|
-
version: "26.
|
|
110
|
-
codexVersion: "0.
|
|
107
|
+
version: "26.803.41515",
|
|
108
|
+
codexVersion: "0.147.0-alpha.6.5",
|
|
111
109
|
bundleName: "ChatGPT.app",
|
|
112
110
|
windows: Object.freeze({
|
|
113
111
|
storeProductId: "9PLM9XGG6VKS",
|
|
@@ -123,12 +121,12 @@ export const PINNED_VENDOR_APPS = Object.freeze({
|
|
|
123
121
|
}),
|
|
124
122
|
downloads: Object.freeze({
|
|
125
123
|
arm64: Object.freeze({
|
|
126
|
-
url: "https://persistent.oaistatic.com/codex-app-prod/ChatGPT-darwin-arm64-26.
|
|
127
|
-
sha256: "
|
|
124
|
+
url: "https://persistent.oaistatic.com/codex-app-prod/ChatGPT-darwin-arm64-26.803.41515.zip",
|
|
125
|
+
sha256: "8abd46bf063bc27cbadcbc2863007ac44365b13a23ede17ceaee81fb9eeaeb9a",
|
|
128
126
|
}),
|
|
129
127
|
x64: Object.freeze({
|
|
130
|
-
url: "https://persistent.oaistatic.com/codex-app-prod/ChatGPT-darwin-x64-26.
|
|
131
|
-
sha256: "
|
|
128
|
+
url: "https://persistent.oaistatic.com/codex-app-prod/ChatGPT-darwin-x64-26.803.41515.zip",
|
|
129
|
+
sha256: "87239a3dd12e2761de515ee78a0b73c02ac907c34c1f01a68dd6f093cf433fb1",
|
|
132
130
|
}),
|
|
133
131
|
}),
|
|
134
132
|
}),
|
|
@@ -149,14 +147,14 @@ const CHATGPT_THREAD_FORK_PROVIDER = /let ([A-Za-z_$][\w$]*)=\{\.\.\.([A-Za-z_$]
|
|
|
149
147
|
const CHATGPT_THREAD_RESUME_PROVIDER = /modelProvider:null,cwd:([A-Za-z_$][\w$]*)\?\.cwd\?\?null,approvalPolicy:null,sandbox:null,config:\1\?\.config\?\?null,developerInstructions:\1\?\.developerInstructions\?\?void 0/gu;
|
|
150
148
|
const CHATGPT_STRUCTURED_PROVIDER_FALLBACK = /allowProviderModelFallback:!0/gu;
|
|
151
149
|
const CHATGPT_RESOURCE_ROOT = "linked_vendor_resources_with_patched_asar";
|
|
152
|
-
const CLAUDE_PLAN_USAGE_GUARD = "if(!
|
|
153
|
-
const IMPEL_CLAUDE_PLAN_USAGE_GUARD = `if(!
|
|
154
|
-
const CLAUDE_DRAFT_AGENT_MENTIONS = 'agentMentionsEnabled:"draft"===
|
|
155
|
-
const IMPEL_CLAUDE_BOUND_AGENT_MENTIONS = 'agentMentionsEnabled:"draft"===
|
|
150
|
+
const CLAUDE_PLAN_USAGE_GUARD = "if(!Pi()){ua();return}if(!d.an().hasOrgPolicyBackend())return;let r=p.n();";
|
|
151
|
+
const IMPEL_CLAUDE_PLAN_USAGE_GUARD = `if(!Pi()){ua();return}${"".padEnd("if(!d.an().hasOrgPolicyBackend())return;".length, " ")}let r=p.n();`;
|
|
152
|
+
const CLAUDE_DRAFT_AGENT_MENTIONS = 'agentMentionsEnabled:"draft"===Ke&&t';
|
|
153
|
+
const IMPEL_CLAUDE_BOUND_AGENT_MENTIONS = 'agentMentionsEnabled:"draft"===Ke?t:E?.agent??!1';
|
|
156
154
|
const CLAUDE_AGENT_MENTION_FILTER = 'return e.filter(e=>"user"===e.source&&(!n||e.name.toLowerCase().includes(n))).slice(0,10)';
|
|
157
|
-
const IMPEL_CLAUDE_BOUND_AGENT_MENTION_FILTER = 'return e.filter(e=>"user"===e.source&&(!n||e.name.toLowerCase().includes(n))&&("string"!=typeof
|
|
155
|
+
const IMPEL_CLAUDE_BOUND_AGENT_MENTION_FILTER = 'return e.filter(e=>"user"===e.source&&(!n||e.name.toLowerCase().includes(n))&&("string"!=typeof v||e.name===v)).slice(0,10)';
|
|
158
156
|
const CLAUDE_AGENT_MENTION_SELECT = 'onSelect:t=>(e(String(t)),Promise.resolve(null))';
|
|
159
|
-
const IMPEL_CLAUDE_BOUND_AGENT_MENTION_SELECT = 'onSelect:t=>"string"==typeof
|
|
157
|
+
const IMPEL_CLAUDE_BOUND_AGENT_MENTION_SELECT = 'onSelect:t=>"string"==typeof v?Promise.resolve({chipText:String(t)}):(e(String(t)),Promise.resolve(null))';
|
|
160
158
|
const LEGACY_CLAUDE_SAFE_STORAGE_NAME = "Claude";
|
|
161
159
|
const CLAUDE_SAFE_STORAGE_METADATA = "safe-storage.json";
|
|
162
160
|
// The pinned Claude renderer decides desktop-vs-web mode SOLELY by matching its
|
|
@@ -301,7 +299,7 @@ export const CURRENT_CONFIG_VERSION = 32;
|
|
|
301
299
|
// — which is what made every `impel update` re-trigger macOS permission
|
|
302
300
|
// prompts. Bump this ONLY when a code change alters the bytes of a built
|
|
303
301
|
// bundle; leave it alone for changes that don't touch bundle contents.
|
|
304
|
-
export const BUNDLE_BUILD_FINGERPRINT = "bundle-2026-08-08.
|
|
302
|
+
export const BUNDLE_BUILD_FINGERPRINT = "bundle-2026-08-08.4";
|
|
305
303
|
|
|
306
304
|
/** Parse the tenant's install manifest, or null when absent/corrupt. */
|
|
307
305
|
export function readTenantManifest(homeDir = os.homedir(), tenantId = null) {
|
|
@@ -2102,11 +2100,61 @@ function patchFixedWidthAsarString(asarPath, original, replacement, label) {
|
|
|
2102
2100
|
return applyFixedWidthAsarPatches(asarPath, archive, patches, label);
|
|
2103
2101
|
}
|
|
2104
2102
|
|
|
2103
|
+
function exportedAsarSymbol(source, localSymbol) {
|
|
2104
|
+
const match = source.match(new RegExp(
|
|
2105
|
+
`Object\\.defineProperty\\(exports,"([^"]+)",\\{enumerable:!0,get:function\\(\\)\\{return ${escapeRegex(localSymbol)}\\}\\}\\)`,
|
|
2106
|
+
"u",
|
|
2107
|
+
));
|
|
2108
|
+
return match?.[1] ?? null;
|
|
2109
|
+
}
|
|
2110
|
+
|
|
2111
|
+
function claudeModularCredentialExpression(archive, requestOffset) {
|
|
2112
|
+
const metadata = readAsarMetadata(archive);
|
|
2113
|
+
const requestRecord = findAsarEntryRecord(metadata.header, metadata.dataOffset, requestOffset);
|
|
2114
|
+
const requestStart = metadata.dataOffset + Number(requestRecord.entry.offset);
|
|
2115
|
+
const requestSource = archive.subarray(
|
|
2116
|
+
requestStart,
|
|
2117
|
+
requestStart + Number(requestRecord.entry.size),
|
|
2118
|
+
).toString("latin1");
|
|
2119
|
+
const importPattern = /([A-Za-z_$][\w$]*)=require\("([^"\n]+)"\)/gu;
|
|
2120
|
+
|
|
2121
|
+
for (const imported of requestSource.matchAll(importPattern)) {
|
|
2122
|
+
const importedPath = path.posix.normalize(path.posix.join(
|
|
2123
|
+
path.posix.dirname(requestRecord.path),
|
|
2124
|
+
imported[2],
|
|
2125
|
+
));
|
|
2126
|
+
const importedEntry = findAsarEntryByPath(metadata.header, importedPath);
|
|
2127
|
+
if (!importedEntry) continue;
|
|
2128
|
+
const importedStart = metadata.dataOffset + Number(importedEntry.offset);
|
|
2129
|
+
const importedSource = archive.subarray(
|
|
2130
|
+
importedStart,
|
|
2131
|
+
importedStart + Number(importedEntry.size),
|
|
2132
|
+
).toString("latin1");
|
|
2133
|
+
if (!importedSource.includes("[custom-3p] Credentials loaded from managed config")) continue;
|
|
2134
|
+
|
|
2135
|
+
const credentialParser = importedSource.match(
|
|
2136
|
+
/([A-Za-z_$][\w$]*)=([A-Za-z_$][\w$]*)\(e,([A-Za-z_$][\w$]*)\(\)\),\1&&[\s\S]{0,250}?\[custom-3p\] Credentials loaded from managed config/u,
|
|
2137
|
+
);
|
|
2138
|
+
const configAccessor = importedSource.match(
|
|
2139
|
+
/function ([A-Za-z_$][\w$]*)\(e\)\{let ([A-Za-z_$][\w$]*)=[A-Za-z_$][\w$]*\(\);return e\?\.ignoreScopes\?[\s\S]{0,200}?\2\.config\}/u,
|
|
2140
|
+
)?.[1];
|
|
2141
|
+
if (!credentialParser || !configAccessor) continue;
|
|
2142
|
+
|
|
2143
|
+
const parserExport = exportedAsarSymbol(importedSource, credentialParser[2]);
|
|
2144
|
+
const errorsExport = exportedAsarSymbol(importedSource, credentialParser[3]);
|
|
2145
|
+
const configExport = exportedAsarSymbol(importedSource, configAccessor);
|
|
2146
|
+
if (!parserExport || !errorsExport || !configExport) continue;
|
|
2147
|
+
const namespace = imported[1];
|
|
2148
|
+
return `${namespace}.${parserExport}(${namespace}.${configExport}(),${namespace}.${errorsExport}()).apiKey`;
|
|
2149
|
+
}
|
|
2150
|
+
return null;
|
|
2151
|
+
}
|
|
2152
|
+
|
|
2105
2153
|
function patchClaudePlanUsageRequest(asarPath) {
|
|
2106
2154
|
const archive = fs.readFileSync(asarPath);
|
|
2107
2155
|
const source = archive.toString("latin1");
|
|
2108
2156
|
const credentialAccessor = source.match(
|
|
2109
|
-
/function ([A-Za-z_$][\w$]*)\(e\)\{var t;return [\s\S]{0,500}?\[custom-3p\] Credentials loaded from managed config/u,
|
|
2157
|
+
/function ([A-Za-z_$][\w$]*)\(e\)\{(?:var t;)?return [\s\S]{0,500}?\[custom-3p\] Credentials loaded from managed config/u,
|
|
2110
2158
|
)?.[1];
|
|
2111
2159
|
if (!credentialAccessor) {
|
|
2112
2160
|
return applyFixedWidthAsarPatches(asarPath, archive, [], "Claude plan-usage gateway request");
|
|
@@ -2116,14 +2164,16 @@ function patchClaudePlanUsageRequest(asarPath) {
|
|
|
2116
2164
|
"u",
|
|
2117
2165
|
);
|
|
2118
2166
|
const configAccessor = source.match(configAccessorPattern)?.[1];
|
|
2119
|
-
|
|
2120
|
-
return applyFixedWidthAsarPatches(asarPath, archive, [], "Claude plan-usage gateway request");
|
|
2121
|
-
}
|
|
2122
|
-
|
|
2123
|
-
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;
|
|
2167
|
+
const requestPattern = /(?:const|let) ([A-Za-z_$][\w$]*)=`\$\{[A-Za-z_$][\w$]*(?:\.[A-Za-z_$][\w$]*)?\(\)\}\/api\/organizations\/\$\{[A-Za-z_$][\w$]*\}\/usage\$\{[A-Za-z_$][\w$]*\?(?:"\?skip_spend=1"|`\?skip_spend=1`):(?:""|``)\}`,([A-Za-z_$][\w$]*)=await ([A-Za-z_$][\w$]*)\.net\.fetch\(\1,\{signal:AbortSignal\.timeout\([A-Za-z_$][\w$]*\)\}\)/gu;
|
|
2124
2168
|
const patches = [...source.matchAll(requestPattern)].map((match) => {
|
|
2125
2169
|
const original = match[0];
|
|
2126
|
-
const
|
|
2170
|
+
const credentialExpression = configAccessor
|
|
2171
|
+
? `${credentialAccessor}(${configAccessor}()).apiKey`
|
|
2172
|
+
: claudeModularCredentialExpression(archive, match.index);
|
|
2173
|
+
if (!credentialExpression) {
|
|
2174
|
+
throw new Error("this desktop app version has an unsupported Claude plan-usage gateway credential accessor; update impel-cli before installing it");
|
|
2175
|
+
}
|
|
2176
|
+
const replacement = `const ${match[1]}="https://gateway.useimpel.com/ui/a/u",${match[2]}=await ${match[3]}.net.fetch(${match[1]},{headers:{key:${credentialExpression}}})`;
|
|
2127
2177
|
if (replacement.length > original.length) {
|
|
2128
2178
|
throw new Error("Claude plan-usage gateway request replacement no longer fits the vendor ASAR contract");
|
|
2129
2179
|
}
|
|
@@ -2135,7 +2185,7 @@ function patchClaudePlanUsageRequest(asarPath) {
|
|
|
2135
2185
|
function patchClaudeSafeStorageName(asarPath) {
|
|
2136
2186
|
const archive = fs.readFileSync(asarPath);
|
|
2137
2187
|
const source = archive.toString("latin1");
|
|
2138
|
-
const startupPattern = /([A-Za-z_$][\w$]*)\.app\.isPackaged\|\|\1\.app\.setName\("Claude"\)/gu;
|
|
2188
|
+
const startupPattern = /([A-Za-z_$][\w$]*)\.app\.isPackaged\|\|\1\.app\.setName\((?:"Claude"|`Claude`)\)/gu;
|
|
2139
2189
|
const patches = [...source.matchAll(startupPattern)].map((match) => {
|
|
2140
2190
|
const original = match[0];
|
|
2141
2191
|
const replacement = `${match[1]}.app.setName(process.env.IMPEL_CN)`;
|
|
@@ -2165,10 +2215,41 @@ function patchFastModeAuthGate(asarPath) {
|
|
|
2165
2215
|
}
|
|
2166
2216
|
|
|
2167
2217
|
function patchDesktopTasksPreload(asarPath, target) {
|
|
2218
|
+
const legacyClaudeFooter = "//# sourceMappingURL=index.pre.js.map\n";
|
|
2168
2219
|
const footer = target === "claude"
|
|
2169
|
-
?
|
|
2220
|
+
? legacyClaudeFooter
|
|
2170
2221
|
: "//# sourceMappingURL=early-bootstrap.js.map";
|
|
2171
2222
|
const loader = "require(process.env.IMPEL_DT)";
|
|
2223
|
+
if (target === "claude") {
|
|
2224
|
+
const archive = fs.readFileSync(asarPath);
|
|
2225
|
+
const source = archive.toString("latin1");
|
|
2226
|
+
const legacyMatches = exactTextMatchCount(source, legacyClaudeFooter);
|
|
2227
|
+
if (legacyMatches === 0) {
|
|
2228
|
+
const appNameMatches = [...source.matchAll(/[A-Za-z_$][\w$]*\.app\.setName\(process\.env\.IMPEL_CN\)/gu)];
|
|
2229
|
+
if (appNameMatches.length !== 1) {
|
|
2230
|
+
return applyFixedWidthAsarPatches(asarPath, archive, [], "Claude desktop Tasks preload");
|
|
2231
|
+
}
|
|
2232
|
+
const metadata = readAsarMetadata(archive);
|
|
2233
|
+
const record = findAsarEntryRecord(metadata.header, metadata.dataOffset, appNameMatches[0].index);
|
|
2234
|
+
const currentFooter = "//# sourceMappingURL=index.js.map";
|
|
2235
|
+
const footerOffset = metadata.dataOffset + Number(record.entry.offset) + Number(record.entry.size)
|
|
2236
|
+
- Buffer.byteLength(currentFooter, "latin1");
|
|
2237
|
+
if (source.slice(footerOffset, footerOffset + currentFooter.length) !== currentFooter) {
|
|
2238
|
+
return applyFixedWidthAsarPatches(asarPath, archive, [], "Claude desktop Tasks preload");
|
|
2239
|
+
}
|
|
2240
|
+
if (loader.length >= currentFooter.length) {
|
|
2241
|
+
throw new Error("desktop Tasks preload no longer fits the vendor ASAR contract");
|
|
2242
|
+
}
|
|
2243
|
+
return applyFixedWidthAsarPatches(asarPath, archive, [{
|
|
2244
|
+
offset: footerOffset,
|
|
2245
|
+
original: currentFooter,
|
|
2246
|
+
replacement: loader.padEnd(currentFooter.length, " "),
|
|
2247
|
+
}], "Claude desktop Tasks preload");
|
|
2248
|
+
}
|
|
2249
|
+
if (legacyMatches !== 1) {
|
|
2250
|
+
return applyFixedWidthAsarPatches(asarPath, archive, [], "Claude desktop Tasks preload");
|
|
2251
|
+
}
|
|
2252
|
+
}
|
|
2172
2253
|
const trailingNewline = footer.endsWith("\n") ? "\n" : "";
|
|
2173
2254
|
if (loader.length >= footer.length - trailingNewline.length) {
|
|
2174
2255
|
throw new Error("desktop Tasks preload no longer fits the vendor ASAR contract");
|
|
@@ -2324,23 +2405,36 @@ function readAsarMetadata(archive) {
|
|
|
2324
2405
|
return { dataOffset, header, headerLength };
|
|
2325
2406
|
}
|
|
2326
2407
|
|
|
2327
|
-
function
|
|
2408
|
+
function findAsarEntryRecord(header, dataOffset, archiveOffset) {
|
|
2328
2409
|
const relativeOffset = archiveOffset - dataOffset;
|
|
2329
2410
|
let found = null;
|
|
2330
|
-
const visit = (directory) => {
|
|
2331
|
-
for (const entry of Object.
|
|
2332
|
-
|
|
2411
|
+
const visit = (directory, parent = "") => {
|
|
2412
|
+
for (const [name, entry] of Object.entries(directory?.files || {})) {
|
|
2413
|
+
const entryPath = parent ? `${parent}/${name}` : name;
|
|
2414
|
+
if (entry.files) visit(entry, entryPath);
|
|
2333
2415
|
else if (entry.offset != null) {
|
|
2334
2416
|
const start = Number(entry.offset);
|
|
2335
|
-
if (start <= relativeOffset && relativeOffset < start + Number(entry.size))
|
|
2417
|
+
if (start <= relativeOffset && relativeOffset < start + Number(entry.size)) {
|
|
2418
|
+
found = { entry, path: entryPath };
|
|
2419
|
+
}
|
|
2336
2420
|
}
|
|
2337
2421
|
}
|
|
2338
2422
|
};
|
|
2339
2423
|
visit(header);
|
|
2340
|
-
if (!found?.integrity) throw new Error("Fast-mode renderer asset has no supported ASAR integrity metadata");
|
|
2424
|
+
if (!found?.entry?.integrity) throw new Error("Fast-mode renderer asset has no supported ASAR integrity metadata");
|
|
2341
2425
|
return found;
|
|
2342
2426
|
}
|
|
2343
2427
|
|
|
2428
|
+
function findAsarEntry(header, dataOffset, archiveOffset) {
|
|
2429
|
+
return findAsarEntryRecord(header, dataOffset, archiveOffset).entry;
|
|
2430
|
+
}
|
|
2431
|
+
|
|
2432
|
+
function findAsarEntryByPath(header, targetPath) {
|
|
2433
|
+
let current = header;
|
|
2434
|
+
for (const part of targetPath.split("/")) current = current?.files?.[part];
|
|
2435
|
+
return current?.offset != null ? current : null;
|
|
2436
|
+
}
|
|
2437
|
+
|
|
2344
2438
|
function updateAsarEntryIntegrity(archive, dataOffset, entry) {
|
|
2345
2439
|
const start = dataOffset + Number(entry.offset);
|
|
2346
2440
|
const contents = archive.subarray(start, start + Number(entry.size));
|
package/src/desktopTasks.js
CHANGED
|
@@ -509,12 +509,16 @@ if (
|
|
|
509
509
|
const parseBounds = (url, window) => {
|
|
510
510
|
const parsed = new URL(url);
|
|
511
511
|
const content = window.getContentBounds();
|
|
512
|
+
const interactiveTop = process.platform === "darwin" ? 48 : 0;
|
|
512
513
|
const number = (name, fallback) => {
|
|
513
514
|
const value = Number.parseInt(parsed.searchParams.get(name) || "", 10);
|
|
514
515
|
return Number.isFinite(value) ? value : fallback;
|
|
515
516
|
};
|
|
516
517
|
const x = Math.max(0, Math.min(content.width - 240, number("x", 0)));
|
|
517
|
-
const y = Math.max(
|
|
518
|
+
const y = Math.max(
|
|
519
|
+
interactiveTop,
|
|
520
|
+
Math.min(content.height - 240, number("y", 0)),
|
|
521
|
+
);
|
|
518
522
|
return {
|
|
519
523
|
x,
|
|
520
524
|
y,
|
|
@@ -606,7 +610,13 @@ if (
|
|
|
606
610
|
const nativeBoardBounds = (window) => {
|
|
607
611
|
const content = window.getContentBounds();
|
|
608
612
|
const x = Math.min(296, Math.max(0, content.width - 240));
|
|
609
|
-
|
|
613
|
+
const interactiveTop = process.platform === "darwin" ? 48 : 0;
|
|
614
|
+
return {
|
|
615
|
+
x,
|
|
616
|
+
y: interactiveTop,
|
|
617
|
+
width: Math.max(240, content.width - x),
|
|
618
|
+
height: Math.max(240, content.height - interactiveTop),
|
|
619
|
+
};
|
|
610
620
|
};
|
|
611
621
|
|
|
612
622
|
const layoutNativeNav = (window) => {
|
|
@@ -825,7 +835,15 @@ if (
|
|
|
825
835
|
}
|
|
826
836
|
if (request?.method === "tools/call") {
|
|
827
837
|
const name = request?.params?.name;
|
|
828
|
-
const allowed = new Set([
|
|
838
|
+
const allowed = new Set([
|
|
839
|
+
"show_tasks",
|
|
840
|
+
"list_tasks",
|
|
841
|
+
"get_task",
|
|
842
|
+
"list_members",
|
|
843
|
+
"create_task",
|
|
844
|
+
"update_task",
|
|
845
|
+
"delete_task",
|
|
846
|
+
]);
|
|
829
847
|
if (!allowed.has(name)) throw new Error("Unsupported Tasks tool.");
|
|
830
848
|
const args = request?.params?.arguments;
|
|
831
849
|
if (args != null && (typeof args !== "object" || Array.isArray(args))) {
|
package/src/vendorCliVersions.js
CHANGED
|
@@ -2,6 +2,6 @@
|
|
|
2
2
|
// Windows installers on the same versions; do not replace these with moving
|
|
3
3
|
// channels such as "stable" or "latest".
|
|
4
4
|
export const PINNED_VENDOR_CLI_VERSIONS = Object.freeze({
|
|
5
|
-
claude: "2.1.
|
|
6
|
-
codex: "0.
|
|
5
|
+
claude: "2.1.220",
|
|
6
|
+
codex: "0.147.0",
|
|
7
7
|
});
|