@hcu-lab.me/mcp-device 1.0.6 → 1.0.8

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.
Files changed (45) hide show
  1. package/README.md +7 -71
  2. package/dist/bootstrap.js +1 -1
  3. package/dist/config-manager.js +1 -1
  4. package/dist/config.js +1 -1
  5. package/dist/custom-stdio.js +1 -2
  6. package/dist/data/onboarding-prompts.json +22 -11
  7. package/dist/device/device-state.d.ts +0 -5
  8. package/dist/device/device-state.js +0 -84
  9. package/dist/device/device.d.ts +1 -1
  10. package/dist/device/device.js +8 -7
  11. package/dist/device/execution-engine.d.ts +10 -1
  12. package/dist/device/execution-engine.js +81 -128
  13. package/dist/device/gateway-channel.d.ts +6 -0
  14. package/dist/device/gateway-channel.js +16 -1
  15. package/dist/device/gateway-tool-adapter.d.ts +3 -3
  16. package/dist/device/gateway-tool-adapter.js +12 -11
  17. package/dist/device/linux-service.d.ts +4 -0
  18. package/dist/device/linux-service.js +10 -3
  19. package/dist/device/runtime-owner.js +2 -2
  20. package/dist/device/self-update.js +3 -1
  21. package/dist/device/windows-service.d.ts +3 -4
  22. package/dist/device/windows-service.js +5 -44
  23. package/dist/npm-scripts/remote.js +0 -2
  24. package/dist/server.js +9 -99
  25. package/dist/terminal-manager.js +1 -1
  26. package/dist/tools/config.d.ts +1 -1
  27. package/dist/tools/filesystem.js +3 -3
  28. package/dist/tools/pdf/markdown.js +1 -1
  29. package/dist/tools/schemas.d.ts +2 -3
  30. package/dist/tools/schemas.js +0 -10
  31. package/dist/ui/config-editor/index.html +1 -1
  32. package/dist/ui/file-preview/index.html +1 -1
  33. package/dist/ui/file-preview/styles.css +2 -2
  34. package/dist/utils/capture.d.ts +5 -28
  35. package/dist/utils/capture.js +11 -455
  36. package/dist/utils/feature-flags.d.ts +0 -47
  37. package/dist/utils/feature-flags.js +5 -199
  38. package/dist/utils/files/docx.d.ts +2 -2
  39. package/dist/utils/files/docx.js +2 -2
  40. package/dist/utils/usageTracker.js +0 -24
  41. package/dist/version.d.ts +1 -1
  42. package/dist/version.js +1 -1
  43. package/package.json +5 -6
  44. package/dist/tools/feedback.d.ts +0 -8
  45. package/dist/tools/feedback.js +0 -132
package/README.md CHANGED
@@ -1,90 +1,26 @@
1
1
  # MCP Device
2
2
 
3
- `@hcu-lab.me/mcp-device` connects a user-owned computer to the authenticated MCP Gateway. The device opens the outbound connection; no inbound device port is required.
4
-
5
3
  The gateway owns accounts, OAuth, device ownership, MCP tool contracts, routing, and usage aggregation. MCP Device owns local device identity, pairing, reconnect lifecycle, bounded execution, background registration, and local status.
6
4
 
7
- ## Quick start
8
-
9
- Canonical production gateway: https://device.hcu-lab.me
10
-
11
- - Dashboard: https://device.hcu-lab.me/dashboard
12
- - Pair device: https://device.hcu-lab.me/pair
13
- - Live setup/help: https://device.hcu-lab.me/help
14
-
15
- Install the current release:
5
+ ## Install
16
6
 
17
7
  ```powershell
18
- npm install -g @hcu-lab.me/mcp-device
8
+ npm install -g @hcu-lab.me/mcp-device@1.0.7
19
9
  mcp-device login
20
10
  mcp-device install
21
11
  mcp-device status
22
12
  ```
23
13
 
24
- `mcp-device login` stays terminal-only: it prints the pairing URL, user code, and QR code, and never opens a browser automatically.
25
-
26
- ## Limited hosted access
27
-
28
- The public source package remains MIT licensed, but access to the hosted `device.hcu-lab.me` gateway is intentionally limited. New hosted accounts are admitted through a small, controlled supply of invite codes rather than open registration. Invite availability may be capped, paused, expired, or revoked as the service capacity and security policy change. Installing the package does not by itself grant a hosted-service account or guarantee that an invite code will be available.
29
-
30
- The hosted Pair/Help pages render their gateway URL and navigation from the deployment that served the page, so staging or custom deployments do not need a production-host rewrite. For the canonical package, `https://device.hcu-lab.me` is the default gateway; `MCP_GATEWAY_URL` is only needed when intentionally using another gateway.
31
-
32
14
  ## Commands
33
15
 
34
16
  ```text
35
17
  mcp-device start in the foreground
36
18
  mcp-device start start in the foreground
37
- mcp-device login explicitly link or switch the gateway account
19
+ mcp-device login link or switch the gateway account
38
20
  mcp-device logout unlink the gateway account from this device
39
- mcp-device status show runtime, manager, connection, security, proxy, usage, and schema state
40
- mcp-device install pair if needed, then install and start a background runtime
41
- mcp-device stop stop the current runtime without deleting identity/account state
42
- mcp-device uninstall remove background registration while preserving identity/account state
21
+ mcp-device status show device and runtime status
22
+ mcp-device install pair if needed, then install and start the background runtime
23
+ mcp-device stop stop the current runtime
24
+ mcp-device uninstall remove background registration while preserving device identity
43
25
  mcp-device --help show command help
44
26
  ```
45
-
46
- `md` is an alias of `mcp-device` on POSIX shells. On Windows, use `mcp-device`; bare `md` has a shell collision with built-in directory-creation commands/aliases and is not the supported invocation.
47
-
48
- On Windows, `install` uses current-user background registration. On Linux, every `install` asks whether to use `systemd --user` or an already configured PM2 installation. MCP Device does not install PM2, run `pm2 startup`, or use `sudo` automatically.
49
-
50
- ## Dashboard updates
51
-
52
- Starting with MCP Device 1.0.5, an installed background device reports its package version to the authenticated gateway and can accept a per-device update requested by its owning account from the dashboard. The control is intentionally narrow: the gateway supplies only an exact stable version, and the device installs only `@hcu-lab.me/mcp-device@<version>`, verifies the installed version, then restarts through its existing Windows, systemd-user, or PM2 lifecycle.
53
-
54
- Installations older than 1.0.5 do not understand this update control. Upgrade those devices to 1.0.5 once with npm; subsequent releases can be applied from the dashboard. Offline devices remain unchanged until they are online and explicitly updated.
55
-
56
- ## First run and trust
57
-
58
- The official gateway base URL is `https://device.hcu-lab.me`. The official package pins the independently distributed application CA and requires protocol v2 before the first network connection. If that CA is absent or invalid, MCP Device fails closed instead of learning trust from the gateway it is about to contact or falling back to protocol v1.
59
-
60
- For a custom gateway, set `MCP_GATEWAY_URL` and provision its application CA through an independent trusted channel before enabling protocol v2. Proxy selection is captured during interactive provisioning and reused by the background runtime.
61
-
62
- ## Local state and 1.0.2 migration
63
-
64
- Canonical state is stored under `~/.mcp-device/`. Existing `~/.hcu-device/` identity/config/status state is migrated non-destructively under serialized runtime ownership. A conflicting canonical and legacy identity fails closed rather than creating a second device identity.
65
-
66
- The device identity is Ed25519. MCP Device 1.0.2 does not use Windows DPAPI for the device private key or proxy configuration. A legacy protected 1.0.1 identity is archived without decrypting it, a fresh local identity is generated, and the device must be paired once again. A legacy protected proxy configuration must be supplied again during `mcp-device login`. The gateway stores only the public device identity and account ownership.
67
-
68
- ## Development
69
-
70
- ```powershell
71
- git clone https://github.com/Hiroshimeow/agent-mcp-device.git
72
- cd agent-mcp-device
73
- npm ci
74
- npm run build
75
- node dist/mcp-device.js --help
76
- ```
77
-
78
- Normal development pushes do not publish npm. After reviewed development work is committed on a clean `main`, a release is intentionally created with:
79
-
80
- ```powershell
81
- npm run release
82
- ```
83
-
84
- That command runs the test suite, bumps the patch version, synchronizes project version files, creates the release commit and `vX.Y.Z` tag, then atomically pushes `main` and the tag. The tag-triggered GitHub Actions workflow performs the npm publish through trusted OIDC publishing. Use `npm run release:minor` or `npm run release:major` only when that version change is intentional.
85
-
86
- For a custom development gateway, set `MCP_GATEWAY_URL`. Supply `MCP_GATEWAY_APP_CA_PATH` from an independent trusted source when using protocol v2. Non-loopback plaintext gateway URLs are rejected.
87
-
88
- ## Upstream execution engine
89
-
90
- The local execution engine is derived from [Desktop Commander MCP](https://github.com/wonderwhy-er/DesktopCommanderMCP). Desktop Commander is MIT licensed; its copyright and MIT license are preserved in this repository's `LICENSE`. The MCP Device product identity, gateway protocol, account/device lifecycle, security layer, and packaging are maintained separately in this repository.
package/dist/bootstrap.js CHANGED
@@ -7,7 +7,7 @@
7
7
  * slow or cloud-synced filesystem — 4 stalled operations exhaust the pool, and
8
8
  * because a stalled syscall keeps its thread until the OS returns (a JS-level
9
9
  * timeout does not cancel it), every subsequent fs op queues for minutes. That
10
- * surfaced as multi-minute tool-call hangs under parallel `claude -p` load.
10
+ * surfaced as multi-minute tool-call hangs under parallel agent load.
11
11
  *
12
12
  * Raising the pool size gives enough headroom that a burst of slow reads no
13
13
  * longer starves the rest. libuv reads UV_THREADPOOL_SIZE only when the pool is
@@ -158,7 +158,7 @@ class ConfigManager {
158
158
  }
159
159
  // Use user's actual shell from environment
160
160
  // On macOS, default to zsh (default since Catalina) since process.env.SHELL
161
- // may not be set when running inside Claude Desktop
161
+ // may not be set when launched by a desktop host
162
162
  const fallbackShell = os.platform() === 'darwin' ? '/bin/zsh' : '/bin/sh';
163
163
  const userShell = process.env.SHELL || fallbackShell;
164
164
  // Return just the shell path - we'll handle login shell flag elsewhere
package/dist/config.js CHANGED
@@ -2,7 +2,7 @@ import path from 'path';
2
2
  import os from 'os';
3
3
  // MCP Device owns one canonical per-user state/config root.
4
4
  export const USER_HOME = os.homedir();
5
- export const CONFIG_DIR = path.resolve(process.env.MCP_DEVICE_CONFIG_DIR || process.env.DESKTOP_COMMANDER_CONFIG_DIR || path.join(USER_HOME, '.mcp-device'));
5
+ export const CONFIG_DIR = path.resolve(process.env.MCP_DEVICE_CONFIG_DIR || path.join(USER_HOME, '.mcp-device'));
6
6
  // Paths relative to the config directory.
7
7
  export const CONFIG_FILE = path.join(CONFIG_DIR, 'config.json');
8
8
  export const TOOL_CALL_FILE = path.join(CONFIG_DIR, 'logs', 'tool-calls.log');
@@ -64,8 +64,7 @@ export class FilteredStdioServerTransport extends StdioServerTransport {
64
64
  this.clientName = clientName.toLowerCase();
65
65
  // Detect Cline and disable notifications
66
66
  if (this.clientName.includes('cline') ||
67
- this.clientName.includes('vscode') ||
68
- this.clientName === 'claude-dev') {
67
+ this.clientName.includes('vscode')) {
69
68
  this.disableNotifications = true;
70
69
  process.stderr.write(`[INFO] MCP Device: Notifications disabled for ${clientName}\n`);
71
70
  }
@@ -1,18 +1,20 @@
1
1
  {
2
2
  "version": "2.0.0",
3
- "description": "Desktop Commander onboarding prompts - V2 simplified (5 prompts only)",
3
+ "description": "MCP Device local onboarding prompts",
4
4
  "prompts": [
5
5
  {
6
6
  "id": "onb2_01",
7
7
  "title": "Organize my Downloads folder",
8
8
  "description": "Clean up and organize your messy Downloads folder into relevant subfolders automatically.",
9
9
  "prompt": "Let's organize your Downloads folder! \n\nFirst, let me check what we're working with. I'll look at your Downloads folder to see how many files are there and what types.\n\nShould I start by analyzing your Downloads folder?",
10
- "categories": ["onboarding"],
10
+ "categories": [
11
+ "onboarding"
12
+ ],
11
13
  "secondaryTag": "Quick Start",
12
14
  "votes": 0,
13
15
  "gaClicks": 0,
14
16
  "icon": "FolderOpen",
15
- "author": "DC team",
17
+ "author": "MCP Device",
16
18
  "verified": true
17
19
  },
18
20
  {
@@ -20,11 +22,14 @@
20
22
  "title": "Explain codebase or repository to me",
21
23
  "description": "Analyze and explain any codebase - local project or GitHub repository - including architecture, dependencies, and how it works.",
22
24
  "prompt": "I'll analyze and explain any codebase for you! 🔍\n\n**What should I analyze?**\n\n*Local project:* `~/work/my-project` (replace with your path)\n*GitHub repo:* `https://github.com/user/repo`\n\nI'll break down the architecture, dependencies, and how everything works together!",
23
- "categories": ["onboarding"], "secondaryTag": "Code Analysis",
25
+ "categories": [
26
+ "onboarding"
27
+ ],
28
+ "secondaryTag": "Code Analysis",
24
29
  "votes": 0,
25
30
  "gaClicks": 0,
26
31
  "icon": "Code",
27
- "author": "DC team",
32
+ "author": "MCP Device",
28
33
  "verified": true
29
34
  },
30
35
  {
@@ -32,12 +37,14 @@
32
37
  "title": "Create organized knowledge/documents folder",
33
38
  "description": "Set up a well-structured knowledge base or document organization system with templates and suggested categories.",
34
39
  "prompt": "Let's create an organized knowledge base! 📚\n\n**Where should I set it up?**\n\n*I suggest: `~/Documents/Knowledge-Base` (replace with your path) or give me a different location.*\n\nI'll create a clean folder structure with templates and organize any existing documents you have!",
35
- "categories": ["onboarding"],
40
+ "categories": [
41
+ "onboarding"
42
+ ],
36
43
  "secondaryTag": "Quick Start",
37
44
  "votes": 0,
38
45
  "gaClicks": 0,
39
46
  "icon": "BookOpen",
40
- "author": "DC team",
47
+ "author": "MCP Device",
41
48
  "verified": true
42
49
  },
43
50
  {
@@ -45,12 +52,14 @@
45
52
  "title": "Analyze my data file",
46
53
  "description": "Upload or point to any data file (CSV, JSON, Excel, etc.) and get comprehensive analysis including patterns, insights, and summary reports.",
47
54
  "prompt": "I'll help you analyze your data file! \n\nWhat's the path to your data file? (e.g., `/Users/yourname/data.csv`)\n\nOnce you give me the path, I'll start by checking what type of file it is and show you a quick preview, then we can dive deeper step by step.",
48
- "categories": ["onboarding"],
55
+ "categories": [
56
+ "onboarding"
57
+ ],
49
58
  "secondaryTag": "Quick Start",
50
59
  "votes": 0,
51
60
  "gaClicks": 0,
52
61
  "icon": "BarChart3",
53
- "author": "DC team",
62
+ "author": "MCP Device",
54
63
  "verified": true
55
64
  },
56
65
  {
@@ -58,12 +67,14 @@
58
67
  "title": "Check system health and resources",
59
68
  "description": "Analyze your system's health, resource usage, running processes, and generate a comprehensive system status report.",
60
69
  "prompt": "Let me check your system health and resources!\n\nI'll start by looking at your CPU, memory, and disk usage, then check for any performance issues.\n\nShould I begin the system analysis?",
61
- "categories": ["onboarding"],
70
+ "categories": [
71
+ "onboarding"
72
+ ],
62
73
  "secondaryTag": "Quick Start",
63
74
  "votes": 0,
64
75
  "gaClicks": 0,
65
76
  "icon": "Activity",
66
- "author": "DC team",
77
+ "author": "MCP Device",
67
78
  "verified": true
68
79
  }
69
80
  ]
@@ -1,7 +1,6 @@
1
1
  export declare const DEVICE_STATE_FILES: readonly string[];
2
2
  export interface DeviceStatePaths {
3
3
  root: string;
4
- legacyRoot: string;
5
4
  identity: string;
6
5
  config: string;
7
6
  status: string;
@@ -9,7 +8,3 @@ export interface DeviceStatePaths {
9
8
  update: string;
10
9
  }
11
10
  export declare function deviceStatePaths(home?: string): DeviceStatePaths;
12
- export declare function migrateLegacyDeviceState(paths?: DeviceStatePaths): Promise<{
13
- migrated: string[];
14
- legacyStateSeen: boolean;
15
- }>;
@@ -1,4 +1,3 @@
1
- import fs from 'fs/promises';
2
1
  import os from 'os';
3
2
  import path from 'path';
4
3
  export const DEVICE_STATE_FILES = Object.freeze([
@@ -8,10 +7,8 @@ export const DEVICE_STATE_FILES = Object.freeze([
8
7
  ]);
9
8
  export function deviceStatePaths(home = os.homedir()) {
10
9
  const root = path.resolve(home, '.mcp-device');
11
- const legacyRoot = path.resolve(home, '.hcu-device');
12
10
  return {
13
11
  root,
14
- legacyRoot,
15
12
  identity: path.join(root, 'gateway-identity.json'),
16
13
  config: path.join(root, 'gateway-config.json'),
17
14
  status: path.join(root, 'gateway-status.json'),
@@ -19,84 +16,3 @@ export function deviceStatePaths(home = os.homedir()) {
19
16
  update: path.join(root, 'update')
20
17
  };
21
18
  }
22
- async function readJsonIfExists(filePath) {
23
- try {
24
- return JSON.parse(await fs.readFile(filePath, 'utf8'));
25
- }
26
- catch (error) {
27
- if (error?.code === 'ENOENT')
28
- return null;
29
- throw new Error(`Invalid MCP Device state file ${filePath}: ${error?.message || error}`);
30
- }
31
- }
32
- async function copyAtomic(source, target) {
33
- const content = await fs.readFile(source);
34
- await fs.mkdir(path.dirname(target), { recursive: true, mode: 0o700 });
35
- const temporary = `${target}.${process.pid}.${Date.now()}.tmp`;
36
- await fs.writeFile(temporary, content, { mode: 0o600, flag: 'wx' });
37
- await fs.rename(temporary, target);
38
- try {
39
- await fs.chmod(target, 0o600);
40
- }
41
- catch { /* Windows ACLs inherit from the user profile. */ }
42
- }
43
- function identityFingerprint(value) {
44
- if (!value)
45
- return null;
46
- const deviceId = String(value.deviceId || '').trim();
47
- const publicKeyPem = String(value.publicKeyPem || '').trim();
48
- return deviceId && publicKeyPem ? `${deviceId}\n${publicKeyPem}` : null;
49
- }
50
- export async function migrateLegacyDeviceState(paths = deviceStatePaths()) {
51
- await fs.mkdir(paths.root, { recursive: true, mode: 0o700 });
52
- const legacyIdentityPath = path.join(paths.legacyRoot, 'gateway-identity.json');
53
- const canonicalIdentity = await readJsonIfExists(paths.identity);
54
- const legacyIdentity = await readJsonIfExists(legacyIdentityPath);
55
- const legacyPresence = await Promise.all(DEVICE_STATE_FILES.map(async (name) => {
56
- try {
57
- await fs.access(path.join(paths.legacyRoot, name));
58
- return true;
59
- }
60
- catch {
61
- return false;
62
- }
63
- }));
64
- const legacyStateSeen = legacyPresence.some(Boolean);
65
- if (canonicalIdentity && legacyIdentity) {
66
- const canonicalFingerprint = identityFingerprint(canonicalIdentity);
67
- const legacyFingerprint = identityFingerprint(legacyIdentity);
68
- if (!canonicalFingerprint || !legacyFingerprint || canonicalFingerprint !== legacyFingerprint) {
69
- throw new Error('MCP Device migration conflict: canonical and legacy device identities differ.');
70
- }
71
- }
72
- if (legacyStateSeen && !legacyIdentity && !canonicalIdentity) {
73
- throw new Error('MCP Device migration failed closed: legacy state exists without a device identity.');
74
- }
75
- const migrated = [];
76
- for (const name of DEVICE_STATE_FILES) {
77
- const source = path.join(paths.legacyRoot, name);
78
- const target = path.join(paths.root, name);
79
- let sourceExists = true;
80
- try {
81
- await fs.access(source);
82
- }
83
- catch {
84
- sourceExists = false;
85
- }
86
- if (!sourceExists)
87
- continue;
88
- await readJsonIfExists(source);
89
- let targetExists = true;
90
- try {
91
- await fs.access(target);
92
- }
93
- catch {
94
- targetExists = false;
95
- }
96
- if (!targetExists) {
97
- await copyAtomic(source, target);
98
- migrated.push(name);
99
- }
100
- }
101
- return { migrated, legacyStateSeen };
102
- }
@@ -2,7 +2,7 @@
2
2
  import { type RuntimeOwnerStatus } from './runtime-owner.js';
3
3
  export declare class MCPDevice {
4
4
  private isShuttingDown;
5
- private desktop;
5
+ private executionEngine;
6
6
  private gatewayChannel?;
7
7
  private gatewayProxyAgent?;
8
8
  private runtimeOwner?;
@@ -2,7 +2,7 @@
2
2
  import { fileURLToPath } from 'url';
3
3
  import os from 'os';
4
4
  import path from 'path';
5
- import { DesktopCommanderIntegration } from './execution-engine.js';
5
+ import { LocalExecutionEngine } from './execution-engine.js';
6
6
  import { GatewayDeviceChannel } from './gateway-channel.js';
7
7
  import { GatewayDeviceConfigStore, createGatewayProxyAgent } from './gateway-config.js';
8
8
  import { GatewayDeviceIdentity } from './gateway-identity.js';
@@ -17,7 +17,7 @@ import { VERSION } from '../version.js';
17
17
  export class MCPDevice {
18
18
  constructor() {
19
19
  this.isShuttingDown = false;
20
- this.desktop = new DesktopCommanderIntegration();
20
+ this.executionEngine = new LocalExecutionEngine();
21
21
  this.setupShutdownHandlers();
22
22
  }
23
23
  setupShutdownHandlers() {
@@ -75,7 +75,7 @@ export class MCPDevice {
75
75
  await acquireRuntimeOwner(this.runtimeOwner, { confirmTakeover: options.confirmTakeover });
76
76
  await this.runtimeOwner.bootstrap();
77
77
  await bootstrapOfficialGatewayTrust(new GatewayDeviceConfigStore());
78
- await this.desktop.initialize();
78
+ await this.executionEngine.initialize();
79
79
  const gatewayStatus = new GatewayDeviceStatusStore();
80
80
  const storedGatewayStatus = await gatewayStatus.load();
81
81
  const gatewayConfig = await new GatewayDeviceConfigStore().load();
@@ -115,7 +115,8 @@ export class MCPDevice {
115
115
  proxyAgent: proxy.agent,
116
116
  securityProtocolFloor: gatewayConfig.securityProtocolFloor,
117
117
  appCaPem: gatewayConfig.appCaPem || undefined,
118
- adapter: new GatewayToolAdapter(this.desktop, { allowedRoots: gatewayConfig.allowedRoots }),
118
+ adapter: new GatewayToolAdapter(this.executionEngine, { allowedRoots: gatewayConfig.allowedRoots }),
119
+ runtimeState: () => this.executionEngine.getRuntimeState(),
119
120
  agentVersion: process.env.npm_package_version,
120
121
  onUpdateRequest: async (targetVersion, { requestId }) => {
121
122
  const record = await identity.loadOrCreate();
@@ -123,7 +124,7 @@ export class MCPDevice {
123
124
  targetVersion,
124
125
  requestId,
125
126
  deviceId: record.deviceId,
126
- childPid: this.desktop.getChildPid(),
127
+ childPid: this.executionEngine.getChildPid(),
127
128
  fromVersion: VERSION
128
129
  });
129
130
  try {
@@ -142,7 +143,7 @@ export class MCPDevice {
142
143
  // shutdown and RuntimeOwner release before arming the helper.
143
144
  // This preserves G5.6: no destructive update work may begin
144
145
  // until the old runtime has finished releasing package handles.
145
- const childPid = this.desktop.getChildPid();
146
+ const childPid = this.executionEngine.getChildPid();
146
147
  await this.shutdown();
147
148
  await signalDeviceUpdateHandoff({ childPid });
148
149
  process.exit(0);
@@ -224,7 +225,7 @@ export class MCPDevice {
224
225
  this.gatewayProxyAgent = undefined;
225
226
  }
226
227
  await new GatewayDeviceStatusStore().markOffline().catch(() => { });
227
- await this.desktop.shutdown();
228
+ await this.executionEngine.shutdown();
228
229
  if (this.runtimeOwner) {
229
230
  await this.runtimeOwner.release().catch(() => { });
230
231
  this.runtimeOwner = undefined;
@@ -4,13 +4,22 @@ interface McpConfig {
4
4
  cwd?: string;
5
5
  env?: Record<string, string>;
6
6
  }
7
- export declare class DesktopCommanderIntegration {
7
+ export declare class LocalExecutionEngine {
8
8
  private mcpClient;
9
9
  private mcpTransport;
10
10
  private isReady;
11
+ private runtimeReason;
12
+ private runtimeGeneration;
13
+ private markUnavailable;
11
14
  initialize(): Promise<void>;
12
15
  resolveMcpConfig(): Promise<McpConfig | null>;
13
16
  getChildPid(): number | null;
17
+ getRuntimeState(): {
18
+ runtime_ready: boolean;
19
+ runtime_reason: string | null;
20
+ execution_runtime_generation: string | null;
21
+ };
22
+ assertReady(): void;
14
23
  callClientTool(toolName: string, args: any, metadata?: any): Promise<{
15
24
  [x: string]: unknown;
16
25
  content: ({