fix(desktop): include diagnostic worker in packaged archive
This commit is contained in:
1 parent
957d2c1285
commit
4825f92a02
5 files changed
+41
-4
No files matched your search
@@ -36,8 +36,8 @@
|
||||
en: 22153a298a6662e1
|
||||
zh: 3600803c8c9d0274
|
||||
/deepseek-harness-desktop/installation-ownership/runtime-and-plugin-activation:
|
||||
en: dba5456514fc687f
|
||||
zh: 2c91553dad51d9ca
|
||||
en: 29c369460bbbb637
|
||||
zh: 177d895e6bfcef37
|
||||
/deepseek-harness-desktop/installation-ownership/host-environment:
|
||||
en: 98cf848762482d48
|
||||
zh: 74f9100a39ec8c2f
|
||||
|
||||
@@ -178,7 +178,7 @@ Native dialog details include at most 1,200 UTF-16 code units and eight diagnost
|
||||
|
||||
Before the first fatal dialog opens, Electron writes a crash report to the platform logs directory (`app.getPath('logs')`: `~/Library/Logs/DeepSeek Harness` on macOS, `logs` under the application’s `userData` directory on Windows and Linux), waiting at most one second for the write; a slow or failed write shows the dialog with an explicit pending or unavailable status. Get diagnostic report checks the same write and reveals a saved file in the system file manager without restarting or stopping the Host; a write that completes after the initial deadline remains available. The user attaches that file to a support ticket. If writing fails, the dialog hides Get diagnostic report and suggests providing a screenshot. The file `crash-<UTC time>-<source>.log` records the source (`host` for a Host exit, `web-boot` for a renderer boot failure, `renderer` for a renderer or document failure, `main` for a shell error), whether the backend had reached ready, application and runtime versions, the error with its enumerable properties and cause chain (cut at 256 KiB), the Host’s own error and explicitly selected startup metadata (at most 64 Ki characters, including a truncation notice; startup errors reserve space for metadata by limiting the original error to 8 Ki characters) when the Host reported a startup failure over IPC before exiting, and the primary window’s recent error-level console output (at most 64 KiB). A Host exit report therefore contains the retained stderr tail, which may include plugin output. A fatal failure during shutdown writes a report without opening a dialog. Files are owner-only where the platform supports it; startup keeps the ten newest reports and removes older ones without touching other files in the directory.
|
||||
|
||||
After saving the basic report, the shell attempts to append recent plugin-management records in an isolated Worker. The completion marker and omission counters distinguish a finished collection from missing or partial material. The Host announces its run ID before profile loading; reported Host errors carry that ID as `hostRunId`, matching operation records from the same lifetime. Failure before this announcement leaves the run identity unknown. Recent operations are context, not proof of cause. Collection reads only two owned files under `logs/plugin-operations`, at most 64 KiB and 100 records; the complete appended section is limited to 64 KiB. A 500 ms deadline requests Worker termination; completion waits for its exit. The basic report remains available independently.
|
||||
After saving the basic report, the shell attempts to append recent plugin-management records in an isolated Worker packaged as `lib/operation-report-worker.js` inside `app.asar`. The completion marker and omission counters distinguish a finished collection from missing or partial material. The Host announces its run ID before profile loading; reported Host errors carry that ID as `hostRunId`, matching operation records from the same lifetime. Failure before this announcement leaves the run identity unknown. Recent operations are context, not proof of cause. Collection reads only two owned files under `logs/plugin-operations`, at most 64 KiB and 100 records; the complete appended section is limited to 64 KiB. A 500 ms deadline requests Worker termination; completion waits for its exit. The basic report remains available independently.
|
||||
|
||||
The journal retains two 256 KiB segments, accepts records up to 4 KiB, and bounds queued writes to 64 KiB. Exit, recovery restart and installer preparation wait at most 500 ms for queued writes; a timeout disables further writes, while an already-issued OS request may still settle. Records cover manager operations observed after Host startup, not direct CLI commands or manual file changes. Package-manager output remains in its existing detailed logs and is not copied into this summary. Missing records, a start without an end, and damaged history do not establish a successful operation. This collection does not diagnose kernel hangs, OOM or native crashes.
|
||||
|
||||
|
||||
@@ -178,7 +178,7 @@ macOS 上自定义菜单保留 Electron 的标准 Window 菜单及应用隐藏
|
||||
|
||||
首个致命弹窗打开前,Electron 会向平台日志目录(`app.getPath('logs')`:macOS 为 `~/Library/Logs/DeepSeek Harness`,Windows 与 Linux 为应用 `userData` 目录下的 `logs`)写入一份崩溃报告,最多等待写入一秒;写入缓慢或失败时明确显示仍在保存或无法保存。“获取诊断报告”检查同一次写入,并在系统文件管理器中定位已保存的文件,不停止 Host 或重启;超过首次等待期限后写入完成的文件仍可获取。用户可将文件作为工单附件;写入失败时隐藏获取报告按钮,并提示提供窗口截图。文件 `crash-<UTC 时间>-<source>.log` 记录来源(`host` 为 Host 退出、`web-boot` 为渲染进程启动失败、`renderer` 为渲染进程或文档失败、`main` 为壳自身错误)、后端是否已就绪、应用与运行时版本、包含可枚举属性与 cause 链的错误(截至 256 KiB)、Host 在退出前通过 IPC 报告启动失败时的错误及显式选择的启动元数据(最多 64 Ki 个字符,包含截断提示;启动错误的原始错误文本限制为 8 Ki 个字符,为元数据保留空间),以及主窗口最近的 error 级 console 输出(最多 64 KiB)。因此 Host 退出报告包含保留的 stderr 尾部,其中可能含有插件输出。关闭过程中的致命失败只写报告、不弹窗。平台支持时文件仅所有者可读;启动时保留最新十份报告并删除更早的,不触碰目录中的其他文件。
|
||||
|
||||
基本报告保存后,壳会尝试通过独立 Worker 追加近期插件管理记录。完成标记和遗漏计数用于区分已完成收集与缺失或不完整的材料。Host 在加载 profile 前报告运行 ID;Host 错误中的 `hostRunId` 与该次运行的操作记录使用同一标识。在此通知之前发生的失败,其运行标识仍为未知。近期操作只是上下文,不是因果证据。收集只读取 `logs/plugin-operations` 下归其管理的两个文件,最多读取 64 KiB 和 100 条记录;完整追加内容不超过 64 KiB。500 ms 期限到达后请求终止 Worker,并在其退出后才确认收集结束。基本报告独立可用。
|
||||
基本报告保存后,壳会尝试通过独立 Worker 追加近期插件管理记录;该 Worker 以 `lib/operation-report-worker.js` 打包在 `app.asar` 中。完成标记和遗漏计数用于区分已完成收集与缺失或不完整的材料。Host 在加载 profile 前报告运行 ID;Host 错误中的 `hostRunId` 与该次运行的操作记录使用同一标识。在此通知之前发生的失败,其运行标识仍为未知。近期操作只是上下文,不是因果证据。收集只读取 `logs/plugin-operations` 下归其管理的两个文件,最多读取 64 KiB 和 100 条记录;完整追加内容不超过 64 KiB。500 ms 期限到达后请求终止 Worker,并在其退出后才确认收集结束。基本报告独立可用。
|
||||
|
||||
操作历史保留两个 256 KiB 文件段,单条记录不超过 4 KiB,排队写入不超过 64 KiB。退出、恢复重启和安装准备最多等待排队写入 500 ms;超时会停用后续写入,但已经发出的操作系统请求仍可能随后结束。记录覆盖 Host 启动后观察到的管理器操作,不包含直接执行的 CLI 命令或手工文件修改。包管理器输出保留在原有详细日志中,不复制到摘要。缺失记录、只有开始没有结束的操作以及损坏的历史,都不能说明操作已成功。此收集不诊断内核卡死、OOM 或原生崩溃。
|
||||
|
||||
|
||||
@@ -135,6 +135,7 @@ export function createElectronBuilderConfig(
|
||||
},
|
||||
files: [
|
||||
'lib/main.js',
|
||||
'lib/operation-report-worker.js',
|
||||
'lib/welcome/**/*',
|
||||
'lib/preload-app.cjs',
|
||||
'lib/preload-mandatory.cjs',
|
||||
|
||||
@@ -125,6 +125,42 @@ async function packageFixture(input: Awaited<ReturnType<typeof fixture>>) {
|
||||
}).pack([{ src: mapping.from, destination: join(destination, 'dsh'), files, metadata }])
|
||||
}
|
||||
|
||||
it('includes the diagnostic worker in the archive selected by the shipping file rules', async () => {
|
||||
const root = await mkdtemp(join(tmpdir(), 'diagnostic-worker-asar-'))
|
||||
roots.push(root)
|
||||
const appDir = join(root, 'app')
|
||||
const resources = join(root, 'resources')
|
||||
const destination = join(resources, 'app')
|
||||
await mkdir(join(appDir, 'lib'), { recursive: true })
|
||||
await mkdir(resources)
|
||||
const worker = join(appDir, 'lib', 'operation-report-worker.js')
|
||||
const excluded = join(appDir, 'lib', 'not-shipped.js')
|
||||
await writeFile(worker, 'export {}')
|
||||
await writeFile(excluded, 'export {}')
|
||||
const config = unsignedWindowsConfig('com.example.diagnostics', join(root, 'dsh'))
|
||||
const filesConfig = config.files.map(entry => typeof entry === 'string' ? entry : { ...entry, filter: [...entry.filter] })
|
||||
const matchers = getFileMatchers({ files: filesConfig }, 'files', destination, {
|
||||
defaultSrc: appDir, globalOutDir: root, customBuildOptions: {}, macroExpander: value => value,
|
||||
})!
|
||||
const matcher = matchers.find(entry => entry.from === appDir)!
|
||||
const filter = matcher.createFilter()
|
||||
const files: string[] = []
|
||||
const metadata = new Map<string, Stats>()
|
||||
for (const file of [worker, excluded]) {
|
||||
const stat = await lstat(file)
|
||||
if (filter(file, stat)) {
|
||||
files.push(file)
|
||||
metadata.set(file, stat)
|
||||
}
|
||||
}
|
||||
await new AsarPackager({ info: { getWorkspaceRoot: async () => root } }, {
|
||||
defaultDestination: destination, resourcePath: resources, options: {}, unpackPattern: () => false,
|
||||
}).pack([{ src: appDir, destination, files, metadata }])
|
||||
const archive = await readAsar(join(resources, 'app.asar'))
|
||||
expect(archive.getFile('lib/operation-report-worker.js').size).toBe(Buffer.byteLength('export {}'))
|
||||
expect(() => archive.getFile('lib/not-shipped.js')).toThrow()
|
||||
})
|
||||
|
||||
it.each([false, true])('unpacks PE files through builder source patterns (external=%s)', async (external) => {
|
||||
const input = await fixture(external)
|
||||
const files = await prepareWindowsAsarUnpack(input.context, input.source)
|
||||
|
||||
Reference in new issue
Block a user