@zhihand/mcp 0.32.3 → 0.32.4

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/bin/zhihand CHANGED
@@ -30,7 +30,7 @@ import { fetchUserCredentials } from "../dist/core/ws.js";
30
30
  import { configureMCP, displayName } from "../dist/cli/mcp-config.js";
31
31
 
32
32
  const DEFAULT_ENDPOINT = "https://api.zhihand.com";
33
- const VERSION = "0.32.3";
33
+ const VERSION = "0.32.4";
34
34
 
35
35
  const CLI_TOOL_MAP = {
36
36
  claude: "claudecode",
@@ -59,10 +59,11 @@ export function configureMCP(backend, previousBackend) {
59
59
  }
60
60
  else {
61
61
  const cmds = MCP_COMMANDS[backend];
62
- const addCmd = cmds.add();
63
62
  console.log(` Configuring MCP for ${DISPLAY_NAMES[backend]} (HTTP transport)...`);
63
+ // Remove existing entry first to avoid "already exists" error on re-pair
64
+ tryRun(cmds.remove());
64
65
  try {
65
- execSync(addCmd, { stdio: "inherit", timeout: 10_000 });
66
+ execSync(cmds.add(), { stdio: "inherit", timeout: 10_000 });
66
67
  configured = true;
67
68
  }
68
69
  catch (err) {
@@ -43,6 +43,11 @@ export declare function loadConfig(): ZhihandConfigV3;
43
43
  * when the daemon and CLI write concurrently (Gemini code review v0.31).
44
44
  */
45
45
  export declare function saveConfig(cfg: ZhihandConfigV3): void;
46
+ /**
47
+ * Clean up legacy config files (v2 schema, credentials.json) before re-pairing.
48
+ * Replaces old config with empty v3 so loadConfig() won't warn.
49
+ */
50
+ export declare function cleanupLegacyConfig(): void;
46
51
  export declare function addUser(user: UserRecord): void;
47
52
  export declare function removeUser(userId: string): void;
48
53
  export declare function addDeviceToUser(userId: string, device: DeviceRecord): void;
@@ -27,11 +27,11 @@ function emptyConfig() {
27
27
  }
28
28
  export function loadConfig() {
29
29
  if (!fs.existsSync(CONFIG_PATH)) {
30
- // Check for v2 or legacy credentials
30
+ // Check for legacy credentials.json (pre-v3)
31
31
  const legacyCredentials = path.join(ZHIHAND_DIR, "credentials.json");
32
- if (!legacyWarningPrinted && (fs.existsSync(legacyCredentials) || checkForV2Config())) {
32
+ if (!legacyWarningPrinted && fs.existsSync(legacyCredentials)) {
33
33
  legacyWarningPrinted = true;
34
- process.stderr.write("[zhihand] old config detected (v2 or legacy) — run 'zhihand pair' to re-pair on v0.31 schema\n");
34
+ process.stderr.write("[zhihand] old config detected (legacy credentials) — run 'zhihand pair' to re-pair on v0.31 schema\n");
35
35
  }
36
36
  return emptyConfig();
37
37
  }
@@ -43,7 +43,7 @@ export function loadConfig() {
43
43
  users: raw.users ?? {},
44
44
  };
45
45
  }
46
- // Old schema version detected
46
+ // Old schema version (v2 or unknown) in config.json
47
47
  if (!legacyWarningPrinted) {
48
48
  legacyWarningPrinted = true;
49
49
  process.stderr.write("[zhihand] old config detected (schema v" + (raw.schema_version ?? "?") + ") — run 'zhihand pair' to re-pair on v0.31 schema\n");
@@ -54,17 +54,6 @@ export function loadConfig() {
54
54
  }
55
55
  return emptyConfig();
56
56
  }
57
- function checkForV2Config() {
58
- if (!fs.existsSync(CONFIG_PATH))
59
- return false;
60
- try {
61
- const raw = JSON.parse(fs.readFileSync(CONFIG_PATH, "utf8"));
62
- return raw && raw.schema_version === 2;
63
- }
64
- catch {
65
- return false;
66
- }
67
- }
68
57
  /**
69
58
  * Atomically write config: write to .tmp, then rename. Prevents corruption
70
59
  * when the daemon and CLI write concurrently (Gemini code review v0.31).
@@ -75,6 +64,27 @@ export function saveConfig(cfg) {
75
64
  fs.writeFileSync(tmpPath, JSON.stringify(cfg, null, 2), { mode: 0o600 });
76
65
  fs.renameSync(tmpPath, CONFIG_PATH);
77
66
  }
67
+ /**
68
+ * Clean up legacy config files (v2 schema, credentials.json) before re-pairing.
69
+ * Replaces old config with empty v3 so loadConfig() won't warn.
70
+ */
71
+ export function cleanupLegacyConfig() {
72
+ const legacyCredentials = path.join(ZHIHAND_DIR, "credentials.json");
73
+ if (fs.existsSync(legacyCredentials)) {
74
+ fs.unlinkSync(legacyCredentials);
75
+ }
76
+ if (fs.existsSync(CONFIG_PATH)) {
77
+ try {
78
+ const raw = JSON.parse(fs.readFileSync(CONFIG_PATH, "utf8"));
79
+ if (!raw || raw.schema_version !== 3) {
80
+ saveConfig(emptyConfig());
81
+ }
82
+ }
83
+ catch {
84
+ saveConfig(emptyConfig());
85
+ }
86
+ }
87
+ }
78
88
  // ── User helpers ──────────────────────────────────────────
79
89
  export function addUser(user) {
80
90
  const cfg = loadConfig();
package/dist/core/pair.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import QRCode from "qrcode";
2
- import { addUser, addDeviceToUser, ensureZhiHandDir, saveState, resolveDefaultEndpoint, getUserRecord, } from "./config.js";
2
+ import { addUser, addDeviceToUser, ensureZhiHandDir, saveState, resolveDefaultEndpoint, getUserRecord, cleanupLegacyConfig, } from "./config.js";
3
3
  import { fetchDeviceProfileOnce, extractStatic } from "./device.js";
4
4
  import { fetchUserCredentials } from "./ws.js";
5
5
  // ── Server API helpers ─────────────────────────────────────
@@ -93,6 +93,8 @@ export async function executePairingNewUser(preferredLabel) {
93
93
  const label = preferredLabel ?? `User-${Date.now().toString(36)}`;
94
94
  // 1. Create user
95
95
  const userResp = await createUser(endpoint, label);
96
+ // Clean up v2/legacy config after network call succeeds (avoids data loss on failure)
97
+ cleanupLegacyConfig();
96
98
  const userId = userResp.user_id;
97
99
  const controllerToken = userResp.controller_token;
98
100
  // 2. Register plugin (get edge_id)
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
1
  import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
- export declare const PACKAGE_VERSION = "0.32.3";
2
+ export declare const PACKAGE_VERSION = "0.32.4";
3
3
  export declare function createServer(): McpServer;
4
4
  export declare function startStdioServer(): Promise<void>;
package/dist/index.js CHANGED
@@ -8,7 +8,7 @@ import { handlePair } from "./tools/pair.js";
8
8
  import { resolveTargetDevice } from "./tools/resolve.js";
9
9
  import { buildControlToolDescription, buildSystemToolDescription, buildScreenshotToolDescription, formatDeviceStatus, extractDynamic, } from "./core/device.js";
10
10
  import { registry } from "./core/registry.js";
11
- export const PACKAGE_VERSION = "0.32.3";
11
+ export const PACKAGE_VERSION = "0.32.4";
12
12
  function errorResult(message) {
13
13
  return { content: [{ type: "text", text: message }], isError: true };
14
14
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zhihand/mcp",
3
- "version": "0.32.3",
3
+ "version": "0.32.4",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "description": "ZhiHand MCP Server — phone control tools for Claude Code, Codex, Gemini CLI, and OpenClaw",