@hellolynk-ai/openclaw-channel 0.2.102 → 0.2.103

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.
@@ -61,8 +61,8 @@ try {
61
61
  "--expected-manifest-sha256", sourceRelease.outerManifestSha256,
62
62
  ]);
63
63
  } else {
64
- const originalLocations = resolveLocations();
65
64
  const accountModule = await importStableCore(PACKAGE_ROOT, "hellolynk-client-account.mjs", "hellolynk_npm_account_runtime_invalid");
65
+ const originalLocations = resolveLocations(accountModule.clientAccountBaseRoot);
66
66
  const baseRoot = accountModule.clientAccountBaseRoot(originalLocations.hostRoot);
67
67
  const packageLocations = { ...originalLocations, hostRoot: baseRoot, finalCurrentRoot: path.dirname(baseRoot) };
68
68
  const accounts = accountModule.createClientAccountActions({ client: metadata.client, storeRoot: baseRoot });
@@ -838,7 +838,7 @@ async function verifyRelease(releaseRoot, packageRoot, expectedMetadata = metada
838
838
  return Object.freeze({ manifestSha256, outerManifestSha256 });
839
839
  }
840
840
 
841
- function resolveLocations() {
841
+ function resolveLocations(getDefaultHostRoot) {
842
842
  if (process.platform !== "win32") fail("hellolynk_npm_windows_only");
843
843
  const home = path.resolve(process.env.USERPROFILE || os.homedir());
844
844
  const localAppData = path.resolve(process.env.LOCALAPPDATA || path.join(home, "AppData", "Local"));
@@ -848,7 +848,7 @@ function resolveLocations() {
848
848
  const codexHome = path.resolve(configuredCodexHome || path.join(home, ".codex"));
849
849
  const configuredHostRoot = String(process.env.HELLOLYNK_NEUTRAL_STORE_ROOT || "").trim();
850
850
  if (configuredHostRoot && !path.isAbsolute(configuredHostRoot)) fail("hellolynk_npm_store_root_invalid");
851
- const hostRoot = path.resolve(configuredHostRoot || path.join(localAppData, "HelloLynk", "host"));
851
+ const hostRoot = path.resolve(configuredHostRoot || getDefaultHostRoot());
852
852
  if (configuredHostRoot && path.basename(hostRoot).toLowerCase() !== "host") {
853
853
  fail("hellolynk_npm_store_root_invalid");
854
854
  }
@@ -1004,6 +1004,12 @@ async function startHostWhenAbsent(runtime, binding) {
1004
1004
  }
1005
1005
 
1006
1006
  async function secureStableReleaseTree(locations, releaseId, options = {}) {
1007
+ const releasePath = path.resolve(locations.finalCurrentRoot, "releases", releaseId);
1008
+ // An existing AppData root can be shared while a new release is redirected
1009
+ // into one desktop app's private cache. Other clients cannot use that release.
1010
+ if (process.platform === "win32" && realpathSync.native(releasePath).toLowerCase() !== releasePath.toLowerCase()) {
1011
+ fail("client_root_alias_rejected");
1012
+ }
1007
1013
  const module = await importCore(
1008
1014
  "hellolynk-platform-credential-store.mjs",
1009
1015
  "hellolynk_npm_client_root_security_unavailable",
@@ -1,4 +1,5 @@
1
1
  import { lstat, mkdir, open, readFile, rename, rm, stat } from "node:fs/promises";
2
+ import { readdirSync } from "node:fs";
2
3
  import { homedir } from "node:os";
3
4
  import { basename, dirname, isAbsolute, join, resolve } from "node:path";
4
5
  import { randomUUID } from "node:crypto";
@@ -19,12 +20,34 @@ const SAFE_SCOPE = /^[a-z][a-z0-9_.:-]{0,127}$/;
19
20
  const MAX_PROFILE_BYTES = 64 * 1024;
20
21
 
21
22
  export function defaultHelloLynkClientRoot(platform = process.platform, env = process.env) {
22
- const home = resolve(String(env.HOME || env.USERPROFILE || homedir()));
23
- if (platform === "win32") return resolve(String(env.LOCALAPPDATA || join(home, "AppData", "Local")), "HelloLynk");
23
+ const home = resolve(String((platform === "win32" ? env.USERPROFILE || env.HOME : env.HOME || env.USERPROFILE) || homedir()));
24
+ if (platform === "win32") {
25
+ const current = join(home, ".hellolynk", "hellolynk-v2");
26
+ // Once selected, another client's older installer must not move us back.
27
+ if (hasWindowsClientInstallation(current)) return current;
28
+ const existing = resolve(String(env.LOCALAPPDATA || join(home, "AppData", "Local")), "HelloLynk");
29
+ // AppData created from a packaged desktop app can be private to that app.
30
+ // Keep an existing installation; an empty failed setup is not an account.
31
+ if (hasWindowsClientInstallation(existing)) return existing;
32
+ return current;
33
+ }
24
34
  if (platform === "darwin") return join(home, "Library", "Application Support", "HelloLynk");
25
35
  return resolve(String(env.XDG_DATA_HOME || join(home, ".local", "share")), "hellolynk");
26
36
  }
27
37
 
38
+ function hasWindowsClientInstallation(root) {
39
+ for (const directory of ["profiles", "releases", "host", "credentials", "e2ee-private-keys"]) {
40
+ try {
41
+ const entries = readdirSync(join(root, directory), { withFileTypes: true });
42
+ if (entries.some((entry) => directory !== "host" || entry.name !== "runtime")) return true;
43
+ } catch (error) {
44
+ // An unreadable existing location must not silently become a fresh account.
45
+ if (error.code !== "ENOENT") return true;
46
+ }
47
+ }
48
+ return false;
49
+ }
50
+
28
51
  function safeId(value, code) {
29
52
  const normalized = String(value || "").trim();
30
53
  if (!SAFE_ID.test(normalized)) throw new Error(code);
@@ -12,10 +12,9 @@ import {
12
12
  } from "node:fs/promises";
13
13
  import { basename, dirname, isAbsolute, join, parse, resolve } from "node:path";
14
14
  import { spawn } from "node:child_process";
15
- import { homedir } from "node:os";
16
15
  import { performance } from "node:perf_hooks";
17
16
  import { withLocalProcessLock } from "./hellolynk-local-process-lock.mjs";
18
- import { readClientProfile } from "./hellolynk-client-profile.mjs";
17
+ import { defaultHelloLynkClientRoot, readClientProfile } from "./hellolynk-client-profile.mjs";
19
18
  import { assertIdentifier } from "./hellolynk-host-auth.mjs";
20
19
  import runtimeSafety from "./hellolynk-runtime-safety.cjs";
21
20
 
@@ -46,10 +45,7 @@ export function defaultNeutralHostStoreRoot(platform = process.platform, env = p
46
45
  }
47
46
  return root;
48
47
  }
49
- const home = resolve(String(env.HOME || env.USERPROFILE || homedir()));
50
- if (platform === "win32") return resolve(String(env.LOCALAPPDATA || join(home, "AppData", "Local")), "HelloLynk", "host");
51
- if (platform === "darwin") return join(home, "Library", "Application Support", "HelloLynk", "host");
52
- return resolve(String(env.XDG_DATA_HOME || join(home, ".local", "share")), "hellolynk", "host");
48
+ return join(defaultHelloLynkClientRoot(platform, env), "host");
53
49
  }
54
50
 
55
51
  export function createNeutralHostInstallationStore(options = {}) {
@@ -34,7 +34,7 @@ export const HELLOLYNK_NEUTRAL_HOST_PROCESS_CONTRACT = "hellolynk-neutral-host-p
34
34
  export const HELLOLYNK_NEUTRAL_HOST_DISCOVERY_CONTRACT = "hellolynk-neutral-host-discovery-v1";
35
35
  // Raised with every release batch, together with the six client versions. A Host reports it
36
36
  // in its health; the higher release stays and the lower one makes room.
37
- export const HELLOLYNK_HOST_RELEASE_ORDINAL = 14;
37
+ export const HELLOLYNK_HOST_RELEASE_ORDINAL = 15;
38
38
 
39
39
  const INSTALLATION_LOCK_CONTRACT = "hellolynk-neutral-host-installation-lock-v2";
40
40
  const INSTALLATION_LOCK_MAX_BYTES = 4 * 1024;
@@ -2,7 +2,7 @@
2
2
  "contract": "hellolynk-client-npm-pack-manifest-v1",
3
3
  "client": "openclaw",
4
4
  "packageName": "@hellolynk-ai/openclaw-channel",
5
- "version": "0.2.102",
5
+ "version": "0.2.103",
6
6
  "workbench": {
7
7
  "path": "runtime/workbench/hellolynk-workbench-build.json",
8
8
  "contract": "hellolynk-shared-workbench-build-v1",
@@ -12,8 +12,8 @@
12
12
  "files": [
13
13
  {
14
14
  "path": "bin/hellolynk-client-setup.mjs",
15
- "bytes": 141769,
16
- "sha256": "0bb0706c06bd193cfa37007dd95e3107b52aacb0a7ebaec2249b153ff7dd772b"
15
+ "bytes": 142207,
16
+ "sha256": "95386fcd9092f31abb3b0441033b3b385b3c355506613da24b4557d5f9cac6ef"
17
17
  },
18
18
  {
19
19
  "path": "bin/hellolynk-mcp-config-shape.mjs",
@@ -37,8 +37,8 @@
37
37
  },
38
38
  {
39
39
  "path": "clients/core/hellolynk-client-profile.mjs",
40
- "bytes": 8282,
41
- "sha256": "4b45a78b4d6c4794a1f494bd95777579c32c56a68321a1d3b484048942ae4742"
40
+ "bytes": 9359,
41
+ "sha256": "8be37831c96610e3d0a64848ada86488970cc6079e49764b47d8a8b2ba852269"
42
42
  },
43
43
  {
44
44
  "path": "clients/core/hellolynk-client-update-entry.mjs",
@@ -212,8 +212,8 @@
212
212
  },
213
213
  {
214
214
  "path": "clients/core/hellolynk-neutral-host-installation-store.mjs",
215
- "bytes": 33525,
216
- "sha256": "b5f6288732af6f9b9c0c750f6002eae657dde9513fc97674f6e59200f3cc9dc6"
215
+ "bytes": 33183,
216
+ "sha256": "dfb6bba4c627082cd6fca8cb38dc786f905e38f3e83ccf91dbfe57e55639e8a2"
217
217
  },
218
218
  {
219
219
  "path": "clients/core/hellolynk-neutral-host-launcher.mjs",
@@ -223,7 +223,7 @@
223
223
  {
224
224
  "path": "clients/core/hellolynk-neutral-host-process.mjs",
225
225
  "bytes": 225161,
226
- "sha256": "af6cb6585baae477f87ee880bd044dffb4c7f71667bfa78bcbf0d4d20e7483af"
226
+ "sha256": "e744bacf65f7b86cbcf7d654189c0e07e09401083e2b6f9053b17c1c3bacd1b4"
227
227
  },
228
228
  {
229
229
  "path": "clients/core/hellolynk-neutral-host-store-adapters.mjs",
@@ -323,7 +323,7 @@
323
323
  {
324
324
  "path": "integrations/openclaw-channel/package.json",
325
325
  "bytes": 2158,
326
- "sha256": "0cb37e6e7c9591ca5877496970f981e08947b924e6a8054071298f909422e439"
326
+ "sha256": "cf7a43ebe53aaad734e452a47161a77759ee333220319808882dfe2b148ac579"
327
327
  },
328
328
  {
329
329
  "path": "integrations/openclaw-channel/setup-entry.mjs",
@@ -398,7 +398,7 @@
398
398
  {
399
399
  "path": "package.json",
400
400
  "bytes": 1985,
401
- "sha256": "0215eaac79151bd9a1080885b4b883342585293753a115140ab466958763a152"
401
+ "sha256": "1de9452f8eadddd1a2d022cb5f0c07c2cf019bdf9166ba76148c5f9bd3776203"
402
402
  },
403
403
  {
404
404
  "path": "README.md",
@@ -427,8 +427,8 @@
427
427
  },
428
428
  {
429
429
  "path": "runtime/core/hellolynk-client-profile.mjs",
430
- "bytes": 8282,
431
- "sha256": "4b45a78b4d6c4794a1f494bd95777579c32c56a68321a1d3b484048942ae4742"
430
+ "bytes": 9359,
431
+ "sha256": "8be37831c96610e3d0a64848ada86488970cc6079e49764b47d8a8b2ba852269"
432
432
  },
433
433
  {
434
434
  "path": "runtime/core/hellolynk-client-update-entry.mjs",
@@ -602,8 +602,8 @@
602
602
  },
603
603
  {
604
604
  "path": "runtime/core/hellolynk-neutral-host-installation-store.mjs",
605
- "bytes": 33525,
606
- "sha256": "b5f6288732af6f9b9c0c750f6002eae657dde9513fc97674f6e59200f3cc9dc6"
605
+ "bytes": 33183,
606
+ "sha256": "dfb6bba4c627082cd6fca8cb38dc786f905e38f3e83ccf91dbfe57e55639e8a2"
607
607
  },
608
608
  {
609
609
  "path": "runtime/core/hellolynk-neutral-host-launcher.mjs",
@@ -613,7 +613,7 @@
613
613
  {
614
614
  "path": "runtime/core/hellolynk-neutral-host-process.mjs",
615
615
  "bytes": 225161,
616
- "sha256": "af6cb6585baae477f87ee880bd044dffb4c7f71667bfa78bcbf0d4d20e7483af"
616
+ "sha256": "e744bacf65f7b86cbcf7d654189c0e07e09401083e2b6f9053b17c1c3bacd1b4"
617
617
  },
618
618
  {
619
619
  "path": "runtime/core/hellolynk-neutral-host-store-adapters.mjs",
@@ -673,12 +673,12 @@
673
673
  {
674
674
  "path": "runtime/neutral-host-release-manifest.json",
675
675
  "bytes": 11228,
676
- "sha256": "1666255ab9676913302d388b5029b9045c46775de7eaff9edd182929d246ec32"
676
+ "sha256": "522ade3e36c0381d48db256668fd939c5402f1449a6d454a8047d869804651e4"
677
677
  },
678
678
  {
679
679
  "path": "runtime/neutral-host-release-pin.json",
680
680
  "bytes": 146,
681
- "sha256": "cdb4c1e7ca4ee27cd217893b5b9b23f9defd2df9f3969ea981cd2abb0e25f35f"
681
+ "sha256": "cdb4607e0793ca1a4633cbccc5c25408e4bf3130d57825f511ec26af8e8fed81"
682
682
  },
683
683
  {
684
684
  "path": "runtime/platform/windows/configure-agent.ps1",
@@ -1,4 +1,4 @@
1
1
  {
2
2
  "contract": "hellolynk-client-npm-pack-pin-v1",
3
- "manifestSha256": "e4a43126d346aea91d0732858273653eea30ab6c1e7e67fbf6deff2a7eb303a7"
3
+ "manifestSha256": "e342c03e99fceeb6b1ae9bf4504d18c82b1613982c6fe30c9522736978b1371f"
4
4
  }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hellolynk-ai/openclaw-channel",
3
- "version": "0.2.102",
3
+ "version": "0.2.103",
4
4
  "private": true,
5
5
  "description": "HelloLynk Messaging channel plugin for the public OpenClaw Windows client",
6
6
  "type": "module",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hellolynk-ai/openclaw-channel",
3
- "version": "0.2.102",
3
+ "version": "0.2.103",
4
4
  "description": "HelloLynk Messaging for OpenClaw: open conversations and let your AI message other people's AI assistants.",
5
5
  "homepage": "https://hellolynk.com",
6
6
  "repository": {
@@ -1,4 +1,5 @@
1
1
  import { lstat, mkdir, open, readFile, rename, rm, stat } from "node:fs/promises";
2
+ import { readdirSync } from "node:fs";
2
3
  import { homedir } from "node:os";
3
4
  import { basename, dirname, isAbsolute, join, resolve } from "node:path";
4
5
  import { randomUUID } from "node:crypto";
@@ -19,12 +20,34 @@ const SAFE_SCOPE = /^[a-z][a-z0-9_.:-]{0,127}$/;
19
20
  const MAX_PROFILE_BYTES = 64 * 1024;
20
21
 
21
22
  export function defaultHelloLynkClientRoot(platform = process.platform, env = process.env) {
22
- const home = resolve(String(env.HOME || env.USERPROFILE || homedir()));
23
- if (platform === "win32") return resolve(String(env.LOCALAPPDATA || join(home, "AppData", "Local")), "HelloLynk");
23
+ const home = resolve(String((platform === "win32" ? env.USERPROFILE || env.HOME : env.HOME || env.USERPROFILE) || homedir()));
24
+ if (platform === "win32") {
25
+ const current = join(home, ".hellolynk", "hellolynk-v2");
26
+ // Once selected, another client's older installer must not move us back.
27
+ if (hasWindowsClientInstallation(current)) return current;
28
+ const existing = resolve(String(env.LOCALAPPDATA || join(home, "AppData", "Local")), "HelloLynk");
29
+ // AppData created from a packaged desktop app can be private to that app.
30
+ // Keep an existing installation; an empty failed setup is not an account.
31
+ if (hasWindowsClientInstallation(existing)) return existing;
32
+ return current;
33
+ }
24
34
  if (platform === "darwin") return join(home, "Library", "Application Support", "HelloLynk");
25
35
  return resolve(String(env.XDG_DATA_HOME || join(home, ".local", "share")), "hellolynk");
26
36
  }
27
37
 
38
+ function hasWindowsClientInstallation(root) {
39
+ for (const directory of ["profiles", "releases", "host", "credentials", "e2ee-private-keys"]) {
40
+ try {
41
+ const entries = readdirSync(join(root, directory), { withFileTypes: true });
42
+ if (entries.some((entry) => directory !== "host" || entry.name !== "runtime")) return true;
43
+ } catch (error) {
44
+ // An unreadable existing location must not silently become a fresh account.
45
+ if (error.code !== "ENOENT") return true;
46
+ }
47
+ }
48
+ return false;
49
+ }
50
+
28
51
  function safeId(value, code) {
29
52
  const normalized = String(value || "").trim();
30
53
  if (!SAFE_ID.test(normalized)) throw new Error(code);
@@ -12,10 +12,9 @@ import {
12
12
  } from "node:fs/promises";
13
13
  import { basename, dirname, isAbsolute, join, parse, resolve } from "node:path";
14
14
  import { spawn } from "node:child_process";
15
- import { homedir } from "node:os";
16
15
  import { performance } from "node:perf_hooks";
17
16
  import { withLocalProcessLock } from "./hellolynk-local-process-lock.mjs";
18
- import { readClientProfile } from "./hellolynk-client-profile.mjs";
17
+ import { defaultHelloLynkClientRoot, readClientProfile } from "./hellolynk-client-profile.mjs";
19
18
  import { assertIdentifier } from "./hellolynk-host-auth.mjs";
20
19
  import runtimeSafety from "./hellolynk-runtime-safety.cjs";
21
20
 
@@ -46,10 +45,7 @@ export function defaultNeutralHostStoreRoot(platform = process.platform, env = p
46
45
  }
47
46
  return root;
48
47
  }
49
- const home = resolve(String(env.HOME || env.USERPROFILE || homedir()));
50
- if (platform === "win32") return resolve(String(env.LOCALAPPDATA || join(home, "AppData", "Local")), "HelloLynk", "host");
51
- if (platform === "darwin") return join(home, "Library", "Application Support", "HelloLynk", "host");
52
- return resolve(String(env.XDG_DATA_HOME || join(home, ".local", "share")), "hellolynk", "host");
48
+ return join(defaultHelloLynkClientRoot(platform, env), "host");
53
49
  }
54
50
 
55
51
  export function createNeutralHostInstallationStore(options = {}) {
@@ -34,7 +34,7 @@ export const HELLOLYNK_NEUTRAL_HOST_PROCESS_CONTRACT = "hellolynk-neutral-host-p
34
34
  export const HELLOLYNK_NEUTRAL_HOST_DISCOVERY_CONTRACT = "hellolynk-neutral-host-discovery-v1";
35
35
  // Raised with every release batch, together with the six client versions. A Host reports it
36
36
  // in its health; the higher release stays and the lower one makes room.
37
- export const HELLOLYNK_HOST_RELEASE_ORDINAL = 14;
37
+ export const HELLOLYNK_HOST_RELEASE_ORDINAL = 15;
38
38
 
39
39
  const INSTALLATION_LOCK_CONTRACT = "hellolynk-neutral-host-installation-lock-v2";
40
40
  const INSTALLATION_LOCK_MAX_BYTES = 4 * 1024;
@@ -32,7 +32,7 @@
32
32
  },
33
33
  {
34
34
  "path": "core/hellolynk-client-profile.mjs",
35
- "sha256": "4b45a78b4d6c4794a1f494bd95777579c32c56a68321a1d3b484048942ae4742"
35
+ "sha256": "8be37831c96610e3d0a64848ada86488970cc6079e49764b47d8a8b2ba852269"
36
36
  },
37
37
  {
38
38
  "path": "core/hellolynk-client-update-entry.mjs",
@@ -176,7 +176,7 @@
176
176
  },
177
177
  {
178
178
  "path": "core/hellolynk-neutral-host-installation-store.mjs",
179
- "sha256": "b5f6288732af6f9b9c0c750f6002eae657dde9513fc97674f6e59200f3cc9dc6"
179
+ "sha256": "dfb6bba4c627082cd6fca8cb38dc786f905e38f3e83ccf91dbfe57e55639e8a2"
180
180
  },
181
181
  {
182
182
  "path": "core/hellolynk-neutral-host-launcher.mjs",
@@ -184,7 +184,7 @@
184
184
  },
185
185
  {
186
186
  "path": "core/hellolynk-neutral-host-process.mjs",
187
- "sha256": "af6cb6585baae477f87ee880bd044dffb4c7f71667bfa78bcbf0d4d20e7483af"
187
+ "sha256": "e744bacf65f7b86cbcf7d654189c0e07e09401083e2b6f9053b17c1c3bacd1b4"
188
188
  },
189
189
  {
190
190
  "path": "core/hellolynk-neutral-host-store-adapters.mjs",
@@ -1,4 +1,4 @@
1
1
  {
2
2
  "contract": "hellolynk-neutral-host-release-pin-v1",
3
- "manifestSha256": "1666255ab9676913302d388b5029b9045c46775de7eaff9edd182929d246ec32"
3
+ "manifestSha256": "522ade3e36c0381d48db256668fd939c5402f1449a6d454a8047d869804651e4"
4
4
  }