@harusame64/desktop-touch-mcp 0.15.6 → 1.0.3

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 (5) hide show
  1. package/LICENSE +21 -21
  2. package/README.ja.md +616 -516
  3. package/README.md +781 -685
  4. package/bin/launcher.js +83 -7
  5. package/package.json +79 -78
package/bin/launcher.js CHANGED
@@ -2,6 +2,7 @@
2
2
 
3
3
  import { execFile, spawn } from "node:child_process";
4
4
  import { createReadStream, createWriteStream, existsSync } from "node:fs";
5
+ import { fileURLToPath } from "node:url";
5
6
  import {
6
7
  mkdir,
7
8
  mkdtemp,
@@ -17,15 +18,15 @@ import path from "node:path";
17
18
  import { Readable } from "node:stream";
18
19
  import { pipeline } from "node:stream/promises";
19
20
 
20
- const PACKAGE_VERSION = "0.15.6";
21
+ const PACKAGE_VERSION = "1.0.3";
21
22
  const RELEASE_TAG = `v${PACKAGE_VERSION}`;
22
23
  const REPO_API_URL = `https://api.github.com/repos/Harusame64/desktop-touch-mcp/releases/tags/${RELEASE_TAG}`;
23
24
  const ASSET_NAME = "desktop-touch-mcp-windows.zip";
24
25
  const RELEASE_METADATA_FILE = ".desktop-touch-release.json";
25
26
  const RELEASE_MANIFEST = {
26
- tagName: "v0.15.6",
27
+ tagName: "v1.0.3",
27
28
  assetName: ASSET_NAME,
28
- sha256: "0bd778c91e32bbb800548acb66ec76b5651af4d64cdb98ca185d0e2635646a78",
29
+ sha256: "f019db6e0194dcf09f7428e8e42af7902de6f842695568eb7897750803d0807e",
29
30
  };
30
31
  const CACHE_ROOT = process.env.DESKTOP_TOUCH_MCP_HOME
31
32
  ? path.resolve(process.env.DESKTOP_TOUCH_MCP_HOME)
@@ -42,6 +43,71 @@ function fail(message) {
42
43
  process.exit(1);
43
44
  }
44
45
 
46
+ export function isDisconnectError(error) {
47
+ return error?.code === "EPIPE" || error?.code === "ERR_STREAM_DESTROYED";
48
+ }
49
+
50
+ export function wireLauncherStdio(child, options = {}) {
51
+ const parentStdin = options.parentStdin ?? process.stdin;
52
+ const parentStdout = options.parentStdout ?? process.stdout;
53
+ const parentStderr = options.parentStderr ?? process.stderr;
54
+ const shutdownGraceMs = options.shutdownGraceMs ?? 1000;
55
+
56
+ let shutdownRequested = false;
57
+ let forcedShutdownTimer = null;
58
+
59
+ function clearForcedShutdownTimer() {
60
+ if (forcedShutdownTimer !== null) {
61
+ clearTimeout(forcedShutdownTimer);
62
+ forcedShutdownTimer = null;
63
+ }
64
+ }
65
+
66
+ function requestChildShutdown() {
67
+ if (shutdownRequested) return;
68
+ shutdownRequested = true;
69
+ try {
70
+ child.stdin?.end();
71
+ } catch {
72
+ // ignore
73
+ }
74
+ forcedShutdownTimer = setTimeout(() => {
75
+ if (child.exitCode === null && !child.killed) {
76
+ try { child.kill("SIGTERM"); } catch { /* ignore */ }
77
+ }
78
+ }, shutdownGraceMs);
79
+ if (forcedShutdownTimer.unref) forcedShutdownTimer.unref();
80
+ }
81
+
82
+ function terminateChild() {
83
+ clearForcedShutdownTimer();
84
+ if (child.exitCode === null && !child.killed) {
85
+ try { child.kill("SIGTERM"); } catch { /* ignore */ }
86
+ }
87
+ }
88
+
89
+ parentStdin.pipe(child.stdin);
90
+ child.stdout?.pipe(parentStdout);
91
+ child.stderr?.pipe(parentStderr);
92
+
93
+ parentStdin.on("end", requestChildShutdown);
94
+ parentStdin.on("close", requestChildShutdown);
95
+ parentStdin.on("error", requestChildShutdown);
96
+
97
+ const onParentOutputError = (error) => {
98
+ if (isDisconnectError(error)) {
99
+ terminateChild();
100
+ }
101
+ };
102
+ parentStdout.on("error", onParentOutputError);
103
+ parentStderr.on("error", onParentOutputError);
104
+
105
+ child.stdin?.on("error", (error) => {
106
+ if (!isDisconnectError(error)) throw error;
107
+ });
108
+ child.on("exit", clearForcedShutdownTimer);
109
+ }
110
+
45
111
  function tagToDirName(tagName) {
46
112
  const safe = String(tagName || "latest").replace(/[^a-zA-Z0-9._-]/g, "_");
47
113
  return safe || "latest";
@@ -286,10 +352,12 @@ function launchServer(releaseDir) {
286
352
  const entry = path.join(releaseDir, "dist", "index.js");
287
353
  const child = spawn(process.execPath, [entry, ...process.argv.slice(2)], {
288
354
  cwd: releaseDir,
289
- stdio: "inherit",
355
+ stdio: ["pipe", "pipe", "pipe"],
290
356
  windowsHide: false,
291
357
  });
292
358
 
359
+ wireLauncherStdio(child);
360
+
293
361
  for (const signal of ["SIGINT", "SIGTERM"]) {
294
362
  process.on(signal, () => {
295
363
  if (!child.killed) child.kill(signal);
@@ -318,6 +386,14 @@ async function main() {
318
386
  launchServer(releaseDir);
319
387
  }
320
388
 
321
- main().catch((error) => {
322
- fail(error instanceof Error ? error.message : String(error));
323
- });
389
+ const launchedAsScript = (() => {
390
+ const entry = process.argv[1];
391
+ if (!entry) return false;
392
+ return path.resolve(entry) === path.resolve(fileURLToPath(import.meta.url));
393
+ })();
394
+
395
+ if (launchedAsScript) {
396
+ main().catch((error) => {
397
+ fail(error instanceof Error ? error.message : String(error));
398
+ });
399
+ }
package/package.json CHANGED
@@ -1,78 +1,79 @@
1
- {
2
- "name": "@harusame64/desktop-touch-mcp",
3
- "version": "0.15.6",
4
- "mcpName": "io.github.Harusame64/desktop-touch-mcp",
5
- "description": "LLM-native Windows computer-use MCP server with 56 tools for screenshots, UIA, mouse/keyboard, Chrome CDP, terminal, SmartScroll, and perception guards",
6
- "engines": {
7
- "node": ">=20.0.0"
8
- },
9
- "type": "module",
10
- "main": "bin/launcher.js",
11
- "bin": {
12
- "desktop-touch-mcp": "bin/launcher.js"
13
- },
14
- "files": [
15
- "bin/launcher.js",
16
- "LICENSE",
17
- "README.md",
18
- "README.ja.md"
19
- ],
20
- "publishConfig": {
21
- "access": "public"
22
- },
23
- "napi": {
24
- "name": "desktop-touch-engine",
25
- "triples": {
26
- "defaults": false,
27
- "additional": [
28
- "x86_64-pc-windows-msvc"
29
- ]
30
- }
31
- },
32
- "repository": {
33
- "type": "git",
34
- "url": "git+https://github.com/Harusame64/desktop-touch-mcp.git"
35
- },
36
- "bugs": {
37
- "url": "https://github.com/Harusame64/desktop-touch-mcp/issues"
38
- },
39
- "homepage": "https://github.com/Harusame64/desktop-touch-mcp#readme",
40
- "license": "MIT",
41
- "scripts": {
42
- "build": "tsc",
43
- "sync-version": "node scripts/sync-version.mjs",
44
- "check:launcher-manifest": "node scripts/check-launcher-manifest.mjs",
45
- "version": "npm run sync-version && git add src/version.ts bin/launcher.js",
46
- "prepare": "tsc",
47
- "start": "node dist/index.js",
48
- "dev": "tsc --watch",
49
- "test": "vitest run",
50
- "test:capture": "node scripts/test-capture.mjs",
51
- "test:unit": "vitest run --project=unit",
52
- "test:e2e": "vitest run --project=e2e",
53
- "test:headed": "HEADED=1 vitest run --project=e2e",
54
- "test:e2e:browser": "vitest run --project=e2e \"tests/e2e/browser-*.test.ts\"",
55
- "test:e2e:window": "vitest run --project=e2e tests/e2e/dock-window.test.ts tests/e2e/dock-auto.test.ts tests/e2e/focus-integrity.test.ts tests/e2e/force-focus.test.ts tests/e2e/screenshot-electron.test.ts tests/e2e/ui-elements-cache.test.ts",
56
- "test:e2e:input": "vitest run --project=e2e tests/e2e/keyboard-focus-lost.test.ts tests/e2e/mouse-focus-lost.test.ts tests/e2e/terminal.test.ts",
57
- "test:e2e:perception": "vitest run --project=e2e tests/e2e/perception-mvp.test.ts tests/e2e/rich-narration-edge.test.ts",
58
- "test:watch": "vitest",
59
- "generate:stub-catalog": "node scripts/generate-stub-tool-catalog.mjs",
60
- "check:stub-catalog": "node scripts/generate-stub-tool-catalog.mjs && git diff --exit-code src/stub-tool-catalog.ts",
61
- "build:rs": "napi build --platform --release",
62
- "build:rs:debug": "napi build --platform",
63
- "artifacts:rs": "napi artifacts"
64
- },
65
- "devDependencies": {
66
- "@modelcontextprotocol/sdk": "^1.10.0",
67
- "@napi-rs/cli": "^3.6.2",
68
- "@nut-tree-fork/nut-js": "^4.2.6",
69
- "@types/node": "^25.6.0",
70
- "@types/ws": "^8.18.1",
71
- "koffi": "^2.9.0",
72
- "sharp": "^0.34.5",
73
- "typescript": "^6.0.2",
74
- "vitest": "^4.1.4",
75
- "ws": "^8.20.0",
76
- "zod": "^4.3.6"
77
- }
78
- }
1
+ {
2
+ "name": "@harusame64/desktop-touch-mcp",
3
+ "version": "1.0.3",
4
+ "mcpName": "io.github.Harusame64/desktop-touch-mcp",
5
+ "description": "LLM-native Windows computer-use MCP server with 56 tools for screenshots, UIA, mouse/keyboard, Chrome CDP, terminal, SmartScroll, and perception guards",
6
+ "engines": {
7
+ "node": ">=20.0.0"
8
+ },
9
+ "type": "module",
10
+ "main": "bin/launcher.js",
11
+ "bin": {
12
+ "desktop-touch-mcp": "bin/launcher.js"
13
+ },
14
+ "files": [
15
+ "bin/launcher.js",
16
+ "LICENSE",
17
+ "README.md",
18
+ "README.ja.md"
19
+ ],
20
+ "publishConfig": {
21
+ "access": "public"
22
+ },
23
+ "napi": {
24
+ "name": "desktop-touch-engine",
25
+ "triples": {
26
+ "defaults": false,
27
+ "additional": [
28
+ "x86_64-pc-windows-msvc"
29
+ ]
30
+ }
31
+ },
32
+ "repository": {
33
+ "type": "git",
34
+ "url": "git+https://github.com/Harusame64/desktop-touch-mcp.git"
35
+ },
36
+ "bugs": {
37
+ "url": "https://github.com/Harusame64/desktop-touch-mcp/issues"
38
+ },
39
+ "homepage": "https://github.com/Harusame64/desktop-touch-mcp#readme",
40
+ "license": "MIT",
41
+ "scripts": {
42
+ "build": "tsc",
43
+ "sync-version": "node scripts/sync-version.mjs",
44
+ "check:launcher-manifest": "node scripts/check-launcher-manifest.mjs",
45
+ "update-sha": "node scripts/update-sha.mjs",
46
+ "version": "npm run sync-version && git add src/version.ts bin/launcher.js",
47
+ "prepare": "tsc",
48
+ "start": "node dist/index.js",
49
+ "dev": "tsc --watch",
50
+ "test": "vitest run",
51
+ "test:capture": "node scripts/test-capture.mjs",
52
+ "test:unit": "vitest run --project=unit",
53
+ "test:e2e": "vitest run --project=e2e",
54
+ "test:headed": "HEADED=1 vitest run --project=e2e",
55
+ "test:e2e:browser": "vitest run --project=e2e \"tests/e2e/browser-*.test.ts\"",
56
+ "test:e2e:window": "vitest run --project=e2e tests/e2e/dock-window.test.ts tests/e2e/dock-auto.test.ts tests/e2e/focus-integrity.test.ts tests/e2e/force-focus.test.ts tests/e2e/screenshot-electron.test.ts tests/e2e/ui-elements-cache.test.ts",
57
+ "test:e2e:input": "vitest run --project=e2e tests/e2e/keyboard-focus-lost.test.ts tests/e2e/mouse-focus-lost.test.ts tests/e2e/terminal.test.ts",
58
+ "test:e2e:perception": "vitest run --project=e2e tests/e2e/perception-mvp.test.ts tests/e2e/rich-narration-edge.test.ts",
59
+ "test:watch": "vitest",
60
+ "generate:stub-catalog": "node scripts/generate-stub-tool-catalog.mjs",
61
+ "check:stub-catalog": "node scripts/generate-stub-tool-catalog.mjs && git diff --exit-code src/stub-tool-catalog.ts",
62
+ "build:rs": "napi build --platform --release && node -e \"const d=require('child_process').execSync('git diff -- index.d.ts').toString();if(d){console.warn('\\n⚠️ napi changed index.d.ts — update native-types.ts!\\n');console.warn(d)}\" && git restore --source=HEAD -- index.d.ts index.js",
63
+ "build:rs:debug": "napi build --platform && node -e \"const d=require('child_process').execSync('git diff -- index.d.ts').toString();if(d){console.warn('\\n⚠️ napi changed index.d.ts — update native-types.ts!\\n');console.warn(d)}\" && git restore --source=HEAD -- index.d.ts index.js",
64
+ "artifacts:rs": "napi artifacts"
65
+ },
66
+ "devDependencies": {
67
+ "@modelcontextprotocol/sdk": "^1.10.0",
68
+ "@napi-rs/cli": "^3.6.2",
69
+ "@nut-tree-fork/nut-js": "^4.2.6",
70
+ "@types/node": "^25.6.0",
71
+ "@types/ws": "^8.18.1",
72
+ "koffi": "^2.9.0",
73
+ "sharp": "^0.34.5",
74
+ "typescript": "^6.0.2",
75
+ "vitest": "^4.1.4",
76
+ "ws": "^8.20.0",
77
+ "zod": "^4.3.6"
78
+ }
79
+ }