@hellolynk-ai/codex-plugin 0.2.100 → 0.2.102-macos.1

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 (47) hide show
  1. package/README.md +17 -17
  2. package/bin/hellolynk-client-setup.mjs +79 -11
  3. package/hellolynk-client-pack-manifest.json +111 -71
  4. package/hellolynk-client-pack-pin.json +1 -1
  5. package/package.json +8 -4
  6. package/plugins/hellolynk-codex/.codex-plugin/plugin.json +1 -1
  7. package/plugins/hellolynk-codex/.mcp.json +20 -19
  8. package/plugins/hellolynk-codex/package.json +1 -1
  9. package/plugins/hellolynk-codex/runtime/bootstrap/core/hellolynk-client-account.mjs +1 -1
  10. package/plugins/hellolynk-codex/runtime/bootstrap/core/hellolynk-client-profile.mjs +25 -2
  11. package/plugins/hellolynk-codex/runtime/bootstrap/core/hellolynk-darwin-host.mjs +256 -0
  12. package/plugins/hellolynk-codex/runtime/bootstrap/core/hellolynk-darwin-vault.mjs +153 -0
  13. package/plugins/hellolynk-codex/runtime/bootstrap/core/hellolynk-host-protected-store.mjs +20 -8
  14. package/plugins/hellolynk-codex/runtime/bootstrap/core/hellolynk-neutral-host-installation-store.mjs +3 -7
  15. package/plugins/hellolynk-codex/runtime/bootstrap/core/hellolynk-platform-credential-store.mjs +68 -14
  16. package/plugins/hellolynk-codex/runtime/bootstrap/platform/darwin/hellolynk-keychain-helper.bin +0 -0
  17. package/plugins/hellolynk-codex/runtime/bootstrap/platform/darwin/hellolynk-keychain-helper.swift +149 -0
  18. package/plugins/hellolynk-codex/runtime/connect-activate.mjs +5 -1
  19. package/plugins/hellolynk-codex/runtime/core/hellolynk-client-account.mjs +1 -1
  20. package/plugins/hellolynk-codex/runtime/core/hellolynk-client-profile.mjs +25 -2
  21. package/plugins/hellolynk-codex/runtime/core/hellolynk-client-update-entry.mjs +7 -3
  22. package/plugins/hellolynk-codex/runtime/core/hellolynk-client-update-runtime.mjs +24 -8
  23. package/plugins/hellolynk-codex/runtime/core/hellolynk-client-update.mjs +23 -9
  24. package/plugins/hellolynk-codex/runtime/core/hellolynk-darwin-host.mjs +256 -0
  25. package/plugins/hellolynk-codex/runtime/core/hellolynk-darwin-vault.mjs +153 -0
  26. package/plugins/hellolynk-codex/runtime/core/hellolynk-host-protected-store.mjs +20 -8
  27. package/plugins/hellolynk-codex/runtime/core/hellolynk-human-confirmation-ledger.mjs +53 -6
  28. package/plugins/hellolynk-codex/runtime/core/hellolynk-local-data-protection.mjs +22 -7
  29. package/plugins/hellolynk-codex/runtime/core/hellolynk-native-addressing-tools.cjs +1 -1
  30. package/plugins/hellolynk-codex/runtime/core/hellolynk-native-human-confirmation-broker.mjs +7 -5
  31. package/plugins/hellolynk-codex/runtime/core/hellolynk-neutral-host-installation-store.mjs +3 -7
  32. package/plugins/hellolynk-codex/runtime/core/hellolynk-neutral-host-launcher.mjs +9 -3
  33. package/plugins/hellolynk-codex/runtime/core/hellolynk-neutral-host-process.mjs +1 -1
  34. package/plugins/hellolynk-codex/runtime/core/hellolynk-platform-credential-store.mjs +68 -14
  35. package/plugins/hellolynk-codex/runtime/core/hellolynk-release-retention.mjs +116 -19
  36. package/plugins/hellolynk-codex/runtime/core/hellolynk-workbench-connection.mjs +5 -3
  37. package/plugins/hellolynk-codex/runtime/neutral-host-release-entry.mjs +1 -1
  38. package/plugins/hellolynk-codex/runtime/neutral-host-release-loader.mjs +1 -1
  39. package/plugins/hellolynk-codex/runtime/neutral-host-release-manifest.json +59 -27
  40. package/plugins/hellolynk-codex/runtime/neutral-host-release-pin.json +1 -1
  41. package/plugins/hellolynk-codex/runtime/platform/darwin/hellolynk-keychain-helper.bin +0 -0
  42. package/plugins/hellolynk-codex/runtime/platform/darwin/hellolynk-keychain-helper.swift +149 -0
  43. package/plugins/hellolynk-codex/server/codex-neutral-production.mjs +17 -9
  44. package/plugins/hellolynk-codex/server/mcp-server.mjs +1193 -1193
  45. package/plugins/hellolynk-codex/server/native-conversation-directory.mjs +33 -33
  46. package/plugins/hellolynk-codex/server/workbench-runtime.mjs +42 -42
  47. package/tools/hellolynk-activate-neutral-host-clients.mjs +5 -1
package/README.md CHANGED
@@ -35,35 +35,35 @@
35
35
 
36
36
  Codex、OpenClaw、TRAE Work、WorkBuddy。装哪个客户端,就选哪个包。同一个账号下,它们共用你的灵信号。
37
37
 
38
- 源码见 [Codex 客户端源码](https://github.com/haoyun18881-beep/HelloLynk/tree/main/clients/codex),完整介绍见 [HelloLynk on GitHub](https://github.com/haoyun18881-beep/HelloLynk)。
38
+ 源码见 [Codex 客户端源码](https://github.com/haoyun18881-beep/HelloLynk/tree/main/clients/codex-macos),完整介绍见 [HelloLynk on GitHub](https://github.com/haoyun18881-beep/HelloLynk)。
39
39
 
40
40
  ## 前提
41
41
 
42
- Windows 10/11、Node.js 22.16 或更高版本、PowerShell 7,以及打开过一次的 Codex。
42
+ Apple 芯片、macOS 13 或更高版本、Node.js 22.16 或更高版本,以及安装在「应用程序」中的 ChatGPT(已打开过 Codex)。
43
43
 
44
44
  ## 安装
45
45
 
46
46
  1. 打开 [HelloLynk 官网(Official site)](https://hellolynk.com)。新用户注册账号;已有账号登录后,查看自己的公开灵信号。
47
47
  2. 两种装法任选一种。
48
48
 
49
- 用安装包,在官网或 [GitHub Release](https://github.com/haoyun18881-beep/HelloLynk/releases) 下载 Codex 安装包,完整解压,在包含 `package` 文件夹的目录打开 PowerShell,运行:
49
+ 推荐用 npm,在终端运行:
50
50
 
51
- ```powershell
52
- node .\package\bin\hellolynk-client-setup.mjs init
51
+ ```sh
52
+ npm install -g @hellolynk-ai/codex-plugin@macos
53
+ hellolynk-codex init
53
54
  ```
54
55
 
55
- 用 npm,在 PowerShell 运行:
56
+ 用安装包,在官网或 [GitHub Release](https://github.com/haoyun18881-beep/HelloLynk/releases) 下载 Codex for Mac 安装包,完整解压,在包含 `package` 文件夹的目录打开 终端,运行:
56
57
 
57
- ```powershell
58
- npm install -g @hellolynk-ai/codex-plugin
59
- hellolynk-codex init
58
+ ```sh
59
+ node ./package/bin/hellolynk-client-setup.mjs init
60
60
  ```
61
61
 
62
62
  3. 完全退出并重新打开 Codex。
63
63
 
64
64
  可以把本说明交给你的本地 AI,请它帮你安装;用安装包时,把解压目录也告诉它。
65
65
 
66
- 下文命令按安装包写法给出。用 npm 装的,把 `node .\package\bin\hellolynk-client-setup.mjs` 换成 `hellolynk-codex`,在任意目录运行。
66
+ 下文命令按安装包写法给出。用 npm 装的,把 `node ./package/bin/hellolynk-client-setup.mjs` 换成 `hellolynk-codex`,在任意目录运行。
67
67
 
68
68
  ## 首次连接
69
69
 
@@ -73,8 +73,8 @@ Windows 10/11、Node.js 22.16 或更高版本、PowerShell 7,以及打开过
73
73
 
74
74
  也可以让 AI 用命令连接,把示例换成自己的公开灵信号:
75
75
 
76
- ```powershell
77
- node .\package\bin\hellolynk-client-setup.mjs connect --hellolynk-id hellolynk:intl:your-name
76
+ ```sh
77
+ node ./package/bin/hellolynk-client-setup.mjs connect --hellolynk-id hellolynk:intl:your-name
78
78
  ```
79
79
 
80
80
  首次连接这台电脑时,命令会给出官网确认链接。AI 把链接给用户;用户确认后,AI 继续执行同一条连接命令。
@@ -83,20 +83,20 @@ node .\package\bin\hellolynk-client-setup.mjs connect --hellolynk-id hellolynk:i
83
83
 
84
84
  插件会自动更新,不用操作。要手动更新,下载新版安装包,在包含 `package` 文件夹的目录运行:
85
85
 
86
- ```powershell
87
- node .\package\bin\hellolynk-client-setup.mjs setup
86
+ ```sh
87
+ node ./package/bin/hellolynk-client-setup.mjs setup
88
88
  ```
89
89
 
90
- 用 npm 装的,先运行 `npm install -g @hellolynk-ai/codex-plugin` 装上新版,再运行 `hellolynk-codex setup`。
90
+ 用 npm 装的,先运行 `npm install -g @hellolynk-ai/codex-plugin@macos` 装上新版,再运行 `hellolynk-codex setup`。
91
91
 
92
92
  ## 卸载
93
93
 
94
- 在包含 `package` 文件夹的目录运行 `node .\package\bin\hellolynk-client-setup.mjs uninstall`。账号、联系人和聊天记录留在这台电脑上,重新安装后不用重新连接。
94
+ 在包含 `package` 文件夹的目录运行 `node ./package/bin/hellolynk-client-setup.mjs uninstall`。账号、联系人和聊天记录留在这台电脑上,重新安装后不用重新连接。
95
95
 
96
96
  用 npm 装的,运行 `hellolynk-codex uninstall`,再运行 `npm uninstall -g @hellolynk-ai/codex-plugin`。
97
97
 
98
98
  ## 求助
99
99
 
100
- 运行 `node .\package\bin\hellolynk-client-setup.mjs doctor` 检查安装,把结果和错误码发到 [haoyun18881@gmail.com](mailto:haoyun18881@gmail.com)。
100
+ 运行 `node ./package/bin/hellolynk-client-setup.mjs doctor` 检查安装,把结果和错误码发到 [haoyun18881@gmail.com](mailto:haoyun18881@gmail.com)。
101
101
 
102
102
  许可:PolyForm Shield License 1.0.0,只覆盖本包内的客户端源码,完整条款见 LICENSE。
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  import crypto from "node:crypto";
4
- import { lstatSync, realpathSync, writeSync } from "node:fs";
4
+ import { constants, lstatSync, realpathSync, writeSync } from "node:fs";
5
5
  import fs from "node:fs/promises";
6
6
  import os from "node:os";
7
7
  import path from "node:path";
@@ -21,6 +21,8 @@ const CHINESE = /^zh\b/i.test(Intl.DateTimeFormat().resolvedOptions().locale);
21
21
  const CLIENT_NAMES = Object.freeze({ codex: "Codex", openclaw: "OpenClaw", "trae-work": "TRAE Work",
22
22
  workbuddy: "WorkBuddy", cursor: "Cursor", dsh: "DSH" });
23
23
  const { packageJson, metadata } = await readPackage();
24
+ const macPackage = metadata.client === "codex" && packageJson.os?.[0] === "darwin"
25
+ && packageJson.cpu?.[0] === "arm64";
24
26
  const commandArguments = process.argv.slice(2).filter((value) => value !== "--json");
25
27
  const command = String(commandArguments.shift() || "help").toLowerCase();
26
28
  const waitForPending = command === "--wait-for-pending";
@@ -61,8 +63,14 @@ try {
61
63
  "--expected-manifest-sha256", sourceRelease.outerManifestSha256,
62
64
  ]);
63
65
  } else {
64
- const originalLocations = resolveLocations();
65
66
  const accountModule = await importStableCore(PACKAGE_ROOT, "hellolynk-client-account.mjs", "hellolynk_npm_account_runtime_invalid");
67
+ const originalLocations = resolveLocations(accountModule.clientAccountBaseRoot);
68
+ if (macPackage && command !== "uninstall") {
69
+ const config = await readJson(path.join(sourceReleaseRoot, ".mcp.json"), "hellolynk_npm_release_invalid", true);
70
+ const commandPath = config.mcpServers?.["hellolynk-codex"]?.command;
71
+ if (typeof commandPath !== "string" || !path.isAbsolute(commandPath)) fail("hellolynk_npm_release_invalid");
72
+ await fs.access(commandPath, constants.X_OK).catch(() => fail("hellolynk_npm_codex_mac_node_required"));
73
+ }
66
74
  const baseRoot = accountModule.clientAccountBaseRoot(originalLocations.hostRoot);
67
75
  const packageLocations = { ...originalLocations, hostRoot: baseRoot, finalCurrentRoot: path.dirname(baseRoot) };
68
76
  const accounts = accountModule.createClientAccountActions({ client: metadata.client, storeRoot: baseRoot });
@@ -84,6 +92,13 @@ try {
84
92
  if (mutating) {
85
93
  await prepareFinalClientRoot(locations);
86
94
  installed = await installStablePackage({ packageClosure, sourceRelease, locations: packageLocations });
95
+ if (metadata.client === "codex") {
96
+ // The invoking updater can still be B255 code. Stop its old cleanup
97
+ // before switching the binding/cache to a release with process records.
98
+ const cleanup = await importStableCore(installed.packageRoot, "hellolynk-release-retention.mjs", "hellolynk_release_retention_unavailable");
99
+ await cleanup.protectRetentionReceipt({ releasesRoot: path.dirname(installed.packageRoot),
100
+ client: "codex", currentRelease: installed.packageRoot });
101
+ }
87
102
  }
88
103
  const activation = await inspectActivation(locations.hostRoot, metadata.profileId);
89
104
  // Both public install commands use the actual account state. Native recovery
@@ -422,7 +437,8 @@ async function uninstallClient(locations) {
422
437
  if (receiverConfigured) await receiver.configureTraeNativeTaskWorker({ storeRoot: locations.hostRoot, enabled: false });
423
438
  }
424
439
  // A binding names the release it starts, so it cannot outlive the releases removed below.
425
- if (await exists(path.join(locations.hostRoot, "capabilities-v1.dpapi.clixml"))) {
440
+ const protectedFile = macPackage ? "protected-v1.sqlite" : "capabilities-v1.dpapi.clixml";
441
+ if (await exists(path.join(locations.hostRoot, protectedFile))) {
426
442
  const store = await importStableCore(PACKAGE_ROOT, "hellolynk-host-protected-store.mjs", "hellolynk_npm_binding_invalid");
427
443
  await store.createHostProtectedStore({ root: locations.hostRoot, followClientAccount: false }).disconnectLocalClient(metadata.client);
428
444
  }
@@ -831,17 +847,20 @@ async function verifyRelease(releaseRoot, packageRoot, expectedMetadata = metada
831
847
  return Object.freeze({ manifestSha256, outerManifestSha256 });
832
848
  }
833
849
 
834
- function resolveLocations() {
835
- if (process.platform !== "win32") fail("hellolynk_npm_windows_only");
836
- const home = path.resolve(process.env.USERPROFILE || os.homedir());
837
- const localAppData = path.resolve(process.env.LOCALAPPDATA || path.join(home, "AppData", "Local"));
838
- const appData = path.resolve(process.env.APPDATA || path.join(home, "AppData", "Roaming"));
850
+ function resolveLocations(getDefaultHostRoot) {
851
+ if (macPackage) {
852
+ if (process.platform !== "darwin" || process.arch !== "arm64") fail("hellolynk_npm_platform_unsupported");
853
+ } else if (process.platform !== "win32") fail("hellolynk_npm_windows_only");
854
+ const home = path.resolve((macPackage ? process.env.HOME : process.env.USERPROFILE) || os.homedir());
855
+ const localAppData = macPackage ? path.join(home, "Library", "Application Support")
856
+ : path.resolve(process.env.LOCALAPPDATA || path.join(home, "AppData", "Local"));
857
+ const appData = macPackage ? localAppData : path.resolve(process.env.APPDATA || path.join(home, "AppData", "Roaming"));
839
858
  const configuredCodexHome = String(process.env.CODEX_HOME || "");
840
859
  if (configuredCodexHome && !path.isAbsolute(configuredCodexHome)) fail("hellolynk_npm_codex_home_invalid");
841
860
  const codexHome = path.resolve(configuredCodexHome || path.join(home, ".codex"));
842
861
  const configuredHostRoot = String(process.env.HELLOLYNK_NEUTRAL_STORE_ROOT || "").trim();
843
862
  if (configuredHostRoot && !path.isAbsolute(configuredHostRoot)) fail("hellolynk_npm_store_root_invalid");
844
- const hostRoot = path.resolve(configuredHostRoot || path.join(localAppData, "HelloLynk", "host"));
863
+ const hostRoot = path.resolve(configuredHostRoot || getDefaultHostRoot());
845
864
  if (configuredHostRoot && path.basename(hostRoot).toLowerCase() !== "host") {
846
865
  fail("hellolynk_npm_store_root_invalid");
847
866
  }
@@ -997,6 +1016,12 @@ async function startHostWhenAbsent(runtime, binding) {
997
1016
  }
998
1017
 
999
1018
  async function secureStableReleaseTree(locations, releaseId, options = {}) {
1019
+ const releasePath = path.resolve(locations.finalCurrentRoot, "releases", releaseId);
1020
+ // An existing AppData root can be shared while a new release is redirected
1021
+ // into one desktop app's private cache. Other clients cannot use that release.
1022
+ if (process.platform === "win32" && realpathSync.native(releasePath).toLowerCase() !== releasePath.toLowerCase()) {
1023
+ fail("client_root_alias_rejected");
1024
+ }
1000
1025
  const module = await importCore(
1001
1026
  "hellolynk-platform-credential-store.mjs",
1002
1027
  "hellolynk_npm_client_root_security_unavailable",
@@ -2239,6 +2264,13 @@ function runCodexJson(args, code, codexHome) {
2239
2264
  }
2240
2265
 
2241
2266
  function minimalEnv({ codexHome = null } = {}) {
2267
+ if (macPackage) return Object.freeze({
2268
+ PATH: process.env.PATH || "/usr/bin:/bin",
2269
+ HOME: process.env.HOME || os.homedir(),
2270
+ TMPDIR: process.env.TMPDIR || os.tmpdir(),
2271
+ LANG: process.env.LANG || "en_US.UTF-8",
2272
+ ...(codexHome ? { CODEX_HOME: codexHome } : {}),
2273
+ });
2242
2274
  return Object.freeze({
2243
2275
  PATH: process.env.Path || process.env.PATH || "",
2244
2276
  PATHEXT: process.env.PATHEXT || "",
@@ -2254,13 +2286,18 @@ function minimalEnv({ codexHome = null } = {}) {
2254
2286
 
2255
2287
  function resolveCodexRunner(codexHome) {
2256
2288
  if (resolvedCodexRunner) return resolvedCodexRunner;
2257
- const searchPath = String(process.env.Path || process.env.PATH || "");
2289
+ const searchPath = String((macPackage ? process.env.PATH : process.env.Path || process.env.PATH) || "");
2258
2290
  let sawLoaderCandidate = false;
2259
2291
  let sawNativeCandidate = false;
2260
2292
  for (const rawEntry of searchPath.split(path.delimiter)) {
2261
2293
  try {
2262
2294
  const logical = rawEntry.trim().replace(/^"(.*)"$/, "$1");
2263
2295
  if (!logical || !path.isAbsolute(logical)) continue;
2296
+ if (macPackage) {
2297
+ const runner = probeMacCodex(path.join(logical, "codex"), codexHome);
2298
+ if (runner) return (resolvedCodexRunner = runner);
2299
+ continue;
2300
+ }
2264
2301
  // nvm/fnm and user profile mappings can put a junction on PATH. Resolve
2265
2302
  // that directory once, then retain the ordinary-file checks below it.
2266
2303
  const entry = realpathSync(path.resolve(logical));
@@ -2314,6 +2351,15 @@ function resolveCodexRunner(codexHome) {
2314
2351
  }
2315
2352
 
2316
2353
  function resolveCodexDesktopRunner(codexHome) {
2354
+ if (macPackage) {
2355
+ for (const directory of ["/Applications", path.join(os.homedir(), "Applications")]) {
2356
+ for (const app of ["ChatGPT.app", "Codex.app"]) {
2357
+ const runner = probeMacCodex(path.join(directory, app, "Contents", "Resources", "codex"), codexHome);
2358
+ if (runner) return runner;
2359
+ }
2360
+ }
2361
+ return null;
2362
+ }
2317
2363
  if (process.platform !== "win32") return null;
2318
2364
  const systemRoot = process.env.SystemRoot || process.env.SYSTEMROOT;
2319
2365
  if (!systemRoot || !path.isAbsolute(systemRoot)) return null;
@@ -2341,6 +2387,22 @@ function resolveCodexDesktopRunner(codexHome) {
2341
2387
  return null;
2342
2388
  }
2343
2389
 
2390
+ function probeMacCodex(logicalPath, codexHome) {
2391
+ // npm and Homebrew commonly expose a symlink. Execute the canonical file directly.
2392
+ try {
2393
+ const command = realpathSync(logicalPath);
2394
+ const metadata = lstatSync(command);
2395
+ if (!metadata.isFile() || !(metadata.mode & 0o111)) return null;
2396
+ const result = spawnSync(command, ["--version"], {
2397
+ encoding: "utf8", shell: false, timeout: 5000, env: minimalEnv({ codexHome }),
2398
+ });
2399
+ if (result.status === 0 && /^codex-cli\s+\d+\.\d+\.\d+/u.test(String(result.stdout || "").trim())) {
2400
+ return Object.freeze({ command, argsPrefix: Object.freeze([]), kind: "native" });
2401
+ }
2402
+ } catch { /* Missing or unusable CLI. */ }
2403
+ return null;
2404
+ }
2405
+
2344
2406
  function resolveRegularDescendantSync(anchor, anchorRealPath, segments) {
2345
2407
  let observed = anchor;
2346
2408
  for (let index = 0; index < segments.length; index += 1) {
@@ -2520,6 +2582,7 @@ function samePath(left, right) {
2520
2582
  const resolved = normalizeWindowsNamespacePath(value);
2521
2583
  let canonical = resolved;
2522
2584
  try { canonical = realpathSync(resolved); } catch { /* comparison can still reject a missing path */ }
2585
+ if (macPackage) return canonical;
2523
2586
  return normalizeWindowsNamespacePath(canonical).replace(/[\\/]+$/u, "").toLowerCase();
2524
2587
  };
2525
2588
  return normalize(left) === normalize(right);
@@ -2639,7 +2702,9 @@ function helpText() {
2639
2702
  : [[say("安装", "Install"), "init"], [say("连接账号", "Connect an account"), connect],
2640
2703
  [say("更新或修复", "Update or repair"), "setup"], [say("检查", "Check"), "doctor"],
2641
2704
  [say("卸载", "Uninstall"), "uninstall"]];
2642
- return `${[`HelloLynk for ${CLIENT_NAMES[metadata.client]}${say("(Windows,Node.js 22.16.0+)", " (Windows, Node.js 22.16.0+)")}`,
2705
+ const platform = macPackage ? " (macOS arm64, Node.js 22.16.0+)"
2706
+ : say("(Windows,Node.js 22.16.0+)", " (Windows, Node.js 22.16.0+)");
2707
+ return `${[`HelloLynk for ${CLIENT_NAMES[metadata.client]}${platform}`,
2643
2708
  ...rows.map(([label, args]) => `${label}${say(":", ": ")}${run} ${args}`),
2644
2709
  say("加 --json 输出一行 JSON。", "Add --json for one line of JSON.")].join("\n")}\n`;
2645
2710
  }
@@ -2713,6 +2778,9 @@ function failureText(failure) {
2713
2778
  function failureReason(code, name) {
2714
2779
  if (code === "hellolynk_node_22_16_required") return say("需要 Node.js 22.16 或更高版本。", "Node.js 22.16 or later is required.");
2715
2780
  if (code === "hellolynk_npm_windows_only") return say("只支持 Windows。", "Windows only.");
2781
+ if (code === "hellolynk_npm_platform_unsupported") return say("此安装包适用于 Apple 芯片的 Mac。", "This package requires an Apple silicon Mac.");
2782
+ if (code === "hellolynk_npm_codex_mac_node_required") return say("请将 ChatGPT 安装到「应用程序」,打开 Codex 后再试。",
2783
+ "Install ChatGPT in Applications, open Codex, and try again.");
2716
2784
  if (code === "hellolynk_npm_connect_id_invalid") {
2717
2785
  return say("灵信号不对。请从官网复制从 hellolynk: 开始的完整灵信号。",
2718
2786
  "This HelloLynk ID is not valid. Copy the complete ID, starting with hellolynk:, from the website.");