impel-cli 0.20.25 → 0.20.27
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 +9 -0
- package/package.json +1 -1
- package/scripts/analyze-native-codex.mjs +62 -0
- package/scripts/profile-native-codex.mjs +5 -0
- package/src/agents.js +8 -3
- package/src/apps.js +1 -1
- package/src/desktopTasks.js +29 -56
- package/src/nativeAgentTransport.js +17 -1
- package/src/selfInvocation.js +2 -0
package/RELEASE_NOTES.md
CHANGED
|
@@ -1,5 +1,14 @@
|
|
|
1
1
|
# Release notes
|
|
2
2
|
|
|
3
|
+
## 0.20.26 — Native task-board navigation
|
|
4
|
+
|
|
5
|
+
- Embeds Tasks in each managed desktop app's content view instead of a
|
|
6
|
+
separate always-on-top window, so selecting another sidebar destination
|
|
7
|
+
reliably dismisses the tenant board and completes the vendor navigation.
|
|
8
|
+
- Removes the redundant desktop frame around the MCP App so the task-board
|
|
9
|
+
toolbar and workspace occupy the complete host content surface.
|
|
10
|
+
- Rebuilds existing managed bundles onto the corrected embedded-view contract.
|
|
11
|
+
|
|
3
12
|
## 0.20.25 — Embedded tenant task boards
|
|
4
13
|
|
|
5
14
|
- Adds a persistent Tasks destination to the exact managed Claude and
|
package/package.json
CHANGED
|
@@ -144,6 +144,27 @@ function rolloutSessionMetadata(events) {
|
|
|
144
144
|
} : { threadId: null, parentThreadId: null };
|
|
145
145
|
}
|
|
146
146
|
|
|
147
|
+
function nativeTerminalStatus(output) {
|
|
148
|
+
if (typeof output !== "string") return null;
|
|
149
|
+
const objectStart = output.indexOf("{");
|
|
150
|
+
if (objectStart < 0) return null;
|
|
151
|
+
let value;
|
|
152
|
+
try {
|
|
153
|
+
value = JSON.parse(output.slice(objectStart));
|
|
154
|
+
} catch {
|
|
155
|
+
return null;
|
|
156
|
+
}
|
|
157
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return null;
|
|
158
|
+
if (value.schema === "impel.native-agent-answer.v1" && value.status === "succeeded") {
|
|
159
|
+
return "succeeded";
|
|
160
|
+
}
|
|
161
|
+
if (value.schema === "impel.native-agent-result.v1"
|
|
162
|
+
&& ["succeeded", "failed", "cancelled", "canceled"].includes(value.status)) {
|
|
163
|
+
return value.status;
|
|
164
|
+
}
|
|
165
|
+
return null;
|
|
166
|
+
}
|
|
167
|
+
|
|
147
168
|
export function summarizeCodexRollouts(rollouts) {
|
|
148
169
|
const toolCounts = {};
|
|
149
170
|
const parentToolCounts = {};
|
|
@@ -156,6 +177,10 @@ export function summarizeCodexRollouts(rollouts) {
|
|
|
156
177
|
let outputTokens = 0;
|
|
157
178
|
let mcpDurationMs = 0;
|
|
158
179
|
let mcpCompletedCalls = 0;
|
|
180
|
+
let terminalResults = 0;
|
|
181
|
+
let successfulTerminalResults = 0;
|
|
182
|
+
let parentSuccessfulTerminalResults = 0;
|
|
183
|
+
let childSuccessfulTerminalResults = 0;
|
|
159
184
|
|
|
160
185
|
for (const events of rollouts) {
|
|
161
186
|
eventCount += events.length;
|
|
@@ -194,6 +219,17 @@ export function summarizeCodexRollouts(rollouts) {
|
|
|
194
219
|
mcpStarts.delete(payload.call_id);
|
|
195
220
|
}
|
|
196
221
|
}
|
|
222
|
+
if (event.type === "response_item" && payload.type === "function_call_output") {
|
|
223
|
+
const terminalStatus = nativeTerminalStatus(payload.output);
|
|
224
|
+
if (terminalStatus) {
|
|
225
|
+
terminalResults += 1;
|
|
226
|
+
if (terminalStatus === "succeeded") {
|
|
227
|
+
successfulTerminalResults += 1;
|
|
228
|
+
if (metadata.parentThreadId) childSuccessfulTerminalResults += 1;
|
|
229
|
+
else parentSuccessfulTerminalResults += 1;
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
}
|
|
197
233
|
if (event.type === "event_msg" && payload.type === "token_count") {
|
|
198
234
|
const usage = payload.info?.total_token_usage;
|
|
199
235
|
if (usage && typeof usage === "object") latestUsage = usage;
|
|
@@ -219,6 +255,10 @@ export function summarizeCodexRollouts(rollouts) {
|
|
|
219
255
|
outputTokens,
|
|
220
256
|
mcpDurationMs,
|
|
221
257
|
mcpCompletedCalls,
|
|
258
|
+
terminalResults,
|
|
259
|
+
successfulTerminalResults,
|
|
260
|
+
parentSuccessfulTerminalResults,
|
|
261
|
+
childSuccessfulTerminalResults,
|
|
222
262
|
};
|
|
223
263
|
}
|
|
224
264
|
|
|
@@ -281,6 +321,10 @@ export function summarizeRawAttempt({ stdoutText, telemetryText = "", rolloutTex
|
|
|
281
321
|
outputTokens: rollout.outputTokens,
|
|
282
322
|
mcpDurationMs: rollout.mcpDurationMs,
|
|
283
323
|
mcpCompletedCalls: rollout.mcpCompletedCalls,
|
|
324
|
+
terminalResults: rollout.terminalResults,
|
|
325
|
+
successfulTerminalResults: rollout.successfulTerminalResults,
|
|
326
|
+
parentSuccessfulTerminalResults: rollout.parentSuccessfulTerminalResults,
|
|
327
|
+
childSuccessfulTerminalResults: rollout.childSuccessfulTerminalResults,
|
|
284
328
|
} : {}),
|
|
285
329
|
parentToolCounts: rollout.parentToolCounts,
|
|
286
330
|
childToolCounts: rollout.childToolCounts,
|
|
@@ -336,6 +380,9 @@ function directGate(report) {
|
|
|
336
380
|
structure: report.structure.maximumThreadCount <= 1
|
|
337
381
|
&& report.structure.totalCodeCells === 0
|
|
338
382
|
&& report.structure.totalCodeWaits === 0
|
|
383
|
+
&& report.structure.successfulTerminalResults === report.successfulSamples
|
|
384
|
+
&& report.structure.parentSuccessfulTerminalResults === report.successfulSamples
|
|
385
|
+
&& report.structure.childSuccessfulTerminalResults === 0
|
|
339
386
|
&& ["spawn_agent", "wait_agent", "send_message", "exec", "wait", "tool_search", "ALL_TOOLS"]
|
|
340
387
|
.every((tool) => !report.structure.allToolCounts[tool])
|
|
341
388
|
&& (report.structure.toolCounts.answer_native_agent || 0) === report.successfulSamples
|
|
@@ -350,6 +397,8 @@ function compatibleGate(report) {
|
|
|
350
397
|
&& report.timings.durationMs.p50 <= (report.sloClass === "cibi" ? 55_000 : 100_000),
|
|
351
398
|
childStructure: report.structure.totalCodeCells === 0
|
|
352
399
|
&& report.structure.totalCodeWaits === 0
|
|
400
|
+
&& report.structure.successfulTerminalResults === report.successfulSamples
|
|
401
|
+
&& report.structure.childSuccessfulTerminalResults === report.successfulSamples
|
|
353
402
|
&& ["exec", "wait", "send_message", "tool_search", "ALL_TOOLS"]
|
|
354
403
|
.every((tool) => !report.structure.childToolCounts[tool]),
|
|
355
404
|
};
|
|
@@ -405,6 +454,19 @@ export function analyzeAggregates(aggregates) {
|
|
|
405
454
|
allToolCounts: mergedCounts(attempts, "toolCounts"),
|
|
406
455
|
parentToolCounts: mergedCounts(successful, "parentToolCounts"),
|
|
407
456
|
childToolCounts: mergedCounts(successful, "childToolCounts"),
|
|
457
|
+
terminalResults: successful.reduce((total, attempt) => total + (attempt.terminalResults || 0), 0),
|
|
458
|
+
successfulTerminalResults: successful.reduce(
|
|
459
|
+
(total, attempt) => total + (attempt.successfulTerminalResults || 0),
|
|
460
|
+
0,
|
|
461
|
+
),
|
|
462
|
+
parentSuccessfulTerminalResults: successful.reduce(
|
|
463
|
+
(total, attempt) => total + (attempt.parentSuccessfulTerminalResults || 0),
|
|
464
|
+
0,
|
|
465
|
+
),
|
|
466
|
+
childSuccessfulTerminalResults: successful.reduce(
|
|
467
|
+
(total, attempt) => total + (attempt.childSuccessfulTerminalResults || 0),
|
|
468
|
+
0,
|
|
469
|
+
),
|
|
408
470
|
maximumThreadCount: successful.reduce((maximum, attempt) => Math.max(maximum, attempt.threadCount || 0), 0),
|
|
409
471
|
totalCodeCells: successful.reduce((total, attempt) => total + (attempt.codeCells || 0), 0),
|
|
410
472
|
totalCodeWaits: successful.reduce((total, attempt) => total + (attempt.codeWaits || 0), 0),
|
|
@@ -390,6 +390,7 @@ export function safeAttemptRecord({ options, index, processResult, summary, json
|
|
|
390
390
|
&& jsonValid
|
|
391
391
|
&& codex.turnCompleted === true
|
|
392
392
|
&& (codex.agentMessages || 0) >= 1
|
|
393
|
+
&& (codex.successfulTerminalResults || 0) === 1
|
|
393
394
|
&& (telemetry.localFailures || 0) === 0
|
|
394
395
|
&& startCalls === 1;
|
|
395
396
|
return {
|
|
@@ -420,6 +421,10 @@ export function safeAttemptRecord({ options, index, processResult, summary, json
|
|
|
420
421
|
childToolCounts: codex.childToolCounts || {},
|
|
421
422
|
codeCells: codex.codeCells || 0,
|
|
422
423
|
codeWaits: codex.codeWaits || 0,
|
|
424
|
+
terminalResults: codex.terminalResults || 0,
|
|
425
|
+
successfulTerminalResults: codex.successfulTerminalResults || 0,
|
|
426
|
+
parentSuccessfulTerminalResults: codex.parentSuccessfulTerminalResults || 0,
|
|
427
|
+
childSuccessfulTerminalResults: codex.childSuccessfulTerminalResults || 0,
|
|
423
428
|
inputTokens: codex.inputTokens || 0,
|
|
424
429
|
cachedInputTokens: codex.cachedInputTokens || 0,
|
|
425
430
|
outputTokens: codex.outputTokens || 0,
|
package/src/agents.js
CHANGED
|
@@ -16,6 +16,8 @@ import {
|
|
|
16
16
|
redactSecretText,
|
|
17
17
|
} from "./config.js";
|
|
18
18
|
import {
|
|
19
|
+
CODEX_NATIVE_AGENT_ATTACHMENT_WINDOW_MS,
|
|
20
|
+
IMPEL_NATIVE_AGENT_ATTACHMENT_WINDOW_ENV,
|
|
19
21
|
IMPEL_NATIVE_AGENT_TELEMETRY_ENV_NAMES,
|
|
20
22
|
IMPEL_NATIVE_AGENT_MCP_TARGET,
|
|
21
23
|
impelNativeAgentMcpInvocation,
|
|
@@ -52,7 +54,7 @@ export const NATIVE_AGENT_RUN_TOOL = "run_native_agent";
|
|
|
52
54
|
export const NATIVE_AGENT_RESUME_TOOL = "resume_native_agent_run";
|
|
53
55
|
export const NATIVE_AGENT_RECOVER_TOOL = "recover_native_agent_runs";
|
|
54
56
|
export const MANAGED_AGENT_MCP_SERVER = "impel_agent";
|
|
55
|
-
export const MANAGED_AGENT_MANIFEST_VERSION =
|
|
57
|
+
export const MANAGED_AGENT_MANIFEST_VERSION = 17;
|
|
56
58
|
|
|
57
59
|
// The host model only selects the fixed MCP tool and faithfully returns its
|
|
58
60
|
// result. Luna preserves deterministic direct-only code-mode routing while the
|
|
@@ -748,9 +750,11 @@ function renderClaudeAgent({ tenantId, agent, name, invocation, recoveryOnly = f
|
|
|
748
750
|
|
|
749
751
|
function codexInvocationEnvironment(invocation, { durableProfile = false } = {}) {
|
|
750
752
|
const entries = Object.entries(invocation.env || {});
|
|
751
|
-
if (!durableProfile) return entries;
|
|
752
753
|
const transient = new Set(IMPEL_NATIVE_AGENT_TELEMETRY_ENV_NAMES);
|
|
753
|
-
return
|
|
754
|
+
return [
|
|
755
|
+
...(durableProfile ? entries.filter(([key]) => !transient.has(key)) : entries),
|
|
756
|
+
[IMPEL_NATIVE_AGENT_ATTACHMENT_WINDOW_ENV, String(CODEX_NATIVE_AGENT_ATTACHMENT_WINDOW_MS)],
|
|
757
|
+
];
|
|
754
758
|
}
|
|
755
759
|
|
|
756
760
|
function renderCodexConfiguration({
|
|
@@ -800,6 +804,7 @@ function renderCodexConfiguration({
|
|
|
800
804
|
`[mcp_servers.${MANAGED_AGENT_MCP_SERVER}]`,
|
|
801
805
|
`command = ${JSON.stringify(invocation.command)}`,
|
|
802
806
|
`args = [${invocation.args.map((argument) => JSON.stringify(argument)).join(", ")}]`,
|
|
807
|
+
"tool_timeout_sec = 120",
|
|
803
808
|
...(eager
|
|
804
809
|
? [`enabled_tools = [${toolNames.map((tool) => JSON.stringify(tool)).join(", ")}]`]
|
|
805
810
|
: []),
|
package/src/apps.js
CHANGED
|
@@ -301,7 +301,7 @@ export const CURRENT_CONFIG_VERSION = 32;
|
|
|
301
301
|
// — which is what made every `impel update` re-trigger macOS permission
|
|
302
302
|
// prompts. Bump this ONLY when a code change alters the bytes of a built
|
|
303
303
|
// bundle; leave it alone for changes that don't touch bundle contents.
|
|
304
|
-
export const BUNDLE_BUILD_FINGERPRINT = "bundle-2026-08-08.
|
|
304
|
+
export const BUNDLE_BUILD_FINGERPRINT = "bundle-2026-08-08.2";
|
|
305
305
|
|
|
306
306
|
/** Parse the tenant's install manifest, or null when absent/corrupt. */
|
|
307
307
|
export function readTenantManifest(homeDir = os.homedir(), tenantId = null) {
|
package/src/desktopTasks.js
CHANGED
|
@@ -254,7 +254,7 @@ const NAVIGATION_SOURCE = String.raw`(() => {
|
|
|
254
254
|
const sidebar = findSidebar();
|
|
255
255
|
if (!sidebar || !(event.target instanceof Node) || !sidebar.contains(event.target)) return;
|
|
256
256
|
select(false);
|
|
257
|
-
signal("hide");
|
|
257
|
+
setTimeout(() => signal("hide"), 0);
|
|
258
258
|
};
|
|
259
259
|
const onResize = () => {
|
|
260
260
|
if (active) signal("layout");
|
|
@@ -480,11 +480,12 @@ if (
|
|
|
480
480
|
const {
|
|
481
481
|
app,
|
|
482
482
|
BrowserWindow,
|
|
483
|
+
WebContentsView,
|
|
483
484
|
ipcMain,
|
|
484
485
|
shell,
|
|
485
486
|
webContents: electronWebContents,
|
|
486
487
|
} = electron;
|
|
487
|
-
if (!app || !BrowserWindow || !ipcMain || !electronWebContents) {
|
|
488
|
+
if (!app || !BrowserWindow || !WebContentsView || !ipcMain || !electronWebContents) {
|
|
488
489
|
record("unsupported-electron-surface");
|
|
489
490
|
return;
|
|
490
491
|
}
|
|
@@ -540,16 +541,7 @@ if (
|
|
|
540
541
|
const createView = (window) => {
|
|
541
542
|
const state = stateFor(window);
|
|
542
543
|
if (state.view && !state.view.webContents.isDestroyed()) return state;
|
|
543
|
-
const view =
|
|
544
|
-
frame: false,
|
|
545
|
-
show: false,
|
|
546
|
-
resizable: false,
|
|
547
|
-
movable: false,
|
|
548
|
-
minimizable: false,
|
|
549
|
-
maximizable: false,
|
|
550
|
-
fullscreenable: false,
|
|
551
|
-
skipTaskbar: true,
|
|
552
|
-
backgroundColor: "#181818",
|
|
544
|
+
const view = new WebContentsView({
|
|
553
545
|
webPreferences: {
|
|
554
546
|
preload: viewPreload,
|
|
555
547
|
contextIsolation: true,
|
|
@@ -558,7 +550,9 @@ if (
|
|
|
558
550
|
spellcheck: false,
|
|
559
551
|
},
|
|
560
552
|
});
|
|
561
|
-
|
|
553
|
+
window.contentView.addChildView(view);
|
|
554
|
+
view.setVisible(false);
|
|
555
|
+
view.setBackgroundColor("#181818");
|
|
562
556
|
allowedViewContents.add(view.webContents);
|
|
563
557
|
internalViewContents.add(view.webContents);
|
|
564
558
|
view.webContents.setWindowOpenHandler(() => ({ action: "deny" }));
|
|
@@ -568,63 +562,45 @@ if (
|
|
|
568
562
|
view.webContents.on("destroyed", () => {
|
|
569
563
|
allowedViewContents.delete(view.webContents);
|
|
570
564
|
internalViewContents.delete(view.webContents);
|
|
571
|
-
|
|
572
|
-
view.on("closed", () => {
|
|
565
|
+
try { window.contentView.removeChildView(view); } catch {}
|
|
573
566
|
if (state.view === view) state.view = null;
|
|
574
567
|
});
|
|
575
|
-
view.on("blur", () => setTimeout(() => {
|
|
576
|
-
const focused = BrowserWindow.getFocusedWindow();
|
|
577
|
-
if (focused === window || focused === state.nativeNav || focused === state.view) return;
|
|
578
|
-
state.visible = false;
|
|
579
|
-
state.view?.hide();
|
|
580
|
-
state.nativeNav?.hide();
|
|
581
|
-
}, 100));
|
|
582
568
|
view.webContents.loadURL(hostUrl).catch((error) => record("view-load-failed", error));
|
|
583
569
|
state.view = view;
|
|
584
570
|
return state;
|
|
585
571
|
};
|
|
586
572
|
|
|
587
|
-
const screenBounds = (window, bounds) => {
|
|
588
|
-
const content = window.getContentBounds();
|
|
589
|
-
return {
|
|
590
|
-
x: content.x + bounds.x,
|
|
591
|
-
y: content.y + bounds.y,
|
|
592
|
-
width: bounds.width,
|
|
593
|
-
height: bounds.height,
|
|
594
|
-
};
|
|
595
|
-
};
|
|
596
|
-
|
|
597
573
|
const show = (window, bounds) => {
|
|
598
574
|
const state = createView(window);
|
|
599
575
|
state.bounds = bounds;
|
|
600
576
|
state.visible = true;
|
|
601
|
-
state.view.setBounds(
|
|
602
|
-
state.view.
|
|
603
|
-
state.view.focus();
|
|
577
|
+
state.view.setBounds(bounds);
|
|
578
|
+
state.view.setVisible(true);
|
|
579
|
+
state.view.webContents.focus();
|
|
604
580
|
const boardStatus = () => ({
|
|
605
581
|
parentBounds: window.getBounds(),
|
|
606
582
|
parentContentBounds: window.getContentBounds(),
|
|
607
583
|
boardBounds: state.view.getBounds(),
|
|
608
|
-
boardVisible: state.
|
|
609
|
-
boardFocused: state.view.isFocused(),
|
|
584
|
+
boardVisible: state.visible,
|
|
585
|
+
boardFocused: state.view.webContents.isFocused(),
|
|
610
586
|
});
|
|
611
587
|
record("board-shown", JSON.stringify(boardStatus()));
|
|
612
588
|
setTimeout(() => {
|
|
613
|
-
if (state.view && !state.view.isDestroyed()) record("board-visible-check", JSON.stringify(boardStatus()));
|
|
589
|
+
if (state.view && !state.view.webContents.isDestroyed()) record("board-visible-check", JSON.stringify(boardStatus()));
|
|
614
590
|
}, 2000);
|
|
615
591
|
};
|
|
616
592
|
const hide = (window) => {
|
|
617
593
|
const state = windows.get(window.id);
|
|
618
594
|
if (!state) return;
|
|
619
595
|
state.visible = false;
|
|
620
|
-
state.view?.
|
|
596
|
+
state.view?.setVisible(false);
|
|
621
597
|
window.webContents.focus();
|
|
622
598
|
};
|
|
623
599
|
|
|
624
600
|
const layoutBoard = (window) => {
|
|
625
601
|
const state = windows.get(window.id);
|
|
626
|
-
if (!state?.visible || !state.view || !state.bounds || state.view.isDestroyed()) return;
|
|
627
|
-
state.view.setBounds(
|
|
602
|
+
if (!state?.visible || !state.view || !state.bounds || state.view.webContents.isDestroyed()) return;
|
|
603
|
+
state.view.setBounds(state.bounds);
|
|
628
604
|
};
|
|
629
605
|
|
|
630
606
|
const nativeBoardBounds = (window) => {
|
|
@@ -800,24 +776,24 @@ if (
|
|
|
800
776
|
state.nativeNav.showInactive();
|
|
801
777
|
state.nativeNav.moveTop();
|
|
802
778
|
}
|
|
803
|
-
if (state?.visible && state.view && !state.view.isDestroyed()) state.view.
|
|
779
|
+
if (state?.visible && state.view && !state.view.webContents.isDestroyed()) state.view.setVisible(true);
|
|
804
780
|
});
|
|
805
781
|
window.on("blur", () => setTimeout(() => {
|
|
806
782
|
const state = windows.get(window.id);
|
|
807
783
|
const focused = BrowserWindow.getFocusedWindow();
|
|
808
|
-
if (focused === state?.nativeNav
|
|
784
|
+
if (focused === state?.nativeNav) return;
|
|
809
785
|
state?.nativeNav?.hide();
|
|
810
|
-
state?.view?.
|
|
786
|
+
state?.view?.setVisible(false);
|
|
811
787
|
}, 1000));
|
|
812
788
|
window.on("minimize", () => {
|
|
813
789
|
const state = windows.get(window.id);
|
|
814
790
|
state?.nativeNav?.hide();
|
|
815
|
-
state?.view?.
|
|
791
|
+
state?.view?.setVisible(false);
|
|
816
792
|
});
|
|
817
793
|
window.on("restore", () => {
|
|
818
794
|
const state = windows.get(window.id);
|
|
819
795
|
state?.nativeNav?.showInactive();
|
|
820
|
-
if (state?.visible) state.view?.
|
|
796
|
+
if (state?.visible) state.view?.setVisible(true);
|
|
821
797
|
});
|
|
822
798
|
window.on("closed", () => {
|
|
823
799
|
const state = windows.get(window.id);
|
|
@@ -830,7 +806,8 @@ if (
|
|
|
830
806
|
if (state.nativeNav) nativeNavOwners.delete(state.nativeNav.webContents);
|
|
831
807
|
try {
|
|
832
808
|
if (state.view) {
|
|
833
|
-
state.view
|
|
809
|
+
window.contentView.removeChildView(state.view);
|
|
810
|
+
state.view.webContents.close();
|
|
834
811
|
}
|
|
835
812
|
if (state.nativeNav) {
|
|
836
813
|
state.nativeNav.destroy();
|
|
@@ -900,7 +877,7 @@ if (
|
|
|
900
877
|
if (focused && (windows.has(focused.id) || internalViewContents.has(focused.webContents))) return;
|
|
901
878
|
for (const state of windows.values()) {
|
|
902
879
|
state.nativeNav?.hide();
|
|
903
|
-
state.view?.
|
|
880
|
+
state.view?.setVisible(false);
|
|
904
881
|
}
|
|
905
882
|
};
|
|
906
883
|
|
|
@@ -949,19 +926,13 @@ export function desktopTasksHostHtml() {
|
|
|
949
926
|
:root { color-scheme: light dark; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; }
|
|
950
927
|
* { box-sizing: border-box; }
|
|
951
928
|
html, body { width: 100%; height: 100%; margin: 0; overflow: hidden; background: Canvas; color: CanvasText; }
|
|
952
|
-
body { display: grid; grid-template-rows:
|
|
953
|
-
header { display: flex; align-items: center; justify-content: space-between; gap: 12px; padding: 0 10px 0 14px; border-bottom: 1px solid color-mix(in srgb, CanvasText 12%, transparent); }
|
|
954
|
-
header strong { font-size: 13px; font-weight: 600; }
|
|
955
|
-
button { border: 0; border-radius: 7px; padding: 5px 9px; background: color-mix(in srgb, CanvasText 8%, Canvas); color: CanvasText; font: inherit; cursor: pointer; }
|
|
956
|
-
button:hover { background: color-mix(in srgb, CanvasText 13%, Canvas); }
|
|
957
|
-
button:focus-visible { outline: 2px solid #7c8cff; outline-offset: 2px; }
|
|
929
|
+
body { display: grid; grid-template-rows: minmax(0, 1fr); }
|
|
958
930
|
iframe { width: 100%; height: 100%; border: 0; background: Canvas; }
|
|
959
931
|
#status { display: grid; place-items: center; padding: 24px; color: color-mix(in srgb, CanvasText 65%, transparent); text-align: center; }
|
|
960
932
|
#status[hidden] { display: none; }
|
|
961
933
|
</style>
|
|
962
934
|
</head>
|
|
963
935
|
<body>
|
|
964
|
-
<header><strong>Tasks</strong><button id="close" type="button" aria-label="Close Tasks">Close</button></header>
|
|
965
936
|
<div id="status" role="status">Loading Impel Tasks…</div>
|
|
966
937
|
<iframe id="widget" title="Impel Tasks" sandbox="allow-scripts allow-forms" hidden></iframe>
|
|
967
938
|
<script>
|
|
@@ -1024,7 +995,9 @@ export function desktopTasksHostHtml() {
|
|
|
1024
995
|
}
|
|
1025
996
|
});
|
|
1026
997
|
|
|
1027
|
-
|
|
998
|
+
window.addEventListener("keydown", (event) => {
|
|
999
|
+
if (event.key === "Escape") bridge.close();
|
|
1000
|
+
});
|
|
1028
1001
|
Promise.all([
|
|
1029
1002
|
bridge.rpc({ method: "resources/read", params: { uri: ${JSON.stringify(DESKTOP_TASKS_RESOURCE_URI)} } }),
|
|
1030
1003
|
bridge.rpc({ method: "tools/call", params: { name: "show_tasks", arguments: { scope: "visible", limit: 50 } } }),
|
|
@@ -21,6 +21,9 @@ import {
|
|
|
21
21
|
normalizeNativeAgentCatalog,
|
|
22
22
|
} from "./agents.js";
|
|
23
23
|
import { extractAnswerFinalText } from "./directAnswer.js";
|
|
24
|
+
import {
|
|
25
|
+
IMPEL_NATIVE_AGENT_ATTACHMENT_WINDOW_ENV,
|
|
26
|
+
} from "./selfInvocation.js";
|
|
24
27
|
import { normalizeTenantId } from "./tenants.js";
|
|
25
28
|
import { renameWithWindowsRetry } from "./windowsFs.js";
|
|
26
29
|
|
|
@@ -62,6 +65,19 @@ const CTOS_START_TIMEOUT_MESSAGE = `MCP tool call failed for ${NATIVE_AGENT_STAR
|
|
|
62
65
|
const MCP_TOOL_RESULT_ERROR = Symbol("native-agent MCP tool result error");
|
|
63
66
|
const TERMINAL_STATUSES = new Set(["succeeded", "failed", "cancelled", "canceled"]);
|
|
64
67
|
|
|
68
|
+
export function nativeAgentAttachmentWindowMs(environment = process.env) {
|
|
69
|
+
const configured = environment?.[IMPEL_NATIVE_AGENT_ATTACHMENT_WINDOW_ENV];
|
|
70
|
+
if (configured === undefined) return DEFAULT_ATTACHMENT_WINDOW_MS;
|
|
71
|
+
if (!/^\d{1,6}$/u.test(configured)) {
|
|
72
|
+
throw new Error(`${IMPEL_NATIVE_AGENT_ATTACHMENT_WINDOW_ENV} must be an integer from 1000 through 300000`);
|
|
73
|
+
}
|
|
74
|
+
const parsed = Number(configured);
|
|
75
|
+
if (!Number.isSafeInteger(parsed) || parsed < 1_000 || parsed > 300_000) {
|
|
76
|
+
throw new Error(`${IMPEL_NATIVE_AGENT_ATTACHMENT_WINDOW_ENV} must be an integer from 1000 through 300000`);
|
|
77
|
+
}
|
|
78
|
+
return parsed;
|
|
79
|
+
}
|
|
80
|
+
|
|
65
81
|
function stableValue(value) {
|
|
66
82
|
if (Array.isArray(value)) return value.map(stableValue);
|
|
67
83
|
if (!value || typeof value !== "object") return value;
|
|
@@ -773,7 +789,7 @@ export class NativeAgentCompositeTransport {
|
|
|
773
789
|
gatewayUrl,
|
|
774
790
|
credential,
|
|
775
791
|
runsRoot = path.join(CONFIG_DIR, "native-agent-runs"),
|
|
776
|
-
attachmentWindowMs =
|
|
792
|
+
attachmentWindowMs = nativeAgentAttachmentWindowMs(),
|
|
777
793
|
maxPolls = DEFAULT_MAX_POLLS,
|
|
778
794
|
now = Date.now,
|
|
779
795
|
randomUUID = crypto.randomUUID,
|
package/src/selfInvocation.js
CHANGED
|
@@ -72,6 +72,8 @@ export const IMPEL_NATIVE_AGENT_TELEMETRY_ENV_NAMES = [
|
|
|
72
72
|
"IMPEL_NATIVE_HOST",
|
|
73
73
|
"IMPEL_NATIVE_HOST_BUILD",
|
|
74
74
|
];
|
|
75
|
+
export const IMPEL_NATIVE_AGENT_ATTACHMENT_WINDOW_ENV = "IMPEL_NATIVE_AGENT_ATTACHMENT_WINDOW_MS";
|
|
76
|
+
export const CODEX_NATIVE_AGENT_ATTACHMENT_WINDOW_MS = 100_000;
|
|
75
77
|
|
|
76
78
|
function managedMcpEnvironment(environment = process.env) {
|
|
77
79
|
const telemetry = Object.fromEntries(
|