@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.
- package/README.md +7 -71
- package/dist/bootstrap.js +1 -1
- package/dist/config-manager.js +1 -1
- package/dist/config.js +1 -1
- package/dist/custom-stdio.js +1 -2
- package/dist/data/onboarding-prompts.json +22 -11
- package/dist/device/device-state.d.ts +0 -5
- package/dist/device/device-state.js +0 -84
- package/dist/device/device.d.ts +1 -1
- package/dist/device/device.js +8 -7
- package/dist/device/execution-engine.d.ts +10 -1
- package/dist/device/execution-engine.js +81 -128
- package/dist/device/gateway-channel.d.ts +6 -0
- package/dist/device/gateway-channel.js +16 -1
- package/dist/device/gateway-tool-adapter.d.ts +3 -3
- package/dist/device/gateway-tool-adapter.js +12 -11
- package/dist/device/linux-service.d.ts +4 -0
- package/dist/device/linux-service.js +10 -3
- package/dist/device/runtime-owner.js +2 -2
- package/dist/device/self-update.js +3 -1
- package/dist/device/windows-service.d.ts +3 -4
- package/dist/device/windows-service.js +5 -44
- package/dist/npm-scripts/remote.js +0 -2
- package/dist/server.js +9 -99
- package/dist/terminal-manager.js +1 -1
- package/dist/tools/config.d.ts +1 -1
- package/dist/tools/filesystem.js +3 -3
- package/dist/tools/pdf/markdown.js +1 -1
- package/dist/tools/schemas.d.ts +2 -3
- package/dist/tools/schemas.js +0 -10
- package/dist/ui/config-editor/index.html +1 -1
- package/dist/ui/file-preview/index.html +1 -1
- package/dist/ui/file-preview/styles.css +2 -2
- package/dist/utils/capture.d.ts +5 -28
- package/dist/utils/capture.js +11 -455
- package/dist/utils/feature-flags.d.ts +0 -47
- package/dist/utils/feature-flags.js +5 -199
- package/dist/utils/files/docx.d.ts +2 -2
- package/dist/utils/files/docx.js +2 -2
- package/dist/utils/usageTracker.js +0 -24
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +5 -6
- package/dist/tools/feedback.d.ts +0 -8
- 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
|
-
##
|
|
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
|
|
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
|
|
40
|
-
mcp-device install pair if needed, then install and start
|
|
41
|
-
mcp-device stop stop the current runtime
|
|
42
|
-
mcp-device uninstall remove background registration while preserving identity
|
|
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
|
|
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
|
package/dist/config-manager.js
CHANGED
|
@@ -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
|
|
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 ||
|
|
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');
|
package/dist/custom-stdio.js
CHANGED
|
@@ -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": "
|
|
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": [
|
|
10
|
+
"categories": [
|
|
11
|
+
"onboarding"
|
|
12
|
+
],
|
|
11
13
|
"secondaryTag": "Quick Start",
|
|
12
14
|
"votes": 0,
|
|
13
15
|
"gaClicks": 0,
|
|
14
16
|
"icon": "FolderOpen",
|
|
15
|
-
"author": "
|
|
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": [
|
|
25
|
+
"categories": [
|
|
26
|
+
"onboarding"
|
|
27
|
+
],
|
|
28
|
+
"secondaryTag": "Code Analysis",
|
|
24
29
|
"votes": 0,
|
|
25
30
|
"gaClicks": 0,
|
|
26
31
|
"icon": "Code",
|
|
27
|
-
"author": "
|
|
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": [
|
|
40
|
+
"categories": [
|
|
41
|
+
"onboarding"
|
|
42
|
+
],
|
|
36
43
|
"secondaryTag": "Quick Start",
|
|
37
44
|
"votes": 0,
|
|
38
45
|
"gaClicks": 0,
|
|
39
46
|
"icon": "BookOpen",
|
|
40
|
-
"author": "
|
|
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": [
|
|
55
|
+
"categories": [
|
|
56
|
+
"onboarding"
|
|
57
|
+
],
|
|
49
58
|
"secondaryTag": "Quick Start",
|
|
50
59
|
"votes": 0,
|
|
51
60
|
"gaClicks": 0,
|
|
52
61
|
"icon": "BarChart3",
|
|
53
|
-
"author": "
|
|
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": [
|
|
70
|
+
"categories": [
|
|
71
|
+
"onboarding"
|
|
72
|
+
],
|
|
62
73
|
"secondaryTag": "Quick Start",
|
|
63
74
|
"votes": 0,
|
|
64
75
|
"gaClicks": 0,
|
|
65
76
|
"icon": "Activity",
|
|
66
|
-
"author": "
|
|
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
|
-
}
|
package/dist/device/device.d.ts
CHANGED
package/dist/device/device.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import { fileURLToPath } from 'url';
|
|
3
3
|
import os from 'os';
|
|
4
4
|
import path from 'path';
|
|
5
|
-
import {
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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
|
|
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: ({
|