impel-cli 0.20.30 → 0.20.32

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 CHANGED
@@ -1,5 +1,25 @@
1
1
  # Release notes
2
2
 
3
+ ## 0.20.32 — Recover transient managed access misses
4
+
5
+ - Retries one exact MCP request when the gateway reports its specific managed
6
+ virtual-key cache-miss rejection, covering catalog binding and direct-answer
7
+ calls before they become visible to the host model.
8
+ - Reuses the same native-answer idempotency key and waits only 250ms, so the
9
+ recovery cannot duplicate an Eve run or add latency to healthy requests.
10
+ - Keeps every nearby authentication and governance rejection definitive and
11
+ bounds a persistent managed-key miss to exactly two attempts.
12
+
13
+ ## 0.20.31 — Complete embedded Tasks controls
14
+
15
+ - Allows the guarded `delete_task` operation through the tenant desktop bridge
16
+ so the MCP App can complete the full task CRUD lifecycle.
17
+ - Keeps the embedded board below the macOS title-bar drag region so Board,
18
+ List, scope, refresh, create, and external-link controls receive pointer
19
+ input normally.
20
+ - Rebuilds managed Claude and ChatGPT bundles onto the corrected Tasks host
21
+ contract while preserving tenant profiles and app state.
22
+
3
23
  ## 0.20.30 — Stable Claude and Codex upgrades
4
24
 
5
25
  - Updates the reviewed native CLI pins to Claude Code 2.1.220 and Codex
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "impel-cli",
3
- "version": "0.20.30",
3
+ "version": "0.20.32",
4
4
  "description": "Prepare isolated Claude and Codex workspaces for every accessible Impel tenant",
5
5
  "type": "module",
6
6
  "bin": {
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-08.3";
302
+ export const BUNDLE_BUILD_FINGERPRINT = "bundle-2026-08-08.4";
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) {
@@ -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(0, Math.min(content.height - 240, number("y", 0)));
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
- return { x, y: 0, width: Math.max(240, content.width - x), height: Math.max(240, content.height) };
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(["show_tasks", "list_tasks", "get_task", "list_members", "create_task", "update_task"]);
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))) {
@@ -63,6 +63,8 @@ const STATE_COMMIT_LEASE_MARGIN_MS = 5_000;
63
63
  const CIBI_START_IN_PROGRESS_CODE = "eve_run_drain_start_in_progress";
64
64
  const CIBI_START_IN_PROGRESS_MESSAGE = "The durable Eve drain workflow is still being enqueued; retry this idempotent start.";
65
65
  const CTOS_START_TIMEOUT_MESSAGE = `MCP tool call failed for ${NATIVE_AGENT_START_TOOL}: The operation was aborted due to timeout: mcp tool call failed`;
66
+ const MANAGED_VIRTUAL_KEY_MISS_MESSAGE = "virtual key not found. The provided virtual key does not exist or has been revoked.";
67
+ const MANAGED_VIRTUAL_KEY_MISS_RETRY_DELAY_MS = 250;
66
68
  const MCP_TOOL_RESULT_ERROR = Symbol("native-agent MCP tool result error");
67
69
  const TERMINAL_STATUSES = new Set(["succeeded", "failed", "cancelled", "canceled"]);
68
70
 
@@ -634,6 +636,12 @@ function toolPayload(message) {
634
636
  return result;
635
637
  }
636
638
 
639
+ function retryableManagedVirtualKeyMiss(error) {
640
+ return error instanceof NativeAgentUpstreamError
641
+ && (error[MCP_TOOL_RESULT_ERROR] === true || error.code === -32000)
642
+ && error.message.includes(MANAGED_VIRTUAL_KEY_MISS_MESSAGE);
643
+ }
644
+
637
645
  export class NativeAgentUpstreamSession {
638
646
  constructor({
639
647
  gatewayUrl,
@@ -756,28 +764,38 @@ export class NativeAgentUpstreamSession {
756
764
  }
757
765
 
758
766
  async call(name, args, { signal } = {}) {
759
- const id = this.nextId++;
760
- try {
761
- const messages = await this.post({
762
- jsonrpc: "2.0",
763
- id,
764
- method: "tools/call",
765
- params: { name, arguments: args },
766
- }, { signal });
767
- return toolPayload(messages.find((message) => message?.id === id));
768
- } catch (error) {
769
- if ((name === NATIVE_AGENT_START_TOOL || name === NATIVE_AGENT_UPSTREAM_ANSWER_TOOL)
770
- && error instanceof NativeAgentUpstreamError
771
- && (error.incompleteResponse
772
- || error.code === CIBI_START_IN_PROGRESS_CODE
773
- || error.data?.code === CIBI_START_IN_PROGRESS_CODE
774
- || error.message === CIBI_START_IN_PROGRESS_MESSAGE
775
- || (error[MCP_TOOL_RESULT_ERROR] === true
776
- && error.message === CTOS_START_TIMEOUT_MESSAGE))) {
777
- error.ambiguous = true;
767
+ for (let attempt = 0; attempt < 2; attempt += 1) {
768
+ const id = this.nextId++;
769
+ try {
770
+ const messages = await this.post({
771
+ jsonrpc: "2.0",
772
+ id,
773
+ method: "tools/call",
774
+ params: { name, arguments: args },
775
+ }, { signal });
776
+ return toolPayload(messages.find((message) => message?.id === id));
777
+ } catch (error) {
778
+ if (attempt === 0 && retryableManagedVirtualKeyMiss(error)) {
779
+ // This gateway-authored miss happens before a native run can exist.
780
+ // One same-session replay repairs transient per-task governance-cache
781
+ // drift while leaving every nearby auth/policy rejection definitive.
782
+ await abortableDelay(MANAGED_VIRTUAL_KEY_MISS_RETRY_DELAY_MS, signal);
783
+ continue;
784
+ }
785
+ if ((name === NATIVE_AGENT_START_TOOL || name === NATIVE_AGENT_UPSTREAM_ANSWER_TOOL)
786
+ && error instanceof NativeAgentUpstreamError
787
+ && (error.incompleteResponse
788
+ || error.code === CIBI_START_IN_PROGRESS_CODE
789
+ || error.data?.code === CIBI_START_IN_PROGRESS_CODE
790
+ || error.message === CIBI_START_IN_PROGRESS_MESSAGE
791
+ || (error[MCP_TOOL_RESULT_ERROR] === true
792
+ && error.message === CTOS_START_TIMEOUT_MESSAGE))) {
793
+ error.ambiguous = true;
794
+ }
795
+ throw error;
778
796
  }
779
- throw error;
780
797
  }
798
+ throw new Error("native-agent MCP retry loop exhausted");
781
799
  }
782
800
  }
783
801