From acd5101e4dcd5749f59ce1f70dcef61e5ff48643 Mon Sep 17 00:00:00 2001 From: Andy Heitke <45763735+heitke@users.noreply.github.com> Date: Fri, 16 Oct 2026 14:18:14 -0400 Subject: [PATCH 1/3] fix: skip macOS AppleDouble files in the model library scan Checkpoint folders on non-HFS+ volumes (exFAT/FAT external drives) carry an AppleDouble companion ('._model-00001-of-00043.safetensors') next to every real file, holding that file's resource fork. The scan's directory listing includes them, so inspect() counted them as weight shards, read their 4 KiB fork payload as a safetensors header, and failed the checkpoint with 'The safetensors header is invalid or incomplete.' The native engine ignores these files, and they are never checkpoint assets, so filter them from the inspected name list. --- app/electron/agent/engine/library.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/app/electron/agent/engine/library.ts b/app/electron/agent/engine/library.ts index 37b12691b1..f04a872bb8 100644 --- a/app/electron/agent/engine/library.ts +++ b/app/electron/agent/engine/library.ts @@ -217,7 +217,10 @@ export class ModelLibrary { } finally { await handle.close() } } - private async inspect(root: Root, directory: string, names: string[], caps: EngineCapabilities, budget: ScanBudget, repo: string | null = null, revision: string | null = null, blobRoot: string | null = null): Promise<{ model: EngineLibraryModel; fingerprint: string }> { + private async inspect(root: Root, directory: string, rawNames: string[], caps: EngineCapabilities, budget: ScanBudget, repo: string | null = null, revision: string | null = null, blobRoot: string | null = null): Promise<{ model: EngineLibraryModel; fingerprint: string }> { + // macOS AppleDouble companions (._file) ride along on non-HFS+ volumes (exFAT drives); + // they are resource forks, never checkpoint assets, and their bytes are not safetensors. + const names = rawNames.filter((name) => !name.startsWith('._') || name === '._.') const model: EngineLibraryModel = { id: `local/${digest(directory)}`, repo, title: repo ?? path.basename(directory), path: directory, source: blobRoot ? 'huggingface' : 'folder', folderId: root.id, revision, modelType: null, format: null, complete: false, compatible: false, loadable: false, reason: null, weightsBytes: null, memoryFloorBytes: null, fitsMemory: null } let fingerprint = directory try { From ac0e8785a340f3246a1ec635e3e357b11cc2599f Mon Sep 17 00:00:00 2001 From: Andy Heitke <45763735+heitke@users.noreply.github.com> Date: Fri, 16 Oct 2026 18:25:42 -0400 Subject: [PATCH 2/3] fix: filter AppleDouble companions from checkpoint discovery too A stray '._' companion in a selected parent matched the checkpoint detection test, so walk() stopped at the parent and never reached the real checkpoint beneath it; filter companions from detection as well and drop the undocumented '._.' exception from both filters. --- app/electron/agent/engine/library.test.ts | 37 +++++++++++++++++++++++ app/electron/agent/engine/library.ts | 8 ++--- 2 files changed, 41 insertions(+), 4 deletions(-) diff --git a/app/electron/agent/engine/library.test.ts b/app/electron/agent/engine/library.test.ts index 2eb8b8902a..9f309cf523 100644 --- a/app/electron/agent/engine/library.test.ts +++ b/app/electron/agent/engine/library.test.ts @@ -155,6 +155,43 @@ try { const large = await lowMemory.scan() assert.equal(large.models.every((model) => !model.loadable), true) + + // AppleDouble companions (._file) are resource forks, never checkpoint assets. + const adModels = path.join(root, 'AppleDouble Models') + const adSharded = path.join(adModels, 'sharded-checkpoint') + await fs.mkdir(adSharded, { recursive: true }) + await fs.writeFile(path.join(adSharded, 'config.json'), JSON.stringify({ model_type: 'qwen3_5', quantization: { bits: 4, group_size: 64 } })) + await fs.writeFile(path.join(adSharded, 'tokenizer.json'), JSON.stringify({ model: { type: 'BPE', vocab: {} } })) + await fs.writeFile(path.join(adSharded, 'model-00001-of-00002.safetensors'), weights()) + await fs.writeFile(path.join(adSharded, 'model-00002-of-00002.safetensors'), weights()) + // Stray invalid companions beside the real shards: not counted as shards, weights, or metadata. + await fs.writeFile(path.join(adSharded, '._model-00001-of-00002.safetensors'), Buffer.alloc(4096, 0xff)) + await fs.writeFile(path.join(adSharded, '._model-00002-of-00002.safetensors'), Buffer.alloc(4096, 0xff)) + const adLib = library({ appHome: path.join(root, 'appledouble-app') }) + const adFound = await adLib.addFolder(adModels) + const adModel = adFound.models.find((model) => model.path === adSharded)! + assert.equal(adModel.complete, true, adModel.reason ?? '') + assert.equal(adModel.loadable, true) + assert.equal(adModel.weightsBytes, 2 * weights().length, 'companions add nothing to the weight total') + assert.equal(adModel.memoryFloorBytes, 2 * weights().length + 2 * 1024 ** 3) + assert.equal((await adLib.resolve(adModel.id)).path, adSharded) + + // A stray companion in the selected parent must not stop discovery of the nested checkpoint below it. + const nested = path.join(adModels, 'nested', 'real-checkpoint') + await fs.mkdir(nested, { recursive: true }) + await checkpoint(nested) + await fs.writeFile(path.join(adModels, '._old.safetensors'), Buffer.alloc(4096, 0xff)) + const rediscovered = await library({ appHome: path.join(root, 'appledouble-nested-app') }).addFolder(adModels) + assert.equal(rediscovered.models.find((model) => model.path === nested)?.loadable, true, 'a stray parent companion does not block nested discovery') + assert.equal(rediscovered.models.some((model) => model.path === adModels), false, 'the parent is not mistaken for a checkpoint') + + // A real corrupt shard still fails the checkpoint. + const corruptShard = path.join(adModels, 'corrupt-shard') + await checkpoint(corruptShard) + await fs.truncate(path.join(corruptShard, 'model.safetensors'), 12) + const corruptFound = await library({ appHome: path.join(root, 'appledouble-corrupt-app') }).addFolder(adModels) + assert.match(corruptFound.models.find((model) => model.path === corruptShard)!.reason!, /safetensors/) + const validRegistry = await fs.readFile(lib.file, 'utf8') await fs.writeFile(lib.file, '{') await assert.rejects(() => library().snapshot(), /library is invalid/) diff --git a/app/electron/agent/engine/library.ts b/app/electron/agent/engine/library.ts index f04a872bb8..5b06cc5809 100644 --- a/app/electron/agent/engine/library.ts +++ b/app/electron/agent/engine/library.ts @@ -218,9 +218,8 @@ export class ModelLibrary { } private async inspect(root: Root, directory: string, rawNames: string[], caps: EngineCapabilities, budget: ScanBudget, repo: string | null = null, revision: string | null = null, blobRoot: string | null = null): Promise<{ model: EngineLibraryModel; fingerprint: string }> { - // macOS AppleDouble companions (._file) ride along on non-HFS+ volumes (exFAT drives); - // they are resource forks, never checkpoint assets, and their bytes are not safetensors. - const names = rawNames.filter((name) => !name.startsWith('._') || name === '._.') + // AppleDouble companions (._file) hold resource forks, never checkpoint assets, so drop them before inspection. + const names = rawNames.filter((name) => !name.startsWith('._')) const model: EngineLibraryModel = { id: `local/${digest(directory)}`, repo, title: repo ?? path.basename(directory), path: directory, source: blobRoot ? 'huggingface' : 'folder', folderId: root.id, revision, modelType: null, format: null, complete: false, compatible: false, loadable: false, reason: null, weightsBytes: null, memoryFloorBytes: null, fitsMemory: null } let fingerprint = directory try { @@ -301,7 +300,8 @@ export class ModelLibrary { visited.add(directory) if (await fs.realpath(directory) !== directory || !(await fs.lstat(directory)).isDirectory()) throw new Error('A model search folder is missing or has been redirected; select it again.') const entries = await this.list(directory, budget) - if (entries.some((entry) => entry.name === 'config.json' || /\.(safetensors|gguf|bin|pt|pth)$/i.test(entry.name))) { await collect(root, directory, entries); return } + const assets = entries.filter((entry) => !entry.name.startsWith('._')) + if (assets.some((entry) => entry.name === 'config.json' || /\.(safetensors|gguf|bin|pt|pth)$/i.test(entry.name))) { await collect(root, directory, assets); return } for (const entry of entries) { this.check(budget) if (!entry.isDirectory() || entry.isSymbolicLink() || entry.name.startsWith('.') || ['blobs', 'node_modules', 'venv', '__pycache__'].includes(entry.name)) continue From e223dd3a955b41681ad5cf27b52f61ae5df8f119 Mon Sep 17 00:00:00 2001 From: Andy Heitke <45763735+heitke@users.noreply.github.com> Date: Fri, 16 Oct 2026 18:56:07 -0400 Subject: [PATCH 3/3] test: rename a collision-prone variable for combining the PRs --- app/electron/agent/engine/library.test.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/electron/agent/engine/library.test.ts b/app/electron/agent/engine/library.test.ts index 9f309cf523..46c0e6b743 100644 --- a/app/electron/agent/engine/library.test.ts +++ b/app/electron/agent/engine/library.test.ts @@ -189,8 +189,8 @@ try { const corruptShard = path.join(adModels, 'corrupt-shard') await checkpoint(corruptShard) await fs.truncate(path.join(corruptShard, 'model.safetensors'), 12) - const corruptFound = await library({ appHome: path.join(root, 'appledouble-corrupt-app') }).addFolder(adModels) - assert.match(corruptFound.models.find((model) => model.path === corruptShard)!.reason!, /safetensors/) + const corruptShardFound = await library({ appHome: path.join(root, 'appledouble-corrupt-app') }).addFolder(adModels) + assert.match(corruptShardFound.models.find((model) => model.path === corruptShard)!.reason!, /safetensors/) const validRegistry = await fs.readFile(lib.file, 'utf8') await fs.writeFile(lib.file, '{')