cloud-drive-renamer/docs/superpowers/plans/2026-03-20-diagnostic-export-completion-plan.md

10 KiB

Diagnostic Export Completion Implementation Plan

For agentic workers: REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (- [ ]) syntax for tracking.

Goal: 补完失败诊断导出与反馈引导剩余链路,使用户在失败结果页中可以直接导出 JSON 诊断文件并看到后续反馈动作。

Architecture: 以 FileSelectorPanel 为诊断状态源,ConfigPanel 仅负责渲染提示条并抛事件;background 通过 diagnostic-service 管理最近日志与导出 payload;content 侧通过 Blob 下载文件,不新增权限。

Tech Stack: TypeScript、Lit、Chrome Extension MV3、chrome.runtime messaging、chrome.storage.local、Vitest、jsdom


Inputs

  • Spec: docs/superpowers/specs/2026-03-20-diagnostic-export-completion-design.md
  • Existing design: docs/superpowers/specs/2026-03-19-diagnostic-export-feedback-design.md
  • Existing ring buffer: src/background/diagnostic-log-store.ts

File Structure

Create

  • src/types/runtime-message.ts
  • src/background/diagnostic-service.ts
  • src/core/diagnostic-session.ts
  • src/utils/diagnostic-download.ts
  • tests/unit/logger.test.ts
  • tests/unit/diagnostic-service.test.ts
  • tests/unit/diagnostic-session.test.ts
  • tests/unit/config-panel-diagnostic-feedback.test.ts
  • tests/unit/file-selector-panel-diagnostic-feedback.test.ts

Modify

  • src/utils/logger.ts
  • src/background/service-worker.ts
  • src/content/index.ts
  • src/content/components/config-panel.ts
  • src/content/components/file-selector-panel.ts
  • src/types/diagnostic.ts
  • src/locales/zh_CN.json
  • src/locales/zh_TW.json
  • src/locales/en.json
  • docs/testing/manual-test-cases.md

Keep Unchanged

  • manifest.json

Task 1: Runtime message 与 background diagnostic service

Files:

  • Create: src/types/runtime-message.ts

  • Create: src/background/diagnostic-service.ts

  • Modify: src/background/service-worker.ts

  • Test: tests/unit/diagnostic-service.test.ts

  • Step 1: 写 diagnostic-service 的失败测试

it('builds export payload from stored last failure and recent logs', async () => {
  const payload = await service.getExportPayload();
  expect(payload.lastFailure?.failure.reason).toBe('batch-execution-failed');
  expect(payload.logs).toHaveLength(2);
});

it('returns null lastFailure when no snapshot is stored', async () => {
  const payload = await service.getExportPayload();
  expect(payload.lastFailure).toBeNull();
});
  • Step 2: 运行测试确认先失败

Run:

npx vitest run tests/unit/diagnostic-service.test.ts

Expected:

  • FAIL,提示 diagnostic-service 或相关 message type 不存在。

  • Step 3: 实现最小 runtime message 类型

Implementation notes:

  • 在 src/types/runtime-message.ts 定义:

    • APPEND_DIAGNOSTIC_LOG
    • GET_DIAGNOSTIC_EXPORT
    • OPEN_EXTERNAL_URL
  • Step 4: 实现 diagnostic-service.ts

Implementation notes:

  • 封装 appendLog(entry)

  • 封装 getExportPayload()

  • 封装 openExternalUrl(url)

  • 读取 DIAGNOSTIC_STORAGE_KEYS.LAST_FAILURE 和 ring buffer

  • Step 5: 接到 service-worker.ts

Implementation notes:

  • service-worker.ts 只做 message routing

  • 不把 payload 组装逻辑散落在 switch 中

  • Step 6: 复跑测试确认通过

Run:

npx vitest run tests/unit/diagnostic-service.test.ts tests/unit/diagnostic-log-store.test.ts

Expected:

  • PASS

Task 2: Logger diagnostic transport

Files:

  • Modify: src/utils/logger.ts

  • Modify: src/content/index.ts

  • Test: tests/unit/logger.test.ts

  • Step 1: 写 logger transport 的失败测试

it('extracts module prefix and forwards structured diagnostic entry', () => {
  const transport = vi.fn();
  configureLoggerDiagnostics({ source: 'content', transport });
  logger.error('[FileSelectorPanel] Retry failed:', new Error('boom'));
  expect(transport).toHaveBeenCalledWith(expect.objectContaining({
    module: 'FileSelectorPanel',
    level: 'ERROR',
    message: 'Retry failed:',
  }));
});
  • Step 2: 运行测试确认先失败

Run:

npx vitest run tests/unit/logger.test.ts

Expected:

  • FAIL,提示 configureLoggerDiagnostics 不存在或 transport 未被调用。

  • Step 3: 在 logger.ts 实现 transport 配置

Implementation notes:

  • 保持既有 logger.info/warn/error 调用方式兼容

  • 用模块前缀正则提取 [Module]

  • transport 异常要吞掉,不影响 console 输出

  • Step 4: 在 content/index.ts 里接入 transport

Implementation notes:

  • 启动时配置一次

  • transport 使用 chrome.runtime.sendMessage

  • 失败时静默降级

  • Step 5: 复跑测试确认通过

Run:

npx vitest run tests/unit/logger.test.ts

Expected:

  • PASS

Task 3: 最近失败快照领域模型

Files:

  • Modify: src/types/diagnostic.ts

  • Create: src/core/diagnostic-session.ts

  • Test: tests/unit/diagnostic-session.test.ts

  • Step 1: 写失败快照构建的失败测试

it('builds failure snapshot from batch results', () => {
  const snapshot = buildLastFailureDiagnosticSnapshot(...);
  expect(snapshot.summary.failed).toBe(2);
  expect(snapshot.failures[0]?.targetName).toBe('new-a.txt');
});

it('builds feedback summary text with platform and file name', () => {
  const text = buildDiagnosticFeedbackText(...);
  expect(text).toContain('夸克网盘');
  expect(text).toContain('cloud-drive-renamer-diagnostic');
});
  • Step 2: 运行测试确认先失败

Run:

npx vitest run tests/unit/diagnostic-session.test.ts

Expected:

  • FAIL,提示诊断 session 纯函数不存在。

  • Step 3: 在 diagnostic.ts 扩展必要类型

Implementation notes:

  • 增加 summary / failure item / prompt state 联合类型

  • 保持现有 ring buffer 类型兼容

  • Step 4: 实现 diagnostic-session.ts

Implementation notes:

  • 提供构造快照、重试统计合并、反馈摘要构造等纯函数

  • Step 5: 复跑测试确认通过

Run:

npx vitest run tests/unit/diagnostic-session.test.ts

Expected:

  • PASS

Task 4: ConfigPanel 结果区诊断提示条

Files:

  • Modify: src/content/components/config-panel.ts

  • Modify: src/locales/zh_CN.json

  • Modify: src/locales/zh_TW.json

  • Modify: src/locales/en.json

  • Test: tests/unit/config-panel-diagnostic-feedback.test.ts

  • Step 1: 写 ConfigPanel 提示条失败测试

it('renders diagnostic ready prompt when finished with failures', async () => {
  const panel = new ConfigPanel();
  panel.finished = true;
  panel.progress = { completed: 2, total: 2, currentFile: '', success: 0, failed: 2 };
  panel.diagnosticPromptState = 'ready';
  panel.diagnosticFailureCount = 2;
  document.body.appendChild(panel);
  await panel.updateComplete;
  expect(panel.shadowRoot?.querySelector('[data-role=\"diagnostic-export-button\"]')).toBeTruthy();
});
  • Step 2: 运行测试确认先失败

Run:

npx vitest run tests/unit/config-panel-diagnostic-feedback.test.ts

Expected:

  • FAIL,提示诊断属性或按钮不存在。

  • Step 3: 在 ConfigPanel 增加诊断只读属性与事件

Implementation notes:

  • 新增 diagnosticPromptState

  • 新增 diagnosticFailureCount

  • 新增 diagnosticFileName

  • 新增 diagnosticErrorMessage

  • 新增导出/反馈相关事件

  • Step 4: 在 renderExecutionView() 插入提示条

Implementation notes:

  • 提示条位置放在 sync status 后、动作区前

  • 不破坏现有 footer 布局

  • Step 5: 补齐 i18n

  • Step 6: 复跑测试确认通过

Run:

npx vitest run tests/unit/config-panel-diagnostic-feedback.test.ts tests/unit/config-panel-undo.test.ts

Expected:

  • PASS

Task 5: FileSelectorPanel 导出与反馈动作闭环

Files:

  • Modify: src/content/components/file-selector-panel.ts

  • Create: src/utils/diagnostic-download.ts

  • Test: tests/unit/file-selector-panel-diagnostic-feedback.test.ts

  • Modify: docs/testing/manual-test-cases.md

  • Step 1: 写 FileSelectorPanel 导出动作失败测试

it('stores a diagnostic snapshot and exposes ready state after failed execution', async () => {
  // arrange failed results
  expect(panel.diagnosticPromptState).toBe('ready');
});

it('downloads diagnostic payload and transitions to exported state', async () => {
  await panel.handleDiagnosticExport();
  expect(downloadDiagnosticPayload).toHaveBeenCalled();
  expect(panel.diagnosticPromptState).toBe('exported');
});
  • Step 2: 运行测试确认先失败

Run:

npx vitest run tests/unit/file-selector-panel-diagnostic-feedback.test.ts

Expected:

  • FAIL,提示导出状态/方法不存在。

  • Step 3: 实现 diagnostic-download.ts

Implementation notes:

  • downloadDiagnosticPayload(payload): Promise<string>

  • buildGithubIssueUrl(...)

  • buildMailtoUrl(...)

  • buildDiagnosticFeedbackText(...)

  • Step 4: 在 FileSelectorPanel 实现诊断状态机

Implementation notes:

  • 在 execute / retry 结果落地后保存最近失败快照

  • 失败数为 0 时隐藏提示条

  • 导出时请求 GET_DIAGNOSTIC_EXPORT

  • 成功后进入 exported

  • 失败后进入 error

  • Step 5: 把状态透传到 ConfigPanel 并接线事件

  • Step 6: 补充手动测试文档

  • Step 7: 复跑针对性测试

Run:

npx vitest run \
  tests/unit/file-selector-panel-diagnostic-feedback.test.ts \
  tests/unit/config-panel-diagnostic-feedback.test.ts \
  tests/unit/diagnostic-session.test.ts \
  tests/unit/diagnostic-service.test.ts \
  tests/unit/logger.test.ts

Expected:

  • PASS

Task 6: 全量验证

Files:

  • Verify only

  • Step 1: 运行完整验证

Run:

npm run validate

Expected:

  • PASS,允许既有 lint warnings 存在,但不得新增 error

  • Step 2: 运行构建验证

Run:

npm run build

Expected:

  • PASS

  • Step 3: 整理手动测试路径

Manual:

  • 在开发环境制造至少 1 个失败结果
  • 验证结果区出现导出入口
  • 点击下载 JSON
  • 检查导出后引导状态
  • 验证“暂不处理”会隐藏提示条