feat(tui): isolate nine Windows process interfaces#685
Merged
huangzesen merged 10 commits intoJul 19, 2026
Merged
Conversation
Add internal/duplaunch, the DuplicateLaunchCheck policy interface: it returns allow/block/unknown from a private, non-creating probe of the kernel's .agent.lock lease (POSIX non-blocking flock; Windows fail-immediately LockFileEx on the msvcrt-locked byte). Unknown blocks. The LaunchAgent launch gate now consults this check instead of process observation; ForceLaunchAgent still bypasses it for /refresh. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
New internal/spawnprocess owns exactly one authority: creating at most one child from a typed Spec (executable/args/env/dir/stdio), returning a Child identity or a typed Error (invalid_spec/not_found/start). Success implies no readiness, ownership, or duplicate-launch safety; POSIX and Windows creation live in private build-tag adapters (CONTRACT.md). The one low-level launch seam (launchAgentUnsafe) now creates the child via spawnprocess.Spawn; LaunchAgent/ForceLaunchAgent return *spawnprocess.Child, with type-only follow-through in waitForLaunchHeartbeat and headless RunSpawn (PID/Release). Validation: go test ./internal/spawnprocess ./internal/process ./internal/headless (ok); go build ./... and go test -run '^$' -exec=/usr/bin/true for windows/amd64 and windows/arm64 (ok); gofmt clean on touched files. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Deliver one native stop request to an immediately identity-verified target, with distinct stale-identity / access-denied / already-absent / unsupported / unknown outcomes. POSIX verifies the kernel command name then signals; Windows verifies image name and liveness and terminates on the same held handle. Caller: the Windows stopTUIProcess stub no longer fakes success. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Own Contract/Port with private POSIX (procfs/sysctl start-token) and Windows (query+wait rights, creation-time token) adapters; observation only — never signals, stops, or escalates, and Unknown/Error are never converted into Exited. Minimal caller seam: stopTUIProcess's existing bounded exit polls now observe the pinned incarnation instead of the ad-hoc signal-0 probe. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Add internal/actionstate: a read-only policy that computes start/restart/ refresh enablement from its own heartbeat observation. Running, Stopped, and Unknown stay distinct; malformed, unreadable, or future heartbeats are Unknown and never enable an action. Absence proof is classified in private POSIX/Windows adapter files. The /cpr seam now revives only on a Stopped verdict and surfaces Unknown with its reason instead of treating it as dead. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Independent Query interface over one project .lingtai root: one record per agent directory with explicit running/absent/unknown/conflict presence from the directory's own manifest/status record checked against a private native PID existence probe (kill(0) on POSIX, query-only OpenProcess on Windows). Whole-query failure is a typed *QueryError, never a silent empty list. Minimal caller seam: the list command's shared warnings section prints unresolved (unknown/conflict) records and typed query failures. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
MigrationGuard answers allow/block/unknown for one offline migration/destructive action on an agent working directory, using only a non-creating probe of the kernel's .agent.lock (POSIX flock; Windows one-byte LockFileEx range probe). Unknown blocks, and the zero-value verdict is Unknown so an uninitialized decision can never permit. The m036 SQLite backfill migration now gates candidate discovery on this verdict instead of process-table observation, and rechecks the lock immediately before each rebuild since the user confirmation prompt can stay open indefinitely. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…evidence Replace the ps/WMIC process-count startup counter with a self-contained AgentCounter query (internal/agentcounter): registry.jsonl + .agent.json + .agent.heartbeat are the only authority, with explicit Known/Unknown state and Issues so failure never passes silently as zero. Private POSIX/Windows adapter files; minimal caller adapter in main.go. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
TUIInstanceGuard: internal/tuiinstance acquires/releases the one TUI singleton ownership token per project scope. Only Acquired permits the protected interactive startup in runPreparedApp; Contended and Unknown refuse distinctly. POSIX flock and Windows share-mode-0 handle locks are private to this interface; no process scan, PID hint, record age, or file-deletion bypass exists. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
This is the replacement for #684. It keeps the reviewed in-process Windows query commit and adds nine unrelated interfaces, each with its own Contract, Port, POSIX implementation, Windows implementation, minimal caller seam, and focused tests.
There is deliberately:
Nine independent interfaces
DuplicateLaunchCheck— non-creating.agent.locklease verdict before ordinary launch.SpawnProcess— typed process creation command.StopProcess— identity-verified stop command.TerminationObservation— observation-only exact-incarnation query.AgentActionState— read-only Running / Stopped / Unknown action enablement.AgentInventory— advisory inventory with typed query failure and explicit unknown/conflict.MigrationGuard— non-creating migration lease gate; Unknown blocks.AgentCounter— semantic count from registry/manifest/heartbeat evidence.TUIInstanceGuard— held singleton token for direct interactive TUI startup.Review result
AgentInventoryblocker was found: thehuman/mailbox placeholder (admin: null) was initially surfaced as an unknown agent. The candidate was amended with the canonical exclusion plus a regression test, then independently re-reviewed: PASS.AgentActionStatereview incorrectly treated the interface's own Contract/Port/platform adapters as forbidden. The authoritative contract requires each interface to own those pieces; a corrected independent review found no blockers: PASS.Consolidated validation
The nine reviewed commits were composed on the exact #684 head. The only textual conflict was in
internal/process/launcher.go; resolution preservesDuplicateLaunchCheckas the independent pre-launch authority andSpawnProcessas the independent execution port.Passed on the integrated head:
git diff --checkgofmtover every changed Go filego test -count=1 ./...go vet ./...go build ./...PR lineage
dev4/windows-tui-native-20260718No merge is requested as part of this handoff.