mirror of
https://github.com/NeuralNomadsAI/CodeNomad.git
synced 2026-08-25 16:22:28 +00:00
## Summary - Follow up #578 by consolidating desktop persistence, restore reconciliation, lifecycle coordination, and regression coverage. - Preserve active drafts and attachments, request-scoped workspace ownership, deletion tombstones, renderer authority, and bounded shutdown behavior. - Fix the reported macOS cleanup failure with targeted BSD process queries and random-token-guarded process-group cleanup, without an unverified PID fallback. ## Platform hardening - Ignore development renderer origins in packaged Electron builds. - Preserve staged Tauri navigation authority and handle confirmed Windows session-end shutdown on the UI thread. - Bound workspace launch preflight, runtime startup, and health readiness. - Retain cleanup ownership after unexpected leaders exit and verify portable POSIX descendants by immutable identity or inherited launch token. - Add real Darwin-only process-group integration tests for macOS CI. ## Scope - 96 files changed. - 6,295 additions and 12,167 deletions, a net reduction of 5,872 lines from the merged implementation. - Consolidated duplicated tests while retaining focused race, durability, cleanup, and platform contracts. ## Validation - pm run typecheck - pm run typecheck --workspace @neuralnomads/codenomad - Electron native suite: 60 passed - Tauri suite: 49 passed - Focused server lifecycle/identity suite: 31 passed, 2 Darwin-only skipped on Windows - Focused UI restore/codec/reconciliation suite: 36 passed - Broader server suite: 59 passed, 3 platform skips - Broader UI suite: 97 passed, 1 skip; 2 Node 25 solid-toast loader failures reproduced on the merged baseline - git diff --check - Final limited gatekeeper: PASS for server/macOS, UI restore, and Electron/Tauri
38 lines
1.3 KiB
TypeScript
38 lines
1.3 KiB
TypeScript
import assert from "node:assert/strict"
|
|
import test from "node:test"
|
|
import { SerializedLifecycle } from "./serialized-lifecycle"
|
|
|
|
test("serializes operations and exposes shutdown before queued work resumes", async () => {
|
|
const lifecycle = new SerializedLifecycle()
|
|
let release!: () => void
|
|
const gate = new Promise<void>((resolve) => { release = resolve })
|
|
let active = 0, maximum = 0
|
|
const first = lifecycle.enqueue(async () => {
|
|
active += 1; maximum = Math.max(maximum, active)
|
|
await gate
|
|
active -= 1
|
|
if (lifecycle.stopped) throw new Error("stopped")
|
|
})
|
|
const second = lifecycle.enqueue(async () => {
|
|
active += 1; maximum = Math.max(maximum, active); active -= 1
|
|
})
|
|
const shutdown = lifecycle.stop(async () => {})
|
|
release()
|
|
await assert.rejects(first, /stopped/)
|
|
await second
|
|
await shutdown
|
|
assert.equal(maximum, 1)
|
|
})
|
|
|
|
test("failed shutdown reopens the lifecycle before queued retries run", async () => {
|
|
const lifecycle = new SerializedLifecycle()
|
|
const shutdown = lifecycle.stop(async () => { throw new Error("cleanup unconfirmed") })
|
|
const retry = lifecycle.enqueue(async () => {
|
|
assert.equal(lifecycle.stopped, false)
|
|
return "restarted"
|
|
})
|
|
|
|
await assert.rejects(shutdown, /cleanup unconfirmed/)
|
|
assert.equal(await retry, "restarted")
|
|
assert.equal(lifecycle.stopped, false)
|
|
})
|