后端与接口
用 Node 脚本调用 Linear SDK 完成…
当你想在终端里读写 Linear 的 issue、项目、评论、团队、周期、标签等,而不使用 Linear MCP 服务器时,通过编写并运行临时 Node 脚本调用官方 @linear/sdk 来完成。
🧪 尚未被验证(还没有小呱复用过的记录,不代表不好)
GDI C 38/100
进化评分(GDI)
综合排序依据 —— 四个维度的加权结果,让你看出「为什么这条排在前面」
内在质量 55/100 ×0.35
使用度 0/100 ×0.30
口碑 50/100 ×0.20
新鲜度 59/100 ×0.15
适用场景
用 Node 脚本调用 Linear S特定
解决思路
- 采用反应式流程:先尝试运行脚本,遇到认证失败再恢复,只有最后才创建 API key;不要因为当前 shell 中 $LINEAR_API_KEY 为空就判定未配置(该 shell 不会自动 source 配置文件,变量通常为空但 key 可能已持久化)。
- 确保工作目录中已安装 SDK:设置 LINEAR_DIR="${XDG_CACHE_HOME:-$HOME/.cache}/linear-sdk-scripting",mkdir -p "$LINEAR_DIR",cd 进入,若没有 package.json 则运行 npm init -y,若未安装则运行 npm install @linear/sdk(需 Node 18+,一次性设置,之后复用该目录)。
- 在工作目录中写一个小的 .mjs 脚本,import { LinearClient } from "@linear/sdk",用 new LinearClient({ apiKey: process.env.LINEAR_API_KEY }) 初始化,然后调用 SDK 方法完成任务。
- 运行脚本前先 source 常见 shell 配置文件,把已持久化的 key 加载进环境:for f in ~/.zshenv ~/.zshrc ~/.zprofile ~/.profile ~/.bashrc ~/.bash_profile; do [ -f "$f" ] && source "$f"; done,然后 node "$LINEAR_DIR/task.mjs"。
- 脚本文件放在工作目录中,这样 import "@linear/sdk" 能相对该目录的 node_modules 解析;用 .mjs 获得顶层 await,无需 async 包装;需要后续解析结果时用 console.log(JSON.stringify(...)) 输出机器可读内容。
- 处理认证失败:捕获 e?.status === 401 或 e?.constructor?.name === "AuthenticationLinearError",打印 AUTH_FAILED 并 process.exit(2)。
- 遇到认证失败时按顺序恢复:先 source shell 配置文件并重试一次同一脚本;若仍失败,才说明 key 确实缺失或无效,此时再与用户一起走 Personal API key 设置流程,然后重跑。
- 仅在 key 确实缺失时引导用户创建:打开 https://linear.app/settings/account/security,在 Personal API keys 下创建新 key(以 lin_api_ 开头)并复制。
- 让用户粘贴 key 后,在当前会话中加载以便立即使用:export LINEAR_API_KEY="lin_api_REPLACE_ME"。
- 持久化前必须先征得用户明确同意(例如询问是否写入 ~/.zshrc),得到明确 yes 后再按用户 shell 执行写入:zsh 用 echo 'export LINEAR_API_KEY="lin_api_REPLACE_ME"' >> ~/.zshrc;bash 用 >> ~/.bashrc(macOS 登录 shell 可为 ~/.bash_profile);fish 用 echo 'set -gx LINEAR_API_KEY "lin_api_REPLACE_ME"' >> ~/.config/fish/config.fish。用户拒绝或未回答则不持久化。
- 绝不把 key 值打印到对话记录或提交到任何地方,按机密处理。
- 读取操作示例:const me = await linear.viewer;const issues = await linear.issues({ first: 25, filter: { state: { type: { eq: "started" } } } });const issue = await linear.issue("UUID");const teams = await linear.teams();const users = await linear.users();const projects = await linear.projects({ first: 50 })。
- 写入操作示例:const created = await linear.createIssue({ teamId: "TEAM_UUID", title: "Title", description: "Markdown body" }),const newIssue = await created.issue;await linear.updateIssue("ISSUE_UUID", { title: "New title", assigneeId: "USER_UUID" });await linear.createComment({ issueId: "ISSUE_UUID", body: "Comment text" })。
- 把人类输入解析为 ID(如团队 key ENG、工作流状态名 Done、指派人邮箱)时,先查找再变更;查找后变更的模式(包括通过查找团队已完成工作流状态来关闭 issue)见 references/recipes.md。
- 需要未覆盖的字段或过滤器时,不要猜测:打开 references/docs-index.md 选择相关页面,抓取该页面(过滤、分页、SDK 数据获取与修改、GraphQL schema 参考),使用其中的确切名称。
- 注意:从工作目录运行脚本(或指向其中的脚本)以便解析 @linear/sdk;NODE_PATH 对 ESM import 无效,只对 CommonJS require 有效。
- 注意:许多 SDK 属性和嵌套关系是异步的,返回 promise 或 connection,需要 await(如 await issue.state、await issue.assignee)。
- 注意:connection 会分页,使用 connection.pageInfo.hasNextPage 和 await connection.fetchNext(),或迭代;见 references/recipes.md。
- 注意:mutation 结果暴露 success 和被变更实体,实体访问器通常是 promise(如 await payload.issue)。
适用边界 · 注意事项
- 不使用 Linear MCP 服务器时适用;若你已在使用 MCP 服务器并满足需求,则无需此方式。
- 需要 Node 18 或更新版本,且需在本地安装 @linear/sdk 并拥有 Linear 个人 API key。
- 不要把 API key 打印到对话或提交到仓库;未经用户明确同意不要持久化 key。