2026-09-17 15:32:28 +03:00
|
|
|
# electron-builder config — LearnHarness desktop (macOS arm64 first).
|
|
|
|
|
#
|
|
|
|
|
# Shape (fact-checked 2026-09-17):
|
|
|
|
|
# - the app's real server (.next/standalone, curated by
|
|
|
|
|
# scripts/build-server.mjs) ships via extraResources — OUTSIDE the asar,
|
|
|
|
|
# because native .node/dylib can't dlopen from a read-only archive and
|
|
|
|
|
# server.js process.chdir()s into its own dir;
|
|
|
|
|
# - the asar holds only the shell (electron/main.cjs + package.json);
|
|
|
|
|
# - signing/notarization config is laid now but inert until a Developer
|
|
|
|
|
# ID certificate exists (identity: null = unsigned local build, which
|
|
|
|
|
# runs fine for personal use — Gatekeeper only gates quarantined apps).
|
|
|
|
|
appId: com.learnharness.LearnHarness
|
|
|
|
|
productName: LearnHarness
|
|
|
|
|
directories:
|
|
|
|
|
output: dist
|
|
|
|
|
files:
|
2026-09-24 20:50:52 +03:00
|
|
|
# Only the shell goes into the asar. ORDER IS LOAD-BEARING (payload
|
|
|
|
|
# wave, 2026-09-24): electron-builder's dependency collector packs the
|
|
|
|
|
# whole production dep tree into node_modules/ REGARDLESS of this
|
|
|
|
|
# allow-list — normalizeFiles turns this array into one {filter: [...]}
|
|
|
|
|
# fileSet, getNodeModuleFileMatcher feeds EVERY filter entry (positives
|
|
|
|
|
# included) to the per-dep copier, and without a negation its implicit
|
|
|
|
|
# '**/*' passes everything (the measured result: a 502MB asar holding
|
|
|
|
|
# next/@ai-sdk/pdfjs/mermaid/puppeteer… while the launcher requires
|
|
|
|
|
# nothing but electron + node builtins — the server ships via
|
|
|
|
|
# extraResources).
|
|
|
|
|
#
|
|
|
|
|
# The fix is gitignore-style ordering (verified against the installed
|
|
|
|
|
# app-builder-lib 26.15.3 + a DEBUG-mode rebuild): '!**/*' first excludes
|
|
|
|
|
# EVERYTHING, the two positives after it re-include only the shell.
|
|
|
|
|
# The per-dep collector then contributes ZERO files — app-builder-lib's
|
|
|
|
|
# filter evaluates each dep file's DESTINATION path (the
|
|
|
|
|
# stat.moduleFullFilePath quirk in util/filter.js getRelativePath), so
|
|
|
|
|
# '!**/*' matches every 'node_modules/<dep>/...' path and the bare
|
|
|
|
|
# positives can never re-include one (DEBUG logs confirm filesCount=0
|
|
|
|
|
# for all 566 modules). If a future electron-builder fixes that quirk,
|
|
|
|
|
# ~1MB of package.json stubs would start landing — harmless. The
|
|
|
|
|
# two-package.json layout avoids the collector entirely but
|
|
|
|
|
# restructures the repo. app.asar.unpacked dies with it: the natives
|
|
|
|
|
# were only unpacked because their packages were packed.
|
|
|
|
|
- "!**/*"
|
2026-09-17 15:32:28 +03:00
|
|
|
- electron/**/*
|
|
|
|
|
- package.json
|
|
|
|
|
extraResources:
|
|
|
|
|
# Copy from the PARENT dir (.next), not .next/standalone itself:
|
|
|
|
|
# electron-builder hard-excludes a copy's root node_modules and the
|
|
|
|
|
# default no-filter pattern is a literal path match (empirically both
|
|
|
|
|
# node_modules/ and .next/ were silently dropped → server died on
|
|
|
|
|
# "Cannot find module 'next'"). With `from: .next` the filter's
|
|
|
|
|
# relative paths start with standalone/, dodging the root-node_modules
|
|
|
|
|
# rule, and the explicit wildcard (minimatch dot:true) reaches
|
|
|
|
|
# standalone/.next and standalone/node_modules.
|
|
|
|
|
- from: .next
|
|
|
|
|
to: server
|
|
|
|
|
filter:
|
|
|
|
|
- "standalone/**/*"
|
|
|
|
|
mac:
|
|
|
|
|
target:
|
|
|
|
|
- target: dmg
|
|
|
|
|
arch:
|
|
|
|
|
- arm64
|
2026-09-24 20:50:52 +03:00
|
|
|
# Locale trim (payload wave, 2026-09-24): English-only app — cuts
|
|
|
|
|
# every non-en .lproj from the frameworks (the STT/mic entitlements
|
|
|
|
|
# don't depend on locales). Revisit only if localization ever lands.
|
|
|
|
|
electronLanguages:
|
|
|
|
|
- en
|
2026-09-17 15:32:28 +03:00
|
|
|
category: public.app-category.education
|
|
|
|
|
# Laid for the STT milestone (researcher-verified): the TCC mic prompt
|
|
|
|
|
# reads this string; macOS asks regardless of Electron's own handlers.
|
|
|
|
|
extendInfo:
|
|
|
|
|
NSMicrophoneUsageDescription: "LearnHarness uses the microphone only for speech-to-text input into your sessions."
|
|
|
|
|
hardenedRuntime: true
|
|
|
|
|
entitlements: build/entitlements.mac.plist
|
|
|
|
|
# Unsigned until a Developer ID certificate exists (research-confirmed:
|
|
|
|
|
# local builds run fine; distribution needs signing + notarization).
|
|
|
|
|
identity: null
|
|
|
|
|
dmg:
|
|
|
|
|
title: "${productName} ${version}"
|