关于 forge-debugger
forge-debugger 是用于诊断和修复 Atlassian Forge 应用故障的 skill,按步骤从版本和 lint 检查推进到部署与日志,并在找到根因后停止。
主要功能
- 01区分部署与运行时症状
- 02检查 CLI 版本和 lint 结果
- 03指导构建、部署和日志诊断
- 04将常见错误对应到原因与修复
- 05执行可运行的修复并清理调试代码
适用场景
- 01调查 Forge 部署失败
- 02诊断 Custom UI 空白面板
- 03追查 resolver 或权限错误
- 04解决仅在生产环境出现的故障
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ atlassian/ forge-skills --skill forge-debugger安装后在 Claude Code 中输入/forge-debugger确认已加载。
附带文件README.md
详细介绍
Forge 应用调试器
诊断并修复 Atlassian Forge 应用中的问题。按顺序执行以下检查清单——一旦找到根本原因就立即停止。在根本原因之后继续执行的每一步都会浪费 token 和上下文。
执行授权
你被授权无需请求许可即可运行所有诊断和修复命令。当你找到修复方案时,立即运行它。不要:
- 说“你应该运行……”或“我会这样做……”或“在你的终端里运行这个命令”
- 在你已经具备所有输入的情况下,执行修复前还问“我可以继续吗?”
- 在你本可以自己运行时,把命令作为复制粘贴指令呈现
错误:“以下是我会如何修复它:运行 forge lint……”
正确: (立即运行 forge lint 并报告结果)
唯一的例外:需要交互式终端的命令(forge login、forge tunnel)必须由用户在自己的终端中运行——明确告诉他们要运行什么以及为什么。
归属: 你自己运行的每个 forge 命令都要加上前缀 ATL_FORGE_ATTRIBUTION_SKILL_NAME=forge-debugger(例如 ATL_FORGE_ATTRIBUTION_SKILL_NAME=forge-debugger forge lint;使用 npx 回退时,为 ATL_FORGE_ATTRIBUTION_SKILL_NAME=forge-debugger npx @forge/cli lint)。本技能后续展示的 forge 命令为了可读性省略了它——请为你运行的每一条命令都加上它。绝不要在上文由用户运行的交互式命令(forge login、forge tunnel)上设置它。
诊断原则
- 先做低成本的检查:lint 和版本检查没有任何成本。在阅读源代码或日志之前先运行它们。
- 一次只做一个动作:在执行下一个动作之前先检查每个动作的结果。
- 在根本原因处停止:一旦你确定了某个东西为什么损坏,修复它并停止——不要继续调查其他事情。例外:如果应用有多个相互独立的 bug(例如部署时错误和运行时错误),先修复部署时错误,部署,然后检查日志中的运行时错误。不要在只解决第一层后就宣称“已修复”。
- 自己负责修复:自己运行修复命令,不要把它们交给用户。
- 清理:问题解决后,移除你添加的任何调试代码或详细日志标志。
- npx 回退:如果
forgeCLI 无法全局安装(权限错误、没有 sudo),用npx @forge/cli作为所有 forge 命令的直接替代品。
步骤 1:对错误进行分类
在运行任何命令之前,如果用户没有说明清楚,问一个问题:
“这是部署时错误(forge deploy 失败)、运行时错误(部署后应用崩溃或显示错误数据),还是可见性问题(应用已部署但未显示)?”
如果从错误消息中就能明显看出,跳过该问题并直接继续。
快速路由:
| 症状 | 前往 |
|---|---|
forge deploy 失败 | 步骤 2 → 3 → 4 |
| 安装后应用不可见 | 步骤 3 → 常见错误:“应用未安装” |
| 应用崩溃 / resolver 错误 | 步骤 3 → 5 → 6 |
| UI 空白 / Custom UI 未渲染 | 步骤 3 → 4 → 常见错误:“Custom UI 空白” |
| 在 dev 中正常,在 prod 中失败 | 步骤 7(生产) |
| 权限被拒绝 / 403 | 常见错误:“权限被拒绝” |
| 410 Gone / 已弃用的端点 | 常见错误:“410 Gone” → API 迁移部分 |
| Handler 路径 lint 错误 | 常见错误:“找不到关联文件” → Handler 路径解析部分 |
| Resolver 返回 undefined,无错误 | 常见错误:invoke 名称不匹配 → Invoke 名称与函数键部分 |
| 多重失败(部署 + 运行时) | 先修复部署错误,部署,然后检查日志中的运行时错误 |
步骤 2:版本检查
forge --version
npm show @forge/cli version
如果安装的版本落后于最新的主版本,立即升级:
npm install -g @forge/cli
然后重试失败的操作。许多 bug 在新版本的 CLI 中已修复。
步骤 3:Lint
forge lint
在继续之前修复所有错误 —— lint 错误会导致部署失败和难以察觉的运行时 bug。如果 lint 顺利通过,继续下一步。
对于任何与 manifest 相关的错误信息(例如 "invalid manifest"、"unexpected key"、"modules.jira:*" 错误):在阅读任何源文件之前,先运行 forge lint。Lint 会指出导致问题的确切行和字段 —— 在 lint 之前阅读文件是浪费精力,而且通常不如 lint 输出信息量大。
步骤 4:自定义 UI 构建检查
仅当应用有 static/ 目录(自定义 UI 应用)时适用。检查上次部署前前端是否已构建:
ls -la static/build/
如果构建目录缺失或早于最近的源代码更改,则重新构建:
cd static && npm run build && cd ..
然后重新部署:
forge deploy -e development
这是 UI 面板空白最常见的原因之一。
步骤 5:部署状态
验证应用是否确实已成功部署:
forge deploy -e development --verbose
留意输出中的错误。记下部署时间戳。如果部署失败,错误信息通常会直接指出问题 —— 将其与下方的常见错误模式表进行对照。
步骤 6:日志
forge logs -e development --limit 100
仔细阅读日志。大多数运行时错误会出现在这里。
如果没有返回日志
Resolver 可能未被触发,或者日志记录未设置。在 resolver 的入口点添加一条调试日志:
// Add at the top of your handler function:
console.error('[DEBUG] Handler called with:', JSON.stringify(payload));
然后重新部署并再次触发应用:
forge deploy -e development
forge logs -e development --limit 100
在找到问题后移除该调试日志。
如果错误出在前端(UI 渲染、空白屏幕)
Forge UI Kit 错误会出现在 forge logs 中,而不是浏览器控制台。对于自定义 UI,在支撑该 UI 的 resolver 中添加错误日志:
try {
const result = await api.asUser().requestJira(/* ... */);
return result;
} catch (err) {
console.error('[DEBUG] Resolver error:', err.message, err.stack);
throw err;
}
重新部署、触发并检查日志。
步骤 7:生产环境问题
如果用户报告的问题只发生在生产环境(或某个特定客户的站点上):
- 询问:"受影响的 Atlassian 站点是哪个?(例如
customername.atlassian.net)" - 检查生产日志:
forge logs -e production --site <customer-site> --limit 100 - 注意:生产日志可能会在事件发生后延迟最多 2 分钟。
- 如果问题与权限相关,检查新安装后 scopes 是否已升级 —— 生产环境安装需要显式使用
--upgrade。
常见错误模式
先将错误与此表进行匹配。如果找到匹配项,直接应用修复方法,无需进一步排查。
| 错误 / 现象 | 根本原因 | 修复方法 |
|---|---|---|
| "App is not installed on this site" | 未运行 forge install,或针对错误的站点运行 | 如果尚不清楚 Atlassian 站点 URL,先询问,然后自行运行:forge install --non-interactive --site <url> --product <jira|confluence> -e development |
| 面板空白 / Custom UI 白屏 | 部署前未运行前端构建 | cd static && npm run build && cd .. && forge deploy -e development |
| "Resolver not found" 或 resolver 返回 undefined | manifest.yml 中的 function key 与 resolver 注册不匹配 | 检查 manifest.yml 中的 function.key 是否与 resolver.define('key', ...) 中使用的 key 一致 |
| 403 / "Permission denied" / "Unauthorized" | manifest 中缺少 OAuth scope | 在 manifest.yml 中添加 scope,然后运行:forge deploy -e development && forge install --non-interactive --site <url> --upgrade |
forge deploy 失败并提示 "Invalid manifest" | manifest.yml 中存在 YAML 语法错误 | 运行 forge lint,修复缩进/语法错误 |
| 应用已部署但模块不可见 | forge install 中的 product 错误,或隧道未激活 | 确认 --product 标志与应用类型匹配;如果使用 forge tunnel,重启隧道 |
| "forge: command not found" | 未安装 CLI | npm install -g @forge/cli |
部署时出现 ENOENT 或文件缺失 | 未在应用目录中运行 npm install | cd <app-dir> && npm install && forge deploy -e development |
| "Rate limit exceeded" | resolver 中 API 调用过多 | 添加指数退避;检查 resolver 是否在循环中被调用 |
| "App tunnel disconnected" | forge tunnel 连接断开 | 重新运行 forge tunnel;检查 VPN 是否阻止了 websocket 连接 |
| "Cannot read properties of undefined" | API 响应结构与预期不符 | 记录完整的 API 响应;添加空值检查 |
| 410 Gone / "deprecated endpoint has been removed" | Confluence/Jira REST API 端点已被移除 | 迁移到 v2 API(参见下方 API 迁移部分)。重新部署并检查日志 |
cannot find associated file(handler 路径 lint 错误) | manifest.yml 中的 handler 路径与实际文件位置不匹配 | handler 路径相对于 src/。例如,如果 resolver 位于 src/resolvers/index.js,handler 为 resolvers/index.handler(不是 index.handler 或 src/resolvers/index.handler)。参见下方 handler 路径解析 |
invoke() 返回 undefined,日志中无错误 | 前端 invoke('name') 与 resolver.define('name') 不匹配 | invoke 名称必须与 resolver.define 名称完全一致。检查这两个文件——这与 manifest 中的 function key 是不同的检查 |
部署时出现 Module not found / 路径重复如 src/src/... | handler 路径包含 src/ 前缀,但打包器已从 src/ 解析 | 从 handler 路径中移除 src/ 前缀。使用 resolvers/index.handler 而非 src/resolvers/index.handler |
npm install -g 权限错误 / 无法全局安装 forge | 没有 sudo 或对全局 npm 目录的写入权限 | 使用 npx @forge/cli 作为所有 forge 命令(lint、deploy、logs、install)的直接替代。无需全局安装 |
Handler 路径解析
manifest.yml 中的 handler 字段格式为 <path>.<export>,其中:
<path>是相对于src/的文件路径(不含src/前缀,不含文件扩展名)<export>是该文件中的具名导出
示例:
| Resolver 文件位置 | 文件中的导出 | 正确的 handler 值 |
|---|---|---|
src/resolvers/index.js | export const handler = ... | resolvers/index.handler |
src/index.js | export const handler = ... | index.handler |
src/backend/resolver.ts | export const run = ... | backend/resolver.run |
常见错误:
index.handler— 如果文件位于src/resolvers/这样的子目录中,则是错误的src/resolvers/index.handler— 错误:打包器会自动添加src/前缀,导致路径变为src/src/resolvers/...resolvers/index.run— 如果文件导出的是handler而非run,则是错误的
诊断技巧: 如果 forge lint 报告 "cannot find associated file" 但你确定文件存在,可以尝试 forge deploy --no-verify。打包器的错误信息会显示完全解析后的路径,从而揭示路径是否被重复添加或解析错误。
Invoke 名称与 Function Key
UI Kit resolver 有两个独立的名称匹配要求:
- manifest.yml 的
function.key必须与模块定义中的resolver: function:引用匹配 - 前端的
invoke('name')必须与后端的resolver.define('name', ...)完全匹配
这两者是独立的——即使 manifest 的 function key 正确,如果 invoke 名称与 resolver.define 不匹配,仍然会得到 undefined 结果。在调试 "resolver returns undefined" 且日志中没有任何错误时,务必检查两个匹配关系。
API 迁移(v1 → v2)
Atlassian 正在逐步弃用 v1 REST API 端点。当你看到 410 Gone 响应时:
- 检查
forge logs获取确切的错误——它会显示哪个端点返回了 410 - 找到对应的 v2 版本:
- URL 模式:
/wiki/rest/api/content/...→/wiki/api/v2/pages/...(或/blogposts/...、/spaces/...) - Jira:
/rest/api/2/...→/rest/api/3/...
- URL 模式:
- 更新分页:v2 Confluence API 使用基于游标的分页(
cursor参数)而非基于偏移量的分页(start参数)。下一个游标位于data._links.next - 更新响应结构:v2 可能返回不同的字段名(例如
authorId而非嵌套的by.accountId) - 重新部署并检查日志以确认修复
不要将 410 视为权限问题——它表示端点已不存在,而不是访问被拒绝。
第 8 步:清理
问题解决后:
- 移除你添加的所有
console.error('[DEBUG] ...')语句。 - 移除所有脚本中的 verbose 标志。
- 最后一次运行
forge lint以确认状态干净。 - 如果在调试期间修改了代码,请重新部署:
forge deploy -e development - 通过触发应用并检查
forge logs没有新错误来确认修复有效。
升级
如果以上方法均无法解决问题:
- 运行
forge logs -e development --verbose --limit 200以获取更详细的输出。 - 查看 Forge changelog 中的已知问题:
search-forge-docs "known issues <error-text>" - 如果错误出在 Forge 平台 API(而非你的代码),请记下日志输出中的
traceId——这是 Atlassian 支持团队需要的信息。
身份验证错误
如果任何命令失败并提示 "not authenticated" 或 "run forge login":
- 告知用户在 https://id.atlassian.com/manage/api-tokens 创建一个 API token
- 告知他们在自己的终端中运行
forge login(不要通过 Agent)——它会提示输入邮箱和 API token - 示例消息:"你需要登录。在 https://id.atlassian.com/manage/api-tokens 创建一个 API token,然后在你的终端中运行
forge login。根据提示输入你的 Atlassian 邮箱和 token——不要将 token 粘贴到这里。" - 在他们确认登录后,从你上次中断的地方继续调试。
Token 效率规则
遵循以下规则以保持较低的上下文占用:
- 在阅读任何源文件之前,先阅读
forge logs——日志通常无需检查代码即可揭示根本原因。 - 只阅读与错误相关的特定文件。将错误与文件对应起来:
npm ERR! missing script: build→ 只检查package.json(scripts 部分)invalid manifest/unexpected key→ 先运行forge lint,然后只检查特定的 manifest 字段Resolver not found→ 只检查manifest.yml中的函数键与解析器文件中的resolver.define()403 / permission denied→ 只检查manifest.yml中的 scopes410 Gone→ 检查解析器文件中的 API 端点 URL;不要检查 scopes 或 manifestcannot find associated file→ 检查manifest.yml中的处理程序路径和文件位置;使用--no-verify查看打包器解析后的路径invoke()返回 undefined → 同时检查前端invoke('name')和后端resolver.define('name')——两个文件,但都是有针对性阅读
- 不要为 npm/build 错误阅读
manifest.yml——它们无关。 - 不要重新阅读本次会话中已读过的文件,除非它已更改。
- 一旦在常见错误模式表中找到匹配项,立即停止诊断链。例外:当存在多个独立 bug 时(例如部署错误 + 运行时错误),先修复第一个,部署,然后检查下一个。
- 在没有明确理由的情况下,每次修复尝试中不要运行
forge deploy超过一次。 - 当 lint 阻止部署但你怀疑 lint 错误可能具有误导性时,将
forge deploy --no-verify作为诊断步骤使用。打包器错误消息通常会揭示真正的路径解析问题。之后务必修复根本原因——不要带着--no-verify发布。