impel-cli 0.20.32 → 0.20.34
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 +11 -10
- package/RELEASE_NOTES.md +21 -0
- package/docs/native-agent-host-capability-matrix.md +4 -4
- package/package.json +1 -1
- package/src/agents.js +4 -4
- package/src/apps.js +1 -1
- package/src/desktopTasks.js +53 -18
package/README.md
CHANGED
|
@@ -187,16 +187,17 @@ it by exact agent ID (preferred) or unique exact title:
|
|
|
187
187
|
impel codex --agent research-agent exec "answer this question"
|
|
188
188
|
```
|
|
189
189
|
|
|
190
|
-
This path loads a generated, tenant-bound profile with
|
|
191
|
-
for the thin adapter turns, a read-only local
|
|
192
|
-
binding, and only that binding's answer/run,
|
|
193
|
-
omits unrelated local repository, app,
|
|
194
|
-
and skill-catalog prompt context; the
|
|
195
|
-
substantive work. The path also omits
|
|
196
|
-
so there is no parent spawn, parent
|
|
197
|
-
developer-instruction, MCP, approval,
|
|
198
|
-
with `--agent`. The selected
|
|
199
|
-
Codex starts. Ordinary `impel
|
|
190
|
+
This path loads a generated, tenant-bound profile with the ultra-fast Codex
|
|
191
|
+
Spark model at low reasoning for the thin adapter turns, a read-only local
|
|
192
|
+
sandbox, the exact fixed MCP binding, and only that binding's answer/run,
|
|
193
|
+
resume, and recovery tools. It omits unrelated local repository, app,
|
|
194
|
+
collaboration, permission, environment, and skill-catalog prompt context; the
|
|
195
|
+
selected Eve agent still performs the substantive work. The path also omits
|
|
196
|
+
the normal parent specialist instructions, so there is no parent spawn, parent
|
|
197
|
+
wait, or relay turn. Model, profile, developer-instruction, MCP, approval,
|
|
198
|
+
sandbox, and feature overrides are rejected with `--agent`. The selected
|
|
199
|
+
tenant and profile integrity must match before Codex starts. Ordinary `impel
|
|
200
|
+
codex` passthrough is unchanged.
|
|
200
201
|
|
|
201
202
|
## Remote Fargate sessions
|
|
202
203
|
|
package/RELEASE_NOTES.md
CHANGED
|
@@ -1,5 +1,26 @@
|
|
|
1
1
|
# Release notes
|
|
2
2
|
|
|
3
|
+
## 0.20.34 — Stabilize desktop Tasks navigation
|
|
4
|
+
|
|
5
|
+
- Places Tasks immediately after Claude's persistent Home/Code switcher in both
|
|
6
|
+
modes and uses the New row as its visual template, so the destination no
|
|
7
|
+
longer jumps above the switcher when the selected mode changes.
|
|
8
|
+
- Prefers matching controls inside the host sidebar, preventing similarly named
|
|
9
|
+
content controls from moving the injected destination into the main surface.
|
|
10
|
+
- Preserves ChatGPT/Codex placement immediately before Pull requests and
|
|
11
|
+
rebuilds existing managed bundles onto the corrected navigation contract.
|
|
12
|
+
|
|
13
|
+
## 0.20.33 — Faster Codex native-agent relay
|
|
14
|
+
|
|
15
|
+
- Uses the ultra-fast Codex Spark model at low reasoning for fixed-binding
|
|
16
|
+
native-agent adapter turns; the selected Eve agent still owns the substantive
|
|
17
|
+
task and model choice.
|
|
18
|
+
- Preserves the direct-only MCP allowlist, read-only sandbox, durable
|
|
19
|
+
continuation recovery, and minimal host prompt while reducing long-answer
|
|
20
|
+
relay latency.
|
|
21
|
+
- Advances the managed profile manifest so existing CLI and Desktop adapters
|
|
22
|
+
refresh immediately on update.
|
|
23
|
+
|
|
3
24
|
## 0.20.32 — Recover transient managed access misses
|
|
4
25
|
|
|
5
26
|
- Retries one exact MCP request when the gateway reports its specific managed
|
|
@@ -37,10 +37,10 @@ is treated as an eager host.
|
|
|
37
37
|
and re-qualified rather than receiving unknown configuration.
|
|
38
38
|
- `mcp__impel_agent` is the native tool namespace. The server id
|
|
39
39
|
`impel_agent` is not equivalent and does not qualify as direct exposure.
|
|
40
|
-
- Generated Codex fixed-binding adapters use
|
|
41
|
-
tool-selection and terminal-relay turns, with
|
|
42
|
-
catalog context disabled. The selected Eve
|
|
43
|
-
still owns the substantive task.
|
|
40
|
+
- Generated Codex fixed-binding adapters use the ultra-fast Codex Spark model
|
|
41
|
+
at low reasoning for the thin tool-selection and terminal-relay turns, with
|
|
42
|
+
unrelated local host and skill-catalog context disabled. The selected Eve
|
|
43
|
+
agent, not this wrapper model, still owns the substantive task.
|
|
44
44
|
|
|
45
45
|
## Requalification
|
|
46
46
|
|
package/package.json
CHANGED
package/src/agents.js
CHANGED
|
@@ -55,12 +55,12 @@ export const NATIVE_AGENT_RESUME_TOOL = "resume_native_agent_run";
|
|
|
55
55
|
export const NATIVE_AGENT_RECOVER_TOOL = "recover_native_agent_runs";
|
|
56
56
|
export const NATIVE_AGENT_CONTINUATION_SCHEMA = "impel.native-agent-continuation.v1";
|
|
57
57
|
export const MANAGED_AGENT_MCP_SERVER = "impel_agent";
|
|
58
|
-
export const MANAGED_AGENT_MANIFEST_VERSION =
|
|
58
|
+
export const MANAGED_AGENT_MANIFEST_VERSION = 19;
|
|
59
59
|
|
|
60
60
|
// The host model only selects the fixed MCP tool and faithfully returns its
|
|
61
|
-
// result.
|
|
62
|
-
//
|
|
63
|
-
const CODEX_AGENT_ADAPTER_MODEL = "gpt-5.
|
|
61
|
+
// result. Spark minimizes those transport-only turns while the selected Eve
|
|
62
|
+
// agent remains responsible for the substantive work.
|
|
63
|
+
const CODEX_AGENT_ADAPTER_MODEL = "gpt-5.3-codex-spark";
|
|
64
64
|
|
|
65
65
|
const NATIVE_AGENT_TOOL_NAMES = [
|
|
66
66
|
NATIVE_AGENT_RUN_TOOL,
|
package/src/apps.js
CHANGED
|
@@ -299,7 +299,7 @@ export const CURRENT_CONFIG_VERSION = 32;
|
|
|
299
299
|
// — which is what made every `impel update` re-trigger macOS permission
|
|
300
300
|
// prompts. Bump this ONLY when a code change alters the bytes of a built
|
|
301
301
|
// bundle; leave it alone for changes that don't touch bundle contents.
|
|
302
|
-
export const BUNDLE_BUILD_FINGERPRINT = "bundle-2026-08-
|
|
302
|
+
export const BUNDLE_BUILD_FINGERPRINT = "bundle-2026-08-09.3";
|
|
303
303
|
|
|
304
304
|
/** Parse the tenant's install manifest, or null when absent/corrupt. */
|
|
305
305
|
export function readTenantManifest(homeDir = os.homedir(), tenantId = null) {
|
package/src/desktopTasks.js
CHANGED
|
@@ -2,6 +2,19 @@ import path from "node:path";
|
|
|
2
2
|
|
|
3
3
|
export const DESKTOP_TASKS_RESOURCE_URI = "ui://impel/tasks/v1/index.html";
|
|
4
4
|
|
|
5
|
+
// Claude's mode switch is the stable landmark across Home and Code, but its
|
|
6
|
+
// plain New row is the visual template. ChatGPT/Codex keeps the established
|
|
7
|
+
// position immediately before Pull requests.
|
|
8
|
+
export const DESKTOP_TASKS_NAV_ANCHOR_RULES = Object.freeze([
|
|
9
|
+
{ pattern: "^pull requests?\\b", position: "before" },
|
|
10
|
+
{ pattern: "^code\\b", position: "after", template: "^new\\b" },
|
|
11
|
+
{ pattern: "^(?:start\\s+)?new\\s+(?:chat|thread)\\b", position: "before" },
|
|
12
|
+
{ pattern: "^new\\b", position: "before" },
|
|
13
|
+
{ pattern: "^scheduled\\b", position: "before" },
|
|
14
|
+
{ pattern: "^plugins?\\b", position: "before" },
|
|
15
|
+
{ pattern: "^cowork\\b", position: "before" },
|
|
16
|
+
]);
|
|
17
|
+
|
|
5
18
|
export function desktopTasksAssetPaths(root) {
|
|
6
19
|
const directory = path.join(root, "desktop-tasks");
|
|
7
20
|
return {
|
|
@@ -12,10 +25,17 @@ export function desktopTasksAssetPaths(root) {
|
|
|
12
25
|
};
|
|
13
26
|
}
|
|
14
27
|
|
|
28
|
+
const NAV_ANCHOR_RULES_SOURCE = JSON.stringify(DESKTOP_TASKS_NAV_ANCHOR_RULES);
|
|
29
|
+
|
|
15
30
|
const NAVIGATION_SOURCE = String.raw`(() => {
|
|
16
31
|
const NAV_ID = "impel-desktop-tasks-nav";
|
|
17
32
|
const NAV_SLOT_ID = "impel-desktop-tasks-nav-slot";
|
|
18
33
|
const ACTIVE_CLASS = "impel-desktop-tasks-active";
|
|
34
|
+
const NAV_ANCHOR_RULES = ${NAV_ANCHOR_RULES_SOURCE}.map((rule) => ({
|
|
35
|
+
...rule,
|
|
36
|
+
pattern: new RegExp(rule.pattern, "i"),
|
|
37
|
+
template: rule.template ? new RegExp(rule.template, "i") : null,
|
|
38
|
+
}));
|
|
19
39
|
const TASKS_ICON = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="3" y="3" width="18" height="18" rx="2"></rect><path d="M9 3v18"></path><path d="M15 3v18"></path></svg>';
|
|
20
40
|
if (window.__impelDesktopTasksCleanup) window.__impelDesktopTasksCleanup();
|
|
21
41
|
|
|
@@ -56,6 +76,12 @@ const NAVIGATION_SOURCE = String.raw`(() => {
|
|
|
56
76
|
|
|
57
77
|
const findControl = (pattern) => {
|
|
58
78
|
const matches = controls().filter((element) => pattern.test(label(element)));
|
|
79
|
+
const sidebar = findSidebar();
|
|
80
|
+
if (sidebar) {
|
|
81
|
+
const sidebarMatch = matches.find((element) => sidebar.contains(element) && visible(element))
|
|
82
|
+
|| matches.find((element) => sidebar.contains(element));
|
|
83
|
+
if (sidebarMatch) return sidebarMatch;
|
|
84
|
+
}
|
|
59
85
|
return matches.find(visible) || matches[0] || null;
|
|
60
86
|
};
|
|
61
87
|
|
|
@@ -134,9 +160,9 @@ const NAVIGATION_SOURCE = String.raw`(() => {
|
|
|
134
160
|
let changed = false;
|
|
135
161
|
while (walker.nextNode()) {
|
|
136
162
|
const text = walker.currentNode.nodeValue || "";
|
|
137
|
-
if (!/(?:new
|
|
163
|
+
if (!/(?:new(?:\s+(?:chat|thread))?|pull requests?|scheduled|plugins?|skills?|cowork|code)\b/i.test(text)) continue;
|
|
138
164
|
walker.currentNode.nodeValue = text.replace(
|
|
139
|
-
/(?:new
|
|
165
|
+
/(?:new(?:\s+(?:chat|thread))?|pull requests?|scheduled|plugins?|skills?|cowork|code)\b/i,
|
|
140
166
|
"Tasks",
|
|
141
167
|
);
|
|
142
168
|
changed = true;
|
|
@@ -195,32 +221,38 @@ const NAVIGATION_SOURCE = String.raw`(() => {
|
|
|
195
221
|
|
|
196
222
|
const placement = (control) => {
|
|
197
223
|
if (!control) return null;
|
|
224
|
+
const controlRect = control.getBoundingClientRect();
|
|
198
225
|
let child = control;
|
|
199
226
|
let parent = control.parentElement;
|
|
200
227
|
while (parent && parent !== document.body) {
|
|
201
|
-
const
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
228
|
+
const rect = parent.getBoundingClientRect();
|
|
229
|
+
const sameVisualRow = Math.abs(rect.top - controlRect.top) <= 8
|
|
230
|
+
&& Math.abs(rect.bottom - controlRect.bottom) <= 8;
|
|
231
|
+
if (!sameVisualRow) break;
|
|
205
232
|
child = parent;
|
|
206
233
|
parent = parent.parentElement;
|
|
207
234
|
}
|
|
208
|
-
return null;
|
|
235
|
+
return parent && parent !== document.body ? { stack: parent, child } : null;
|
|
209
236
|
};
|
|
210
237
|
|
|
211
238
|
const ensureNav = () => {
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
239
|
+
let anchorRule = null;
|
|
240
|
+
let anchor = null;
|
|
241
|
+
for (const rule of NAV_ANCHOR_RULES) {
|
|
242
|
+
anchor = findControl(rule.pattern);
|
|
243
|
+
if (anchor) {
|
|
244
|
+
anchorRule = rule;
|
|
245
|
+
break;
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
const template = anchorRule?.template ? findControl(anchorRule.template) || anchor : anchor;
|
|
218
249
|
lastAnchor = anchor;
|
|
219
|
-
if (!nav?.isConnected) nav = makeNav(
|
|
250
|
+
if (!nav?.isConnected) nav = makeNav(template);
|
|
220
251
|
const target = placement(anchor);
|
|
252
|
+
const templateTarget = placement(template);
|
|
221
253
|
if (target) {
|
|
222
254
|
if (!slot?.isConnected || (slot !== nav && !slot.contains(nav))) {
|
|
223
|
-
slot =
|
|
255
|
+
slot = templateTarget?.child === template ? nav : templateTarget?.child.cloneNode(false) || nav;
|
|
224
256
|
if (slot !== nav) {
|
|
225
257
|
slot.id = NAV_SLOT_ID;
|
|
226
258
|
slot.removeAttribute("aria-label");
|
|
@@ -228,11 +260,14 @@ const NAVIGATION_SOURCE = String.raw`(() => {
|
|
|
228
260
|
slot.append(nav);
|
|
229
261
|
}
|
|
230
262
|
}
|
|
231
|
-
|
|
232
|
-
|
|
263
|
+
const after = anchorRule?.position === "after";
|
|
264
|
+
const correctlyPlaced = slot.parentElement === target.stack
|
|
265
|
+
&& (after ? slot.previousElementSibling === target.child : slot.nextElementSibling === target.child);
|
|
266
|
+
if (!correctlyPlaced) {
|
|
267
|
+
target.stack.insertBefore(slot, after ? target.child.nextElementSibling : target.child);
|
|
233
268
|
}
|
|
234
269
|
} else if (anchor?.parentElement) {
|
|
235
|
-
anchor.insertAdjacentElement("afterend", nav);
|
|
270
|
+
anchor.insertAdjacentElement(anchorRule?.position === "after" ? "afterend" : "beforebegin", nav);
|
|
236
271
|
slot = nav;
|
|
237
272
|
} else if (!nav.isConnected) {
|
|
238
273
|
slot = null;
|