攝影或3C

使用 VS Code LM API 調用 GitHub Copilot 模型進行三語同義詞批次擴展

## 從免管理員 Node.js 環境建置到 `vscode.lm` 模型偵測與 checkpoint 輸出

這份教學記錄如何從零開始執行這個 VS Code extension demo,

包含公司電腦常見的安裝權限限制、免管理員 Node.js 安裝方式、

三語同義詞批次擴展,以及如何列出目前可用的 LLM model。

## 目標

這個專案示範三件事:

1. 使用 VS Code extension 呼叫 `vscode.lm`。

2. 讀取 `keywords.json`,批次產生英文、簡中、西語墨西哥同義詞。

3. 偵測目前 VS Code Copilot LM API 實際可用的模型。

目前命令如下:

“`text

Demo: Ask LM and Save Markdown

Demo: Expand Synonyms Batch

Demo: List Available LM Models

“`

定義於 package.json中:

{
  "name": "vscode-lm-demo-js",
  "displayName": "VS Code LM Demo JS",
  "description": "Minimal JavaScript demo for asking vscode.lm and saving the answer as Markdown.",
  "version": "0.0.1",
  "engines": {
    "vscode": "^1.90.0"
  },
  "categories": [
    "Other"
  ],
  "main": "./extension.js",
  "contributes": {
    "commands": [
      {
        "command": "demo.askLmAndSaveMd",
        "title": "Demo: Ask LM and Save Markdown"
      },
      {
        "command": "demo.expandSynonymsBatch",
        "title": "Demo: Expand Synonyms Batch"
      },
      {
        "command": "demo.listAvailableLmModels",
        "title": "Demo: List Available LM Models"
      }
    ]
  },
  "devDependencies": {
    "@types/vscode": "^1.90.0"
  }
}

## 專案位置

“`powershell

D:\user\Python\vscode-lm-demo-js

“`

主要檔案:

extension.js       VS Code extension 主程式
package.json       extension 命令註冊
keywords.json      expand synonyms 的輸入 keyword
lm_config.json     預設 LLM model 設定
export\            batch/state/final/model list 輸出資料夾

## 1. 安裝 Node.js

VS Code extension 開發需要 Node.js 和 npm。

Node.js 可以理解成「讓 JavaScript 在瀏覽器外執行的環境」。

平常 JavaScript 常見於瀏覽器裡,例如網頁互動;

但 VS Code extension 不是跑在一般網頁裡,
而是跑在 VS Code 的 extension host 裡,

因此需要 Node.js 這個 JavaScript 執行環境來開發、安裝套件、執行工具。

用 Python 類比的話,可以先這樣理解:

Python 語言        你寫 .py 時使用的程式語言
python.exe         負責執行 .py 程式的執行器 / interpreter
pip                負責安裝 Python 套件
requirements.txt   常用來記錄 Python 專案依賴

JavaScript 語言    你寫 .js 時使用的程式語言
node.exe / Node.js  負責執行 .js 程式的執行器 / runtime
npm                負責安裝 JavaScript / Node.js 套件
package.json       記錄 Node.js 專案資訊命令依賴與 VS Code extension 設定

VS Code            編輯器不是 JavaScript 的執行器本身

所以在 terminal 裡,兩邊概念大概像這樣:

python my_script.py
node my_script.js

在這個專案裡,真正的 extension 主程式是 `extension.js`。

Node.js 提供開發時需要的 JavaScript 執行環境,
npm 則根據 `package.json` 安裝開發依賴。

npm 是 JavaScript / Node.js 專案的套件管理工具,
角色接近 Python 裡的 `pip`。

Python 常用 `pip install -r requirements.txt`
安裝 `requirements.txt` 裡列出的套件;

Node.js 專案則常用 `npm install` 安裝 `package.json` 裡列出的套件。

以本專案的 `package.json` 來看:

{
  "main": "./extension.js",
  "contributes": {
    "commands": [
      {
        "command": "demo.expandSynonymsBatch",
        "title": "Demo: Expand Synonyms Batch"
      }
    ]
  },
  "devDependencies": {
    "@types/vscode": "^1.90.0"
  }
}

其中:

main              告訴 VS Code extension 的入口檔是 extension.js
contributes       告訴 VS Code 這個 extension 要貢獻哪些功能例如命令面板命令
devDependencies  開發時需要安裝的套件這裡的 @types/vscode 用來提供 VS Code API 的型別提示

`”@types/vscode”: “^1.90.0″` 可以拆成兩部分看:

@types/vscode  套件名稱
^1.90.0         版本範圍

`@types/vscode` 前面的 `@` 不是 email 的小老鼠意思,
而是 npm 的「scope」命名規則。

白話來說,scope 可以先理解成 npm 套件名稱前面的「群組名稱」或「分類資料夾」。

它的格式通常是:

“`text

@群組名稱/套件名稱

“`

所以:

“`text

@types/vscode

“`

可以理解成:

“`text

@types 這個群組底下的 vscode 套件

“`

這裡的 `@types` 不是這個專案自己隨便取的名字,

而是 npm 生態裡常見的型別定義套件群組。

`@types/*` 這類套件通常是 TypeScript/JavaScript 開發時用的型別定義檔,

讓 VS Code 知道
`vscode.window`、`vscode.commands`、`vscode.lm`
這些 API 大概有哪些方法和屬性。

例如:

@types/node
@types/react
@types/express
@types/vscode

這些通常都代表「替某個 JavaScript 套件或環境補型別提示」。

但是 `@xxx/yyy` 這種格式本身不限定只能叫 `@types`。

其他團隊或工具也可以有自己的群組名稱,例如:

@babel/core
@vitejs/plugin-react
@microsoft/signalr
@angular/core

所以可以這樣記:

@types 是一個常見且有固定用途的群組名稱用來放型別定義套件
@xxx/yyy 這種寫法是 npm  scoped package 格式xxx 可以是不同組織或工具自己的名稱

那 `1.90.0` 是哪來的?它不是隨便寫的,
而是跟 `package.json` 裡的這段對齊:

"engines": {
  "vscode": "^1.90.0"
}

`engines.vscode` 表示
這個 extension 預期支援的 VS Code 版本範圍。

這裡寫 `^1.90.0`,
意思是這個 extension 以 VS Code `1.90.0`
這個 API 版本作為最低相容基準。

所以 `devDependencies` 裡的 `@types/vscode` 也用 `^1.90.0`,
讓開發時看到的 VS Code API 型別提示,
跟 extension 宣告支援的 VS Code API 版本一致。

它跟你目前安裝的 VS Code 版本有關,
但不是一定要完全一樣。

你現在的 VS Code 版本是 `1.122.1`,
比 `1.90.0` 新很多,所以符合 `^1.90.0` 的要求,
可以執行這個 extension。

可以把它想成 Python 套件常見的最低版本要求:

需要 Python >= 3.9
你電腦是 Python 3.12
所以可以跑

對應到這個 extension 就是:

需要 VS Code >= 1.90.0
你電腦是 VS Code 1.122.1
所以可以跑

那為什麼不是直接寫 `1.122.1`?

因為 `1.90.0` 是這個 demo extension 建立時採用的相容基準,

意思是「不要要求使用者一定要裝到最新 VS Code,
只要版本不低於這個基準就好」。

如果未來真的需要使用 VS Code `1.122` 才有的新 API,

才需要把 `engines.vscode` 和
`@types/vscode` 一起提高到接近 `^1.122.0`。

`1.90.0` 和 `1.122.1` 的差別,
可以理解成 VS Code API 的新舊差距。

VS Code 每個版本可能會新增 extension 能使用的 API,

例如新的 editor 功能、新的 Copilot/Language Model API 能力、或新的資料格式。

如果某個功能是在 `1.90.0` 之後才加入的,

那用 `@types/vscode@1.90.0` 開發時可能看不到那個 API,
程式也不應該宣告自己支援 VS Code `1.90.0`。

例如以後如果想把圖片送給 LLM,

這就很可能需要比較新的 VS Code Language Model API
支援圖片或 binary data 的 message part。

如果圖片輸入 API 是在比較新的 VS Code 才支援,
那就應該做兩件事:

1. 確認目前安裝的 VS Code 版本真的支援該 API
2.  package.json 裡的 engines.vscode  @types/vscode 提高到支援該 API 的版本

也就是說,不能只看你電腦現在是 `1.122.1` 就直接放心使用新 API;

extension 的 `package.json` 也要誠實宣告「這個 extension 至少需要哪個 VS Code 版本」。

否則如果 package 寫 `^1.90.0`,但程式使用只有 `1.122` 才有的 API,

那在舊版 VS Code 上就可能出現找不到 API、命令失敗、或 extension 啟動錯誤。

`^1.90.0` 前面的 `^` 是 npm 的版本範圍語法,意思是允許安裝相容的新版本。

以 `^1.90.0` 來說,npm 可以安裝 `1.90.0`、`1.91.0`、`1.92.3` 這類仍在 `1.x.x` 範圍內的版本,

但不會自動升到 `2.0.0`,因為主版本改成 2 可能代表不相容。

如果寫成:

"@types/vscode": "1.90.0"

就表示固定只能用 `1.90.0`,彈性比較小。

所以執行:

npm.cmd install

它會讀取 `package.json`,把 `devDependencies` 裡的 `@types/vscode` 安裝到 `node_modules`。

這個動作類似 Python 專案裡用 `pip install` 安裝開發或執行所需的套件。

一般情況可以直接安裝 Node.js LTS MSI,

但公司電腦可能沒有管理員權限,或 `winget` 不存在。

### 一般安裝方式

到 Node.js 官網下載 Windows Installer:

“`text

https://nodejs.org/en/download

“`

選:

“`text

Windows Installer (.msi)

“`

安裝完成後重新開啟 PowerShell / VS Code,檢查:

“`powershell

node -v

npm -v

“`

### 如果 winget 不存在

如果執行:

“`powershell

winget install OpenJS.NodeJS.LTS

“`

出現:

“`text

winget : 無法辨識 ‘winget’

“`

代表 Windows 沒有安裝 winget / App Installer。

這時不用卡在 winget,直接用 Node.js 官網下載 MSI 或 ZIP。

## 2. 繞過安裝權限的 Node.js 安裝方式

這次實際採用的是「用 MSI 抽出檔案,不正式安裝」的方式。

這適合 MSI 正式安裝時被權限、公司政策或檔案寫入限制擋住的情境。

### 2.1 先下載 MSI

從 Node.js 官網下載:

“`text

node-v24.16.0-x64.msi

“`

假設下載到:

C:\Users\SavingKing\Downloads\node-v24.16.0-x64.msi

### 2.2 嘗試正式 per-user 安裝

這一步不一定成功,但可以先試:

$msi = "$env:USERPROFILE\Downloads\node-v24.16.0-x64.msi"
$log = Join-Path $env:TEMP 'node-msi-user-install.log'
Start-Process msiexec.exe -ArgumentList @('/i', $msi, 'ALLUSERS=2', 'MSIINSTALLPERUSER=1', '/passive', '/norestart', '/L*v', $log) -Wait

如果最後 `node -v` / `npm -v` 還是找不到,或 log 裡看到類似:

Error 1310. Error writing to file: ...\nodejs\corepack
Verify that you have access to that directory.

就改用 MSI 抽取法。

### 2.3 用 msiexec 抽出 MSI 內容

這個方式不走正式安裝,不需要寫系統層 registry,也比較能避開權限問題。

$msi = "$env:USERPROFILE\Downloads\node-v24.16.0-x64.msi"
$target = "$env:LOCALAPPDATA\Programs\nodejs-msi-extract"
$log = Join-Path $env:TEMP 'node-msi-admin-extract.log'

if (Test-Path $target) {
    Remove-Item $target -Recurse -Force
}

New-Item -ItemType Directory -Force -Path $target | Out-Null
Start-Process msiexec.exe -ArgumentList @('/a', $msi, '/qn', "TARGETDIR=$target", '/L*v', $log) -Wait

抽出後,真正的 Node.js 目錄會在:

C:\Users\SavingKing\AppData\Local\Programs\nodejs-msi-extract\PFiles64\nodejs

檢查:

$nodeDir = "$env:LOCALAPPDATA\Programs\nodejs-msi-extract\PFiles64\nodejs"
& "$nodeDir\node.exe" -v
& "$nodeDir\npm.cmd" -v

這次成功的版本是:

“`text

node v24.16.0

npm 11.13.0

“`

### 2.4 加到使用者 PATH

$nodeDir = "$env:LOCALAPPDATA\Programs\nodejs-msi-extract\PFiles64\nodejs"
$currentUserPath = [Environment]::GetEnvironmentVariable('Path', 'User')

if (-not (($currentUserPath -split ';') -contains $nodeDir)) {
    [Environment]::SetEnvironmentVariable('Path', (($currentUserPath.TrimEnd(';') + ';' + $nodeDir).TrimStart(';')), 'User')
}

這段比較像 Python 的:

os.environ["PATH"] += r";C:\Users\SavingKing\AppData\Local\Programs\nodejs-msi-extract\PFiles64\nodejs"

但它不是只改目前 process,而是寫到 Windows 的 User PATH,重開 PowerShell / VS Code 後仍然有效。

它不是 `sys.path.append(…)`。

`sys.path` 是 Python `import` 模組時搜尋 `.py` 檔的路徑;

這裡要改的是 Windows shell 尋找 `node.exe` / `npm.cmd` 這類可執行檔的路徑。

然後關掉並重開 PowerShell / VS Code。

## 3. npm 被 PowerShell 執行原則擋住怎麼辦

如果執行:
npm install
出現:
因為這個系統上已停用指令碼執行,所以無法載入 npm.ps1
不要改系統政策,直接用 Windows command shim:
npm.cmd install
或用完整路徑:

$nodeDir = "$env:LOCALAPPDATA\Programs\nodejs-msi-extract\PFiles64\nodejs"
& "$nodeDir\npm.cmd" install

## 4. 安裝本專案依賴

進入專案:

cd D:\user\Python\vscode-lm-demo-js
npm.cmd install

成功時會看到類似:

added 1 package
found 0 vulnerabilities

## 5. 啟動 Extension Development Host

在 VS Code 開啟此資料夾:

“`text

D:\user\Python\vscode-lm-demo-js

“`

按:

“`text

F5

“`

如果 F5 沒反應,可以從上方選:

“`text

Start Debugging

“`

儲蓄保險王

儲蓄險是板主最喜愛的儲蓄工具,最喜愛的投資理財工具則是ETF,最喜愛的省錢工具則是信用卡