@hirey/hi-mcp-server 0.1.11 → 0.1.13

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 CHANGED
@@ -86,6 +86,8 @@ npm install -g @hirey/hi-mcp-server
86
86
  }
87
87
  ```
88
88
 
89
+ 这里的 `HI_MCP_STATE_DIR` 必须直接指向 profile 对应的叶子目录;不要只写父目录 `/Users/you/.openclaw/hi-mcp`,否则虽然 `openclaw-main.json` 还能落盘,但 receiver config 和 doctor 会把它识别成非 canonical OpenClaw 布局。
90
+
89
91
  普通用户首次接入后的典型顺序:
90
92
 
91
93
  1. 用宿主把 `hi-mcp-server` 作为 `stdio` MCP server 挂上
@@ -100,7 +102,7 @@ npm install -g @hirey/hi-mcp-server
100
102
 
101
103
  对 OpenClaw 的普通用户本地 vendor 安装,不要显式传 `receiver_command="hi-agent-receiver"` 或 `receiver_command_argv=["hi-agent-receiver"]`。这两种旧形态都会重新把启动语义写回“按 PATH 找全局命令”。OpenClaw 要么不传 receiver 启动覆盖,让安装流默认落到 `~/.openclaw/vendor/hi/node_modules/.bin/hi-agent-receiver`,要么只传指向该本地 vendor binary 的精确 `receiver_command_argv`。
102
104
 
103
- 如果宿主此刻就知道“当前用户会话就是 Hi 以后该回去的默认线程”,`hi_agent_install` 也可以直接带上 `host_session_key`、`default_reply_channel`、`default_reply_to`、`default_reply_account_id`、`default_reply_thread_id`、`route_missing_policy`。这组字段会同时写进 installation 的 `delivery_capabilities` 和本地 receiver config,避免出现 gateway 已经知道默认 route、但本地 receiver 还沿旧配置投递的漂移。
105
+ OpenClaw 的普通用户安装,默认就应该把当前聊天绑成 Hi 以后回来的默认线程。因此 `hi_agent_install` 应直接带上 `host_session_key`、`default_reply_channel`、`default_reply_to`、`default_reply_account_id`、`default_reply_thread_id`、`route_missing_policy`。这组字段会同时写进 installation 的 `delivery_capabilities` 和本地 receiver config,避免出现 gateway 已经知道默认 route、但本地 receiver 还沿旧配置投递的漂移。如果拿不到当前聊天的 canonical `host_session_key`,OpenClaw 安装不应宣告成功,而应先把 continuity blocker 说明白。
104
106
 
105
107
  安装后如果要显式验证 continuation route,可以用 `hi_agent_test_delivery`:既可以直接传 `host_session_key` / `reply_*` 做一次显式 route probe,也可以在 installation 已设置 `default_reply_route` 时不传这些字段,让 gateway 自动沿当前 installation 的默认 route 发 probe。
106
108
 
@@ -124,11 +126,18 @@ npm install -g @hirey/hi-mcp-server
124
126
  - `HI_MCP_STATE_DIR`
125
127
  - 本地 state 目录。未显式指定时,默认落到稳定 home 目录:`~/.hirey/hi-mcp/<profile>`。
126
128
  - OpenClaw 普通用户建议显式固定到 canonical 目录,例如 `/Users/you/.openclaw/hi-mcp/openclaw-main`,方便后续 `hi-agent-receiver` 直接复用同一份身份 state。
129
+ - 不要把它设置成 bare parent dir `/Users/you/.openclaw/hi-mcp`;OpenClaw 场景下必须把 profile 叶子目录也包含进去。
127
130
 
128
131
  ### 本地 state
129
132
 
130
133
  state 会按 profile 落到 `HI_MCP_STATE_DIR/<profile>.json`。
131
134
 
135
+ 对 OpenClaw 而言,推荐的 canonical 形态就是:
136
+
137
+ - `HI_MCP_PROFILE=openclaw-main`
138
+ - `HI_MCP_STATE_DIR=/Users/you/.openclaw/hi-mcp/openclaw-main`
139
+ - 最终 state file = `/Users/you/.openclaw/hi-mcp/openclaw-main/openclaw-main.json`
140
+
132
141
  文件内部明确分成两块:
133
142
 
134
143
  - `identity`
@@ -12,4 +12,15 @@ export declare function resolveInstallDefaultReplyDeliveryContext(args: {
12
12
  defaultReplyAccountId?: unknown;
13
13
  defaultReplyThreadId?: unknown;
14
14
  }): DefaultReplyDeliveryContext | null;
15
+ export declare function resolveInstallRouteMissingPolicy(args: {
16
+ hostKind: 'openclaw' | 'generic';
17
+ explicitRouteMissingPolicy?: unknown;
18
+ defaultReplyRoute?: Record<string, unknown> | null;
19
+ }): {
20
+ ok: true;
21
+ routeMissingPolicy: string;
22
+ } | {
23
+ ok: false;
24
+ error: 'missing_openclaw_default_reply_route';
25
+ };
15
26
  //# sourceMappingURL=defaultReplyRoute.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"defaultReplyRoute.d.ts","sourceRoot":"","sources":["../src/defaultReplyRoute.ts"],"names":[],"mappings":"AAIA,MAAM,MAAM,2BAA2B,GAAG;IACxC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,EAAE,EAAE,MAAM,GAAG,IAAI,CAAC;IAClB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1B,CAAC;AAEF,wBAAgB,yCAAyC,CAAC,IAAI,EAAE;IAC9D,QAAQ,EAAE,UAAU,GAAG,SAAS,CAAC;IACjC,aAAa,EAAE,OAAO,CAAC;IACvB,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,qBAAqB,CAAC,EAAE,OAAO,CAAC;IAChC,oBAAoB,CAAC,EAAE,OAAO,CAAC;CAChC,GAAG,2BAA2B,GAAG,IAAI,CAyBrC"}
1
+ {"version":3,"file":"defaultReplyRoute.d.ts","sourceRoot":"","sources":["../src/defaultReplyRoute.ts"],"names":[],"mappings":"AAIA,MAAM,MAAM,2BAA2B,GAAG;IACxC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,EAAE,EAAE,MAAM,GAAG,IAAI,CAAC;IAClB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1B,CAAC;AAEF,wBAAgB,yCAAyC,CAAC,IAAI,EAAE;IAC9D,QAAQ,EAAE,UAAU,GAAG,SAAS,CAAC;IACjC,aAAa,EAAE,OAAO,CAAC;IACvB,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,qBAAqB,CAAC,EAAE,OAAO,CAAC;IAChC,oBAAoB,CAAC,EAAE,OAAO,CAAC;CAChC,GAAG,2BAA2B,GAAG,IAAI,CAyBrC;AAED,wBAAgB,gCAAgC,CAAC,IAAI,EAAE;IACrD,QAAQ,EAAE,UAAU,GAAG,SAAS,CAAC;IACjC,0BAA0B,CAAC,EAAE,OAAO,CAAC;IACrC,iBAAiB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;CACpD,GAAG;IACF,EAAE,EAAE,IAAI,CAAC;IACT,kBAAkB,EAAE,MAAM,CAAC;CAC5B,GAAG;IACF,EAAE,EAAE,KAAK,CAAC;IACV,KAAK,EAAE,sCAAsC,CAAC;CAC/C,CAcA"}
@@ -26,3 +26,18 @@ export function resolveInstallDefaultReplyDeliveryContext(args) {
26
26
  }
27
27
  return null;
28
28
  }
29
+ export function resolveInstallRouteMissingPolicy(args) {
30
+ const explicitRouteMissingPolicy = normalizeText(args.explicitRouteMissingPolicy);
31
+ // OpenClaw 安装默认就要把当前聊天绑成默认续聊入口;否则安装不该继续宣告成功。
32
+ if (args.hostKind === 'openclaw' && !args.defaultReplyRoute) {
33
+ return {
34
+ ok: false,
35
+ error: 'missing_openclaw_default_reply_route',
36
+ };
37
+ }
38
+ return {
39
+ ok: true,
40
+ routeMissingPolicy: explicitRouteMissingPolicy
41
+ || (args.defaultReplyRoute ? 'use_explicit_default_route' : ''),
42
+ };
43
+ }
package/dist/server.js CHANGED
@@ -11,11 +11,11 @@ import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/
11
11
  import { CallToolRequestSchema, ListToolsRequestSchema, } from '@modelcontextprotocol/sdk/types.js';
12
12
  import { AGENT_GATEWAY_EVENT_TOPICS, normalizeAgentEndpointList, normalizeAgentInstallationDeliveryDeclaration, normalizeAgentSubscriptionList, normalizeText, } from '@hirey/hi-agent-contracts';
13
13
  import { createHiAgentClients, exchangeHiAgentClientCredentialsToken, HiAgentGatewayClient, HiAgentPlatformClient, } from '@hirey/hi-agent-sdk';
14
- import { readState, resolveCanonicalOpenClawStateDir, resolveDefaultStateDir, resolveLegacyStateFiles, resolveStateFile, updateState, normalizeStateProfile, } from './state.js';
14
+ import { readState, resolveCanonicalOpenClawStateDir, resolveDefaultStateDir, resolveLegacyStateFiles, resolveStateFile, validateOpenClawStateDir, updateState, normalizeStateProfile, } from './state.js';
15
15
  import { looksLikeOpenClawSessionKey, validateOpenClawSessionKey, } from './openclaw-session-key.js';
16
16
  import { buildInstallReceiverCommandArgv, } from './receiver-command.js';
17
17
  import { applyReceiverRuntimeSnapshot, receiverConfigMaterialEquals, } from './receiver-config-material.js';
18
- import { resolveInstallDefaultReplyDeliveryContext, } from './defaultReplyRoute.js';
18
+ import { resolveInstallDefaultReplyDeliveryContext, resolveInstallRouteMissingPolicy, } from './defaultReplyRoute.js';
19
19
  const CAPABILITY_CACHE_TTL_MS = 30_000;
20
20
  const RECEIVER_STOP_TIMEOUT_MS = 3_000;
21
21
  const RECEIVER_STOP_POLL_MS = 100;
@@ -113,8 +113,8 @@ function controlTools() {
113
113
  host_adapter_url: { type: 'string', description: 'enable_local_receiver=true 时可选:宿主本地接收入口。OpenClaw 默认 full endpoint 为 http://127.0.0.1:18789/hooks/agent;注意 OpenClaw 配置里的 hooks.path 应保持 /hooks,而不是 /hooks/agent。' },
114
114
  host_adapter_bearer_token: { type: 'string', description: 'host_adapter_kind=openclaw_hooks 时必填:本地 hooks bearer token。' },
115
115
  openresponses_model: { type: 'string', description: 'host_adapter_kind=openresponses 时必填:receiver 发给本地入口使用的 model。' },
116
- host_session_key: { type: 'string', description: '可选:把当前 OpenClaw 当前会话显式设为 default continuation route 的 canonical full session_key。只能使用结构化宿主来源返回的完整 key;不要从 openclaw status / openclaw sessions / TUI footer 这类展示文本里抄值。' },
117
- route_missing_policy: { type: 'string', description: "可选:'use_explicit_default_route'|'fail_closed'。默认在提供 host_session_key/default_reply_* 时使用 use_explicit_default_route,否则为 null。" },
116
+ host_session_key: { type: 'string', description: 'OpenClaw 安装默认应传:把当前 OpenClaw 当前会话设为 default continuation route 的 canonical full session_key。只能使用结构化宿主来源返回的完整 key;不要从 openclaw status / openclaw sessions / TUI footer 这类展示文本里抄值。' },
117
+ route_missing_policy: { type: 'string', description: "可选:'use_explicit_default_route'|'fail_closed'。OpenClaw 安装默认要求当前聊天 ready,因此在提供 host_session_key/default_reply_* 时应使用 use_explicit_default_route;缺失 default route 时安装会直接失败,而不是继续留下 continuity_not_ready。" },
118
118
  default_reply_channel: { type: 'string', description: '可选:default continuation route 的 channel。' },
119
119
  default_reply_to: { type: 'string', description: '可选:default continuation route 的宿主 target。' },
120
120
  default_reply_account_id: { type: 'string', description: '可选:default continuation route 的 account_id。' },
@@ -836,6 +836,7 @@ function buildDoctorSummary(args) {
836
836
  route_missing_policy: routeMissingPolicy,
837
837
  default_reply_route: defaultReplyRoute,
838
838
  default_reply_route_validation: args.defaultReplyRouteValidation,
839
+ openclaw_state_dir_validation: args.openClawStateDirValidation,
839
840
  delivery_probe: args.deliveryProbe,
840
841
  delivery_probe_diagnostics: args.deliveryProbeDiagnostics,
841
842
  };
@@ -1087,11 +1088,23 @@ async function handleDoctor(args) {
1087
1088
  reason: null,
1088
1089
  session_key: null,
1089
1090
  };
1091
+ let openClawStateDirValidation = null;
1090
1092
  if (!state.identity) {
1091
1093
  blockers.push('missing_agent_identity');
1092
1094
  }
1093
- if (installState.host_kind === 'openclaw' && config.stateDir !== resolveCanonicalOpenClawStateDir(config.profile)) {
1094
- warnings.push('openclaw_state_dir_not_canonical');
1095
+ if (installState.host_kind === 'openclaw') {
1096
+ const validation = validateOpenClawStateDir(config.stateDir, config.profile);
1097
+ openClawStateDirValidation = {
1098
+ configured_state_dir: validation.configured_state_dir,
1099
+ canonical_state_dir: validation.canonical_state_dir,
1100
+ reason: validation.reason,
1101
+ };
1102
+ if (!validation.is_canonical) {
1103
+ warnings.push('openclaw_state_dir_not_canonical');
1104
+ if (validation.reason === 'missing_profile_leaf') {
1105
+ warnings.push('openclaw_state_dir_missing_profile_leaf');
1106
+ }
1107
+ }
1095
1108
  }
1096
1109
  if (includeRemote && state.identity) {
1097
1110
  try {
@@ -1198,6 +1211,7 @@ async function handleDoctor(args) {
1198
1211
  deliveryProbe,
1199
1212
  deliveryProbeDiagnostics,
1200
1213
  defaultReplyRouteValidation,
1214
+ openClawStateDirValidation,
1201
1215
  }));
1202
1216
  }
1203
1217
  async function handleInstall(args) {
@@ -1261,8 +1275,19 @@ async function handleInstall(args) {
1261
1275
  requireOpenClawSessionKey: hostKind === 'openclaw',
1262
1276
  hostKind,
1263
1277
  });
1264
- const routeMissingPolicy = normalizeText(args.route_missing_policy)
1265
- || (defaultReplyRoute ? 'use_explicit_default_route' : '');
1278
+ const routeMissingPolicyResolution = resolveInstallRouteMissingPolicy({
1279
+ hostKind,
1280
+ explicitRouteMissingPolicy: args.route_missing_policy,
1281
+ defaultReplyRoute,
1282
+ });
1283
+ if (!routeMissingPolicyResolution.ok) {
1284
+ return fail(routeMissingPolicyResolution.error, {
1285
+ host_kind: hostKind,
1286
+ hint: 'OpenClaw installs must bind the current chat as the default continuation route. Read the canonical full current session key from a structured OpenClaw host source and pass it as host_session_key.',
1287
+ expected_route_missing_policy: 'use_explicit_default_route',
1288
+ });
1289
+ }
1290
+ const routeMissingPolicy = routeMissingPolicyResolution.routeMissingPolicy;
1266
1291
  const desiredDeliveryCapabilities = buildInstallationDeliveryDeclaration({
1267
1292
  enableLocalReceiver,
1268
1293
  receiverTransport,
package/dist/state.d.ts CHANGED
@@ -40,6 +40,13 @@ export declare const DEFAULT_HI_MCP_PROFILE = "default";
40
40
  export declare function normalizeStateProfile(raw: unknown): string;
41
41
  export declare function resolveDefaultStateDir(profileRaw: unknown): string;
42
42
  export declare function resolveCanonicalOpenClawStateDir(profileRaw?: unknown): string;
43
+ export type OpenClawStateDirValidation = {
44
+ configured_state_dir: string;
45
+ canonical_state_dir: string;
46
+ is_canonical: boolean;
47
+ reason: 'canonical' | 'missing_profile_leaf' | 'non_canonical';
48
+ };
49
+ export declare function validateOpenClawStateDir(stateDirRaw: unknown, profileRaw?: unknown): OpenClawStateDirValidation;
43
50
  export declare function resolveLegacyStateFiles(profileRaw: unknown): string[];
44
51
  export declare function buildDefaultState(profile: string): HiAgentPersistedState;
45
52
  export declare function resolveStateFile(args: {
@@ -1 +1 @@
1
- {"version":3,"file":"state.d.ts","sourceRoot":"","sources":["../src/state.ts"],"names":[],"mappings":"AAIA,MAAM,MAAM,oBAAoB,GAAG;IACjC,QAAQ,EAAE,MAAM,CAAC;IACjB,eAAe,EAAE,MAAM,CAAC;IACxB,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,aAAa,EAAE,MAAM,CAAC;IACtB,oBAAoB,EAAE,MAAM,CAAC;IAC7B,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,qBAAqB,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;CACvD,CAAC;AAEF,MAAM,MAAM,oBAAoB,GAAG;IACjC,iBAAiB,EAAE,MAAM,CAAC;IAC1B,iBAAiB,EAAE,MAAM,CAAC;IAC1B,UAAU,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF,MAAM,MAAM,mBAAmB,GAAG;IAChC,wBAAwB,EAAE,MAAM,CAAC;IACjC,mBAAmB,EAAE,MAAM,GAAG,IAAI,CAAC;IACnC,OAAO,EAAE;QACP,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;QACzB,oBAAoB,EAAE,MAAM,GAAG,IAAI,CAAC;QACpC,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;QAC5B,wBAAwB,EAAE,MAAM,GAAG,IAAI,CAAC;QACxC,mBAAmB,EAAE,MAAM,GAAG,IAAI,CAAC;KACpC,CAAC;IACF,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B,CAAC;AAEF,MAAM,MAAM,qBAAqB,GAAG;IAClC,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,oBAAoB,GAAG,IAAI,CAAC;IACtC,QAAQ,EAAE,oBAAoB,GAAG,IAAI,CAAC;IACtC,OAAO,EAAE,mBAAmB,CAAC;CAC9B,CAAC;AAeF,eAAO,MAAM,sBAAsB,YAAY,CAAC;AAEhD,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,OAAO,GAAG,MAAM,CAE1D;AAED,wBAAgB,sBAAsB,CAAC,UAAU,EAAE,OAAO,GAAG,MAAM,CAIlE;AAED,wBAAgB,gCAAgC,CAAC,UAAU,GAAE,OAAyB,GAAG,MAAM,CAG9F;AAED,wBAAgB,uBAAuB,CAAC,UAAU,EAAE,OAAO,GAAG,MAAM,EAAE,CAMrE;AAED,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,GAAG,qBAAqB,CAOxE;AAED,wBAAgB,gBAAgB,CAAC,IAAI,EAAE;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,UAG3E;AAED,wBAAsB,SAAS,CAAC,IAAI,EAAE;IACpC,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;CACjB,GAAG,OAAO,CAAC,qBAAqB,CAAC,CAoCjC;AAED,wBAAsB,UAAU,CAAC,IAAI,EAAE;IACrC,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,qBAAqB,CAAC;CAC9B,iBAIA;AAED,wBAAsB,WAAW,CAAC,IAAI,EAAE;IACtC,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,CAAC,OAAO,EAAE,qBAAqB,KAAK,qBAAqB,CAAC;CACpE,kCASA"}
1
+ {"version":3,"file":"state.d.ts","sourceRoot":"","sources":["../src/state.ts"],"names":[],"mappings":"AAIA,MAAM,MAAM,oBAAoB,GAAG;IACjC,QAAQ,EAAE,MAAM,CAAC;IACjB,eAAe,EAAE,MAAM,CAAC;IACxB,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,aAAa,EAAE,MAAM,CAAC;IACtB,oBAAoB,EAAE,MAAM,CAAC;IAC7B,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,qBAAqB,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;CACvD,CAAC;AAEF,MAAM,MAAM,oBAAoB,GAAG;IACjC,iBAAiB,EAAE,MAAM,CAAC;IAC1B,iBAAiB,EAAE,MAAM,CAAC;IAC1B,UAAU,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF,MAAM,MAAM,mBAAmB,GAAG;IAChC,wBAAwB,EAAE,MAAM,CAAC;IACjC,mBAAmB,EAAE,MAAM,GAAG,IAAI,CAAC;IACnC,OAAO,EAAE;QACP,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;QACzB,oBAAoB,EAAE,MAAM,GAAG,IAAI,CAAC;QACpC,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;QAC5B,wBAAwB,EAAE,MAAM,GAAG,IAAI,CAAC;QACxC,mBAAmB,EAAE,MAAM,GAAG,IAAI,CAAC;KACpC,CAAC;IACF,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B,CAAC;AAEF,MAAM,MAAM,qBAAqB,GAAG;IAClC,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,oBAAoB,GAAG,IAAI,CAAC;IACtC,QAAQ,EAAE,oBAAoB,GAAG,IAAI,CAAC;IACtC,OAAO,EAAE,mBAAmB,CAAC;CAC9B,CAAC;AAeF,eAAO,MAAM,sBAAsB,YAAY,CAAC;AAEhD,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,OAAO,GAAG,MAAM,CAE1D;AAOD,wBAAgB,sBAAsB,CAAC,UAAU,EAAE,OAAO,GAAG,MAAM,CAIlE;AAED,wBAAgB,gCAAgC,CAAC,UAAU,GAAE,OAAyB,GAAG,MAAM,CAG9F;AAED,MAAM,MAAM,0BAA0B,GAAG;IACvC,oBAAoB,EAAE,MAAM,CAAC;IAC7B,mBAAmB,EAAE,MAAM,CAAC;IAC5B,YAAY,EAAE,OAAO,CAAC;IACtB,MAAM,EAAE,WAAW,GAAG,sBAAsB,GAAG,eAAe,CAAC;CAChE,CAAC;AAEF,wBAAgB,wBAAwB,CACtC,WAAW,EAAE,OAAO,EACpB,UAAU,GAAE,OAAyB,GACpC,0BAA0B,CA2B5B;AAED,wBAAgB,uBAAuB,CAAC,UAAU,EAAE,OAAO,GAAG,MAAM,EAAE,CAMrE;AAED,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,GAAG,qBAAqB,CAOxE;AAED,wBAAgB,gBAAgB,CAAC,IAAI,EAAE;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,UAG3E;AAED,wBAAsB,SAAS,CAAC,IAAI,EAAE;IACpC,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;CACjB,GAAG,OAAO,CAAC,qBAAqB,CAAC,CAoCjC;AAED,wBAAsB,UAAU,CAAC,IAAI,EAAE;IACrC,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,qBAAqB,CAAC;CAC9B,iBAIA;AAED,wBAAsB,WAAW,CAAC,IAAI,EAAE;IACtC,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,CAAC,OAAO,EAAE,qBAAqB,KAAK,qBAAqB,CAAC;CACpE,kCASA"}
package/dist/state.js CHANGED
@@ -17,6 +17,10 @@ export const DEFAULT_HI_MCP_PROFILE = 'default';
17
17
  export function normalizeStateProfile(raw) {
18
18
  return String(raw || '').trim() || DEFAULT_HI_MCP_PROFILE;
19
19
  }
20
+ function normalizeStateDirPath(raw) {
21
+ const text = typeof raw === 'string' ? String(raw).trim() : '';
22
+ return text ? path.resolve(text) : '';
23
+ }
20
24
  export function resolveDefaultStateDir(profileRaw) {
21
25
  const profile = normalizeStateProfile(profileRaw);
22
26
  // 本地 installation state 必须落到稳定 home 目录,不能继续跟着 cwd 漂。
@@ -26,6 +30,34 @@ export function resolveCanonicalOpenClawStateDir(profileRaw = 'openclaw-main') {
26
30
  const profile = normalizeStateProfile(profileRaw);
27
31
  return path.join(os.homedir(), '.openclaw', 'hi-mcp', profile);
28
32
  }
33
+ export function validateOpenClawStateDir(stateDirRaw, profileRaw = 'openclaw-main') {
34
+ const canonicalStateDir = resolveCanonicalOpenClawStateDir(profileRaw);
35
+ const configuredStateDir = normalizeStateDirPath(stateDirRaw) || canonicalStateDir;
36
+ if (configuredStateDir === canonicalStateDir) {
37
+ return {
38
+ configured_state_dir: configuredStateDir,
39
+ canonical_state_dir: canonicalStateDir,
40
+ is_canonical: true,
41
+ reason: 'canonical',
42
+ };
43
+ }
44
+ const bareOpenClawStateDir = path.join(os.homedir(), '.openclaw', 'hi-mcp');
45
+ if (configuredStateDir === bareOpenClawStateDir) {
46
+ // OpenClaw 的 canonical 布局要求 stateDir 自己就是 profile 叶子目录,不能只指向父目录。
47
+ return {
48
+ configured_state_dir: configuredStateDir,
49
+ canonical_state_dir: canonicalStateDir,
50
+ is_canonical: false,
51
+ reason: 'missing_profile_leaf',
52
+ };
53
+ }
54
+ return {
55
+ configured_state_dir: configuredStateDir,
56
+ canonical_state_dir: canonicalStateDir,
57
+ is_canonical: false,
58
+ reason: 'non_canonical',
59
+ };
60
+ }
29
61
  export function resolveLegacyStateFiles(profileRaw) {
30
62
  const profile = normalizeStateProfile(profileRaw);
31
63
  return [
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hirey/hi-mcp-server",
3
- "version": "0.1.11",
3
+ "version": "0.1.13",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "main": "dist/server.js",