@alfe.ai/openclaw-chat 0.9.5 → 0.9.6

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/dist/plugin.d.cts CHANGED
@@ -599,6 +599,15 @@ interface AnchorEnv {
599
599
  requireMainFilename: string | undefined;
600
600
  argv1: string | undefined;
601
601
  execPath: string;
602
+ /**
603
+ * Well-known global `node_modules` directories to try as `<dir>/openclaw`
604
+ * anchors, independent of PATH / `which` / execPath. Load-bearing when the
605
+ * plugin runs in-process inside a runtime whose PATH is stripped or whose
606
+ * `child_process` is sandboxed (homebrew-keg self-hosted macOS), so every
607
+ * environment-derived anchor above returns nothing. Optional — defaults to
608
+ * none (tests that don't exercise this pass `undefined`).
609
+ */
610
+ globalModulesDirs?: string[];
602
611
  }
603
612
  /**
604
613
  * Compute the ordered, de-duplicated list of resolver anchors to try, each
package/dist/plugin.d.ts CHANGED
@@ -599,6 +599,15 @@ interface AnchorEnv {
599
599
  requireMainFilename: string | undefined;
600
600
  argv1: string | undefined;
601
601
  execPath: string;
602
+ /**
603
+ * Well-known global `node_modules` directories to try as `<dir>/openclaw`
604
+ * anchors, independent of PATH / `which` / execPath. Load-bearing when the
605
+ * plugin runs in-process inside a runtime whose PATH is stripped or whose
606
+ * `child_process` is sandboxed (homebrew-keg self-hosted macOS), so every
607
+ * environment-derived anchor above returns nothing. Optional — defaults to
608
+ * none (tests that don't exercise this pass `undefined`).
609
+ */
610
+ globalModulesDirs?: string[];
602
611
  }
603
612
  /**
604
613
  * Compute the ordered, de-duplicated list of resolver anchors to try, each
package/dist/plugin2.cjs CHANGED
@@ -3,6 +3,7 @@ let node_fs_promises = require("node:fs/promises");
3
3
  let node_fs = require("node:fs");
4
4
  let node_child_process = require("node:child_process");
5
5
  let node_path = require("node:path");
6
+ let node_url = require("node:url");
6
7
  let node_os = require("node:os");
7
8
  let _alfe_ai_chat = require("@alfe.ai/chat");
8
9
  let _alfe_ai_agent_api_client = require("@alfe.ai/agent-api-client");
@@ -2072,24 +2073,33 @@ let resolveRouteEnvelope = null;
2072
2073
  * degrades `chat.abort` to a logged no-op (Stop still seals the UI) rather than
2073
2074
  * a hard failure.
2074
2075
  */
2075
- function loadOpenClawSdk(req, log, anchor) {
2076
- let resolvedDispatch = false;
2077
- try {
2078
- const channelInbound = req("openclaw/plugin-sdk/channel-inbound");
2079
- if (channelInbound.dispatchInboundDirectDmWithRuntime) {
2080
- dispatchInbound = channelInbound.dispatchInboundDirectDmWithRuntime;
2081
- resolvedDispatch = true;
2076
+ async function loadOpenClawSdk(req, log, anchor) {
2077
+ const loadSubpath = async (subpath) => {
2078
+ try {
2079
+ const mod = await import((0, node_url.pathToFileURL)(req.resolve(subpath)).href);
2080
+ return {
2081
+ ...typeof mod.default === "object" ? mod.default : void 0,
2082
+ ...mod
2083
+ };
2084
+ } catch {}
2085
+ try {
2086
+ return req(subpath);
2087
+ } catch {
2088
+ return;
2082
2089
  }
2083
- } catch {}
2084
- try {
2085
- const harness = req("openclaw/plugin-sdk/agent-harness");
2086
- if (harness.abortEmbeddedAgentRun) abortEmbeddedAgentRun = harness.abortEmbeddedAgentRun;
2087
- if (harness.resolveActiveEmbeddedRunSessionId) resolveActiveRunSessionId = harness.resolveActiveEmbeddedRunSessionId;
2088
- } catch {}
2089
- try {
2090
- const envelope = req("openclaw/plugin-sdk/inbound-envelope");
2091
- if (envelope.resolveInboundRouteEnvelopeBuilderWithRuntime) resolveRouteEnvelope = envelope.resolveInboundRouteEnvelopeBuilderWithRuntime;
2092
- } catch {}
2090
+ };
2091
+ let resolvedDispatch = false;
2092
+ const channelInbound = await loadSubpath("openclaw/plugin-sdk/channel-inbound");
2093
+ if (channelInbound?.dispatchInboundDirectDmWithRuntime) {
2094
+ dispatchInbound = channelInbound.dispatchInboundDirectDmWithRuntime;
2095
+ resolvedDispatch = true;
2096
+ }
2097
+ const harness = await loadSubpath("openclaw/plugin-sdk/agent-harness");
2098
+ const abortRun = harness?.abortAgentHarnessRun ?? harness?.abortEmbeddedAgentRun;
2099
+ if (abortRun) abortEmbeddedAgentRun = abortRun;
2100
+ if (harness?.resolveActiveEmbeddedRunSessionId) resolveActiveRunSessionId = harness.resolveActiveEmbeddedRunSessionId;
2101
+ const envelope = await loadSubpath("openclaw/plugin-sdk/inbound-envelope");
2102
+ if (envelope?.resolveInboundRouteEnvelopeBuilderWithRuntime) resolveRouteEnvelope = envelope.resolveInboundRouteEnvelopeBuilderWithRuntime;
2093
2103
  if (resolvedDispatch) log.info(`Resolved OpenClaw SDK from ${anchor} (hard-abort=${abortEmbeddedAgentRun && resolveActiveRunSessionId ? "available" : "unavailable"})`);
2094
2104
  return resolvedDispatch;
2095
2105
  }
@@ -2160,6 +2170,7 @@ function computeOpenClawSdkAnchors(deps) {
2160
2170
  try {
2161
2171
  push(deps.which("openclaw"));
2162
2172
  } catch {}
2173
+ for (const dir of deps.globalModulesDirs ?? []) push((0, node_path.join)(dir, "openclaw", "package.json"));
2163
2174
  for (const base of [deps.execPath, safeRealpath(deps.realpath, deps.execPath)]) {
2164
2175
  if (!base) continue;
2165
2176
  try {
@@ -2178,6 +2189,27 @@ function safeRealpath(realpath, p) {
2178
2189
  }
2179
2190
  }
2180
2191
  /**
2192
+ * Well-known global `node_modules` locations to try as SDK anchors, in priority
2193
+ * order. Environment-INDEPENDENT (no PATH / `which` / execPath), so they resolve
2194
+ * the SDK even when the in-process plugin context has a stripped PATH or a
2195
+ * sandboxed `child_process` (the homebrew-keg self-hosted macOS case where every
2196
+ * environment-derived anchor returns nothing). Non-existent candidates are
2197
+ * harmless — `createRequire` just fails and the next anchor runs. `NODE_PATH`,
2198
+ * when set, is an explicit module-dir list, so honour it too.
2199
+ */
2200
+ function candidateGlobalModulesDirs() {
2201
+ const dirs = [
2202
+ "/opt/homebrew/lib/node_modules",
2203
+ "/usr/local/lib/node_modules",
2204
+ "/usr/lib/node_modules",
2205
+ "/usr/local/share/npm/lib/node_modules"
2206
+ ];
2207
+ const home = process.env.HOME;
2208
+ if (home) dirs.push((0, node_path.join)(home, ".npm-global", "lib", "node_modules"));
2209
+ for (const d of (process.env.NODE_PATH ?? "").split(node_path.delimiter)) if (d) dirs.push(d);
2210
+ return dirs;
2211
+ }
2212
+ /**
2181
2213
  * Resolve OpenClaw SDK functions from the running process.
2182
2214
  *
2183
2215
  * The openclaw package is NOT in the plugin's node_modules (it's a peer dep).
@@ -2186,19 +2218,20 @@ function safeRealpath(realpath, p) {
2186
2218
  * relocated-node layouts), then to a `which openclaw` lookup, then fall back to
2187
2219
  * deriving the global modules path from process.execPath.
2188
2220
  */
2189
- function resolveOpenClawSdk(log) {
2221
+ async function resolveOpenClawSdk(log) {
2190
2222
  const pathEnv = process.env.PATH;
2191
2223
  const anchors = computeOpenClawSdkAnchors({
2192
2224
  realpath: node_fs.realpathSync,
2193
2225
  which: () => whichOpenClaw(pathEnv),
2194
2226
  requireMainFilename: require$1.main?.filename,
2195
2227
  argv1: process.argv[1],
2196
- execPath: process.execPath
2228
+ execPath: process.execPath,
2229
+ globalModulesDirs: candidateGlobalModulesDirs()
2197
2230
  });
2198
2231
  for (const anchor of anchors) try {
2199
- if (loadOpenClawSdk((0, node_module.createRequire)(anchor), log, anchor)) return;
2232
+ if (await loadOpenClawSdk((0, node_module.createRequire)(anchor), log, anchor)) return;
2200
2233
  } catch {}
2201
- log.warn("OpenClaw SDK not resolvable — chat dispatch will not work");
2234
+ log.warn(`OpenClaw SDK not resolvable — chat dispatch will not work. argv1=${process.argv[1] ?? "<none>"} execPath=${process.execPath} PATH=${pathEnv ? "set" : "EMPTY"} anchorsTried=[${anchors.join(", ")}]`);
2202
2235
  }
2203
2236
  let pluginRuntime = null;
2204
2237
  let chatClient = null;
@@ -2945,7 +2978,7 @@ const plugin = {
2945
2978
  log.info(`Registered ${String(a2aTools.length)} agent tools`);
2946
2979
  }
2947
2980
  const pluginConfig = (((api.config ?? {}).plugins?.entries)?.["@alfe.ai/openclaw-chat"] ?? {}).config ?? {};
2948
- const startChatService = () => {
2981
+ const startChatService = async () => {
2949
2982
  const action = decideChatServiceStart({
2950
2983
  connectInFlight: connectingPromise !== null,
2951
2984
  clientPresent: chatClient !== null,
@@ -2966,7 +2999,7 @@ const plugin = {
2966
2999
  }
2967
3000
  globalThis.__alfeChatPluginActivated = true;
2968
3001
  log.info("Chat plugin registering...");
2969
- resolveOpenClawSdk(log);
3002
+ await resolveOpenClawSdk(log);
2970
3003
  pluginRuntime = api.runtime ?? null;
2971
3004
  let thisConnect = null;
2972
3005
  thisConnect = Promise.resolve().then(() => {
package/dist/plugin2.js CHANGED
@@ -3,6 +3,7 @@ import { mkdir, open, readFile, readdir, stat, unlink, writeFile } from "node:fs
3
3
  import { existsSync, realpathSync } from "node:fs";
4
4
  import { execFileSync } from "node:child_process";
5
5
  import { basename, delimiter, dirname, isAbsolute, join, resolve } from "node:path";
6
+ import { pathToFileURL } from "node:url";
6
7
  import { homedir } from "node:os";
7
8
  import { ChatServiceClient, resolveAlfeChat } from "@alfe.ai/chat";
8
9
  import { AgentApiClient, installToolErrorCapture } from "@alfe.ai/agent-api-client";
@@ -2072,24 +2073,33 @@ let resolveRouteEnvelope = null;
2072
2073
  * degrades `chat.abort` to a logged no-op (Stop still seals the UI) rather than
2073
2074
  * a hard failure.
2074
2075
  */
2075
- function loadOpenClawSdk(req, log, anchor) {
2076
- let resolvedDispatch = false;
2077
- try {
2078
- const channelInbound = req("openclaw/plugin-sdk/channel-inbound");
2079
- if (channelInbound.dispatchInboundDirectDmWithRuntime) {
2080
- dispatchInbound = channelInbound.dispatchInboundDirectDmWithRuntime;
2081
- resolvedDispatch = true;
2076
+ async function loadOpenClawSdk(req, log, anchor) {
2077
+ const loadSubpath = async (subpath) => {
2078
+ try {
2079
+ const mod = await import(pathToFileURL(req.resolve(subpath)).href);
2080
+ return {
2081
+ ...typeof mod.default === "object" ? mod.default : void 0,
2082
+ ...mod
2083
+ };
2084
+ } catch {}
2085
+ try {
2086
+ return req(subpath);
2087
+ } catch {
2088
+ return;
2082
2089
  }
2083
- } catch {}
2084
- try {
2085
- const harness = req("openclaw/plugin-sdk/agent-harness");
2086
- if (harness.abortEmbeddedAgentRun) abortEmbeddedAgentRun = harness.abortEmbeddedAgentRun;
2087
- if (harness.resolveActiveEmbeddedRunSessionId) resolveActiveRunSessionId = harness.resolveActiveEmbeddedRunSessionId;
2088
- } catch {}
2089
- try {
2090
- const envelope = req("openclaw/plugin-sdk/inbound-envelope");
2091
- if (envelope.resolveInboundRouteEnvelopeBuilderWithRuntime) resolveRouteEnvelope = envelope.resolveInboundRouteEnvelopeBuilderWithRuntime;
2092
- } catch {}
2090
+ };
2091
+ let resolvedDispatch = false;
2092
+ const channelInbound = await loadSubpath("openclaw/plugin-sdk/channel-inbound");
2093
+ if (channelInbound?.dispatchInboundDirectDmWithRuntime) {
2094
+ dispatchInbound = channelInbound.dispatchInboundDirectDmWithRuntime;
2095
+ resolvedDispatch = true;
2096
+ }
2097
+ const harness = await loadSubpath("openclaw/plugin-sdk/agent-harness");
2098
+ const abortRun = harness?.abortAgentHarnessRun ?? harness?.abortEmbeddedAgentRun;
2099
+ if (abortRun) abortEmbeddedAgentRun = abortRun;
2100
+ if (harness?.resolveActiveEmbeddedRunSessionId) resolveActiveRunSessionId = harness.resolveActiveEmbeddedRunSessionId;
2101
+ const envelope = await loadSubpath("openclaw/plugin-sdk/inbound-envelope");
2102
+ if (envelope?.resolveInboundRouteEnvelopeBuilderWithRuntime) resolveRouteEnvelope = envelope.resolveInboundRouteEnvelopeBuilderWithRuntime;
2093
2103
  if (resolvedDispatch) log.info(`Resolved OpenClaw SDK from ${anchor} (hard-abort=${abortEmbeddedAgentRun && resolveActiveRunSessionId ? "available" : "unavailable"})`);
2094
2104
  return resolvedDispatch;
2095
2105
  }
@@ -2160,6 +2170,7 @@ function computeOpenClawSdkAnchors(deps) {
2160
2170
  try {
2161
2171
  push(deps.which("openclaw"));
2162
2172
  } catch {}
2173
+ for (const dir of deps.globalModulesDirs ?? []) push(join(dir, "openclaw", "package.json"));
2163
2174
  for (const base of [deps.execPath, safeRealpath(deps.realpath, deps.execPath)]) {
2164
2175
  if (!base) continue;
2165
2176
  try {
@@ -2178,6 +2189,27 @@ function safeRealpath(realpath, p) {
2178
2189
  }
2179
2190
  }
2180
2191
  /**
2192
+ * Well-known global `node_modules` locations to try as SDK anchors, in priority
2193
+ * order. Environment-INDEPENDENT (no PATH / `which` / execPath), so they resolve
2194
+ * the SDK even when the in-process plugin context has a stripped PATH or a
2195
+ * sandboxed `child_process` (the homebrew-keg self-hosted macOS case where every
2196
+ * environment-derived anchor returns nothing). Non-existent candidates are
2197
+ * harmless — `createRequire` just fails and the next anchor runs. `NODE_PATH`,
2198
+ * when set, is an explicit module-dir list, so honour it too.
2199
+ */
2200
+ function candidateGlobalModulesDirs() {
2201
+ const dirs = [
2202
+ "/opt/homebrew/lib/node_modules",
2203
+ "/usr/local/lib/node_modules",
2204
+ "/usr/lib/node_modules",
2205
+ "/usr/local/share/npm/lib/node_modules"
2206
+ ];
2207
+ const home = process.env.HOME;
2208
+ if (home) dirs.push(join(home, ".npm-global", "lib", "node_modules"));
2209
+ for (const d of (process.env.NODE_PATH ?? "").split(delimiter)) if (d) dirs.push(d);
2210
+ return dirs;
2211
+ }
2212
+ /**
2181
2213
  * Resolve OpenClaw SDK functions from the running process.
2182
2214
  *
2183
2215
  * The openclaw package is NOT in the plugin's node_modules (it's a peer dep).
@@ -2186,19 +2218,20 @@ function safeRealpath(realpath, p) {
2186
2218
  * relocated-node layouts), then to a `which openclaw` lookup, then fall back to
2187
2219
  * deriving the global modules path from process.execPath.
2188
2220
  */
2189
- function resolveOpenClawSdk(log) {
2221
+ async function resolveOpenClawSdk(log) {
2190
2222
  const pathEnv = process.env.PATH;
2191
2223
  const anchors = computeOpenClawSdkAnchors({
2192
2224
  realpath: realpathSync,
2193
2225
  which: () => whichOpenClaw(pathEnv),
2194
2226
  requireMainFilename: require.main?.filename,
2195
2227
  argv1: process.argv[1],
2196
- execPath: process.execPath
2228
+ execPath: process.execPath,
2229
+ globalModulesDirs: candidateGlobalModulesDirs()
2197
2230
  });
2198
2231
  for (const anchor of anchors) try {
2199
- if (loadOpenClawSdk(createRequire(anchor), log, anchor)) return;
2232
+ if (await loadOpenClawSdk(createRequire(anchor), log, anchor)) return;
2200
2233
  } catch {}
2201
- log.warn("OpenClaw SDK not resolvable — chat dispatch will not work");
2234
+ log.warn(`OpenClaw SDK not resolvable — chat dispatch will not work. argv1=${process.argv[1] ?? "<none>"} execPath=${process.execPath} PATH=${pathEnv ? "set" : "EMPTY"} anchorsTried=[${anchors.join(", ")}]`);
2202
2235
  }
2203
2236
  let pluginRuntime = null;
2204
2237
  let chatClient = null;
@@ -2945,7 +2978,7 @@ const plugin = {
2945
2978
  log.info(`Registered ${String(a2aTools.length)} agent tools`);
2946
2979
  }
2947
2980
  const pluginConfig = (((api.config ?? {}).plugins?.entries)?.["@alfe.ai/openclaw-chat"] ?? {}).config ?? {};
2948
- const startChatService = () => {
2981
+ const startChatService = async () => {
2949
2982
  const action = decideChatServiceStart({
2950
2983
  connectInFlight: connectingPromise !== null,
2951
2984
  clientPresent: chatClient !== null,
@@ -2966,7 +2999,7 @@ const plugin = {
2966
2999
  }
2967
3000
  globalThis.__alfeChatPluginActivated = true;
2968
3001
  log.info("Chat plugin registering...");
2969
- resolveOpenClawSdk(log);
3002
+ await resolveOpenClawSdk(log);
2970
3003
  pluginRuntime = api.runtime ?? null;
2971
3004
  let thisConnect = null;
2972
3005
  thisConnect = Promise.resolve().then(() => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@alfe.ai/openclaw-chat",
3
- "version": "0.9.5",
3
+ "version": "0.9.6",
4
4
  "description": "OpenClaw chat plugin for Alfe — web widget and mobile app channels",
5
5
  "type": "module",
6
6
  "main": "./dist/plugin.js",
@@ -27,7 +27,7 @@
27
27
  "openclaw.plugin.json"
28
28
  ],
29
29
  "dependencies": {
30
- "@alfe.ai/agent-api-client": "^0.10.0",
30
+ "@alfe.ai/agent-api-client": "^0.11.0",
31
31
  "@alfe.ai/chat": "^0.0.16",
32
32
  "@alfe.ai/config": "^0.3.0"
33
33
  },