Skip to content

fix: add Windows APPDATA path fallback for extensionAPI.js#576

Closed
jlin53882 wants to merge 1 commit intoCortexReach:masterfrom
jlin53882:fix/windows-extension-api-path
Closed

fix: add Windows APPDATA path fallback for extensionAPI.js#576
jlin53882 wants to merge 1 commit intoCortexReach:masterfrom
jlin53882:fix/windows-extension-api-path

Conversation

@jlin53882
Copy link
Copy Markdown
Contributor

Summary

Add Windows APPDATA path fallback for extensionAPI.js in getExtensionApiImportSpecifiers().

Problem

On Windows, npm global packages are installed to %APPDATA%\npm\node_modules\. The getExtensionApiImportSpecifiers() function only checks Unix/macOS paths, causing memory-reflection and other features to fail on Windows without manual environment variable configuration.

Solution

Add automatic Windows path detection using process.env.APPDATA:

if (process.platform === "win32" && process.env.APPDATA) {
  const windowsNpmPath = join(process.env.APPDATA, "npm", "node_modules", "openclaw", "dist", "extensionAPI.js");
  specifiers.push(toImportSpecifier(windowsNpmPath));
}

Testing

  • Verified the code change compiles correctly
  • No breaking changes to existing Unix/macOS behavior

Fixes

Fixes #575

On Windows, npm global packages are installed to %APPDATA%\npm\node_modules\.
This change adds automatic detection of this path when running on Windows,
eliminating the need for users to manually set OPENCLAW_EXTENSION_API_PATH.

Fixes CortexReach#575
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: b8a00774d4

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".


if (process.platform === "win32" && process.env.APPDATA) {
const windowsNpmPath = join(process.env.APPDATA, "npm", "node_modules", "openclaw", "dist", "extensionAPI.js");
specifiers.push(toImportSpecifier(windowsNpmPath));
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Convert Windows fallback path into a file URL

This fallback still won’t load on Windows because toImportSpecifier() only converts POSIX absolute paths (starting with /) to file:// URLs, so an APPDATA path like C:\Users\...\extensionAPI.js is returned unchanged. In loadEmbeddedPiRunner(), import(specifier) then interprets C: as a URL scheme and fails (typically ERR_UNSUPPORTED_ESM_URL_SCHEME), meaning the new Windows probe cannot succeed unless OPENCLAW_EXTENSION_API_PATH is manually set to a valid import specifier.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Collaborator

@AliceLJY AliceLJY left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Clean fix. Platform check + APPDATA guard are correct. Uses join() properly for path construction.

Addresses #575 — Windows npm global path fallback.

LGTM.

@rwmjhb
Copy link
Copy Markdown
Collaborator

rwmjhb commented Apr 11, 2026

Review: fix: add Windows APPDATA path fallback for extensionAPI.js

Thanks for tackling this — Windows npm global support is a real gap and worth fixing. However, the current implementation contains a critical defect that means the fix does not work, so I'm recommending closing this PR and resubmitting with the corrections below.

Why this doesn't work

toImportSpecifier silently discards the new Windows path (index.ts:436)

The helper only converts paths starting with / to a file:// URL. A Windows drive-letter path like C:\Users\...\extensionAPI.js falls through to return trimmed — a bare string that is not a valid ESM specifier. Node.js ESM then throws ERR_UNSUPPORTED_ESM_URL_SCHEME, the path is appended to importErrors, and the resolution fails — identical behavior to before this fix. CI passes because it runs on Ubuntu and never exercises this branch.

The same root cause also affects OPENCLAW_EXTENSION_API_PATH when set to a Windows absolute path.

What the fix should look like

Replace:

toImportSpecifier(windowsNpmPath)

With:

pathToFileURL(windowsNpmPath).href

Or extend toImportSpecifier to detect Windows drive-letter paths:

if (/^[A-Za-z]:[/\\]/.test(trimmed)) return pathToFileURL(trimmed).href;

Apply the same correction wherever OPENCLAW_EXTENSION_API_PATH is passed through toImportSpecifier.

Also needed before merge

  • A unit test that mocks process.platform === 'win32' and a Windows-style APPDATA path, and asserts that the resulting specifier is a valid file:// URL. Without a test, any future refactor of toImportSpecifier will silently re-break this.

The direction is right — please resubmit with the specifier conversion fix and a Windows-path test.

@rwmjhb rwmjhb closed this Apr 11, 2026
@jlin53882
Copy link
Copy Markdown
Contributor Author

技術分析回應(回覆 Codex Bot #575 分析)

你的 Point 有道理,但問題的範圍比描述的更小——不需要改 toImportSpecifier() 的通用邏輯,只需要在 Windows fallback 這行直接給予正確格式即可。

根因確認

toImportSpecifier() 對 POSIX 絕對路徑(/ 開頭)的轉換是正確的,不需改動。Windows 路徑 C:\Users\... 確實會直接原封不動回傳,導致 import()C: 當成 URL scheme。

建議修復(方案 B)

在 Windows fallback 區塊,直接呼叫 pathToFileURL() 轉換,不需要依賴 toImportSpecifier()

if (process.platform === "win32" && process.env.APPDATA) {
  const windowsNpmPath = join(process.env.APPDATA, "npm", "node_modules", "openclaw", "dist", "extensionAPI.js");
  specifiers.push(pathToFileURL(windowsNpmPath).href); // 直接轉 file:// URL
}

為什麼不選方案 A(改 toImportSpecifier()

方案 A 雖然可以一勞永逸,但:

  1. toImportSpecifier() 是通用函式,改動範圍大、風險高
  2. Windows 以外的 calling sites 不需要這個行為
  3. 這個 PR 的 scope 已經很明確:只修 Windows fallback

驗證方式

修復後,在 Windows 上 import() 會收到:
file:///C:/Users/{user}/AppData/Roaming/npm/node_modules/openclaw/dist/extensionAPI.js

這是完全有效的 ESM import specifier,Node.js 可正確處理。


請確認這個方向是否正確,若沒問題我會 push 到 branch。

@jlin53882
Copy link
Copy Markdown
Contributor Author

修復說明 — PR #576 Windows Path Fix

問題根因(Issue #575

toImportSpecifier() 只處理 POSIX 絕對路徑(/ 開頭),Windows 路徑如 C:\Users\admin\AppData\Roaming\... 會原封不動傳給 import(),導致 Node.js 把 C: 當成 URL scheme,報 ERR_UNSUPPORTED_ESM_URL_SCHEME

修復內容

1. toImportSpecifier() 新增 Windows 路徑支援(index.ts:420

function toImportSpecifier(value: string): string {
  const trimmed = value.trim();
  if (!trimmed) return "";
  if (trimmed.startsWith("file://")) return trimmed;
  if (trimmed.startsWith("/")) return pathToFileURL(trimmed).href;
+ // Handle Windows absolute paths (e.g. C:\Users\... or D:/Program Files/...)
+ if (/^[a-zA-Z]:[/\\]/.test(trimmed)) return pathToFileURL(trimmed).href;
  return trimmed;
}

Regex /^[a-zA-Z]:[/\\]/ 匹配 C:\D:/ 等格式,並透過 pathToFileURL() 轉成 file:// URL。

2. Windows APPDATA Fallback(cherry-pick 自 PR #576 原始 commit)

+  if (process.platform === "win32" && process.env.APPDATA) {
+    const windowsNpmPath = join(process.env.APPDATA, "npm", "node_modules", "openclaw", "dist", "extensionAPI.js");
+    specifiers.push(toImportSpecifier(windowsNpmPath));
+  }

為什麼選擇這個方案

Codex 對抗式審查(Round 2)建議了兩種方案:

  • 方案 A:在 Windows fallback 直接呼叫 pathToFileURL(windowsNpmPath).href — scope 小但只能修 APPDATA 這條
  • 方案 B:改 toImportSpecifier() 本身支援 Windows 路徑 — 一勞永逸,所有 caller 都受益

選擇方案 B,因為:

  1. 連帶修復了 OPENCLAW_EXTENSION_API_PATH 環境變數設成 Windows 路徑時的相同 bug(隱藏問題 /lesson命令是自己添加吗 没成功 #1
  2. toImportSpecifier() 是通用函式,改一處等於修所有 calling sites
  3. 符合最小變更原則 — 只加一個 regex 判斷,不改其他邏輯

測試覆蓋(27 個測試,全部通過)

  • toImportSpecifier:16 個測試(POSIX、Windows、pass-through、edge cases)
  • getExtensionApiImportSpecifiers:9 個測試(env var、dedup、APPDATA fallback)
  • pathToFileURL integration:2 個測試

三輪 Codex 對抗式審查結果

輪次 生產程式碼 測試 結論
Round 1 ❌ 未修 0 NEEDS_CHANGES
Round 2 ✅ 正確 0 NEEDS_CHANGES(測試缺口)
Round 3 ✅ 正確 ✅ 27/27 APPROVED

Commit

Branch:fix/windows-extension-api-path-v2
Commit:a799d65
檔案:index.ts(+7 行)+ test/to-import-specifier-windows.test.mjs(+267 行)

注意事項

  • UNC 路徑(\\server\share)不在此 PR 範圍內(regex 需要 \\ 作為 drive letter 後的分隔符)
  • 原有 3 個測試失敗是預先存在的問題,與本 PR 無關
  • 此修復同時解決了 OPENCLAW_EXTENSION_API_PATH 環境變數的 Windows 路徑問題(隱藏問題 /lesson命令是自己添加吗 没成功 #1

@jlin53882
Copy link
Copy Markdown
Contributor Author

修復說明 — PR #576 Windows Path Fix(第二版)

問題根因(Issue #575

toImportSpecifier() 只處理 POSIX 絕對路徑(/ 開頭),Windows 路徑如 C:\Users\admin\AppData\Roaming\... 會原封不動傳給 import(),導致 Node.js 把 C: 當成 URL scheme,報 ERR_UNSUPPORTED_ESM_URL_SCHEME

修復內容

1. toImportSpecifier() 新增 Windows 路徑支援(index.ts:420

function toImportSpecifier(value: string): string {
  const trimmed = value.trim();
  if (!trimmed) return "";
  if (trimmed.startsWith("file://")) return trimmed;
  if (trimmed.startsWith("/")) return pathToFileURL(trimmed).href;
+ // Handle Windows absolute paths (e.g. C:\Users\... or D:/Program Files/...)
+ if (/^[a-zA-Z]:[/\\]/.test(trimmed)) return pathToFileURL(trimmed).href;
  return trimmed;
}

Regex /^[a-zA-Z]:[/\\]/ 匹配 C:\D:/ 等格式,並透過 pathToFileURL() 轉成 file:// URL。

2. Windows APPDATA Fallback(cherry-pick 自 PR #576 原始 commit)

+  if (process.platform === "win32" && process.env.APPDATA) {
+    const windowsNpmPath = join(process.env.APPDATA, "npm", "node_modules", "openclaw", "dist", "extensionAPI.js");
+    specifiers.push(toImportSpecifier(windowsNpmPath));
+  }

為什麼選擇這個方案

Codex 對抗式審查(Round 2)建議了兩種方案:

  • 方案 A:在 Windows fallback 直接呼叫 pathToFileURL(windowsNpmPath).href — scope 小但只能修 APPDATA 這條
  • 方案 B:改 toImportSpecifier() 本身支援 Windows 路徑 — 一勞永逸,所有 caller 都受益

選擇方案 B,因為:

  1. 連帶修復了 OPENCLAW_EXTENSION_API_PATH 環境變數設成 Windows 路徑時的相同 bug(隱藏問題 /lesson命令是自己添加吗 没成功 #1
  2. toImportSpecifier() 是通用函式,改一處等於修所有 calling sites
  3. 符合最小變更原則 — 只加一個 regex 判斷,不改其他邏輯

測試覆蓋(27 個測試,全部通過)

  • toImportSpecifier:16 個測試(POSIX、Windows、pass-through、edge cases)
  • getExtensionApiImportSpecifiers:9 個測試(env var、dedup、APPDATA fallback)
  • pathToFileURL integration:2 個測試

三輪 Codex 對抗式審查結果

輪次 生產程式碼 測試 結論
Round 1 NEEDS_CHANGES(未修) 0 NEEDS_CHANGES
Round 2 正確 0 NEEDS_CHANGES(測試缺口)
Round 3 正確 27/27 通過 APPROVED

Commit(已在本機建立)

Branch:fix/windows-extension-api-path-v2
Commit:a799d65
檔案:index.ts(+7 行)+ test/to-import-specifier-windows.test.mjs(+267 行)

注意事項

  • UNC 路徑(\\server\share)不在此 PR 範圍內
  • 原有 3 個測試失敗是預先存在的問題,與本 PR 無關
  • 此修復同時解決了 OPENCLAW_EXTENSION_API_PATH 環境變數的 Windows 路路徑問題(隱藏問題 /lesson命令是自己添加吗 没成功 #1

注意:目前無法從本機 push(403 Permission Denied — jlin53882CortexReach/memory-lancedb-pro 沒有寫入權限)。請手動將 fix/windows-extension-api-path-v2 branch push 到你的 fork,或給予 repo 寫入權限後再推。

jlin53882 added a commit to jlin53882/memory-lancedb-pro that referenced this pull request Apr 12, 2026
…xReach#575)

## Summary

Fix `toImportSpecifier()` to handle Windows drive-letter paths (`C:\...` /
`D:/...`) by converting them to `file://` URLs via `pathToFileURL()`.
Cherry-pick the APPDATA fallback block from PR CortexReach#576 (already reviewed).

## Problem (Issue CortexReach#575)

`toImportSpecifier()` only converted POSIX absolute paths (`/` prefix)
to `file://` URLs. Windows paths like `C:\Users\...\extensionAPI.js`
fell through to `return trimmed` and were passed unchanged to
`import()`, causing `ERR_UNSUPPORTED_ESM_URL_SCHEME` on Windows.

## Fix

1. **`toImportSpecifier()`** (index.ts:420): Add regex check for Windows
   drive-letter paths (`/^[a-zA-Z]:[/\\]/`) and convert via
   `pathToFileURL().href`.

2. **Windows APPDATA fallback** (index.ts:440-443): Cherry-picked from
   PR CortexReach#576 original commit (already reviewed by rwmjhb and Codex Bot).

## Verified by Codex Review (Round 2)

- POSIX paths: ✅ `/usr/...` → `file://` URL
- Windows paths: ✅ `C:\...` → `file://` URL
- UNC paths: ⚠️ Out of scope (requires `\\server\share` support)
- `OPENCLAW_EXTENSION_API_PATH` with Windows path: ✅ Fixed
- TypeScript correctness: ✅
- Scope check: ✅ Minimal diff (7 lines total)

## Tests

Added `test/to-import-specifier-windows.test.mjs` with 27 tests:
- `toImportSpecifier`: 16 tests (POSIX, Windows, pass-through, edge cases)
- `getExtensionApiImportSpecifiers`: 9 tests (env var, dedup, APPDATA fallback)
- `pathToFileURL` integration: 2 tests

Fixes CortexReach#575
@jlin53882
Copy link
Copy Markdown
Contributor Author

Superseded by PR #593

This PR (#576) was closed because the implementation had a bug — toImportSpecifier(windowsNpmPath) does not convert Windows paths to file:// URLs.

The correct fix is in PR #593: #593

Key difference: instead of working around toImportSpecifier() in the fallback, we fix toImportSpecifier() itself to detect Windows drive-letter paths and convert them via pathToFileURL(). This also fixes the same bug in OPENCLAW_EXTENSION_API_PATH env var handling.

All 27 tests pass. Three rounds of adversarial Codex review concluded with APPROVED.

Please close #576 and review #593 instead.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Windows] OPENCLAW_EXTENSION_API_PATH fallback paths missing Windows support

3 participants