Commit Graph

10 Commits

Author SHA1 Message Date
fullex
9b9570116a refactor(db): replace libsql with better-sqlite3 + sqlite-vec (#16626) 2026-07-02 13:21:13 +08:00
fullex
9c1cbfae8e feat(concurrency): add createLatestReconciler and migrate ApiGateway (#16239) 2026-06-21 12:47:33 +08:00
fullex
c2faf96995 docs(lifecycle): clarify IPC registration alone does not make a service lifecycle
Prevent reading the IPC-handler table as a reason to promote an IPC-only class into lifecycle:

- Add a "placement, not promotion" note before the table, scoping it to services that are already lifecycle and clarifying row 3 ("belongs to the domain") only decides handler placement.
- Tighten the stateless-handler note: a class whose only job is registering stateless IPC is not a lifecycle service.
- Add Common Mistakes #8 ("Lifecycle service as an IPC bucket").
2026-06-04 23:23:04 -07:00
fullex
72b9105364 refactor(lifecycle): make onAllReady a fire-and-forget supplement
`LifecycleManager.allReady()` was holding `await Promise.allSettled(_doAllReady)`,
making every `onAllReady` body a synchronous bootstrap dependency. This
contradicted the hook's JSDoc ("post-bootstrap supplement, not a critical
initialization gate") and gave any in-hook deferred work an oversize blast
radius — a 60 s wait inside one service stalled `ALL_SERVICES_READY` and
delayed bootstrap completion.

Align the implementation with the JSDoc:
- `allReady()` becomes `void`. It synchronously invokes every initialized
  service's `_doAllReady()`, attaches an async `.catch` that re-emits
  `SERVICE_ERROR`, then emits `ALL_SERVICES_READY` immediately.
- `Application.bootstrap()` drops its `await` on `allReady()`.
- `LifecycleManager` tests adjusted: drop redundant `await`s, rewrite
  `resolves.toBeUndefined()` as `not.toThrow()`, drain microtasks before
  asserting on the now-async `SERVICE_ERROR` emit, and add a test
  exercising the fire-and-forget contract with a never-resolving hook.

`ALL_SERVICES_READY` now fires when hooks are *invoked*, not when they
complete. Docs reflect the contract change: a "Hook vs Event" comparison
in `lifecycle-overview.md`, two new Common Mistakes in
`lifecycle-decision-guide.md`, and an `onAllReady` business-work pattern
template in `lifecycle-usage.md` showing the \`setTimeout\` + signal +
\`onStop\` join model used by JobManager.
2026-05-20 06:14:24 -07:00
fullex
16f2e1c7a8 feat(lifecycle): add BaseService.registerInterval helper
Wraps setInterval with auto-unref, exception isolation, and cleanup
via the existing registerDisposable channel. Returns a Disposable.

Replaces 5 ad-hoc setInterval patterns (CacheService, PreferenceService,
WindowManager, ProxyManager, FileProcessingTaskService) — unifies
three pre-existing cleanup styles and fixes a missing unref() in
ProxyManager.

WindowManager: warmupGcTimer cleanup moves from onDestroy to onStop
(via registerDisposable) — acceptable for this singleton.

Skipped (YAGNI): registerTimeout, immediate/unref options,
activation-scoped variant. QuickAssistantService keeps bare
setInterval — its lifecycle is finer than activation.
2026-05-08 20:25:04 -07:00
fullex
826a453579 docs(test-mocks): clarify scope boundary and document lifecycle service testing
The mocks README described what was mocked but never stated that
tests/__mocks__/main/ is intentionally limited to cross-cutting
infrastructure. Without that boundary in writing, feature-specific
lifecycle services were getting registered into defaultServiceInstances,
bloating the global default surface without serving any other test.

Adds an explicit Scope section with a pattern-selection table, documents
the canonical local-stub pattern for feature-specific lifecycle services
(vi.mock on @application + MockBaseService stand-in), and a Common
Assertions table covering phase, dependencies, IPC handlers, and
disposables. Adds the missing Main PreferenceService section to match the
other three infrastructure service docs. Links the lifecycle README to
the new testing guidance.
2026-04-20 06:31:55 -07:00
fullex
bafed0d0e1 refactor(window-manager): migrate main window & fix macOS Dock semantics
- Rename WindowService -> MainWindowService (git mv, preserves blame/log)
- Register WindowType.Main in windowRegistry (singleton, showMode: manual);
  MainWindowService drives construction via wm.open and retains business
  logic only: IPC handlers, tray-aware close, crash recovery, show/toggle
- 50 call sites renamed (@DependsOn, application.get keys, imports)

WM Dock visibility refactored from visibility-based to existence-based:
- updateDockVisibility predicate drops isVisible/isMinimized check — a
  hidden main window must not remove the Dock icon (Cmd+W semantics)
- Add wm.setMacShowInDockByType(type, value) for tray-mode transitions;
  keyed by type so services can suppress Dock before the first instance
  exists (tray-on-launch path)
- Reduce triggers to window creation, destruction, and type-override
  changes; show/hide/minimize/restore no longer affect Dock state
- dockShouldBeVisible initializes true to match Electron's default

MainWindowService uses setMacShowInDockByType for tray-on-launch, close-
to-tray, and reopen-from-tray paths, replacing manual app.dock?.hide()
calls that raced against WM.

Docs updated across window-manager/{README, overview, platform,
api-reference, migration-guide}. New MainWindowService unit test covers
the close matrix (isQuitting, win/linux tray on/off, mac default, mac
tray on_close, fullscreen edge, Dock override assertions) and crash
recovery (first reload vs second-within-60s forceExit).
2026-04-19 06:52:03 -07:00
fullex
d5aa32e281 docs(lifecycle): clarify that cross-phase @DependsOn is redundant
Phase ordering already guarantees BeforeReady services (PreferenceService,
DbService, CacheService, DataApiService) are ready before WhenReady starts,
so declaring @DependsOn across phases adds noise and misleads readers about
same-phase coupling. The rule existed in lifecycle-overview but was buried
in a bullet; reinforce it in the docs AI assistants scan first.

- CLAUDE.md: add a bullet under the Lifecycle section stating @DependsOn
  is for same-phase deps only
- lifecycle/README.md: new "Cross-Phase Dependencies Are Automatic"
  callout section and a matching Anti-patterns row
- lifecycle/lifecycle-overview.md: promote the line-87 note to a blockquote
  callout and annotate the Dependency Rules table
- lifecycle/lifecycle-decision-guide.md: add Common Mistake #5 with
  bad/good code examples
2026-04-17 19:27:20 -07:00
fullex
9b451b87a9 refactor(paths): add @application path alias for main/core/application
Align with the existing @logger alias convention by introducing
@application as a short alias for src/main/core/application. This
reduces import verbosity across ~130 main-process files while keeping
4 intentional sub-path imports (@main/core/application/Application)
unchanged to preserve the vi.mock bypass mechanism in tests.

Configured in tsconfig.node.json and electron.vite.config.ts; Vitest
inherits the alias automatically.

Signed-off-by: fullex <0xfullex@gmail.com>
2026-04-11 22:06:00 -07:00
亢奋猫
a83f98fd24 docs: consolidate bilingual docs, add link checker and architecture overview (#14138)
Co-authored-by: fullex <106392080+0xfullex@users.noreply.github.com>
2026-04-09 16:01:40 +08:00