# 用 VS Code 扩展连接命令、文件与任务记录

原文: https://yishto.com/learn/application-platforms/vscode-extension-task-notes/

作者: [Yishto](https://yishto.com/about/)

构建项目任务记录扩展，连接命令声明、扩展生命周期和限定存储，明确工作区信任、URI与取消写入规则。

首次发布: 2026-11-10
内容更新: 2026-11-10

任务记录扩展提供两个动作：查看当前项目笔记，给一个任务追加记录。它会读写数据，所以需要明确记录属于哪个工作区、命令什么时候生效，以及打开不可信项目时哪些功能可以运行。

本课用合成任务 ID，不读取终端历史或自动运行项目命令。第一版采用编辑器原生选择与输入界面，不需要 webview；以后加入复杂界面时再处理其独立安全边界。

## 从命令声明到执行函数

扩展 manifest 中的 contribution 声明命令及用户看到的标题，扩展代码注册实际处理函数。声明一个菜单项不等于实现了行为。扩展激活时建立注册与监听，停用时释放资源；注册对象加入 disposables，避免反复激活造成重复处理。

激活机制与最低 `engines.vscode` 版本有关，按当前官方说明选择事件和贡献点，不把旧样例中的事件配置当作所有版本要求。工程先验证命令出现，再验证调用到正确处理函数。

命令应有稳定 ID，显示标题可翻译。处理函数接收参数时仍需检查类型和范围，因为调用不一定来自菜单。未知任务或缺少工作区应返回可理解信息，不默认写进第一个找到的目录。

## 任务与存储作用域

任务记录包含任务 ID、文本、记录时间与对应项目身份。多根工作区需要明确选择哪一个 folder；不同项目不能仅靠同名任务标题混在一起。记录 ID 保持稳定，列表展示顺序由明确字段决定。

个人笔记可以使用扩展提供的工作区存储；需要共享的文件另走用户明确选择的导出流程。本课默认不将记录自动写入仓库，也不把服务秘密存进普通 JSON。全局偏好与项目数据分开，避免换项目时看到上一项目的任务。

资源使用 URI 表示。远程工作区和虚拟文件系统不一定对应本机路径，优先使用编辑器 workspace 文件系统接口，而不是直接把 URI 路径交给 Node 的本地文件操作。若某项能力仅支持本地，明确检查并说明限制。

## 建立扩展开发工程

按官方指南准备 Node.js 与 Git，用 VS Code Extension Generator 创建 TypeScript 工程。打开 `src/extension.ts`，通过 F5 启动 Extension Development Host，确认模板命令可执行。这里是供读者运行的步骤，本文未运行扩展宿主。

在 manifest 加入查看与保存命令，在激活函数注册两个 handler。查看读取所属项目的记录存储并展示任务选择；保存先选择项目和任务，再输入正文。用户取消任何一步都返回，不创建空记录、不触发后续写入。

加入存储适配器，统一读取、验证、保存与错误映射。启动检查 schema，读取失败保留原记录并显示错误。文件保存采用平台支持的安全写入策略；操作失败不要覆盖现有内容，也不要把“调用已发出”显示成保存完成。

## Workspace Trust 的判断要进入执行路径

官方文档允许在 manifest 声明完全、有限或不支持受限工作区。本课采用有限支持：查看笔记可以运行，具有副作用的保存路径要求信任。这是本扩展的明确策略，不表示所有记笔记扩展都必须采用相同限制。

界面可以用信任条件隐藏动作，但隐藏不足以阻止代码调用，handler 仍检查当前信任状态。工作区配置可能含恶意参数，特别是用于执行命令或决定任意写入路径的配置；本课不开放 shell 执行入口。

下面 Python 检查有限命令集合。它是策略模型，不运行 VS Code API，也不实现真实信任状态变化。

```python
def command_allowed(command, trusted):
    read_only = {"show_notes", "list_tasks"}
    if command in read_only:
        return True
    return trusted and command == "save_note"
assert command_allowed("show_notes", False)
assert not command_allowed("save_note", False)
assert command_allowed("save_note", True)
assert not command_allowed("run_shell", True)
print(command_allowed("save_note", False))
```

实际输出 `False`。受限模式下保存被拒绝，查看允许，未知 `run_shell` 即使信任也拒绝。真实扩展以 `workspace.isTrusted` 等官方 API 读取状态，并按实际能力说明限制；不要仅信任传入参数中的一个布尔值。

## 路径、监听与重入

如果增加共享文件导出，先让用户选择目标，检查 URI 是否在允许范围，并确认覆盖已有文件。路径检查需处理父目录跳转与真实文件系统行为，不能用简单字符串前缀保证边界。本课先把可写范围固定为扩展自己的存储。

文件 watcher 可能对自己的写入发事件。给操作分配 ID，并区分外部变化与自身保存，避免“检测变化、再次写入”的无限循环。批量变化可以防抖，仍要保证最终读取当前内容，而不是把延迟事件当作完整历史。

一次保存期间继续输入时，旧保存响应只确认自己的快照。新输入保持未保存状态。多窗口同时改同一记录，需要版本或冲突策略，不能因属于同一个工作区就假定只有一个写入者。

## 错误与界面扩展

没有工作区时提示打开或选择项目；只读资源时允许查看但解释不能保存；容量或编码错误保留输入供重试。取消是用户的正常选择，不当作异常弹窗。日志记录错误码和操作 ID，避免写入完整笔记或私人路径。

若未来使用 webview，要设置内容安全策略、限制本地资源根和校验消息，不把笔记正文拼接为可执行脚本。webview 自身与扩展宿主的权限不同，页面发送“运行任务”不自动构成授权。


输入记录先定义最大文本规模与编码，并在写入前检查。保存一条空白笔记是允许还是拒绝要明确，不依靠提示框自动保证；时间信息说明来源，仅用于展示时不要把它当并发版本。查看命令排序稳定，任务ID与标题分别显示。

对异步选择流程建立操作上下文：选择时记录工作区URI，输入完成后再次确认该项目仍有效。如果用户中途关闭项目或切换工作区，停止保存并保留可复制文本，不能把旧输入落到新项目。若文件提供者不支持某项写入能力，返回受控错误。测试远程URI时记录提供者与实际能力，没有覆盖的环境在验收中保留未知状态。

## 练习：验收项目隔离

建立两个教学项目，分别保存同名任务的不同记录，切换后只能看到所属项目内容。测试没有工作区、取消输入、受限模式、保存失败和扩展重新加载，已确认记录不丢失，不创建空条目。

检查菜单隐藏后直接调用保存命令仍受信任策略限制。停用扩展时监听与注册被释放，重复启动不会重复响应。若只完成本地环境测试，记录远程工作区仍未验证；Python 策略通过不能证明URI读写或扩展生命周期已正确运行。

## 资料来源与延伸阅读

- [Extension development guide](https://code.visualstudio.com/api/get-started/your-first-extension)
- [Workspace trust for extensions](https://code.visualstudio.com/api/extension-guides/workspace-trust)

资料核验：2026-11-10。教学示例不代表线上实测。

## 相关文章

- [装好工具之后，怎样确认项目真的能运行](https://yishto.com/learn/developer-workflow/packages-editors-and-ai-cli/)
- [把一次修改做成可审阅、可恢复的提交](https://yishto.com/learn/developer-workflow/git-ssh-and-review/)
