projmux 0.10.0 → 0.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README-ko.md +90 -72
- package/README.md +24 -16
- package/docs/agent-workflow.md +86 -23
- package/docs/ai-agent-shortcuts.md +63 -278
- package/docs/architecture.md +678 -16
- package/docs/cli-guide.md +1367 -0
- package/docs/cli.md +1239 -1091
- package/docs/configuration.md +185 -136
- package/docs/globalization.md +16 -12
- package/docs/hooks.md +90 -67
- package/docs/install.md +22 -6
- package/docs/keybindings.md +223 -60
- package/docs/legacy-cli-retirement.md +64 -0
- package/docs/legacy-diagnostics-inventory.md +23 -0
- package/docs/migration-plan.md +6 -3
- package/docs/notify-os-focus-poc.md +36 -15
- package/docs/notify-queue.md +21 -19
- package/docs/operational-diagnostics.md +190 -11
- package/docs/repo-layout.md +4 -1
- package/docs/resource-attribution.md +16 -0
- package/docs/session-restore.md +27 -9
- package/docs/settings-ia.md +232 -162
- package/docs/statusbar.md +228 -48
- package/docs/testing.md +9 -9
- package/docs/theme-palette.md +0 -3
- package/docs/tmux-surface-inventory.md +2 -2
- package/docs/upgrading.md +138 -23
- package/docs/usage-tracking.md +120 -34
- package/package.json +5 -5
package/docs/agent-workflow.md
CHANGED
|
@@ -30,16 +30,65 @@
|
|
|
30
30
|
- `make fix`: safe automatic fixes such as `go fix` and repository-approved cleanup steps.
|
|
31
31
|
- `make npm-pack`: macOS-hosted local npm binary package staging and `npm pack --dry-run` for the root package plus platform packages, including native-key-adapter checks for both Darwin architectures; release staging reuses the release matrix archives.
|
|
32
32
|
- `make security`: pinned govulncheck, gosec, staticcheck, gitleaks history/current-tree, actionlint, and shellcheck gates. Reviewed gosec/staticcheck findings use checked-in fingerprint/count baselines so only new findings fail.
|
|
33
|
-
- `make test
|
|
34
|
-
- `make test
|
|
33
|
+
- `make test` / `make test-integration` / `make test-e2e`: Agent Usage HUD provider/window visibility coverage pins the `UsageSupported()` provider order and explicit Claude/Codex `5h`+Weekly versus Antigravity Weekly-only capability matrix; missing/invalid on/default and atomic 0600 leaf persistence; the full overall/provider/window saved-effective parent matrix and restoration; en-US/ko-KR Settings View navigation; ambient-only filtering after collect/load/cache/backoff; weekly-only official-window width shedding; zero hidden label/bar/separator/staleness residue and all-provider-off empty text; all-on status/generator byte parity; lossless explicit table/JSON and CachedState popup; unchanged cache/backoff/provider-enablement byte/hash/inode/mtime sentinels; and Settings save to generated/live exact source-file apply.
|
|
34
|
+
- `make test` / `make test-integration`: Settings IA Phase 4 row-0 HUD visibility coverage pins default/saved/invalid effective-source projection; independent Notifications HUD and Agent Usage HUD persistence; byte-identical default app/standalone output; exact four-combination range/alignment/full-width behavior; all-off one-line (`status on`) convergence with the structural Window row, quiet autosave, and no stale row residue; Settings-generated config source reload; unchanged notify queue and usage snapshot state; and production exact-socket live tmux apply across all four combinations under the integration smoke's guarded socket cleanup.
|
|
35
|
+
- `make test` / `make test-integration`: Settings IA Phase 5 row-1 segment controls cover Project, Working directory, Git, Resources, Clock, and Settings launcher independently: five visibility files reuse the Phase 4 missing/invalid→on default, saved/effective/source, atomic 0600 persistence, generated-config no-write, and live exact `source-file` apply contracts; Resources has no duplicate visibility file and uses `live-resources` alone to remove its range/job and guard the sampler/cache mutation path; cwd/Git detail Views own separate Visible and Icon controls so icon off preserves their text; app/standalone exact mixed output removes hidden ranges and owned spacing with retired Kube ranges/jobs absent; and Settings launcher off retains the CLI/default-keybinding Settings entry.
|
|
36
|
+
- `make test` / `make test-integration` / `make test-e2e`: Settings IA Phase 6 retires the hidden Project recipe and Effective merge handlers/catalog/i18n plus every Kube-specific product projection. Named regressions pin the Project tree to Automation and Snapshots, reject public and internal Kube status routes, prove app/standalone generated configs contain no Kube range/job/binding, remove Kube from popup/sidebar switch previews and hook/session environments, preserve project hooks/trust plus `[startup]` and arbitrary generic `[env]` keys, and make a legacy `[kube]` update fail with the exact documented diagnostic while preserving original bytes and mtime. The integration smoke checks the same generated/live tmux absence on an isolated exact socket.
|
|
37
|
+
- `make test`: CLI information architecture v2 Phase 0 Cobra command catalog and help boundary: the `internal/cli` manifest holds every public route plus the 2 hidden internal helpers with exactly one canonical/shortcut/compatibility/internal disposition each (34 public, 9/7/13/5 tally, the ninth canonical being the `get` node the selector Phase added) and zero orphan routes in either direction against the canonical route manifest, which pins `rebind project`, `prune project`, `agent usage`, and the Pane-read `cwd` field projection alongside the closed shared `-o uid|name|ref|metadata|json|pane-id|none` catalog that deliberately excludes `cwd`; a golden fixture freezes the byte-identical top-level listing now rendered from the manifest and a command-tree golden freezes the Cobra surface (36 route nodes, hidden flags, `DisableFlagParsing` on every bridge, no injected `help`/`completion`/`__complete` command); a raw-argv table proves each bridge forwards `--`, positional arguments, unknown flags, and payload tails untouched, that handler-returned `flag.ErrHelp` and exit coders survive the Cobra boundary, and that unknown commands keep `unknown command: <token>` on stderr with exit 1 rather than a usage error; and the help no-side-effect negative tests prove every root, nested, and hidden internal help invocation exits 0 with stdout-only manifest help across every `flag`-equivalent spelling — both dash prefixes of `help`/`h`, bare and with any `=value`, matched on the flag name and pinned against the real `flag` package, with a guard that no leaf parser defines a competing `help`/`h` flag, reaches no handler, writes nothing into an isolated home, records zero operational-error journal rows through the same policy the process entrypoint uses and zero phantom state-changing success rows at any route depth (the diagnostics direct-help classifier walks positional sub-route words but stops at the first flag, so `upgrade --ref --help` and a literal `pin add help` path stay conservatively mutation-capable), skips the legacy hook filesystem migration, and — with a bounded timeout regression guard — no longer blocks on the `popup-wait-key` tty read, while a help flag after `--` stays payload and a bare nested `help` word still reaches its handler.
|
|
38
|
+
- `make test`: CLI information architecture v2 Phase 1 resource metadata foundation: `internal/core/metadata` unit and table tests cover the closed `Project`/`Window`/`Pane`/`Agent` kind set under `apiVersion: projmux.io/v1alpha1`, the one-time name-base seed priorities for every kind (Agent topics and raw pane titles are excluded everywhere), name-key validation, the persisted `nameReservations` suffix allocator proving the lowest free suffix is scan-order independent and that an explicit collision fails with `ErrNameConflict` and zero reservations written, offline Project bootstrap topology with a resolvable `spec.primaryPaneRef`, uid immutability across runtime creation, teardown, and rebind, zero heuristic uid merges (same-basename roots stay distinct; only an exact saved root reuses its uid), rebind and root-missing/root-returning `MissingRoot` condition lifecycle with preserved first-observed timestamps and name reservations, reverse-order operation rollback restoring a byte-identical registry, the closed Agent phase set with its exit classification and resumable Offline/Failed transitions, `schemaVersion` classification that fails closed on any newer envelope and on an unversioned document (production registers no migration step, since v1 is the first shipped envelope), a `testdata/registry-v0-source.json` → `testdata/registry-v1-migrated.golden` migration pair driven by a test-injected older step with reservation backfill that never renumbers existing names, full registry structural validation, and Session State round-tripping through additive `omitempty` `metadata` blocks at the unchanged snapshot `version: 1` including deterministic positional reconciliation of pre-metadata snapshots. `internal/integrations/metadata` covers the locked `<state>/projmux/metadata/registry.json` store: a newer `schemaVersion`, malformed JSON, and a content-bearing document with no `schemaVersion` are all refused byte-for-byte with no write, no temp file, no backup, and no quarantine on `Load`/`Update`/`Migrate`, while an absent, empty, or whitespace-only file still yields a fresh empty registry; migration atomicity is proven against a test-registered older step by injected failures after the backup, after the staged temp write, and just before the atomic replace, each leaving the original bytes and no leaked temp; a successful migration keeps a verifiable pre-migration backup and is idempotent; a failing operation writes nothing; a bootstrap registry golden freezes the camelCase file format and 0600 mode; concurrent registrations serialize through the lock with unique allocated names; and an end-to-end test round-trips an offline snapshot through both the registry store and the session-state store, reconciling every Window and Pane back by uid. The tmux mirror tests pin the exact session/window/pane option writes, the new window-scoped options, `automatic-rename off` on managed windows, `rename pane` touching only `@projmux_pane_label` and never `pane_title`, uid ↔ target resolution in both directions, and write-free legacy observation. `internal/app` and `cmd/projmux` prove the metadata usage-error seam: explicit name and rebind-root collisions reach exit code 2 through the existing `UsageError` path with zero mutations, while a newer registry schema stays a runtime error at exit code 1.
|
|
39
|
+
- `make test`: CLI information architecture v2 Phase 2 selector and read-only resolution: `internal/core/selector` unit and table tests cover the pure selector grammar and the read-only resolution engine over a structurally validated registry fixture that carries duplicate `displayName`s, an offline Project, a `MissingRoot` Project, and Window/Pane names repeated across owner scopes. An aggregate negative table proves the excluded forms resolve **0 occurrences** — an implicit comma split of two real names, a duplicate `displayName`, a real `spec.root`/`spec.cwd` path, a tmux `%N`/`@N`/`$N` handle, and a bare uid without the `uid:` prefix — while `displayName` is still reported as ambiguity context and the `uid:` form does resolve. A recorded per-stage trace pins the fixed name/uid-union -> AND label-filter -> uid-dedupe order with a 3/2/1 shape no other ordering can produce; repeated singular `--window`/`--pane` occurrences union in argv order and collapse by uid; the Pane universe is owner-scoped across Projects, Windows, and Agent-managed Panes; Window/Pane status is inherited from the owning Project as live/offline/`missing-root` with `MissingRoot` outranking a stale live session; and the resolver never mutates the registry it is handed. The `<verb, kind>` cardinality matrix pins the contract cells (`get windows` 0..N, `rename window` exact-one, repeated `create --window` 1..N) and a violation returns a usage error whose ambiguity listing is bounded to 5 candidate rows carrying name/`displayName`/owner context plus an omitted count. `internal/cli` proves `cwd` is accepted by exactly one canonical route: `ResolveOutputToken` grants it only on `get pane` and rejects it on every other read kind and on every named mutation route, the shared `-o` catalog still excludes it, and the new `get` node owns only the `pane` kind while the `current` compatibility route is left untouched. `internal/app` covers the route: `get pane --current -o cwd` emits a single trailing-newline path scalar from one tmux `display-message` query; `-o cwd` without `--current` and `--current` with any other projection or with selectors are usage errors with 0 bytes on stdout and 0 tmux calls; ambiguity, no-match, an emptied label filter, and an unresolvable `--project` scope are exact-one violations with 0 bytes on stdout; the output table pins default/uid/name/ref/metadata/json/none for a resolved read; the read loads the registry through a store path that creates no directory and no lock file when no registry exists; and `get` is excluded from the pre-dispatch legacy-hook filesystem migration. `internal/integrations/metadata` pins the zero-side-effect `LoadReadOnly` read, and `cmd/projmux` proves a bounded cardinality failure reaches exit code 2 with the listing on stderr and 0 bytes on stdout.
|
|
40
|
+
- `make test`: Implicit active target selector Phase 3 managed runtime binding convergence: a normal live-reload `config apply` invokes the existing registry matcher/reconciler/mirror only after successful `source-file` and routes every inventory and mirror call through the exact supplied `-L` socket; `--no-reload` and config/keymap preflight failures make zero live calls. Generated app config installs synchronous `after-new-window` and `after-split-window` boundaries that pass the expanded absolute `#{socket_path}` to hidden plumbing and use exact `-S` routing with no default socket or inherited `$TMUX` fallback. Unit/integration tables cover blank bindable Window/Pane repair to the original registry uids, ambiguous and foreign refusal, identity/owner/name-reservation preservation, two-socket isolation, and a repeat pass with zero `set-option`/`rename-window` calls and zero registry byte write. `get pane`, `describe pane`, and active-target resolution open zero write transactions and issue only the required option read. The CLI catalog, public option/environment surface, registry schema, Project scope, and heuristic/name/cwd matching remain unchanged.
|
|
41
|
+
- `make test` / `make test-integration` / `make test-e2e`: public resource reconciliation adds `projmux reconcile resources [--dry-run] [--socket <name> | --socket-path <absolute>] [-o json]` to the CLI manifest/help/reference. One planner runs the production Registry reconciler, mutator, matcher, and tmux Mirror over a cloned Registry and a zero-write tmux overlay; normalized allocation display values keep stable item keys/order without making opaque UIDs a matching key. Tests pin missing/stale/foreign/orphan Registry and tmux items, human/JSON target plus changed/no-op/failed counts, exact `-L`, absolute/inherited `-S`, no-flag outside-tmux pre-mutation usage refusal, two-socket isolation, dry-run byte stability, repeat no-op, and whole-session containment for unknown/duplicate/wrong-owner bindings, including a rootless UID-less session whose name is claimed by multiple Registry Projects. Execute scopes observation to Registry graphs safely attributable to the selected socket, replans under the Registry lock, commits Registry authority before non-transactional mirror writes, guards every planned live write through its current Project/Window/Pane UID binding before the first mutation, and reports completed stages, each current remaining drift item in human and JSON output, and the exact retry. Injected Registry commit failure publishes zero planned UID and changes neither Registry nor tmux; injected post-commit tmux failure leaves one authoritative identity graph that the exact retry converges without duplicates. A second socket and its pre-existing Registry graph remain byte/model identical. `doctor`, `get`, and `describe` remain read-only, the route skips unrelated legacy/config migration, and no config apply, default-socket fallback, state-loss recovery, heuristic merge, rename/rebind, or Agent semantic-status work is introduced.
|
|
42
|
+
- `make test` / `make test-integration` / `make test-e2e`: rename/rebind transport convergence keeps Registry uid/name/root authority and writes only the corresponding exact live field after the Registry transaction: Project name → `@projmux_project_name` without session rename, Window name → `@projmux_window_name` without `displayName`/`window_name`, Pane name → `@projmux_pane_label` without `pane_title`, and Project root → `@projmux_project_path` without filesystem or uid change. Public `rename agent` adds the exact-one Agent cardinality/aliases and changes only Window-scoped `metadata.name` plus its reservation, preserving topic annotations, provider, lifecycle linkage, and managed Pane metadata with zero tmux writes. Unit tables pin field-specific call logs, offline and inventory-unavailable later convergence, duplicate UID refusal, and post-commit live-write failures that exit nonzero with the public reconcile retry while retaining durable Registry drift. Immediate projection exists only for an inherited absolute `$TMUX` socket, routes every lookup/write through exact `-S`, targets stable `$N`/`@N`/`%N` handles, and performs zero tmux calls outside tmux or for a malformed relative inherited socket. Public reconcile treats a known unique Project UID as authoritative over the stale old path after rebind, plans/guards only the path-anchor write, repeats no-op, and keeps unknown/duplicate claims fail-closed. The isolated real-tmux smoke uses inherited-environment removal plus a validated exact socket path, asserts session/window/pane runtime names and a second socket remain unchanged, exercises offline later reconcile and injected option-write failure/retry, and cleans only the contained sockets.
|
|
43
|
+
- `make test` / `make test-e2e`: canonical resource create lifecycle reentrancy coverage pins the private, session-scoped create lease passed atomically through `new-session -e`, exact-socket/session lifecycle inspection, live-only deferral, stale-lease cleanup, and a second in-transaction reconciliation after explicit mirrors. Standalone `after-new-window`/`after-split-window` hooks remain synchronous. Window/Pane materialization preserves combined tmux output on non-zero exit, accepts only one exact newly observed `@N`/`%N` handle for ownership-checked reverse rollback, emits zero stdout on failure, keeps the registry byte-identical, reports ambiguous or ownership-mismatched residual drift, and never removes an unrelated object. The isolated tmux smoke exercises `--create-window`, exact returned pane IDs, registry/runtime uid agreement, and forced synchronous-hook failure cleanup; the existing Agent-create smoke covers canonical creation in a live managed Window with its stub provider.
|
|
44
|
+
- `make test` / `make test-e2e`: Window resource deletion converges the registry cascade and its exact live tmux binding. Explicit UID and selector-omitted active Window paths inventory only `-L projmux`, require exactly one `@projmux_window_uid` under the owning Project's Registry-authoritative exact session, validate the optional session `@projmux_project_uid` mirror when present, and refuse missing, duplicate, foreign, stale-session, or foreign-caller-socket bindings before any write. The plan and confirmation include the exact `@N` kill plus the implicit Project-session end when the selected set removes its last live Window; `--dry-run` renders both resource and live cascades with zero Registry transactions and zero tmux writes. External deletion revalidates both signatures under the Registry lock, kills exact live targets before committing the descendant delete, preserves the Project and sibling Windows, leaves Registry bytes untouched on tmux failure, and reports exact removed `@N`/session plus retained Registry UIDs if the store commit fails. A self-target commits the exact Registry cascade, writes and flushes the complete result, then queues a shell-quoted background `kill-window` through the same exact socket so caller teardown cannot interrupt its durable result; queue failure is nonzero and names the committed Registry/live-orphan drift. The isolated real-tmux smoke strips inherited `TMUX`/`TMUX_PANE` for external calls, verifies the actual socket path under its smoke root, covers two-Window sibling preservation, last-Window session termination, and implicit self-target output/Registry/live completion, then cleans up only that exact socket.
|
|
45
|
+
- `make test` / `make test-e2e`: Pane and Agent live-binding deletion extends the same fail-closed boundary to `delete pane|agent`. One exact `-L projmux` Pane inventory joins each Registry Pane uid through its owning Agent/Window/Project graph to the exact `@projmux_pane_uid`, `@projmux_window_uid`, optional session Project uid, and Registry-authoritative session projection; missing, duplicate, foreign-Window/Project, stale-session, and foreign-caller-socket rows cause zero writes. Agent deletion derives its runtime targets only from its Registry-owned managed Panes—never process content—and removes the Agent, managed Pane resources, and exact `%N` objects while preserving sibling Panes, Windows, and owner graph; deleting the current managed Pane alone preserves the Agent as `Offline` with a cleared `paneRef`. Dry-run, confirmation, and result output list every exact Pane plus implicit last-Pane Window and last-Window session cascades. Execution revalidates both resource and live signatures under the Registry lock, kills external targets before commit, and reports already-killed exact Pane/window/session/Pane-uid tuples with retained Registry UIDs on partial tmux or store failure. A caller-containing plan writes the complete deleted-Pane tombstone set under the Registry lock before commit; a partial tombstone or store failure restores every reachable marker while the Registry identities still exist, and any incomplete rollback keeps those Registry owners authoritative. After commit and flush, exact-socket background kills are queued only from revalidated tombstones, so any unqueued survivor remains explicitly tombstoned and retryable. Both anchored import and repair matching refuse that marker, preventing a failed delayed kill from re-importing a deleted Pane as an orphan. The isolated smoke strips inherited `TMUX`/`TMUX_PANE`, validates both socket paths below its dedicated root, covers sibling, last-Pane, managed-Pane-to-Offline, Agent cascade, anti-reimport, and second-socket preservation, and cleans up only the validated exact sockets.
|
|
46
|
+
- `make test-e2e`: Implicit active target selector Phase 3 runs installed-shape apply and lifecycle convergence against real tmux servers under a dedicated `TMUX_TMPDIR`, after stripping inherited `TMUX`/`TMUX_PANE`. It verifies the real `#{socket_path}` stays below the smoke root; deleted managed Window/Pane uid options return to their original registry identities after exact-socket apply; a newly created Window and a split Pane carry bindings before the creating tmux command returns and before an implicit read; repeat apply/lifecycle leaves registry bytes and bindings unchanged; a second socket remains untouched; and cleanup kills only the validated exact sockets.
|
|
47
|
+
- `make test`: Implicit active target selector Phase 2 scopes selector-omitted `get windows|panes|agents` inside tmux to the Project derived from the active Window uid mirror and registry owner chain through the selector engine's single `windowScope` seam. Tables pin inside/outside/missing-binding behavior, explicit `--project` parity, registry-wide `--all-projects`, read-route rejection of bare `--all`, unchanged global `get projects`, and unchanged notification/snapshot/destructive boundaries; the generated CLI reference documents the 0.x feature-minor default narrowing and its same-release escape hatch.
|
|
48
|
+
- `make test-e2e`: Implicit active target selector Phase 2 extends the isolated real-tmux registry smoke with multiple Projects, proves a synthetic current client sees only its Project's Panes by default and every Project with `--all-projects`, preserves outside-tmux global inventory, and refuses a missing active Window binding with zero stdout. The smoke strips inherited `TMUX`/`TMUX_PANE`, uses a dedicated `TMUX_TMPDIR` and unique socket, guards the queried actual socket root, and cleans up only exact validated sockets.
|
|
49
|
+
- `make test`: CLI information architecture v2 Phase 3 public verb-to-kind and runtime-domain parity: `internal/cli` grows six canonical top-level nodes (`delete`, `describe`, `rebind`, `rename`, `restore`, `runtime`) alongside the existing `get`, taking the manifest to 40 public routes plus the 2 hidden helpers with a 15/7/13/5 disposition tally and zero orphans in either direction; a written-out inventory table proves all 33 originally inventoried routes survive with an unchanged disposition and hidden flag, the added kind tokens do not shadow an existing subcommand under `pin`/`tag`/`prune`/`attach`, and both goldens are regenerated together. `internal/core/selector` adds the Project and Agent resolution pipelines through the same three-stage engine — a Project list read over the whole registry, an Agent set scoped by `--project`/`--window` with Window-scoped name uniqueness — and keeps `displayName`, `spec.root`, and tmux handles structurally unmatchable; Agent references render without a `--agent` flag spelling because the grammar has none. `internal/app` covers the routes: the plural reads are 0..N with an empty result as a success and a `<Kind>List`/`<Kind>MetadataList` envelope for the structured modes, `describe` is exact-one per kind with a key/value description block, and a maintained adoption table asserts every route resolves against the declared `<verb, kind>` cardinality cell rather than a per-route rule. `focus project|window|pane` resolves an already-live exact-one target from read-only `list-sessions`/`list-windows`/`list-panes` and exits 2 on an offline Project, Window, or Pane, on a prefix-match fallback, and on an ambiguous live match, with zero session/window/pane-creating tmux verbs in the call log, while the legacy `focus --target` spelling keeps its prefix-match and index fallbacks. `attach project` forwards to the Project open path only from outside tmux and returns a usage error naming `projmux focus project <ref>` from inside a client, reaching the open path zero times on every refusal. `rename` changes only `metadata.name` and its scope reservation, and a collision, an ambiguous target, or a missing `--name` commits zero writes. `rebind project` rewrites only `spec.root`, measured by walking a real temporary directory tree before and after, refuses a non-existent, relative, or already-bound root with zero writes, and leaves two Projects that come to share a basename as two uids. `prune project` requires `--missing` and `--older-than`, lists candidates bounded to 5 rows plus an omitted count without opening a write transaction, excludes recovered roots, live runtimes, and freshly observed missing roots, deletes only under `--yes`, and short-circuits an empty registry. `delete` preflights the full uid set and the whole descendant plan, prints it under `--dry-run` with zero transactions, requires confirmation for any cascade or multi-target run while exempting an exact-one leaf Pane, exits 2 without `--yes` in non-interactive mode, aborts when the cascade plan changes between preflight and execution, and leaves a validating registry in which a Window cascade preserves its Project, an Agent cascade preserves its Window and sibling Panes, and deleting an Agent-owned current Pane leaves the Agent alive as Offline. The runtime domain and the remaining canonical spellings are parity aliases proven by an argv-forwarding table that pins the exact tail handed to `sessions`, `attach auto`, `kill tagged`, `tag`, `runtime prune`, `notify list|ack`, and `session-state status|delete|restore`, relays their streams and errors untouched, and reaches no other handler. `get` and `describe` stay off the pre-dispatch legacy-hook filesystem migration while the mutation routes keep the historical behavior.
|
|
50
|
+
- `make test`: CLI information architecture v2 Phase 4 Agent namespace and lifecycle parity: `internal/cli` grows two canonical top-level nodes (`agent`, `create`), taking the manifest to 42 public routes plus the 2 hidden helpers with a 17/7/13/5 disposition tally and zero orphans in either direction; the written-out inventory table still proves all 33 originally inventoried routes survive unchanged, `ai`, `usage`, and `status usage` included, and both goldens are regenerated together. The Agent provider enum is derived from the provider catalog rather than hand-written, so an aggregate table proves `selective`, `resume`, and `shell` are members of neither the enum nor the create-shortcut set while `selective`/`resume` stay a named closed picker-adapter concept; the `create <provider>` shortcuts are opt-in through an explicit catalog flag, collide with no resource kind or shared verb, and render in their own `Provider shortcuts` help group instead of among the resource kinds. `internal/app` covers the routes: a written-out argv table proves `create agent --provider`, `create codex|claude|antigravity`, and `create pane` normalize onto the exact `ai split` argv the current spelling parses — `--placement` for the bare positional, `-o pane-id` for `--print-pane-id`, and the `--` payload forwarded untouched — while a missing `--provider`, a picker spelling, `shell`, an unknown provider, a shortcut that respells its own provider, a `left` placement, and the legacy `--force-agent`/`--agent`/`--print-pane-id` flags are all usage errors that reach the split handler zero times, and the projections needing the resource-backed create composition fail as runtime errors so exit 2 keeps meaning invalid input. `agent status|topic|integrate` forward raw argv to the handler that owns them and `agent usage` forwards to the top-level usage handler instance with no prefix at all, which is measured as byte-identical stdout/stderr/exit against `usage` for six flag spellings. `agent resume` resolves exactly one existing Agent through the shared selector engine and the newly declared `<resume, Agent>` matrix cell, accepts only Offline and Failed, refuses a Running Agent with a usage error that names `focus pane` rather than performing it, and on every path forwards to no other handler and opens zero registry transactions. The Agent lifecycle table pins the `Pending -> Running -> Offline/Failed` transition set and the exit-classification mapping, and both a normal managed-Pane exit and an explicit `delete pane` through the public route leave the Agent alive as Offline with its uid, name, and owner intact and its `paneRef` cleared.
|
|
51
|
+
- `make test`: CLI information architecture v2 Phase 5 internal plumbing isolation: `internal/cli` adds the hidden `internal` namespace, keeps plumbing out of public listings, and proves zero catalog/canonical/handler orphans. Generated standalone/app config and popup/hook payloads are exhaustively extracted so every emitted command uses an executable `internal` route. Raw tails, unknown flags, tmux formats, direct help, diagnostics classification, and bounded TTY helpers remain covered through their canonical internal spellings; newly generated artifacts contain no pre-namespace plumbing route.
|
|
52
|
+
- `make test`: CLI information architecture v2 Phase 6 detached Project runtime materialization and Window/Pane create: `internal/cli` makes `create window` a real executable node and gives both resource-backed create nodes the full shared `-o uid|name|ref|metadata|json|pane-id|none` catalog, with the public route count, disposition tally, and both goldens unchanged because no top-level route is added; a help-honesty test resolves every advertised `-o` token against the canonical route, runs each one end to end, and rejects any usage synopsis naming a flag the parser does not define. `internal/core/selector` adds the `<create, Project>` exact-one cell beside the existing `<create, Window>` 1..N and `<create, Pane>` exact-one cells, and the maintained adoption record gains all three. `internal/app` covers the routes against an in-memory tmux server that models sessions, windows, panes, scoped options, and the escaped format separator: a Project whose `status.session` is absent or not live is materialized in the background and its brand-new session's initial window and pane are adopted onto the Project's first stored Window and its `primaryPaneRef` instead of being left as an orphan; the result kind follows the route rather than the side effects, so `create window` emits a `WindowList` even though it also creates a Pane and `create pane --create-window` emits a `PaneList` even though it also creates a Window; a missing `--window` name is a plain no-match with zero mutations and only `--create-window` promotes it to an atomic Window-plus-initial-Pane ensure inside the same single transaction, while an already-existing name is reused rather than duplicated; every fan-out target splits its own anchor exactly once, an explicit `--pane` resolves exact-one inside each target Window, and a missing or stale `spec.primaryPaneRef` is exit 2 with 0 stdout, 0 registry writes, and no `split-window` at all even when a live pane is available to fall back to; a pre-create hook refusal leaves zero registry mutations and zero runtime objects while a post-create hook warning is a logged success; no path issues `switch-client`, `select-window`, `select-pane`, or `attach-session`, reads any focus format, or omits `-d` from a window or pane creation; `--placement right|down` maps onto the closed `-h`/`-v` split axis; the runtime ledger rolls back in reverse order and only removes objects still carrying the uid this operation mirrored onto them, leaving a bystander session and a re-bound window untouched; the negative table proves `displayName`, bare uids, commas, `--create-window` without an exact name or with `--selector`, `left` placement, the Pane-read `cwd` projection, and a `MissingRoot` Project are all usage errors with zero mutations; and `create pane` without `--project` still forwards the byte-identical legacy shell-split argv, with the discriminator pinned across every flag spelling and proven not to fire on payload text. The registry's first real production use is exercised against the actual locked store on a real filesystem: a create from a completely empty state creates `registry.json` at 0600 below a 0700 directory with no leaked lock, registers every discovered workdir with a bootstrap Window and a resolvable `primaryPaneRef`, and validates; a second create extends it without renumbering or re-identifying a Project; six concurrent `--create-window` runs on one name serialize through the `O_CREATE|O_EXCL` lock and converge on exactly one Window uid with one Pane per racer and one live tmux window; and a legacy-state fixture proves the first real import allocates `window`/`window-1` independently of runtime attributes, projects the observed `window_name`s into displayName, exposes the separation through `describe window`, turns `automatic-rename` off, mirrors the allocated uids back onto exactly the tmux objects it imported, and does not create new identities on a second pass. `internal/integrations/metadata` pins the tmux format separator contract that first use exposed: formats carry the escaped `\037` spelling because tmux 3.5a renders a raw `0x1F` as its octal escape while tmux 3.6 passes it through, and row parsing folds the escaped spelling back before splitting.
|
|
53
|
+
- `make test-e2e`: CLI information architecture v2 Phase 6 detached create against a real tmux server on a dedicated exact socket under the smoke root, with inherited `TMUX`/`TMUX_PANE` stripped from every call, the real `#{socket_path}` proven to be inside that root before cleanup, and only that socket killed: a pre-create hook refusal creates neither the registry nor a session and writes nothing to stdout; a post-create hook failure still commits and prints its result with the warning on stderr, and the registry lands at 0600; the legacy naming migration gives an `automatic-rename on` Window the stable name `window`, retains its observed `window_name` as the separately described displayName instead of deriving identity from its user Pane label, turns automatic-rename off, and mirrors the Window and Pane uids onto the live objects; `--placement right` and `--placement down` produce the two split axes measured from real `pane_left`/`pane_top` geometry, run from inside a real pane whose completion signal is an exit-code marker file rather than pane contents or `send-keys`, and leave the session's active window and pane unchanged with neither new pane active; `--create-window` converges on exactly one Window and still returns a `pane/` ref; a stale `primaryPaneRef` is exit 2 with 0 stdout, a byte-identical registry, and no new pane; and an injected `split-window` failure rolls the operation back to the exact window count and registry bytes it started from.
|
|
54
|
+
- `make test`: CLI information architecture v2 Phase 7 Agent create composition: `create agent` and the `codex`/`claude`/`antigravity` shortcuts gain a resource-backed detached route behind the same `--project` dispatch discriminator `create pane` uses, so the `--project`-less invocation stays the byte-identical `ai split` bridge while the canonical route allocates a Window-owned Agent plus its Agent-owned `<agent-name>-pane` managed Pane, reuses the Phase 6 anchor resolution, `--create-window` ensure, operation ledger and rollback, and enforces a new `{create, Agent} = 1..N` fan-out cell that four tests falsify when it is weakened; a matrix covers provider-required refusals on every canonical spelling, shortcut-to-canonical registry-snapshot equivalence, non-reuse against a Window that already owns a running Agent of the same provider (`codex` → `codex-1` → `codex-2`, first Agent's `status.paneRef` untouched), Window-scoped explicit `--name` (legal across two Windows, exit 2 with zero mutations inside one), payload-after-`--` reaching the provider launch but never the Agent or Pane name, all seven shared `-o` modes end to end with `AgentList`/`AgentMetadataList` envelopes for a single result and `-o pane-id` resolving to the managed Pane rather than the anchor, multi-window fan-out hitting each Window's own anchor exactly once, four failure stages each leaving the registry byte-identical with no `Failed` Agent behind, six racers converging on one ensured Window uid under the real on-disk lock with `-race -count=10`, the Settings enabled-agents gate applying to the canonical route as a plain error without promoting `--force-agent`, and a help-honesty audit that runs every advertised `-o` token and every advertised `--flag` of the Agent node and all three shortcuts; the identity projections of the compatibility bridge become exit 2 naming `--project` as the fix instead of exit 1 claiming the composition is unwired.
|
|
55
|
+
- `make test-e2e`: CLI information architecture v2 Phase 7 Agent create against a real tmux server on the same dedicated exact socket under the smoke root, with inherited `TMUX`/`TMUX_PANE` stripped from every call and only the verified `#{socket_path}` killed: a stub provider binary proves the launch actually ran in the created pane with the project root as its cwd, the managed pane carries both the Projmux Pane uid mirror and the `@projmux_ai_managed`/`@projmux_ai_agent` options, the active window and pane are unchanged and the new pane is not active, the `codex` shortcut allocates `codex-1` instead of reusing the first Agent, a `--` payload reaches the provider argv while the name stays `codex-2`, a missing `--provider` and an explicit name collision are each exit 2 with zero stdout and an unchanged registry md5, and the `--project`-less bridge still refuses its identity projections with a message naming `--project`.
|
|
56
|
+
- `make test` / `make test-e2e`: canonical create even-axis parity shares the legacy AI split geometry parser, row/column peer selector, and deterministic remainder distributor across `create pane`, `create agent`, and every provider shortcut; route tests pin split → Window-local geometry read → axis-only resize ordering for explicit/default anchors, right/down placement, fan-out, ensured Windows, one-pane no-op, malformed/unreadable topology, unrelated rows/columns, and silent post-split observation/resize failures with zero false rollback. The shared geometry format carries the materializer's escaped `\037` row separator rather than a raw tab, and a dedicated test pins both that the format holds no raw tab and that a `_`-sanitized row parses as no geometry: tmux 3.5a rewrites a raw tab in list output to `_` while 3.6 emits it verbatim, so the tab spelling parsed every row as a single field and made equalization a silent no-op on 3.5a — the version the e2e image runs. The isolated real-tmux create smoke repeats horizontal and vertical canonical creates to four panes, measures a maximum one-cell size difference, preserves raw pane IDs, Registry mirrors, focus, and an unrelated Window's exact geometry, and retains exact socket-contained cleanup.
|
|
57
|
+
- `make docs`: regenerates `docs/cli.md` from the `internal/cli` command manifest through `go run ./internal/tools/gendocs`. The render goes to stdout and is captured through a temp file, so a failed generator cannot truncate the checked-in page. Run it whenever a route, summary, usage synopsis, output mode, or field projection changes; `make test` fails until the checked-in page matches.
|
|
58
|
+
- `make test`: CLI information architecture v2 Phase 8 generated CLI reference: `docs/cli.md` is rendered from the command tree in `internal/cli/catalog.go` -- the same manifest the binary renders `projmux help` from -- and the hand-maintained prose it used to hold moved to `docs/cli-guide.md`, which the generated page, `README.md`, and `README-ko.md` all link. The drift gate compares the checked-in page byte for byte against a fresh render and names `make docs` in its failure, so the CI `Unit Tests` job catches a stale page; a determinism test renders twice and rejects an embedded repository or temp path, which is what makes regeneration on an unchanged tree a guaranteed no-op. Coverage is a two-way diff rather than a count: every public route and sub-route in the tree has a section and every section in the document is a real node, with a non-vacuity guard that both a canonical and a shortcut route exist to cover. The internal boundary is held on the published page as well as in the primary listing -- no hidden route gets a section, and no `Canonical spelling:` line may point at an executable path absent from the manifest. The generator reads the command tree and never `canonical.go`; canonical-only summaries are therefore checked as an explicit divergent set rather than leaking into command help. Advertisement-honesty checks keep registry reads aligned with the outputs their handlers implement and keep restore limited to its shipped dry-run preview contract.
|
|
59
|
+
- `make test`: Agent provider session binding Phase 0 persists a validated provider-discriminated `sessionRef` for Claude, Codex, and Antigravity without coupling lifecycle phase or Pane ownership to conversation identity. Metadata/store tests cover structural refusal, deep clones, pre-field byte-compatible reads, exact provider folding, and durable observation timestamps. `internal/app` drives canonical `internal agent-hook ingest` payloads for all providers against an in-memory Registry and proves correct provider-member population, option preservation, zero-write negative cases, conversation retention after Pane release, and stable `describe agent`, `get agents`, and `agent resume` behavior.
|
|
60
|
+
- `make test`: Implicit active target selector Phase 0 active target for the read and rename verbs: inside tmux, a completely empty selector on `get pane`, `describe project|window|pane|agent`, `rename project|window|pane`, and `rebind project` resolves the active tmux target instead of the whole registry, through one injectable seam in the registry route layer that every one of those routes shares. `internal/app` proves the seam rather than the outcome alone: inside-tmux detection is a table over `$TMUX`/`$TMUX_PANE` that costs **zero** tmux calls whenever the process is not a client — a bare `display-message` from outside a client still answers for the most-recently-used session, so "does tmux answer" is not the test — and inside a client the recorded argv is exactly `display-message -p -t %46 -F #{@projmux_pane_uid}` / `#{@projmux_window_uid}`, read lazily so a Pane or Agent route never queries the window option and a Window or Project route never queries the pane option. Ancestors come from registry `ownerRef`, not from more tmux options: the Project is the owner of the active Window and the Agent is the owner of the active Pane, and the session-scoped `@projmux_project_uid` is never consulted because it is measurably empty on live sessions. The refusal contract is pinned as exact strings for all eight shapes (pane/window with no mirror, pane/window mirroring a uid the registry does not hold, a shell Pane with no owning Agent, a window with no registered owning Project), each asserted to be a usage error carrying neither the `want exactly one` wording nor a candidate listing, and at route level to leave 0 bytes on stdout, 0 transactions, 0 writes, and a byte-identical registry snapshot. Acceptance is measured on call counts as well as output: every explicit form — a positional ref, a `uid:` ref, a `--project`/`--window` scope, a `--selector` label, and an unmatched ref — consults the active-target seam **zero** times and keeps its exact pre-fallback result, and outside tmux all seven adopting invocations keep their byte-identical `resolve <kind>: the current selector matched N ..., want exactly one` summary and exit 2. The maintained cardinality adoption record gains a nine-route table that runs the same argv three ways against the same declared cell — mapped target satisfies it, outside tmux still violates it, unmapped target refuses with the fallback's own message — so the fallback cannot be mistaken for a relaxed exact-one. `get pane --current` is proven not to be a duplicate and is not deprecated: `-o cwd` stays byte-identical with exactly one live `#{pane_current_path}` query and zero fallback consultations, and both of its usage errors keep their exact text. `internal/core/selector` records why the fallback has no value-token spelling: `current`, `active`, and four sibling candidates all pass `ValidateName` and parse as bare `metadata.name` occurrences, so a sentinel would shadow a real resource, while `.` and `@` remain rejected as names and are therefore the documented escape hatch for a future explicit spelling. `delete` is unchanged by construction — the seam is nil on every route that does not opt in — and the rendering the provider-session-ref change added to the same file is re-pinned: `resourceSummary` keeps its `kind`/`registry` parameters and the Agent `session=<provider>:<id>` suffix, which no other kind grows.
|
|
61
|
+
- `make test`: Implicit active target selector Phase 1 destructive verb containment: an omitted selector on `delete window|pane|agent` no longer means the whole registry. The measured baseline is that it did, everywhere -- `delete pane --dry-run` with nothing else on the argv planned all 5 fixture Panes, and a 1..N cell is satisfied by that, so no cardinality rule was ever going to catch it. The route now sets the shared active-target seam plus a `wholeSetFlag`, and `resolveQueryFlags.resolve` refuses the empty selector outright whenever the fallback resolved nothing, before `selector.Enforce` is reached. Acceptance is measured per kind on the plan rather than on the exit code, because the pre-change whole-registry fan-out also exited 0 under `--dry-run`: inside tmux the plan header is exactly `would delete 1 pane and 0 descendant resources` / `1 window and 4` / `1 agent and 1`, the one target line is asserted verbatim, and every uid outside the plan is asserted absent from the output. Outside tmux all three kinds refuse with `resolve <kind>: no selector was given and no active tmux target resolved, so nothing was selected; ...` at exit 2 with 0 bytes on stdout, 0 transactions, 0 writes, and a byte-identical registry snapshot -- including under `--yes`, which answers the confirmation and has never been allowed to answer which resources, and including for `delete window` and `delete agent` whose baselines were 33-line and 11-line whole-registry plans. The refusal is asserted to be neither the 1..N cardinality error nor the seam's unmapped-target refusal, so all three failures stay distinguishable; an unmapped active target keeps the seam's own message and is asserted never to advise `--all`. The whole-registry fan-out survives only under an explicit `--all`, which is a flag and not a value token because `ValidateName` leaves `all`, `current`, and `active` legal resource names that a sentinel would shadow; it is proven byte-identical in and out of tmux with the active-target seam consulted **zero** times, and it is refused next to any selector. Every string the route prints says "in the registry" rather than a bare "all", pinning which scope this `--all` is while projmux has only one. The confirmation carve-out for an exact-one leaf Pane is narrowed by exactly one condition -- the operator has to have named the target -- so the implicit and `--all` deletes always prompt while `delete pane log --project alpha --window main` still does not. Regression is measured as identity, not resemblance: eight explicit argv shapes (positional ref, `uid:` ref, multi-ref fan-out, `--project`/`--window` scope, `--selector` label, an unmatched ref) each run twice against the same fixture, once with the active target pointing at a different resource and once outside tmux, and both runs must produce identical stdout and identical error text with **zero** seam consultations, with `resolve pane: --pane zzz-nonexistent matched no panes, want at least one` pinned verbatim. The declared `<delete, kind>` cells stay 1..N deliberately: cardinality answers how many targets a resolved selector may address, and the containment changes which resources an empty selector resolves in the first place.
|
|
62
|
+
- `make test`: Agent provider session binding Phase 1 resume materialization: `agent resume <ref>` stops at a stub no longer and rebinds the existing Agent, building the provider's *resume* argv from `status.sessionRef`, splitting a detached managed Pane on the target Window's `spec.primaryPaneRef` through the create routes' own transaction, ledger, rollback, and materializer, and attaching it to the Agent that was already there -- the success test asserts the Agent count is unchanged, the `metadata.uid` and `metadata.name` are the ones that were already stored, `status.phase` is `Running`, `status.paneRef` resolves to a Pane the Agent owns with `role: agent`, the stored conversation pointer is unchanged, exactly one registry transaction commits, the Settings enabled-agents gate ran exactly once, and the one `split-window` argv actually issued carries the stored conversation id, with no client-moving command anywhere. The no-fallback contract is measured as a count rather than as an error string: a twelve-row refusal table -- an Agent with no `sessionRef` at all, a conversation the provider's resume builder rejects, a missing provider binary, a provider disabled in Settings, a `Running` Agent, an Agent that still owns a Pane, a ref contradicting `spec.provider`, a `MissingRoot` Project, a Window with no `spec.primaryPaneRef`, an ambiguous reference, and a no-match -- each requires **zero** new Agents, **zero** registry transactions and writes, **zero** `split-window` calls, zero tmux calls of any kind, zero managed-pane bindings, and a byte-identical registry and tmux snapshot; a separate rolled-back-runtime test injects a failing split and requires zero commits, the Agent still `Offline` with no Pane, and exactly one launch attempt which was the resume rather than a fresh start; and a reflection guard requires the resume launch seam not to satisfy the create launch seam, not to expose `PlanAgentLaunch`, and to take the conversation id as a required input, so no fresh-start argv is reachable from the route at all. The four Phase 0 handoff items are adjudicated with tests: the tie-break is that **the conversation is never a selector** -- three Agents sharing one conversation are run across three registry permutations and the referenced Agent is always the one rebound, the siblings never change phase or pointer, and the uid-ordered stderr disclosure and the launched argv are byte-identical every time; `observedAt` is **not** a gate, proven by two refs identical except for an `observedAt` a decade apart producing identical streams and identical argv, and by the stored value surviving the rebind unrewritten; Codex's turn id stays unstored and unimplemented, pinned by a per-provider resume-argv table requiring exactly three elements with no turn slot (`claude --resume <id>`, `codex resume <id>`, `agy --conversation <uuid>`) plus four unusable-id refusals; and an Agent with **no ref at all** fails as a non-usage state error naming `create agent` rather than performing it. A permanent-exclusion guard runs the plan twice with a Claude transcript path pointing at a nonexistent file and at nothing, requiring identical results, so the transcript is proven to be a stored path and never a read. `agent resume` remains a read-only refusal on every ineligible path, the `Running` refusal stays byte-identical with and without a stored ref because the phase gate runs before the ref is read, and the wiring test pins that the route shares the create command's runtime instance rather than a second materializer.
|
|
63
|
+
- `make test`: Agent liveness transition Phase 0 a dead managed Pane releases its Agent: when the tmux pane behind an Agent's managed Pane is gone the Agent moves to `Offline` and drops `status.paneRef`, so `agent resume` reaches its normal path without an explicit `projmux delete pane` first. The subject is an inventory diff rather than an event handler and the tests state it as one: `after-kill-pane` fires with an empty `#{hook_pane}` so no hook can name the pane that died, and `#{pane_dead_status}`/`#{pane_dead_signal}` are empty at hook time for a clean exit, a non-zero exit, and a SIGKILL alike -- they populate only under `remain-on-exit on`, which suppresses `pane-exited` entirely and changes pane lifecycle -- so every swept death is classified `AgentExitNormal` and `Failed` is never inferred. `internal/integrations/metadata` gains `Mirror.LivePaneUIDs`, the mirrored-uid half of the diff, sharing its one `list-panes -a -F '#{@projmux_pane_uid}\037#{pane_id}'` query with `PaneTargetForUID` so the two can never disagree about which Panes still have a transport binding. `internal/app` covers the sweep: the core case asserts `Offline`, a cleared `paneRef`, a deleted managed Pane, the recorded liveness reason, and a `status.sessionRef` preserved pointer-identical, because the conversation pointer is exactly what makes a released Agent resumable; a five-row phase table cross-checks the selection against `CanTransitionAgent` itself rather than against a hardcoded list, so a phase outside the closed table is skipped with its Agent, `paneRef`, and managed Pane all untouched instead of forced to `Offline`, and the table is never widened; and an Agent holding no `paneRef` is never handed a fresh reason or transition timestamp. Cost is measured in transactions rather than in an unchanged registry, because both tmux pane-exit hooks fire on every pane exit in every session: a sweep that finds every mirrored uid live queries tmux exactly once and opens **zero** write transactions, an unreadable inventory releases nothing, reports no error, and opens zero transactions -- fail closed, since an unreadable inventory is indistinguishable from an empty one and treating it as empty would offline every managed Agent on a machine whose tmux server simply is not up -- and a real death opens exactly one. Both triggers are proven end to end: the reconciler path releases a dangling `paneRef` through a real mutation route while leaving a mirrored Agent `Running` on its own Pane, the ordering is read off the recorded tmux argv so the inventory query must follow the last `@projmux_pane_uid` write of the same pass (a freshly imported Pane must never look dead, which is also why there is no one-shot migration -- the first pass resolves every pre-existing dangling ref and the second finds nothing left to do), and the hidden `internal tmux release-dead-agent-panes` route dispatches, releases, opens one transaction, prints nothing, and refuses arguments because it is a sweep and not a per-pane handler. The generated `pane-exited` and `after-kill-pane` hooks are pinned as one shared backgrounded body that runs `rebalance-panes` first under its own `|| true` and then the sweep under its own, so pane layout never depends on whether the registry sweep succeeded and the sweep still runs when there was no layout to rebalance; the theme config byte-identity goldens move with that shared addition. The pre-existing explicit `delete pane` -> `Offline` transition is re-pinned unchanged and still recorded as `deleted`, so the two paths stay distinguishable in `describe agent`. A pane-exit sweep that waits behind a newer create now refreshes the exact mirrored Pane UID inside the Registry transaction before releasing anything, preserving the newer Agent as `Running` with its Agent-owned Pane; a failed locked refresh aborts with zero writes while a true death still commits one release.
|
|
64
|
+
- `make test`: Registry runtime observation Phase 0 observed status for Window and Pane: `Window`/`Pane` status is no longer inherited from the owning Project's stored `status.session.live` bool -- a bool written `true` at legacy import, refreshed only by the reconciler, and never seen by the read verbs at all, so a registry object bound to nothing live reported `live` forever. `internal/core/selector` gains `ObservedStatus(missingRoot, bound)` as the single derivation rule every kind goes through, pinned by a four-row truth table plus a resolver table that reads one unchanged registry against three different machines (the alpha project running, one pane of a live window closed, and nothing running at all) and requires the reported status to follow the observation every time; the negative guard flips `status.session.live` both ways against one fixed observation and demands byte-identical Window and Pane statuses, which is the falsifiable form of "zero remaining stored-value paths", and it is repeated at route level over real `get windows`/`get panes` output. `MissingRoot` precedence is re-pinned on all three kinds at once -- Project, plus a Window and a Pane the observation says are demonstrably live -- so the preservation contract still outranks a stale runtime. `internal/integrations/metadata` gains `Mirror.LiveWindowUIDs`, the Window half of the registry-versus-machine diff, sharing its one `list-windows -a` query with `WindowTargetForUID` exactly as `LivePaneUIDs` shares `list-panes -a` with `PaneTargetForUID`; both inventories are proven to drop unclaimed tmux objects, to issue exactly one read command each, to write nothing, and to propagate a query failure rather than flatten it into an empty inventory. `internal/core/metadata` gains `RuntimeObservation`, a `MissingRuntime` condition with reason `RuntimeUnbound` on `Window.status` and `Pane.status`, and `Mutator.ObserveRuntimeBindings`, covered for set/clear symmetry, a preserved `firstObservedAt` across repeat observations, and the preservation contract itself: no resource deleted, no uid or name changed, no name reservation released; `Window.status` is declared `omitzero` and a serialization test proves a condition-free Window still round-trips byte-identically to a pre-observation registry, which is what keeps the addition inside `schemaVersion: 1`. `internal/app` covers the observation seam and the reconciler: the snapshot is taken once per process invocation and memoized (five resolutions, one `list-panes -a` and one `list-windows -a`), a failed query fails to *offline* per inventory half and never back to a stored value, and a nil lookup is the empty observation. The reconciler integration test fires **no hook at all** -- panes and windows simply stop existing on the fake server -- and the next pass records `MissingRuntime` on exactly the vanished uids, keeps every resource queryable, preserves `firstObservedAt` on a repeat pass, and clears the condition when the runtime returns on the same uids; an unreadable inventory records nothing, matching the dead-pane sweep's fail-closed tolerance. The acceptance table drives the real `intmetadata.Mirror` over a fake tmux server through the real `get` route: the reported `live` count is asserted as an inequality against the actual tmux pane count while the server is torn down one pane at a time, closing one pane offlines exactly that Pane on the next query with no hook and no write while its siblings stay live and it stays selectable, and a server that is up but mirrors no `@projmux` uid at all -- the tmux-restart shape, and the exact machine state that produced the defect -- reports zero live Windows and zero live Panes while still listing every one of them.
|
|
65
|
+
- `make test`: Registry runtime observation Phase 1 binding reapply and adoption: the `@projmux_window_uid`/`@projmux_pane_uid` options were written once, at legacy-session import time, and never again -- a tmux server restart or an option reset left every live window and pane carrying no uid at all, which is what made `projmux delete pane` with no selector fail with *the active tmux pane carries no `@projmux_pane_uid`* in almost every pane on the measured machine, and the import guard `!result.ProjectReused || len(reg.WindowsOf(projectUID)) == 0` made that permanent by *avoiding* duplicate Windows instead of repairing the drift. `internal/core/metadata` gains `BindingMatcher`, the single structural matching rule: Project scope first, then ordinal alignment (the session's tmux windows in `window_index` order against that Project's registry Windows in creation order, panes the same way inside a matched Window), returning exactly one of rebind/adopt/unmatched/refused. Two table tests, one per kind, pin every decision the rule may make against a two-Project fixture that deliberately carries the Window name `one` and the Pane name `zsh` in both Projects -- so a name-based match would cross and be caught -- and every refusal has its own row: an unresolved session scope, a uid the registry has never heard of (never adopted, reported as its own `AdoptionForeign` outcome so the anchored import path may mint rather than reuse -- projmux itself produces unknown uids, because a reconcile rolled back by a pre-create hook refusal has already written them onto non-transactional tmux options), a uid another Project owns, a Pane of a sibling Window, a uid two live objects both carry, a candidate already bound to a different live tmux object (skipped, never stolen), and a candidate already claimed earlier in the same pass; `paneUIDsInWindowOrder` is pinned to registry insertion order against a Window that mixes shell and managed Panes, because borrowing `snapshotPanesOf`'s shell-then-managed grouping would shear the alignment. `ImportLegacySession` takes a pass-scoped matcher and always walks `legacy.Windows`; `ImportedWindow`/`ImportedPane` gain an `Origin` of created/adopted/rebound, and adopted objects are reported to the adapter for mirroring but never recorded in the transaction ledger, proven by an empty `Created` on a pure-adoption re-import and by a single-entry ledger when an adopted Window still imports one extra Pane it has no candidate for. Import-path negatives cover zero duplicate Windows across two passes with every uid wiped, zero cross-project adoption for two same-shaped sessions, and and a foreign uid that mints a fresh Window instead of re-identifying the unbound one sitting right next to it, while a uid another Project owns produces nothing at all. `internal/integrations/metadata` extends `ObserveLegacySessionTargets` to read the uid each live object already carries (5-field window rows, 9-field pane rows), pinned for a bound window and a blank one in the same session. `internal/app` wires two binding steps against one pre-pass live-uid observation taken through the Phase 0 read seam: the anchored import path, and a new `reapplyUnresolvedBindings` for sessions with no `@projmux_project_path` -- the shape every session on the measured machine had -- which resolves through the Project<->session-name edge `refreshSessionProjections` maintains and creates nothing. The reconciler suite runs the measured fixture directly: one live blank window, a Project reachable only through `status.session.name`, two unbound registry Windows, and a stored `status.session.live` of `false` that nothing is allowed to consult; a **single** pass writes `win-first`/`pan-first` onto the live objects together with `automatic-rename off` and the name mirror, creates and re-identifies nothing, and leaves `MissingRuntime` on exactly the Window and Pane that really are unbound. A second pass leaves both the registry and the whole fake tmux server byte-identical. The refusals are covered at route level too: a session no Project claims and a session two Projects both claim each write nothing, two Projects with two sessions each reach only their own objects, a foreign uid is left exactly as found with none of its panes bound, a Window already bound to another live tmux window is not stolen (the blank window takes the next candidate instead), and a binding write that fails is skipped rather than failing the create that triggered the reconcile.
|
|
66
|
+
- `make test`: Registry runtime observation Phase 2 stable Window identity and runtime display projection: the `LegacyWindowNameSeed` table supplies tmux `window_name`, both automatic-rename modes, Pane label, provider, known shell, topic, and raw title and requires every row to return only `FallbackWindowNameBase`; an isolated two-Window import allocates `window`/`window-1`, records the observed `window_name`s as duplicate-allowed `metadata.displayName`, and proves `describe window` renders stable `Name` and runtime `DisplayName` as separate rows. A re-import after an explicit `rename window` keeps every existing uid, `metadata.name`, ownerRef, and name reservation while updating only displayName, and the unanchored binding-reapply fixture repeats that negative guard at the reconciler seam. `internal/integrations/metadata` pins the split transport: `@projmux_window_name` continues to mirror stable metadata.name while tmux `window_name` is driven by displayName, with an empty legacy displayName falling back safely to metadata.name. The explicit resource rename test proves `projmux rename window ... --name` does not change displayName; Pane `pane`/`pane-1` import naming and provider-base Agent naming/linkage/status remain covered by their existing Phase 3/4 tests.
|
|
67
|
+
- `make test`: Registry runtime observation Phase 3 orphan live pane import: Phase 1 taught the binding-repair path to *adopt*, and adoption needs an existing registry Pane to adopt into -- so a live pane created outside the Registry had no counterpart, stayed permanently unbound, and kept `projmux delete pane` with no selector refusing with *carries no `@projmux_pane_uid`* in the operator's own active pane; on the measured socket exactly one live pane out of seven carried a binding and the active one was not it. `internal/core/metadata` gains `Mutator.ImportOrphanPane`, which mints one shell-role Pane owned by an already-paired Window through the same `addPaneTx`/`storePaneStatus` primitives the legacy import path uses rather than a second write convention, and its unit tests pin the two fixed decisions as the things that would otherwise go wrong: the name is `FallbackPaneNameBase` uniquified by the registry allocator (`pane`, then `pane-1`) and is asserted to be neither the `claude` command nor the `@projmux_pane_label` that `LegacyPaneNameSeed` would have produced, because `metadata.name` is contractually never derived from a runtime attribute while the runtime reading still lands in `status.displayTitle`; and a pane whose observed provider, topic and command all say `claude` mints **zero** Agents, because deciding registry topology from pane content is the inference direction the track refuses. The cwd table covers the observed value and the fallback to the owning Project root, and an unknown Window is `ErrNotFound` with a `reflect.DeepEqual`-identical registry, which is what lets the caller treat the error as "skip this pane". `internal/app` opens the one gap `reapplySessionBindings` had -- `if !paneMatch.Matched() { continue }` -- by threading the `Mutator` and operation id into the repair path and resolving each pane through `paneBindingFor`. The end-to-end reconciler test registers the orphan, mirrors its uid *and* its name onto the live tmux pane through the existing whole `MirrorPane` write, leaves the paired sibling on `pan-first`, keeps `MissingRuntime` off the pane this pass bound, and then runs a **second** pass that leaves the registry and the whole fake tmux server byte-identical -- the regression that would appear without the `binder.Claim` on what was just minted. The registration rule is a table with a row per outcome: a blank pane with no candidate left is registered, a uid the registry has never heard of is registered (never adopted -- projmux itself produces unknown uids after a rolled-back reconcile writes them onto non-transactional tmux options), while a uid a sibling Window owns, two live panes carrying one Pane's uid, a pane under a Window carrying a foreign uid, a pane under a live window with no registry Window left (the Window layer still creates nothing), a session no Project claims, and a session two Projects both claim all register **zero**; every registration is additionally asserted to land under a Window owned by `prj-alpha`. The cross-project negative runs two Projects, two sessions and an orphan in each against Window and Pane names that collide across them, and requires each registration to sit under its own Project's Window -- the boundary is structural, since the owning Window was paired earlier in the same walk. The diff audit is the preservation contract: a uid/name/owner/spec snapshot of every pre-existing object must come out identical, no name reservation may be released, and the object count may only grow. Tolerance is pinned by injecting a `NewUID` that fails for `KindPane`: reconcile returns nil, nothing is mirrored, and the adoption work that did succeed is kept.
|
|
68
|
+
- `make test`: Registry runtime observation Phase 4 agent runtime linkage and observed status: three defects that only look separate. Phase 3 registered every orphan live pane as a Window-owned *shell* Pane whatever it was running, nothing ever wrote `status.paneRef` for a pane it had not itself launched, and `agentMatch` inherited Agent status from the owning Window (`status = windowMatch.Status`) -- so on the measured socket `get panes` printed an empty AGENT column for every row while `get agents` showed two finished conversations as `live` and hid the three that were running, and `claude-1` reported `Phase: Offline` next to `Status: live`. `internal/core/selector` derives Agent status from the Agent's own runtime object -- the managed Pane its `status.paneRef` names -- through the same single `ObservedStatus(missingRoot, bound)` rule, with the owning Window contributing only its Project's `MissingRoot` flag and specifically not its liveness; a five-Agent fixture under one live Window (running with a live pane, running with a dead pane, released, pending, failed) pins the table, an invariance test flips the owner Window's observation with every other input held fixed and requires byte-identical Agent answers (the falsifiable form of "zero inheritance paths", with the Window itself asserted to have moved so the invariance is not vacuous), an exhaustive sweep over all 8 live-pane subsets proves no reachable observation reports `live` for a non-`Running` phase, an empty observation against a stored `status.session.live` of `true` reports every Agent offline, a dangling `paneRef` is offline rather than live, and `MissingRoot` still outranks a live managed pane on every Agent at once. `internal/core/metadata` gains `Mutator.LinkAgentPane`, whose evidence rule is authorship rather than content: `pane_current_command` is never read and `@projmux_ai_agent` -- the option the AI routes write when projmux itself launches an agent -- is the sole marker, which is the same option `bindLegacyPaneTx` already trusted on its create path, so a pane the operator typed `claude` into is refused exactly as Phase 1's rule requires. It resolves an already-Agent-owned Pane to its Agent, otherwise attaches to an Agent of the *same Window* whose `status.sessionRef` records the identical provider conversation as the pane's `@projmux_ai_session_id`/`@projmux_ai_thread_id` (an exact identifier equality with `provider` compared too, so a Codex thread id is never equated with a Claude session id), and otherwise mints one; ambiguity mints rather than guesses because two Agents recording one conversation is legal state, and a candidate already claimed this pass or holding another `paneRef` is not a candidate at all. Eleven unit tests pin every branch plus the preservation contract: the linked Pane keeps its uid and its name while its reservation follows it into the Agent scope with no leftover Window-scoped entry, the Pane count cannot move, an unknown Window or Pane is `ErrNotFound` with a `reflect.DeepEqual`-identical registry, an unrecognized provider spelling still yields an Agent on the `agent` name base, two live panes reporting one conversation cannot claim one Agent, and a second pass rebinds without rewriting anything. `internal/integrations/metadata` reads the two conversation ids on the existing `list-panes` query (11-field pane rows) so linkage costs no extra tmux call. `internal/app` calls the linkage on the Pane `paneBindingFor` just settled on, discarding the error rather than escalating it *or* skipping the binding write that already succeeded; the reconciler suite runs two live agent panes and one plain shell through one pass and requires a populated AGENT column and `Role: agent` on both agent panes, an untouched shell pane, an Agent count equal to the live agent pane count and a `live` Agent count that matches it, a byte-identical registry *and* fake tmux server on the second pass, a four-row authorship table (projmux-launched, hand-typed `claude`, a shell, an unrecognized provider), tolerance under a `NewUID` that fails for `KindAgent` (reconcile returns nil, zero Agents, and the pane keeps the binding and the shell role it already had), an Agent that goes offline on the next read when its pane closes with no hook and no reconcile while staying queryable, and the one visible consequence stated rather than left implicit -- a promoted Pane now joins the managed-Pane lifecycle, so the dead-agent-pane sweep removes that Pane row while the Agent itself survives with the same uid, name, and `sessionRef`, still resumable.
|
|
69
|
+
- `make test`: Columnar default for list reads Phase 0 plus display-first resource projection: the default human plural reads (`get projects|windows|panes|agents`) are space-aligned tables whose first two columns are always `DISPLAY NAME`, `NAME`, followed by the existing per-kind columns in their prior relative order (`STATUS`, owner chain, optional AGENT/SESSION, `AGE`). Four whole-table goldens pin Project aliases, the already-projected tmux Window display/tab beside its distinct stable name, and current Pane/Agent fallback; the fallback uses metadata.name only when `strings.TrimSpace(metadata.displayName)` is empty and preserves a non-empty stored displayName byte-for-byte. Adversarial Pane `status.displayTitle` and Agent topic values, raw-title wording, tmux handles, duplicate display aliases, and selector negatives prove that secondary display data is never promoted and that only metadata.name or explicit `uid:` remains selectable. Each golden also asserts zero box/rule characters, tabs, and trailing whitespace. Widths stay terminal-display-cell based through `projmuxpicker.VisibleLen`; Hangul, long values, empty interior/trailing cells, and the direct rune-count falsification remain covered. The table remains gated on `OutputModeDefault` plus plural `list`: singular `get`, `describe`, and rename/create summaries remain byte-frozen, as do scalar `-o uid|name|ref|none` and whole List-envelope `-o metadata|json` projections. Zero rows still succeed with zero stdout/stderr bytes, and the injected-clock AGE boundary/determinism suite remains unchanged.
|
|
70
|
+
- `make test`: Resource timestamps surfacing Phase 0 timestamps in read surfaces: the registry has always stored `metadata.createdAt` on every resource, `Condition.firstObservedAt`/`lastTransitionAt` on every observed condition, and `Agent.status.lastTransitionAt` on every Agent, and `-o json` has always emitted them -- but no human-facing surface printed a single one of them, so `describe pane` carried zero time rows and the columnar `get` carried no `AGE`. Both now render, and nothing new is collected: no tmux query, no schema field, and no second relative-time implementation. The plural reads gain an `AGE` column, last on all four kinds because that is the one column whose width moves with the clock and last is the only position where growing it cannot walk an owner-chain column sideways; it is rendered through `i18n.FormatDuration`'s compact form, the same single implementation `notify list` already renders its own AGE through. `internal/app` pins the arithmetic as a boundary table asserted from both sides of every unit rollover (`59s`/`1m`, `59m`/`1h`, `23h`/`1d`, up to `900d`), plus the three cases that render an empty cell rather than a number -- a uid that has left the registry, a resource stored before `createdAt` was stamped whose zero Time would otherwise date it to year 1, and a caller that passed no clock -- and a whole-table golden spanning `9s`/`47m`/`6h`/`11d` in one read, which is also the alignment case because the widest cell sets the column. Determinism is stated as a two-sided claim rather than a single assertion, since only the pair is falsifiable: the same injected clock twice must be byte-identical (which a renderer ignoring the clock would also satisfy) **and** a clock advanced three days must produce a different table (which a renderer reading `time.Now` would fail), so only a renderer reading the passed-in clock and nothing else survives both. The clock reaches exactly one projection: `writeResourceProjection` takes it as an explicit parameter and the singular call sites (`get pane`, `describe`, `rename`, and the create fan-out, whose default projection is the `<kind>/<name> created` line and never the table) pass the zero Time, which `resourceAgeCell` renders as no age at all rather than as "created exactly now". `describe` gains absolute UTC instants instead: a `CreatedAt` row beside the identity rows on all four kinds, `PhaseSince` under an Agent's phase, and the second half of a condition's stored pair (`lastTransitionAt` beside the `firstObservedAt` that was already there), each omitted when the registry file predates the field so a pre-`createdAt` registry keeps its exact current block. The machine-consumer contract is frozen the whole way: `-o uid|name|ref|none` byte for byte, and `-o metadata|json` as whole documents rather than by substring -- they are rendered from the same `ObjectMeta` the AGE cell reads, so a new key anywhere in either reddens. The Columnar track's `describe pane` byte-golden moves by exactly one row and keeps its own purpose intact: what it guards is that the columnar table is reachable only with `list` true, and a header line or a padded column in a singular route still reddens it.
|
|
71
|
+
- `make test`: Settings IA re-cut Phase 0 full navigation cutover: the visible Settings tree is declared once in `internal/app/settings_nav.go` and frozen by `internal/app/testdata/settings-nav-tree.golden`, so an IA change is a golden diff rather than a shape spread across the section loops. Structural tests prove the catalog is a tree (unique ids, resolvable parents, a scope root at the top of every path), that every control hangs off exactly one owning `[View]` and that only a View owns children (row-affordance exclusivity), and that each rendered picker value maps onto exactly one navigation node whose owning loop the closed reachability table actually handles (control-owner cardinality); the drift guard runs in both directions, so a section loop cannot grow a row the golden does not show. The removed-path negative guard proves `Labs`, the separate `Theme` root, `Project recipe` and `Effective merge view` are neither rendered, nor catalogued, nor routable through `runSection` — the retired handlers, action metadata, and i18n entries are absent rather than hidden redirects — and the legacy-copy guard rejects the retired vocabulary (`AI Settings`, `Project Picker`, `Project Root`, `Workdirs`, `Enabled agents`, `Default split mode`, `Resume picker`, `Session State`, `Kill Session`, `New window`, `Hook quiet policy`, `Delivery sources`, `Labs`, `Usage HUD`, `Path icon`, `Notify icon`, …) across navigation labels, rendered rows and keymap display labels, in both locales. Display renaming is proven display-only: the keymap action IDs (`new-window`, `Sidebar:KillSession`, `ai-split-right`, …), the `sessionstate:`/`project-hooks:`/`live-resources:`/`statusbar-decoration:`/`workdir:`/`projdir:`/`switch:`/`keymap:`/`theme:` action spellings and their owner contracts are all unchanged behind the renamed rows. Keybinding navigation is category-based: an exhaustiveness test requires every catalog action to carry exactly one explicit category (never an ID-prefix inference), every surface action to sit in the sidebar/picker category with a display label for its surface, one display label per action, and each action to render exactly once across the rendered categories, while the category rows carry their members' action IDs, labels, chords and state so search still crosses the category boundary. The action detail projects the product semantics the target IA asks for — target kind, result kind, placement and anchor — and pins that every interactive right/down split declares the explicit current-Pane anchor and a right/down placement, that `Create <Provider> Agent` is always-new, and that resume names the existing `Offline`/`Failed` Agent it rebinds. Navigation is proven side-effect free (opening the root, every section and every container writes no config and runs no tmux command), every `[State]` row carries the catalogued passive value so Enter can never fall through, and the promoted rows keep their old state at the new route (Resources reads the same `live-resources` file it read from Labs, the project automation policy the same `project-hooks` file, Theme the same global `[theme]` block through `Appearance > Theme`). The pinned Project item view keeps Project identity separable (display name, unique name, uid, bound root, condition, missing-since, runtime) and offers same-uid remediation through the canonical `rebind project` route instead of re-pinning, with the unregistered-path case rendering a disabled rebind row carrying its reason. The Agent Usage HUD ownership guard keeps `agent usage` canonical: no Settings row spells a `Usage` resource or a `get usage` read, and `docs/settings-ia.md` names the owner.
|
|
72
|
+
- `make test`: Settings IA re-cut Phase 1 Automation and Notification ownership: the two containers are proven to be different product concepts by their labels alone. Automation names only Projmux-owned user scripts and the policy that gates them (`Projmux session lifecycle`, `After notification queued`, `Project automation policy`) and never a Provider or an integration; Notifications names only delivery and projection and never a lifecycle script or a `[hooks.*]` key. The Provider inventory is pinned to the Claude/Codex/Antigravity enum: the tmux bell producer is filtered out of Provider Integrations by producer identity and rendered flat at its own `tmux event source` View, whose wiring row says in words that the bell is not an Agent Provider. `Agent event behavior` renders the same Provider enum, so a Provider can never be wireable in one destination and missing from the other, and a provider x event matrix walks every event to its four-way `default`/`notify`/`state`/`quiet` choice and asserts each choice is addressed to the provider and event that rendered it. The two Provider destinations are proven disjoint: install/remove/conflict/config-path/`Check integration` rows exist only in the wiring detail and the `ai-hook-set:` choices only in the behavior view, with neither surface rendering the other's action prefix. `Check integration` (and `Check` for the bell) is an observable read-only action rather than a placeholder: it re-reads the shipped doctor diagnostic, reports status/config path/conflict as Settings feedback, shells out to nothing, leaves the config tree byte-identical, and errors on an unknown id. The `[hooks.send-noti]` + `PROJMUX_NOTIFY_HOOK` parity test sets both at once and proves they are a supported combination rather than an either/or: each keeps its own resolved value, the desktop row disclaims the fan-out and the Automation row disclaims the sender, neither row renders the other's value, and the three session lifecycle events stay empty. An automation event x scope matrix walks `pre-create`/`post-create`/`post-attach`/`send-noti` in both scopes, keeps the technical `[hooks.<event>]` spelling in the state row, requires the project scope to name its missing-context reason instead of falling through to a global value, and pins `send-noti` as a sibling of the lifecycle list rather than a fourth member of it. The attention guard keeps live Pane badges out of every Notifications surface while the badge style keeps its Appearance home, and the retired `Hook quiet policy` vocabulary is gone from the shared UI text catalog and from the rendered rows in both locales while staying on the negative-guard list.
|
|
73
|
+
- `make test`: interaction-first Keybindings details keep action state, current single keys/sequences, and add/manage/remove/reset/test actions ahead of passive explanation. `TestSettingsKeybindingActionDetailMatrix` verifies semantic/handler/`internal/cli` manifest parity directly against the internal models while separately proving every rendered selectable row is handled; `TestSettingsKeybindingActionDetailPrioritizesStateBindingsAndActions` freezes the default/custom/unbound row order and mutation reachability; `TestSettingsKeybindingKeyDetailRowsAreAllHandled` keeps replace/remove/test routes and requires an unavailable test row to carry both reason and next step; and `TestSettingsKeybindingRetiredContainerCopyIsGone` renders Action/Key/Sequence surfaces in en-US and ko-KR and rejects visible Target/Result/Placement/Anchor/Handler, canonical storage/delivery, cancellation teaching, and Advanced/Details/Delivery/About-style containers. Delivery outcome, one-reader, unavailable/cancel/no-write, capture/typed normalization, feedback-stage recovery, protected-action, reserved-key, sequence storage/runtime, and distinct create/resume parity tests remain in the maintained suite.
|
|
74
|
+
- `make test-e2e`: Settings IA re-cut Phase 0 native navigation smoke against the real attached tmux client: a deep search from the Settings root walks `Appearance > Status Bar > Git > Icon` — proving search lands on the owning View rather than executing a control, and that reaching the icon chooser writes no decoration file — then returns to the root through the Back rows, and the keybinding recorder flow now reaches its action through the `Launch & popups` category, searching for the action's own name at the root to prove search crosses the category boundary.
|
|
75
|
+
- `make test`: lifecycle hook context coverage verifies that the production client supplies `projmux` socket metadata, standard persistent and ephemeral `post-create` receive the exact non-empty pane id returned by session creation, `pre-create` receives no pane id before creation, and empty socket/pane values are omitted from the hook environment.
|
|
76
|
+
- `make test`: atomic project and private-global config writes preserve existing regular-file metadata, resolve valid relative and multi-hop symlinks to the final target without replacing link inodes, retain `0644`/`0600` defaults for missing destinations, recover dangling symlinks as regular files, and preserve original content with no temp artifacts across resolve/stat/create/write/close/chown/chmod/rename failures. Source-level global and Settings project writer tests exercise the production entrypoints with isolated home/repository paths.
|
|
77
|
+
- `make test`: fast unit coverage for app-layer AI split native agent launch/selective popup-toggle/settings/status/notification parity including AI pane option metadata, watcher metadata bootstrap for existing panes, capture-backed reply detection, missing-pane watcher shutdown, armed focus-only reply badge clearing, busy attention preservation on focus clear, manual AI topic preservation while watcher status still updates, agent-labeled desktop notification message context with pane-title-first body text, global/project-local lifecycle hook dispatch for post-create/pre-create/post-attach/send-noti with project hook and `.projmux/config.toml` trust-store hashing plus env/settings kill-switch gating, declarative startup command and hook run coverage, `send-noti` stdin JSON delivery plus `PROJMUX_NOTIFY_*` env payload, notify queue write success/failure/depth-guard dispatch rules, notify/statusbar/sidebar origin-client focus routing, project config generic env session environment application without Kube-specific projection, project hook/trust writes with startup/env compatibility, startup command send-keys orchestration plus startup pane replay markers, pre-create abort behavior, and shared projmux notification icon paths, and scoped even row/column resizing after shell and agent splits, status-bar git segment parity including muted git branch block styling, compact dirty/staged/ahead/behind state colors, and bounded git child execution, statusbar pwd display-only native-framed path popup with shared popup-wait-key/no-extra-payload-line command coverage, no clipboard or tmux buffer copy, and popup-wait-key cursor/raw-mode restore coverage, statusbar usage native HUD popup alignment/height-budget/threshold palette/muted sync-staleness/fallback coverage without raw CLI popup or popup-toggle stacking, statusbar settings click popup fallback and settings chip right-edge rendering without default trailing space, popup-toggle stale marker recovery, isolated `projmux shell` tmux app launch/config generation including home fallback plus project-context default session targeting from `PROJMUX_CWD` or nearest project marker, app-owned project-name statusbar layout, distinct project badge color, and quiet debounced session-state autosave command/app-config trigger, shell-entry welcome release prompt and inline update handling, shell update skip-by-latest-tag behavior plus best-effort stale-cache refresh, pane/window keybindings, keymap.toml tmux override rendering/stale unbinds including retired direct/UserKey cleanup, Settings Keybindings root/list/detail capture flows including parse-error rows, unsafe raw capture and timeout guards, disable/reset writes, app config regeneration, live tmux source-file reload, no-live-tmux save behavior, and stage-by-stage apply recovery copy, window rename bindings, pane rename helper/binding, pane-exit rebalance command/hooks, hook-pane and after-select-pane based attention focus hooks, attention badge toggle/clear/list/window rendering, attach/current/kill/pin/preview/prune/sessions/session-popup/settings commands, switch, tag, tmux helper commands, update status/check/apply cache and installer detection including GitHub Release binary asset selection/extraction/replacement, doctor versioned read-only report/section/verbosity contracts, AI notify integration diagnostics, and Session State resume metadata diagnostics, Settings AI notify integration diagnostics read-only status/conflict/CLI guidance, and Settings About update status/check action wiring, untitled standalone popup-toggle marker close/config install, direct popup minimum sizing, AI picker minimum width and height, sidebar minimum width and compact badge spacing, preview select writes, popup render output after cycling, switch picker pin action behavior without inline settings rows, nested settings hub sections for AI defaults, project picker filesystem scan/pin actions, Project Root settings source/shadowing/set/current/clear flows, app/keybinding info including Ctrl-M rename forwarding, and About version/source rendering, switch picker focused-session kill, switch picker launcher-key abort bindings, switch explicit project-root, unconfigured-root, and weak managed-root heuristic parity, switch popup hiding new-session candidates while sidebar keeps create-capable rows, switch row project-name display with `~` pinned to the top and live-session-first sorting, pretty-path, preview context without retired Kube metadata, switch settings subcommand flows including add-current-pin, interactive add-pin picker, and settings label/preview polish including Phase 2 Settings/hookmaker/project-startup/trust/quit destructive row color regression strings, native preview wiring, baseline picker surface parity including prompt/footer/header fallback without app-name filler and search-key scoped card matching, sidebar compact action-only key footer, sidebar preview-window/start-position behavior without focus-time session switching, sidebar row/window ANSI styling with pane-aggregated attention badge state and AI topic labels, Alt+2/Alt+3 legacy popup row, preview-window, pane metadata, and pane-snapshot parity, switch read0 card rows with active/inactive title styling, right-side status badges, combined directory/git metadata with muted inactive branch styling and bounded slow-repository branch enrichment, statusbar-matched block window tabs with window attention badges, read0 expect-key action parsing, restored pin/tag card badges, and restrained selected-row marker styling, switch preview metadata without duplicated directory/git rows, preview metadata rendering, popup pane display names for AI agents, AI topics, and shell commands, switch preview cycle bindings, sessions picker preview/cycle/open/kill wiring including attached-session fallback behavior, sessions picker launcher-key abort bindings, popup/switch preview summary formatting, popup sessions tmux entry helpers, switch/popup/session rendering, session identity, session-state Claude/Codex/Antigravity resume and declarative startup replay, session snapshot capture/autosave recipe classification including save/autosave pre-capture resume metadata refresh from live AI session ids including Antigravity conversation ids, Claude transcript paths, and Codex rollout log cwd matching/ambiguity skips, candidate discovery, config path derivation, popup preview read-models, and pure state rules including preview, tag, and lifecycle stores.
|
|
78
|
+
- `make test`: fast unit coverage for app-layer AI split native agent launch/selective popup-toggle/settings/status/notification parity including AI pane option metadata, watcher metadata bootstrap for existing panes, capture-backed reply detection, missing-pane watcher shutdown, armed focus-only reply badge clearing, busy attention preservation on focus clear, manual AI topic preservation while watcher status still updates, agent-labeled desktop notification message context with pane-title-first body text, global/project-local lifecycle hook dispatch for post-create/pre-create/post-attach/send-noti with project hook and `.projmux/config.toml` trust-store hashing plus env/settings kill-switch gating, declarative startup command and hook run coverage, `send-noti` stdin JSON delivery plus `PROJMUX_NOTIFY_*` env payload, notify queue write success/failure/depth-guard dispatch rules, notify/statusbar/sidebar origin-client focus routing, project config generic env session environment application without Kube-specific projection, project hook/trust writes with startup/env compatibility, startup command send-keys orchestration plus startup pane replay markers, pre-create abort behavior, and shared projmux notification icon paths, and scoped even row/column resizing after shell and agent splits, status-bar git segment parity including muted git branch block styling and compact dirty/staged/ahead/behind state colors, statusbar pwd display-only native-framed path popup with shared popup-wait-key/no-extra-payload-line command coverage, no clipboard or tmux buffer copy, and popup-wait-key cursor/raw-mode restore coverage, statusbar usage native HUD popup alignment/height-budget/threshold palette/muted sync-staleness/fallback coverage without raw CLI popup or popup-toggle stacking, statusbar settings click popup fallback and settings chip right-edge rendering without default trailing space, popup-toggle stale marker recovery, isolated `projmux shell` tmux app launch/config generation including home fallback plus project-context default session targeting from `PROJMUX_CWD` or nearest project marker, app-owned project-name statusbar layout, distinct project badge color, and quiet debounced session-state autosave command/app-config trigger, shell-entry welcome release prompt and inline update handling, shell update skip-by-latest-tag behavior plus best-effort stale-cache refresh, pane/window keybindings, keymap.toml tmux override rendering/stale unbinds including retired direct/UserKey cleanup, Settings Keybindings root/list/detail capture flows including parse-error rows, unsafe raw capture and timeout guards, disable/reset writes, app config regeneration, live tmux source-file reload, no-live-tmux save behavior, and stage-by-stage apply recovery copy, window rename bindings, pane rename helper/binding, pane-exit rebalance command/hooks, hook-pane and after-select-pane based attention focus hooks, attention badge toggle/clear/list/window rendering, attach/current/kill/pin/preview/prune/sessions/session-popup/settings commands, switch, tag, tmux helper commands, update status/check/apply cache and installer detection including GitHub Release binary asset selection/extraction/replacement, doctor versioned read-only report/section/verbosity contracts, AI notify integration diagnostics, and Session State resume metadata diagnostics, Settings AI notify integration diagnostics read-only status/conflict/CLI guidance, and Settings About update status/check action wiring, untitled standalone popup-toggle marker close/config install, direct popup minimum sizing, AI picker minimum width and height, sidebar minimum width and compact badge spacing, preview select writes, popup render output after cycling, switch picker pin action behavior without inline settings rows, nested settings hub sections for AI defaults, project picker filesystem scan/pin actions, Project Root settings source/shadowing/set/current/clear flows, app/keybinding info including Ctrl-M rename forwarding, and About version/source rendering, switch picker focused-session kill, switch picker launcher-key abort bindings, switch explicit project-root, unconfigured-root, and weak managed-root heuristic parity, switch popup hiding new-session candidates while sidebar keeps create-capable rows, switch row project-name display with `~` pinned to the top and live-session-first sorting, pretty-path, preview context without retired Kube metadata, switch settings subcommand flows including add-current-pin, interactive add-pin picker, and settings label/preview polish including Phase 2 Settings/hookmaker/project-startup/trust/quit destructive row color regression strings, native preview wiring, baseline picker surface parity including prompt/footer/header fallback without app-name filler and search-key scoped card matching, sidebar compact action-only key footer, sidebar preview-window/start-position behavior without focus-time session switching, sidebar row/window ANSI styling with pane-aggregated attention badge state and AI topic labels, Alt+2/Alt+3 legacy popup row, preview-window, pane metadata, and pane-snapshot parity, switch read0 card rows with active/inactive title styling, right-side status badges, combined directory/git metadata with muted inactive branch styling, statusbar-matched block window tabs with window attention badges, read0 expect-key action parsing, restored pin/tag card badges, and restrained selected-row marker styling, switch preview metadata without duplicated directory/git rows, preview metadata rendering, popup pane display names for AI agents, AI topics, and shell commands, switch preview cycle bindings, sessions picker preview/cycle/open/kill wiring including attached-session fallback behavior, sessions picker launcher-key abort bindings, popup/switch preview summary formatting, popup sessions tmux entry helpers, switch/popup/session rendering, session identity, session-state Claude/Codex/Antigravity resume and declarative startup replay, session snapshot capture/autosave recipe classification including save/autosave pre-capture resume metadata refresh from live AI session ids including Antigravity conversation ids, Claude transcript paths, and Codex rollout log cwd matching/ambiguity skips, candidate discovery, config path derivation, popup preview read-models, and pure state rules including preview, tag, and lifecycle stores.
|
|
35
79
|
- `make test` also covers GitHub Release updater resource and integrity boundaries: bounded compressed responses, decompressed tar streams, total and per-file regular bytes, entry counts, required SHA-256 asset digests, release-host/redirect allowlisting, scratch cleanup, and no atomic replacement after rejection.
|
|
36
80
|
- `make test` also freezes Doctor schema-versioned plain/JSON fixtures, exact text/JSON row and section projection parity, shared-inventory parity, default-versus-verbose detail ownership, projected exit semantics, Phase 2 ordered runtime/log typed findings (backend, bounded socket probe/output, bounded regular generated-config reads and digest drift, state/log/journal permissions, non-regular/symlink/oversize rejection, Windows ACL privacy uncertainty, and bounded safe errors), exact removed-flag migration errors, typed display-only remediation, raw path/socket/routing/message/config/argv negative coverage, support-report scalar-array allowlisting and schema compatibility, and the strict no-installer/no-migration/no-operational-journal write or repair boundary across the full flag matrix.
|
|
37
81
|
- `make test` also covers resume-title cleaning at the shared Claude/Codex/Antigravity choke point: known Claude command, local-command, task-notification, and system-reminder scaffolding is discarded so discovery falls through to the first real prompt, while inline `<`, leading HTML, and custom-element prompts remain intact.
|
|
38
82
|
- `make test` also covers the hardcoded usage HUD manual refresh key, full enabled-adapter collection through the existing throttle/backoff policy, cooldown no-op, cached popup rerender, and unchanged click/`u` cache-only behavior.
|
|
83
|
+
- `make test` also covers usage collection-failure visibility: Claude/Codex/Antigravity adapter tables for one, several, and all rows failing field validation plus an empty array, asserting the surviving snapshot contents, the exact bounded warning string (count + row-index/field reasons, capped at five with `(+N more)`), and negative assertions that a skipped row is never fabricated as `0%`, a zero reset, or a synthesized identity; the two shape failures that still abort a whole Claude collect (non-array `limits`, the 64-row cap) versus a partial collect that refreshes the healthy rows; privacy guards that no raw upstream value, reset timestamp, opaque bucket ID, or decoder message reaches a warning; `formatStatusUsage` staleness goldens for fresh/stale/very-stale with the fresh golden byte-identical to the pre-change output and the age indicator driven by `staleAfter`/`veryStaleAfter` alone; and the `usage.collect.outcome` operations-journal family — closed provider/failure schema with shape rejection, one row per failing provider, zero rows on success, once-per-run suppression of identical tuples, best-effort appends that never change the command result, and `projmux diagnostics log --component usage --tail N` rendering.
|
|
84
|
+
- `make test` also covers usage staleness at the statusbar width: a width-parameterized table over the budgets the generated tmux config can hand the renderer (100/120/140/160, the share a 120/140/160-191/240-column client leaves after the notify reservation) x fresh/stale(>10m)/very-stale(>1h) pins that a stale provider carries a marker at every one of those widths, that width pressure can no longer evict the `~`/`~~` staleness signal together with the purely cosmetic level-0 `(3m)` indicator, and that the three states stay mutually distinguishable at each width; one usage-budget table golden freezes the exact bytes (color escapes included) at 40/60/80/120/160 for all three levels and for both the three-provider fixture and the shape an actual install renders, its 120-cell rows are byte-identical to the `status-usage-w120-*.golden` files it replaced, and the two narrow budgets get their own test that pins the marker as present at 60 and the `~~`/`~` collapse under hard truncation at 40 as a ladder limitation rather than a budget one; and a fresh-state parity golden generated by the pre-change tree (98ec3b1) across widths 0/40/50/60/80/100/120/160/200 proves a healthy install is repainted at no width, backed by a direct assertion that the stale-only tiers collapse byte-exactly onto their neighbours when nothing is stale. The plain `~`/`~~` marker the colorless text tiers now emit is asserted colorless and confined to providers that opted into the age signal.
|
|
85
|
+
- `make test` also covers the statusbar row-0 width budgets: the generated tmux config derives both `--max-width` arguments on `status-format[0]` from `#{client_width}` instead of the former hardcoded 80/120, splitting the row as notify=min(client_width/2, clamp(client_width-140, 20, 80)) and usage=client_width-notify, reserving notify's measured 20-cell floor rather than its 80-cell design cap so a 191-column client gets 140 usage cells instead of the 111 PR #624 left it, so a miniature tmux-format interpreter — modelled on measured tmux 3.6 behaviour, including that a bare `#{<:a,b}` is a string comparison and only `#{e|<:a,b}` is numeric — evaluates the emitted formats against the widths measured on a real server, and pins that the two budgets sum to exactly the row at every width from 2 to 400, that neither segment is ever budgeted to zero (which `--max-width` reads as unbounded), that notify keeps exactly its historical 80 on every row at least 220 wide and is never squeezed below its 20-cell reservation on a row that can host it, that the usage budget is monotone in the client width and reaches the old 120 constant already on a 140-column terminal, that it never comes out below min(client_width-20, 120) at any width (the corrective regression guard PR #624 failed), and that it clears the measured 124 cells Claude's weekly bar needs at the reported 191-column width and first does so at 144, that every nested conditional uses the fail-safe numeric `e|<` form and the innermost false branch is the literal 80 so an unevaluable comparison degrades to the historical reservation, and that neither budget is a literal cell count; a product-shape usage fixture pins that the old 120-cell budget dropped Claude's weekly bar and that the second-bar tier returns at 124 cells with the staleness marker intact; and the generated-config digest goldens for the fallback theme and every preset move together with the one intended line.
|
|
86
|
+
- `make test` also covers the usage segment's element-priority degradation: `usageShedOrder` in `internal/app/usagecmd/usage.go` is the single definition of the drop order (cosmetic age text, then stale age text with the `~`/`~~` marker kept, then a provider's secondary window bar, then bars segment-wide, then long labels), per-provider rules run tail-first over the canonical provider order, and `docs/statusbar.md`'s `Usage element drop order` section is read by the test rather than duplicated so the two cannot drift; a width-sweep table pins the exact element set every fixture renders at 40/60/80/100/120/160/200 for three shapes — the installed shape, plus two shapes where more than one provider is eligible for the per-provider rules, which is the only way to tell element-priority degradation apart from the whole-segment `first tier that fits` ladder it replaced (at 120 cells the dual-window shape now renders 118 cells keeping Claude's second window and shedding only Codex's, where whole-segment selection drew 92); the ordering guarantees are asserted as width relations derived from the renderer rather than at hand-picked widths, so an age indicator is always shed at a strictly wider row than any official window bar and the `~`/`~~` marker outlives every official window bar; every reachable shed state is walked directly to prove no step removes a provider, its official window (5h, otherwise weekly), or its staleness marker, and that each step strictly narrows the segment; and a wide-width parity golden generated by the pre-change tree (`main` 6dfed76) plus the unchanged `status-usage-budgets.golden`, `status-usage-fresh-widths.golden` and the three staleness goldens prove a row wide enough to shed nothing is byte-identical to what whole-segment selection produced.
|
|
39
87
|
- `make test` also covers Settings > AI Settings > Enabled agents Phase 0 config behavior: missing config enables Claude, Codex, and Antigravity, unknown saved provider names are ignored without disabling known providers, Settings toggles persist Claude/Codex/Antigravity only, shell/selective are absent from enabled-agent rows, and a saved default split mode warns when its provider is disabled.
|
|
40
88
|
- `make test` also covers the Settings information-density/feedback contract: compact About producers and removed static-guide negative guards, canonical `setup` / `setup terminal` / read-only `doctor` destinations, single-source no-project guidance with project-context action preservation, Appearance/Theme/About ownership copy, and popup-visible passive mutation success/failure/validation feedback with replacement/clear and rendered-entry reachability guards. Dedicated Welcome, key-capture/probe/diagnostic, and read-only viewer outputs remain outside generic mutation feedback.
|
|
41
89
|
- `make test` also covers native Alt-1 sidebar `Sidebar:KillSession` mutable refresh: the action kills through the focused-session safety path, keeps the native picker session open, refreshes rows and preview with `picker.Action.Mutate`/`DeferredUpdate`, and preserves the previous-live-session guard.
|
|
42
90
|
- `make test` also covers Notify sidebar pane-grouped read-model rows and interactions: collapsed pane inbox group construction, fixed three-line group cards with stable project/provider, topic/context, aggregate metadata, and latest-preview slots including topic-with-project cases, child-count badges that match expandable child rows without rendering `+0`, childless group headers without strong fold affordance, selected/expanded marker-only row shape changes, duplicate label/preview reduction, worst-severity aggregation, inactive/gone group display and child-count rendering, pane-less fallback grouping, compact newest-first child event rows with warn/critical severity preservation, Right/Left fold mutation plus childless Right no-op refresh, folded and expanded live group Enter focus+ack with mixed-severity critical rows, inactive-but-routable group Enter focus+ack, gone group Enter cleanup without focus including critical rows, target-gone race cleanup, transient focus-failure no-ack refresh, child Enter focus/ack preservation, explicit group acknowledgement including mixed-severity critical rows, and grouped deferred refresh output with expanded-state pruning.
|
|
91
|
+
- `make test` also covers the installed-surface coherence contract: localized Session State summaries and Project Picker Back/open guidance; single-label Resource search plus disabled empty shared-bucket feedback; en-US/ko-KR Sessions row/preview labels with the concise open/close footer visible in actual 80x24 projmux and 112x30 daylight native frames; Notify empty read-only close-only chrome; and INFO/WARN/CRIT Clear All confirmation with Esc/Cancel no-write and explicit confirm feedback.
|
|
43
92
|
- `make test` also covers the AI provider metadata registry for Claude/Codex/Antigravity launch providers: registry-derived enabled-agent defaults and ordering, Settings enabled-agent rows, AI picker visibility for disabled providers, ambient usage model scope derivation for currently registered adapters, hook diagnostic provider metadata, Antigravity session-state support metadata, and explicit diagnostics for disabled providers.
|
|
44
93
|
- `make test` also covers the Antigravity v1.1.12 hook contract: authoritative CLI `--event` selection with legacy payload fallback, sanitized camelCase common/invocation/post-tool/Stop fixtures, empty/absent/populated `workspacePaths` handling with inherited-pane-first attribution, explicit-error-centric Stop severity including unknown-reason diagnostics, the official five-event catalog with disabled permission-changing `PreToolUse`, and valid non-permission-changing hook response JSON.
|
|
45
94
|
- `make test` also covers the Antigravity v1.1.12 statusline bridge: official stacked managed-object golden, settings install/reinstall/remove byte and mode preservation, custom-command conflict and malformed/symlink/permission preflight, empty custom stdout, official snake_case identity/agent/confirmation/context-token/quota fixture parsing, busy/quiet state mapping including Stop → late busy → idle completion preservation and next-PreInvocation reset, stable approval dedupe identity, structured conversation-local context sidecar writes with the legacy string-percent fallback retained as private hook/notify diagnostics, opaque quota bucket ordering/identity and collision guards, remaining-fraction validation/conversion, independent absolute/relative reset persistence, and context-only/empty/null/disabled/malformed quota degradation without context usage snapshots.
|
|
@@ -47,21 +96,25 @@
|
|
|
47
96
|
- `make test` also covers Codex rollout rate-limit window classification by `window_minutes`: old-schema primary 5-hour plus secondary weekly snapshots, new-schema primary weekly plus null secondary behavior, unknown-window skipping, and golden snapshot output for both rollout schemas.
|
|
48
97
|
- `make test` also covers AI semantic badge renderer aggregation for window-list, sidebar rows, switch window tabs, popup pane summaries, and pane-border topic badges using prompt-required > response-complete > in-progress priority while preserving blank no-state lanes, response-complete live badge consume on attention clear without idling action-required/progress badges, plus Settings > Appearance AI badge style selection for dot/emoji/off pane-border, Alt-1 sidebar window/preview tabs, and tmux window-status compatibility with dot as the persisted/config fallback.
|
|
49
98
|
- `make test` also covers AI semantic badge Phase 3 theme-role hardening: `@projmux_ai_badge_kind` storage values and aggregate priority stay unchanged, `minimal` remains a read-time alias for the `off` badge style, progress/success/action-required badge roles stay distinct, permission/input status badges do not use critical red, and critical notify queue severity does not drive live AI status badge colors or desktop notification urgency.
|
|
50
|
-
- `make test` also covers keybinding surface tier catalog rules, action-centered `keymap.toml` `keys = [...]` multi-alias parsing/writing, quoted internal `Surface:Action` tables, legacy popup action ID aliases, canonical popup toggle names, AI split popup-vs-direct action labels, generated tmux config multi-alias rendering, global/direct conflict detection, surface-scoped native picker command conflict detection, Settings Keybindings list/search/detail surface-aware picker-local labels, compact action-list state copy, flat
|
|
51
|
-
- `make test` also covers known retired live no-prefix cleanup for the old `C-t` pane-label binding: cleanup renders before current binds, explicit current `C-t` reassignment wins, repeated apply is byte-idempotent, and `keymap
|
|
99
|
+
- `make test` also covers keybinding surface tier catalog rules, action-centered `keymap.toml` `keys = [...]` multi-alias parsing/writing, quoted internal `Surface:Action` tables, legacy popup action ID aliases, canonical popup toggle names, AI split popup-vs-direct action labels, generated tmux config multi-alias rendering, global/direct conflict detection, surface-scoped native picker command conflict detection, Settings Keybindings list/search/detail surface-aware picker-local labels, compact action-list state copy, flat single-key/sequence action detail rows, key detail remove/test/replace rows, one visible Add binding flow, and one typed binding surface; the unified native recorder's 0–4 stroke reducer, length-driven single-versus-sequence save, empty Enter/Backspace no-op, last-stroke pop, Esc zero-mutation cancellation, four-stroke cap, continuous native byte-stream comma draft rendering with canonical space-form results, conflict retry, and one-reader/no-event-leak lifecycle; capture/typed comma-or-legacy-space normalization and byte-identical save/apply output, atomic single↔sequence replacement, comma list/detail/diagnostic display with space route/disk/runtime parity, and negative guards against the retired Add sequence, Record next stroke, selectable stroke-remove, and Sequence Editor authoring routes; the reserved Enter/Escape/Tab/Backspace/Delete/navigation base-key classifier across tmux aliases and modifiers, identical capture/typed/final-save rejection before schema/file/config/live-tmux writes, later-printable and first-stroke/raw/conflict parity, shipped PlainChord/PlainChords/PrefixChord/Sequences protected-action inventory, reasoned whole-editor read-only rendering, forged dispatch/direct-helper no-write, retained delivery tests/navigation, and existing schema-v2/default/runtime parse-render-bind parity; collapsed Troubleshooting entry copy, Settings delivery diagnostics that split logical key/raw bytes/tmux received key while distinguishing missing, ambiguous, adapter-needed, and delivered states, safe direct key pool and risky/reserved diagnostic-only copy, Projmux-owned Ghostty/Windows Terminal advanced delivery copy, raw escape/CSI-u/xterm modified/UserKey/UserSequence rejection from primary keymap storage, Labs compatibility redirect to the Keybindings root, existing macOS capture/add-key flows, unsafe raw capture, reset behavior, stale guide docs guards, and welcome/runtime footer copy that avoids hardcoded launch-key guides.
|
|
100
|
+
- `make test` also covers known retired live no-prefix cleanup for the old `C-t` pane-label binding: cleanup renders before current binds, explicit current `C-t` reassignment wins, repeated apply is byte-idempotent, and unrelated bindings remain unchanged. `TestTmuxApplyRetiresStalePaneLabelChordAndMigratesKeymapOnce` additionally pins that the first apply migrates the keymap to `schema_version = 2` and the second writes no bytes and leaves exactly one backup.
|
|
101
|
+
- `make test` / `make test-integration` / `make test-e2e`: keymap multi-stroke Phase 0 pins v2 `sequences` parse/render/merge, marker-only v1 migration with pre-v2 backup and rollback, repeat no-op bytes, deterministic two-to-four-stroke trie/table generation, shared prefixes across standalone/app actions, duplicate/strict-prefix/single-first-stroke conflict rejection, rejection of the undeliverable `C-m`/`C-i`/`C-[` spellings a terminal reports as `Enter`/`Tab`/`Escape`, unsafe and picker-local/command/output/default-sequence negatives, apply-ordered retire of the recorded roots/tables strictly before `source-file` (the generated config records that state but never removes it, because a `run-shell` loop is not ordered against a sourced file), native modified-stroke transport allowlisting without independent dispatch, and zero-write config/live failure ordering. The isolated real-tmux paths prove single dispatch for shared-prefix `mouse.toggle`/`window.create`, Escape and unknown continuation cancellation to `root` with zero raw pane input, terminal and native `send-keys -K -c` logical-stream parity, repeated apply idempotence, sequence removal cleanup, and unchanged single-chord behavior.
|
|
102
|
+
- `make test` / `make test-integration` / `make test-e2e`: keymap multi-stroke Phase 1 Settings authoring pins one shared 1–4 stroke Add/replace recorder, picker-local sequence exclusion, en-US/ko-KR locale and navigation golden reachability, shared reserved-key policy with first-plain rejection and later-plain acceptance, typed/captured canonical v2 keymap and generated-config byte parity, length-driven single/sequence add and atomic cross-kind replace plus strict-prefix conflict recovery, saved/prepared/running-session reporting including no-live-tmux recovery, native-macOS-on/off versus Linux/WSL logical authoring parity with transport differences confined to Delivery diagnostics, and zero keymap/generated-config/live-server mutation from navigation, cancellation, Backspace editing, or delivery tests.
|
|
103
|
+
- `make test`: Settings IA re-cut Phase 3 versioned keymap action-ID migration. The action catalog carries a `CanonicalID` beside the runtime `ID`, and `keymapActionManifest` derives the exhaustive old→canonical table from it, so `TestKeymapManifestCoversEveryCatalogActionExactlyOnce` fails on any action without a v1 spelling or any manifest row that resolves to no action, `TestKeymapCanonicalIDsAreUniqueAndDistinctFromLegacyIDs` rejects a canonical id that duplicates another action's canonical or legacy id, `TestKeymapRetiredIDsAreDisjointFromTheManifest` keeps retired ids out of the rename table and requires a remediation for each, `TestKeymapCanonicalIDsUseTheDottedSchema` pins the dotted lower-case shape and that the writer quotes it, and `TestKeymapDispositionIsExactlyOnePerTable` proves every table gets exactly one of canonical/coalesce/preserve-unknown/retired-remediation. Parser coverage adds the root `schema_version` marker with duplicate, forward-version and unknown-root-key refusals, and rejects an unquoted dotted table because that is a nested TOML table rather than a dotted key (`TestKeymapV1FileParsesAndRoundTrips`, `TestKeymapRejectsUnquotedDottedTableAndFutureSchema`). `TestKeymapMigrationPreservesEffectiveBindings` migrates a fixture carrying a custom multi-alias, `keys = []`, a transport-dependent additive alias, a legacy `plain` and a legacy `prefix` and requires the merged chord table to be identical before and after. The apply half is covered by `TestKeymapMigrationCoalescesIdenticalDualTables`, `TestKeymapMigrationRefusesConflictingDualTablesWithZeroWrites` (no keymap write, no backup, no tmux call), `TestKeymapMigrationPreservesUnknownTables`, `TestKeymapMigrationRepeatRunIsAByteWriteFreeNoOp` (unchanged bytes *and* unchanged mtime), `TestKeymapMigrationOnAbsentFileIsANoOp`, `TestKeymapMigrationBackupIsDigestNamedExclusiveAndReused`, `TestKeymapMigrationRefusesToClobberAForeignBackup`, `TestKeymapMigrationFailsClosedWhenTheDirectoryIsReadOnly`, `TestKeymapMigrationPreservesFileModeAndSymlinkTarget` (writes through the link, keeps 0600), `TestKeymapRollbackRestoresV0` and `TestKeymapRollbackRefusesACorruptBackup`. Convergence and the write boundary are pinned by `TestSettingsKeySaveConvergesAV0KeymapToV2`, `TestSettingsKeySaveAbortsWhenMigrationConflicts` (Schema/Saved/Prepared/Running-session stages), `TestTmuxApplyRefusesToApplyWhenTheKeymapMigrationFails`, `TestTmuxApplyNoReloadMigratesWithoutTouchingTheServer`, `TestConfigRenderReportsMigrationOnStderrAndWritesNoKeymap` (the preflight never reaches the generated artifact on stdout) and `TestReadOnlyRoutesNeverRewriteTheKeymap`, which drives the real dispatcher against an isolated HOME/XDG for `help`, `version`, `get`, `describe`, `agent usage`, `doctor --help`, both `config render` artifacts and `update apply --dry-run`. `TestUpdateDryRunPreviewsTheMigrationStageWithoutPromisingADiff` requires the preview to name the stage and leak no canonical id, and `TestPostUpdateApplyArgsAlwaysReachTheNewBinary` pins that `--no-apply` becomes `config apply --no-reload` so an installer suppresses the reload without skipping the migration. `TestKeymapAndRegistrySchemaMarkersAreIndependent` and `TestKeymapMigrationFailureLeavesTheRegistryUntouched` keep the keymap `schema_version` domain separate from the resource registry `apiVersion`/`schemaVersion` envelope, with separate backups and no shared transaction.
|
|
52
104
|
- Darwin native-key focused coverage includes portable physical chord parsing for Alt/Option, Control, Control-Option, Shift, letters/digits/navigation/function keys, `darwin && cgo` synthetic event-to-canonical-chord mapping for Option, Control, shifted letters, function keys, and arrows with unmatched/plain event pass-through, shared `keymap.toml` custom-action loading (including `M-a`), focused tmux client discovery, canonical `send-keys -K -c` dispatch through the existing root key table, native Settings Add key capture winning over simultaneous terminal text/error results after ignoring the activation Enter while the non-Darwin path preserves immediate terminal capture, default-on shell startup, `PROJMUX_NATIVE_KEYS=0`/`false` and Settings `[ui].native_keys = false` broker opt-out gates, broker direct no-op behavior, one-time pre-permission consent guidance, broker-only process replacement after an Accessibility wait so fresh macOS permission state is observed without restarting tmux, preservation of the direct no-server shutdown boundary while permission is pending, and an explicit Linux/Windows/no-CGO shell startup no-op boundary.
|
|
53
105
|
- `make test` covers the default picker key ownership across catalog, generated tmux config, terminal adapters, setup probes, and native popup close hints: `Alt-4` opens AI Resume as a guaranteed launch default, while `Alt-7` opens the AI split picker as its editable default.
|
|
54
106
|
- `make test` also covers canonical `projmux setup terminal` terminal detection, preview no-write, apply/backup, Ghostty candidate conflicts, Windows Terminal merge, config overrides, and symlink refusal/allow; removed top-level command dispatch/help negatives, canonical rejection and help absence of the removed legacy-only `--dry-run` flag, and setup remediation hints are asserted separately.
|
|
55
107
|
- `make test` also covers the direct split pane-id output contract: `--print-pane-id` parsing, explicit Claude/Codex/Antigravity/shell output as exactly one `%N` line, unchanged empty stdout without the flag, prompt argv-tail preservation, pre-launch rejection for saved-default/selective/resume picker paths, actionable missing/invalid tmux result errors, and the tmux `split-window -P -F "#{pane_id}"` contract.
|
|
56
108
|
- `make test` also covers welcome revisit policy: legacy welcome state remains readable without suppressing shell entry, Enter continues without storing release skip, `s` stores an update skip for the current latest tag when an update is available, source installs show disabled Upgrade guidance, stale update cache refresh is best-effort, Settings > About > Welcome opens a Settings-native viewer without pending state, and shell prompt display does not schedule a redundant attach popup.
|
|
57
109
|
- `make test` also covers transport-dependent app tmux defaults for pane/window navigation (`M-Left`/`M-Right`/`M-Up`/`M-Down` and `M-S-Left`/`M-S-Right`) while keeping visible default chords, allowing additive safe plain aliases that do not store or remove the transport defaults, and no UserKey/CSI-u generated fallback.
|
|
58
|
-
- `make test` also covers direct `projmux
|
|
110
|
+
- `make test` also covers direct `projmux create agent --provider <claude|codex|antigravity>` and `projmux create pane` launches, enabled-agent gating for disabled direct launches and disabled saved defaults, `--force-agent` as an explicit direct CLI-only override, selective picker filtering with all-disabled shell fallback guidance, resume picker routing/New delegation/zero-session fallback/Phase 1 fresh fallback contract, config-default preservation, extra args appended to resolved agent executables, managed pane metadata, title watcher startup, layout application, plain shell split behavior, selective picker delegation, invalid direct-agent usage errors, and regressions that direct concrete-agent and saved-default splits create a new pane without probing existing AI pane metadata or selecting an existing pane, including when launched from the current AI pane.
|
|
59
111
|
- `make test` also covers managed Antigravity hooks integration in an isolated home: named-entry install/dry-run/remove/idempotency, byte-preserving unmanaged JSON edits, explicit four-event absolute commands with no `PreToolUse` permission policy, valid non-blocking stdout fallbacks, conflict/malformed/symlink/permission diagnostics, provider registry/doctor/Settings install-remove-dry-run guidance, PreInvocation thinking/busy state, quiet PostInvocation/PostToolUse bookkeeping with tool-error diagnostics, and Stop decision/notify behavior.
|
|
60
|
-
- `make test` also covers Settings rendered-entry reachability across root/section/detail builders with a closed owner-loop table, handlerless-value rejection, passive info/disabled Enter no-op behavior, `send-noti` visibility in Hooks, no
|
|
112
|
+
- `make test` also covers Settings rendered-entry reachability across root/section/detail builders with a closed owner-loop table, handlerless-value rejection, passive info/disabled Enter no-op behavior, `send-noti` visibility in Hooks, no retired Project recipe or Effective merge route/catalog/i18n residue, AI/Labs view-first detail rows, Appearance Path/Git/Notify icon direct off/symbol/emoji preview selection with no Change page, Notifications root/Desktop notifications/Delivery sources relocation, removal of standalone queue/hook-override rows, `PROJMUX_NOTIFY_HOOK` state merged into Delivery sources, localized Korean Desktop notifications root/detail chrome without visible English residue, Delivery sources command-row clipboard copy, and Labs limited to Live system resources plus overview-first Project Hooks while legacy picker env/file values remain native-compatible.
|
|
61
113
|
- `make test` also covers the macOS/Linux/WSL live resource status Lab: default-off and atomic saved-value persistence, direct Labs on/off mutation plus live tmux option update, generated app/standalone conditional placement between git and clock for both Lab modes, independent CPU 70/90 and memory 75/90 warning/critical boundary classification, mixed-severity per-metric tmux style runs without visible severity words, secondary-style unavailable values without severity leakage, fixed four-column percent slots and invariant metric/segment visible widths across nil/0/9/15/69/70/74/75/89/90/99/100 under default/custom themes, light/dark semantic-role rendering, Linux `/proc/stat` first/delta/reset/malformed/overflow and stale-reference handling, Linux `/proc/meminfo` `MemAvailable` semantics, macOS native Mach CPU tick and free/inactive memory sampling, 0–100 clamping, atomic private sample-cache writes, and compact unavailable rendering.
|
|
62
|
-
- `make test` also covers AI desktop notification dedupe precedence (env override > Settings saved value > default), Desktop notifications mode persistence through `desktop-notify-mode`, saved-config precedence over live tmux options, `projmux
|
|
114
|
+
- `make test` also covers AI desktop notification dedupe precedence (env override > Settings saved value > default), Desktop notifications mode persistence through `desktop-notify-mode`, saved-config precedence over live tmux options, `projmux config apply` regeneration of `@projmux_desktop_notify_mode`, configured dedupe-window collapse/send behavior, Settings > Notifications AI dedupe preset/custom rows, explicit notify focus consume rules for selected critical rows and older same-pane non-critical AI cleanup, preservation of critical/permission/stop-failure/external/git/k8s rows during bulk cleanup, `projmux internal focus --uri` compatibility-input queue consume, and attention clear paths that do not ack the queue.
|
|
115
|
+
- `make test` also covers the two-state desktop notification contract: `NormalizeDesktopNotifyMode` accepting only `off`/`notify` while reading retired `raise`/`auto-raise`/`autoraise` literals as `notify`, per-source legacy-alias resolution that keeps env > saved file > tmux option precedence instead of falling through, a platform-neutral `notify` default including WSL + Windows Terminal, saved/tmux-applied values restricted to `off`/`notify`, Settings > Notifications > Desktop notifications offering exactly `Off` and `Notify` with no `Raise` row/description/search keyword in English and Korean, WSL Toasts carrying no `launch`/`activationType="protocol"` payload and writing no `projmux://` protocol-handler registration, and `projmux focus` never dispatching a host-window focus adapter in any mode.
|
|
63
116
|
- `make test` also covers AI hook runtime action precedence over catalog defaults, runtime quiet for known Codex notify events, runtime notify for known Claude quiet events, generic in-app-only notify rows for known Codex hook events without specialized handlers, suppression of desktop notification and `send-noti` dispatch on that generic path, separation of runtime hook action from catalog install events, Settings > Notifications hook quiet policy display/write behavior without external install/remove execution, hook desktop notification payload parity with the in-app queue text across the shared OS notification payload, normal/transient OS urgency and expiration for critical AI queue rows, and dormant title/capture fallback gating once a pane is hook-active.
|
|
64
|
-
- `make test` also covers Settings > Session State as global settings-only UI with default-off auto-save, Sidebar startup picker relocation/compatibility, and no window/pane tree, Settings > Project > Session State project-derived identity plus project auto-save override/effective source rows and distinct Save latest snapshot / Save named snapshot labels, closed-project save disabled reasons, named snapshot portable path conversion, project/global auto-save precedence, Projects > Sessions > State read-only latest/named snapshot overview with window/pane cwd/recipe/agent-resume health, user-facing
|
|
117
|
+
- `make test` also covers Settings > Session State as global settings-only UI with default-off auto-save, Sidebar startup picker relocation/compatibility, and no window/pane tree, Settings > Project > Session State project-derived identity plus project auto-save override/effective source rows and distinct Save latest snapshot / Save named snapshot labels, closed-project save disabled reasons, named snapshot portable path conversion, project/global auto-save precedence, Projects > Sessions > State read-only latest/named snapshot overview with window/pane cwd/recipe/agent-resume health, user-facing canonical snapshot status/save/delete/restore actions including explicit manual save bypass of disabled autosave and agent resume status/confidence preview, and Project open sidebar startup coverage for Session State opt-in `Start project`, default-off empty creation, Latest snapshot, Named snapshot, Empty session, Back, saved-at row metadata, existing-session skip, startup-before-trust ordering, detached sidebar open continuation before client-scoped separate trust popup handoff without sidebar inline trust UI, trust approve continuation, and trust deny/cancel no-session sidebar refresh behavior.
|
|
65
118
|
- `make test` also covers `projmux shell` usage without startup selector flags, project-context default target lookup from `PROJMUX_CWD` or nearest project marker, explicit `--session` separation from project-derived defaults, and direct empty attach behavior without shell startup picker/replay.
|
|
66
119
|
- `make test` also covers pane identity separation and projection: canonical `rename-pane-label` prompts with `pane label:` initialized only from the current label, Enter confirms, empty Enter clears, and native Esc cancels; unchanged Ctrl-Shift-M default and Settings expose only `rename-pane-label`, while stale `[bindings.rename-pane-topic]` keymaps fail with an exact `[bindings.rename-pane-label]` replacement. AI topic set/clear keep existing topic/manual ownership, no raw-title action is exposed, and pane border/window tab/popup/sidebar/recent-window resolve user label → agent AI topic → known shell → raw title.
|
|
67
120
|
- `make test` also covers session snapshot pane identity capture, old/new decode, and replay field-matrix contracts: `Pane.Label`, raw title, recipe topic/manual ownership, startup fields, and agent/resume metadata stay separate; old snapshots leave label and ownership absent without equality inference; tmux creation-returned pane ids are the replay targets; and agent direct-start never copies a saved topic into the raw title.
|
|
@@ -70,10 +123,10 @@
|
|
|
70
123
|
- `make test` also covers manual Session State Save snapshot and restore dry-run preview actions, title-first non-agent pane preview labels with legacy snapshot fallback, agent pane health-first bounded rows that keep status/confidence/source ahead of the full resume id while retaining id/title in the unbounded model, missing-snapshot messaging, and the absence of the removed statusbar State shortcut.
|
|
71
124
|
- `make test` also covers legacy named-snapshot storage compatibility for `.projmux/layouts/*.toml`, supported interpolation validation, malformed-file list warnings, portable conversion helpers, dry-run conversion to the session-state restore preview with source labels, missing current-session failure, destructive live replay helper behavior with fresh/internal source marking and fresh saved-snapshot cleanup, and the session-state live replay helper that stages windows, moves them by tmux ID, and removes extra live windows.
|
|
72
125
|
- `make test` also covers the project-local executable artifact trust boundary for named snapshots: one-read exact-byte parse/hash reuse, SHA-256 allow-once/allow-always decisions, changed-byte and rename/replacement reauthorization, final-file and parent-component symlink rejection, config-absent and `PROJMUX_PROJECT_HOOKS=off` independence, non-interactive fail-closed behavior, commandless-layout compatibility, terminal-control escaping for layout names/descriptions/window names/agent topics/command previews, and deny/error paths that stop before restore, session/pane creation, or startup `send-keys`.
|
|
73
|
-
- `make test` also covers `projmux
|
|
74
|
-
- `make test` also covers `projmux
|
|
75
|
-
- `make test` also covers `projmux
|
|
76
|
-
- `make test` also covers `projmux
|
|
126
|
+
- `make test` also covers `projmux agent integrate codex` default hooks install/idempotence/dry-run/removal, compatibility legacy Codex notify mode install/idempotence, dry-run preview, unmanaged `notify = ...` conflict refusal, managed-block removal, catalog-driven Codex hook event installation with local override merging, nested inline Codex hook schema, `[features]` merge/preservation, preservation of unrelated Codex/Claude config and unmanaged hook entries, Settings Codex `/hooks` review notice and tested-version rows, and remove-all behavior for projmux-managed Codex blocks.
|
|
127
|
+
- `make test` also covers canonical `projmux internal agent-hook ingest codex-hook` event parsing, PermissionRequest critical queue rows with tool/action metadata, Stop info queue rows, UserPromptSubmit busy/no-queue behavior, pane-level semantic badge kind writes that keep permission, response complete, and in-progress states distinct, quiet/no-notify diagnostics for non-firing Codex hook events including override-added catalog events, cataloged hook notification body formatting, hook-active pane marking, topic preservation without hook candidate writes, and mutable resume metadata writes for `@projmux_ai_resume_id`, source, and updated-at.
|
|
128
|
+
- `make test` also covers `projmux agent integrate claude` user-level Claude Code hook settings install/idempotence, dry-run preview, unmanaged projmux ingest command conflict refusal across all settings events, managed-command removal by marker even for stale events outside the current catalog, preservation of unrelated settings/hooks, catalog-driven Claude hook event installation with local override merging, and managed wiring for the 29 Claude Code 2.1.140 events in the embedded default catalog.
|
|
129
|
+
- `make test` also covers canonical `projmux internal agent-hook ingest claude-hook` core and extra Claude Code hook ingest for event parsing, transcript fallback, cataloged hook notification body formatting, permission summary formatting, UserPromptSubmit busy/no-queue behavior, Notification severity/text mapping, pane-level semantic badge kind writes for permission, input, response complete, and in-progress states, StopFailure/TeammateIdle text/severity/metadata mapping, SubagentStop quiet/no-notify diagnostics, unknown future-event quiet fallback, hook-active pane marking, topic preservation without hook candidate writes, mutable resume metadata writes for `@projmux_ai_resume_id`, source, and updated-at, and Claude transcript path preservation.
|
|
77
130
|
- `make test` also covers the Globalization Phase 0 English baseline for AI desktop notification summaries/bodies and hook-ingest queue text while preserving agent names, tool names, commands, paths, and provider payload values as literals/data.
|
|
78
131
|
- `make test` also covers the Globalization Phase 1 message catalog foundation: locale resolver priority and normalization, `ko-KR` to `en-US` fallback, missing fallback-key errors, `en-US` completeness for foundation keys, and plain-text versus ANSI/tmux-styled fragment API separation.
|
|
79
132
|
- `make test` also covers the Globalization Phase 2 formatter foundation: compact/full relative age and duration formatting, locale-specific just-now text, notification count plural/count preservation, list joins that preserve payload items, status token and target label localization, terminal cell-width measurement/truncation, and ANSI/tmux style wrappers treated as zero-width.
|
|
@@ -83,25 +136,30 @@
|
|
|
83
136
|
- `make test` also covers the Globalization Phase 4 Settings and popup guidance migration: `en-US`/`ko-KR` Settings root title/chips/rows/footer rendering, native picker search/empty/footer rendering without overflow, Settings row padding by terminal cell width, shell welcome guide catalog rendering, and long Korean ANSI/tmux-styled guide truncation safety while preserving key/command/path literals.
|
|
84
137
|
- `make test` also covers the Globalization Phase 5 locale settings surface: `PROJMUX_LOCALE` > global `[ui].locale` > `LC_ALL` > `LC_MESSAGES` > `LANG` > `en-US` priority, Settings > Appearance > Language / Locale row/detail visibility, `auto` current-locale/source display, unsupported locale fallback warnings, global config writes, and preserved command/config/env/path literals.
|
|
85
138
|
- `make test` also covers the Globalization Phase 6 governance guard: Go string-literal audit classification for hardcoded Korean candidates, English user-facing candidates, and ignored literal/data/debug examples; no unapproved runtime Korean literals outside catalog/formatter/test fixtures; `en-US` coverage for every embedded default catalog key; and required `ko-KR` coverage for migrated notify, Settings, picker, welcome, update, and help surfaces.
|
|
86
|
-
- `make test` also covers `projmux
|
|
87
|
-
- `make test` also covers `projmux
|
|
88
|
-
- `make test` also covers
|
|
89
|
-
- `make test` also covers
|
|
139
|
+
- `make test` also covers `projmux agent integrate tmux-bell` dry-run/install/remove tmux command planning, managed `alert-bell` hook append/idempotence/removal, preservation of unmanaged bell hooks, and canonical `projmux internal agent-hook ingest bell --pane` queue push/metadata/dedupe behavior for non-AI-managed panes.
|
|
140
|
+
- `make test` also covers upgrade-safe managed ingest producer convergence: fresh Codex/Claude/Antigravity hooks, Antigravity Statusline, and tmux bell writers use `projmux internal agent-hook ingest`; marker-owned 0.10.1 fixtures migrate transactionally while missing and unmanaged providers remain untouched; dry-runs show every target and old→canonical command; repeats perform zero file/tmux mutations; later-provider conflicts preflight before any write; injected Antigravity second-file and tmux Nth-command failures restore original bytes, options, and unrelated hooks; `config apply --no-reload` migrates files without live calls; and normal apply targets the requested exact `-L` socket.
|
|
141
|
+
- `make test` also covers `projmux diagnostics agent-hook` tail/path rendering and bounded JSONL log trimming for ingest diagnostics.
|
|
142
|
+
- `make test` also covers the Phase 0 operational diagnostics foundation: closed safe-event schema, control/length/home sanitization, lossy stable top-level error messages with dynamic pane/title/body/transcript/config-value exclusion, exhaustive allowlisted top-level/multi-mode command classification including direct-help and explicit dry-run success exclusion with boolean `=false` safeguards, exactly-once state-changing/error outcomes with explicit zero-success/error-one coverage for the six automatic `internal agent-hook ingest`, attention arm/clear/window, session-state autosave, and recent-window record paths plus an explicit-mutation success regression, private permission repair, platform replace-existing bounded complete-record retention, corrupt-tail recovery, OS-owned inter-process lock identity/crash recovery and explicit 200 ms budget, concurrent short-process rotation, common text/JSON/tail/filter reader fixtures, and unchanged top-level runtime/usage/exitCoder output and exit semantics.
|
|
143
|
+
- `make test` also covers Operational diagnostics Phase 2 lifecycle adoption: the maintained explicit-mutation inventory (attach/current/kill/sessions/switch plus session-popup open, window recent, runtime prune, focus session switching, shell open-app, snapshot replay creation, popup-toggle cancel restore, and config apply); session create/attach/switch/kill and `config apply` start/outcome success/error tables; composite create-then-attach and prune-kill-then-attach failure-stage attribution while preserving one outer pair; shared run IDs and no duplicate top-level outcome; best-effort store/write failure injection; closed operation/code pairing; apply typed no-server versus generic runner failure classification; focus success sealing at the actual switch-client boundary; unchanged read-only/hot-path zero-success recording; typed no-write runtime health projection with latest-state and bounded failure-code semantics; Doctor runtime/log typed consumer reuse; and support-report raw socket/path/session/window/pane/name negative fixtures. `make test-integration` additionally runs real create/attach/switch/kill success/failure routing against a run-unique `-L` socket, validates exact lifecycle pairs and apply classifications without raw routing, and guards cleanup with the queried actual socket path beneath the run-unique smoke root.
|
|
144
|
+
- `make test` also covers Operational diagnostics Phase 3 Session State adoption: the closed outcome/operation/code/source/six-count schema; direct and popup manual save/delete, Settings latest/named save and current/project delete, deduplicated prune delete, and actual project-startup latest/named restore ownership; exact snapshot and item aggregates; error count omission; Settings feedback error capture; append-failure best-effort ownership; autosave session/config/source/interval/debounce/store/save/set-option failure ownership including quiet error-one and project on/off precedence over a broken global config, plus repeated autosave success/no-op zero-volume behavior; same-run coexistence with the runtime lifecycle pair; and seeded path/command/session metadata negative fixtures. `make test-integration` exercises manual save, autosave success/error, actual latest restore, and aggregate delete against the guarded run-unique tmux socket and isolated XDG root, including exact snapshot cleanup and raw metadata negative checks.
|
|
145
|
+
- `make test` also covers Operational diagnostics Phase 4 notify/focus adoption: the closed transition/disposition/provider/category/route schema and cross-family rejection; explicit notify enqueue ownership with queued/deduplicated/failed outcomes; secondary attention and nested prune-reconcile enqueue ownership isolation with no-change zero volume; external-hook, Linux, WSL Toast/fallback, disabled, unavailable, desktop-dedupe, and visible-pane delivery outcomes; one shared process recorder with identical-tuple hot-path coalescing; append-failure best-effort semantics; focus direct/queue/toast request classification with unresolved, notify-only, fallback, and focused outcomes; same-run coexistence with the existing `session.switch` lifecycle pair without a generic duplicate; unchanged `PROJMUX_FOCUS_DEBUG` output; and seeded summary/body/tag/group/title/path/UUID plus support-report negative fixtures.
|
|
146
|
+
- `make test` also covers Operational diagnostics Phase 5 AI watcher/ingest adoption: the closed provider/event-kind/result/failure schema, provider-specific kind catalogs, result/failure tuple compatibility, and cross-family rejection; watcher start plus pane-gone/hook-active terminal ownership, actual launch-failure classification, per-run tuple coalescing, and no per-poll records; Codex/Claude/Antigravity malformed, read, oversized, unmatched, unsupported-event, and route-error projection plus tmux-bell valid, blank, and pane-not-found coverage; zero common AI events for normal state/notify/known-quiet/deduped ingress while Phase 4 notify retains its transition; legacy `ai-ingest.log` producer, `diagnostics agent-hook`, bounded retention, and support count-consumer parity; append-failure best-effort ownership with no generic duplicate; and seeded prompt/tool/path/UUID/conversation/session/title negative fixtures for operations and support output.
|
|
147
|
+
- `make test` also covers Operational diagnostics Phase 6 resource adoption and legacy review: exact closed resource source/result/failure tuples and cross-family rejection; production app graph wiring through Resource Inspector lifecycle → tmux inventory/project discovery/procfs attribution; unavailable, partial, stale, collection error, and actual context-deadline scan-budget fixtures; normal sample/refresh zero volume, persistent-transition coalescing, silent recovery plus anomaly re-entry, and append-failure best-effort UI/CLI preservation; separate host-only status sampler zero ownership; operations text/JSON and error-only support projection with partial/stale omission; seeded CPU/MEM/PID/process/path/title/command/UUID/session/error text negative fixtures; common journal retention/rotation regression; and the file/surface legacy diagnostic inventory without breaking removal.
|
|
90
148
|
- `make test` also covers the Phase 1 explicit redacted support report: complete preview-before-write ordering, deterministic private archive entries and manifest schema/redaction metadata, Doctor schema-version-1 structural reuse with closed static diagnostic allowlists, strict no-repair bounded operations reads, config-presence-only and AI-ingest count-only projection, exhaustive seeded free-text/path/routing/content negative redaction, missing/corrupt/unreadable source reasons, collision/partial-temp safety, and report success/error exclusion from legacy-hook migration and operational outcomes.
|
|
91
149
|
- `make test` also covers welcome revisit policy: legacy `skip_version` readability without shell suppression, `s` Skip until next vs Enter continue, Settings > About > Welcome native viewer, best-effort shell update cache refresh, and attach-popup no-duplicate/no-op behavior.
|
|
92
150
|
- `make test` also covers `projmux quit` action-picker rows, cancel/close no-op behavior, explicit quit of only app-owned tmux runtimes marked by `@projmux_app=1`, missing/default runtime no-ops, dispatcher wiring, and `Settings > About > Quit projmux` routing through the same picker before any shutdown side effect.
|
|
93
151
|
- `make test` also covers the built-in semantic palette foundation: non-empty fallback truecolor/tmux tokens, distinct action/attention/AI/progress/danger roles, native picker chip/current/titlebar render strings including titlebar frame `surface` / `chrome_foreground` inheritance without separate overlay ANSI, statusbar git/notify/usage/settings palette regressions, attention/pane-border/popup/switch progress color guards, renderer-only lead-mode topic prefix styling, settings/trust/destructive row color guards, global-only theme resolver behavior for `global`/`fallback` source labels (project `[theme]` is not a source), preset fill, explicit token override, unknown-preset/invalid-color warnings that ignore only the global layer, and truecolor-to-tmux mapping with generated `xterm*:RGB` terminal feature support, semantic role map (`RenderRoles`/`ANSIRoles`) fallback byte-identity for non-background historical palette literals plus explicit-theme repaint of Tier A/B chrome/state roles while Tier C renderer-only literals stay fixed, split foreground behavior where legacy `foreground` fills `text_primary` and `chrome_foreground` but `text_primary` does not repaint frame/title/search/border/status chrome, Phase 6 public token (`progress`/`success`/`action_required`/`pane_active_bg`/`focus`) repaint of the tmux and ANSI roles with `action_required` kept independent of `critical`, default `projmux` background tokens pinned to terminal default without separate terminal preset variants, Phase 6b pane-body-vs-popup/status background separation where an explicit `background` repaints the inactive pane body, an explicit `surface` repaints popups/native frames, and an explicit `status_background` repaints only the bottom status bar, native popup-toggle `display-popup -s` body style propagation from the effective theme without touching global popup/shell/status styles, and Settings global theme editing with the merged Global/Effective view, directly selectable prefixed theme token rows, no legacy `foreground` row, no project theme editor, and no font keys.
|
|
94
152
|
- `make test` also covers Recent Windows Phase 0 state/model behavior: server-scoped file paths, missing/corrupt state policy with corrupt-file backup, MRU newest-first recording, same-window dedupe and promotion, default queue limiting, current-window exclusion, cross-session candidate retention, gone-window pruning against live window inventory, and label fallback rules that keep win/pane ids as debug fallback instead of the primary row label.
|
|
95
153
|
- `make test` also covers Recent Windows Phase 1 native picker behavior: `projmux window recent` empty-state messaging, cross-session candidate picker rows with descriptive project/session/window/pane command age metadata, pane summaries mirroring visible pane labels with AI topic and known-shell command precedence, four visible pane cells before compact `+N` overflow, window-only switching without pane restoration, switch-failure refresh/prune handling, and gone-window pruning before picker selection.
|
|
96
|
-
- `make test` also covers notify reconcile eviction policy: expired rows are removed only when their real tmux pane/session target is gone, expired live and unexpired gone rows remain pending, inventory failures skip target-based eviction, hard-cap overflow keeps the newest 256 rows, and
|
|
97
|
-
- `make test` also covers stale state cleanup policy: successful prune,
|
|
154
|
+
- `make test` also covers notify reconcile eviction policy: expired rows are removed only when their real tmux pane/session target is gone, expired live and unexpired gone rows remain pending, inventory failures skip target-based eviction, hard-cap overflow keeps the newest 256 rows, and runtime prune triggers cleanup through the reconcile hook after session kills.
|
|
155
|
+
- `make test` also covers stale state cleanup policy: successful prune, runtime stop, runtime sessions picker, and switch/sidebar session kills trigger best-effort preview-row cleanup; notify refresh publishing sweeps dead-PID sockets while preserving live-PID sockets; snapshot prune listing distinguishes dead sessions from old live persistent sessions without deleting either, explicit named deletion removes only selected snapshots, malformed snapshots remain preserved with a warning, and doctor documents the manual-only retention policy.
|
|
98
156
|
- `make test` also covers Recent Windows Phase 2/3/4 keybinding, popup, and runtime recorder integration: `RecentWindows:Open` owns the guaranteed `M-3` launch default, generated tmux config uses client-scoped `tmux popup-toggle recent-windows`, the popup body runs `projmux window recent`, generated tmux config installs background `window record` hooks for window and client-session changes plus first-use population without `session-window-changed`, `window record` snapshots current tmux socket/session/window/active-pane metadata into the socket-scoped store with escaped field parsing, repeated same-window record fires dedupe instead of growing entries, the queue remains bounded by `recentwindows.DefaultLimit`, Settings > Keybindings shows Recent Windows with the `M-3` default, setup probe text names Recent Windows, `SessionPopupToggle` no longer owns the guaranteed `M-3` default, and escaped tmux field separators are parsed for current/list window metadata.
|
|
99
157
|
- `make test` also covers the Linux resource-attribution Phase 0 contract: tmux-only typed socket/session/window/pane PID/TTY/current-path/project-anchor inventory without unsupported placeholder values; explicit project-anchor priority plus read-only current-path fallback through canonical pinned/root-child discovery, longest-root matching, outside/home exclusion, and linked explicit/fallback conflict handling; one-pass procfs stat/meminfo collection; PID+starttime reuse defense and SID ownership; first/invalid/logical-CPU-change unknown CPU; host-share/core-equivalent CPU and RSS/host-ratio memory; unique pane-to-window-to-project conservation; linked-anchor `Shared / ambiguous`, missing-anchor `Unassigned`, setsid escape, fast-exit/race/permission partial states; and explicit host remainder/overage without silent clamping. The opt-in `PROJMUX_RESOURCE_PROJECT_FALLBACK_SMOKE=1 go test -run TestResourceProjectFallbackTransientSmoke -v ./internal/integrations/tmux` test provides an isolated read-only fallback fixture, while `PROJMUX_RESOURCE_TMUX_SOCKET=projmux PROJMUX_RESOURCE_EXPECT_PROJECT_ROOT=/path/to/project go test -run TestResourceAttributionRealTmuxReadOnlySmoke -v ./internal/integrations/tmux` provides sanitized live-socket project-bucket/count evidence; benchmark commands and current measurements are maintained in [resource-attribution.md](resource-attribution.md).
|
|
100
|
-
- `make test` also covers the Resource Inspector Phase 1 vertical slice: immediate non-actionable warming chrome; Project → Window → Pane → read-only detail hierarchy with project/window `PANES n` and pane `PROCESSES n` projections; explicit attributed buckets plus the non-actionable Other summary; shared label → active-agent topic → interactive shell → raw-title pane identity precedence with reused `Process <PaneCommand>`/PID-SID/Pane %N/TTY secondary and detail naming; resource-only Right/Enter forward, Left back with root no-op, all-depth Esc close, and complete Alt-Left action/hint removal; statusbar-parity CPU 70/90 and memory 75/90 exact semantic boundaries with severity-word-free values, unavailable `--`, lifecycle text, and resolved default/custom theme roles; Name-default Tab-computed CPU/Memory/Name ordering that remains stable across automatic refresh; stable-id search metadata plus refresh selection/query/breadcrumb/focus preservation and vanished-row nearest-neighbor behavior; fresh/stale/partial/unavailable/empty/gone/overage transitions with atomic refresh-progress/footer updates; an exact fixed five-row divider/Host/Attributed/Coverage/Sample bottom summary dock that remains independent of scroll/search and separate from the action footer, with bounded diagnostics on Sample only, minimum navigable list height, and no divider/border bleed; changed-row synchronized differential frames at 80x24 and wide en-US/ko-KR layouts; truthful RSS-sum rendering; immediate automatic pre-collection not-fresh progress with the last complete sample retained, gated non-overlapping two-second and Ctrl-R sampling, cancellation, and prior-sample disposal; direct CLI and client-scoped popup mode; no-default `Resources:Open` catalog/Settings/config/custom-alias close behavior; statusbar `resources` range/click byte-equivalence, Labs visibility independence, other-client isolation, and existing `projmux status resources`/window-click fallback regression.
|
|
158
|
+
- `make test` also covers the Resource Inspector Phase 1 vertical slice: immediate non-actionable warming chrome; Project → Window → Pane → read-only detail hierarchy with project/window `PANES n` and pane `PROCESSES n` projections; explicit attributed buckets plus the non-actionable Other summary; shared label → active-agent topic → interactive shell → raw-title pane identity precedence with reused `Process <PaneCommand>`/PID-SID/Pane %N/TTY secondary and detail naming; resource-only Right/Enter forward, Left back with root no-op, all-depth Esc close, and complete Alt-Left action/hint removal; statusbar-parity CPU 70/90 and memory 75/90 exact semantic boundaries with severity-word-free values, unavailable `--`, lifecycle text, and resolved default/custom theme roles; Name-default Tab-computed CPU/Memory/Name ordering that remains stable across automatic refresh; stable-id search metadata plus refresh selection/query/breadcrumb/focus preservation and vanished-row nearest-neighbor behavior; fresh/stale/partial/unavailable/empty/gone/overage transitions with atomic refresh-progress/footer updates; an exact fixed five-row divider/Host/Attributed/Coverage/Sample bottom summary dock that remains independent of scroll/search and separate from the action footer, with bounded diagnostics on Sample only, minimum navigable list height, and no divider/border bleed; changed-row synchronized differential frames at 80x24 and wide en-US/ko-KR layouts; truthful RSS-sum rendering; immediate automatic pre-collection not-fresh progress with the last complete sample retained, gated non-overlapping two-second and Ctrl-R sampling, cancellation, and prior-sample disposal; direct CLI and client-scoped popup mode; no-default `Resources:Open` catalog/Settings/config/custom-alias close behavior; statusbar `resources` range/click byte-equivalence, Labs visibility independence, other-client isolation, and existing `projmux internal status resources`/window-click fallback regression.
|
|
101
159
|
- `make test` also covers the Resource Inspector readable-layout Phase 0 contract: non-duplicating scope breadcrumbs; separate host, attributed, Other, diagnostic, list/detail, and contextual-action bands; primary identity separated from secondary context; vertically comparable CPU/Memory/count clusters; deterministic 80x24 and wide themed frame geometry without border bleed; en-US/ko-KR copy and explicit Unassigned/Shared stable-root parity; read-only pane detail without search, pointer, Enter, or sort affordances; explicit non-actionable Other/empty/vanished surfaces; populated/empty deferred action reconciliation without hidden sort; and resource-scoped directional hierarchy flow while collector, attribution, cadence, and client-scoped popup contracts remain unchanged.
|
|
102
160
|
- Current focused unit coverage also includes strict notify SOT behavior
|
|
103
161
|
(TTL does not remove rows, focus success and target-gone clicks ack,
|
|
104
|
-
reconcile reports inactive `queue-stale` rows), `
|
|
162
|
+
reconcile reports inactive `queue-stale` rows), `get notifications --live` queue/live explanations, notify sidebar
|
|
105
163
|
three-line grouped card rendering with child-count/fold semantics plus focus/ack/non-critical-clear/clear-all
|
|
106
164
|
actions, notify/statusbar/sidebar attention-vs-AI palette assertions including muted inactive/gone rows,
|
|
107
165
|
native picker-session-local `a` ack that refreshes the sidebar without
|
|
@@ -120,9 +178,14 @@
|
|
|
120
178
|
- Doctor focused unit coverage includes tmux required/stale behavior on every host, Windows `stty` skip behavior, and tmux bell fallback diagnostics.
|
|
121
179
|
- Shell focused unit coverage includes `projmux shell` routing to `tmux -L projmux -f <generated config> new-session -A -s <session> [-c <cwd>]`, generated tmux config callbacks, native key-broker platform policy, runtime overrides, and nested-socket guards.
|
|
122
180
|
- `make test` also covers npm retire/staging path canonicalization for the resolved projmux executable so generated tmux config and hooks never embed a `node_modules/.projmux-<hash>` directory, plus error-suppressed attention and rebalance-panes hooks.
|
|
123
|
-
- `make test
|
|
124
|
-
- `make test-
|
|
125
|
-
- `make test
|
|
181
|
+
- `make test` also covers the public config spelling: `projmux config edit [--get|--set <mode>]`, `config render standalone|app`, and `config apply` forward raw argv to their manual leaf handlers; flags, unknown tokens, streams, handler errors, and side effects stay on those handlers. `make install` and every update path emit `projmux config apply`, while generated plumbing uses only the hidden `internal` namespace.
|
|
182
|
+
- `make test` also covers Legacy CLI retirement Phase 2: the exact removed-public argv matrix returns action-aware replacement guidance with stdout/handler/pre-dispatch mutation zero; `attach project`, `focus project|window|pane`, `pin project`, and `prune project|snapshot` remain exact raw-argv forwards; removed pre-namespace internal tokens have no catalog or top-level handler and use root unknown-command exit 1. The hidden producer compatibility gate admits only the exact byte allowlist recorded in the retirement ledger; missing/future/custom events, different flag order, extras, the removed detailed-log route, and every other legacy AI argv are denied before handler reach, stdout, or migration. The maintained-doc scan rejects executable recommendations for every retired route outside explicit retirement/upgrading/historical records. Catalog/canonical/handler two-way audits, root/command-tree/reference goldens, the exact retired route set, preserved Shortcut/kind aliases, and generated producer scans close the topology and drift contracts.
|
|
183
|
+
- `make test` also covers the canonical manifest honesty audit: every canonical spelling resolves to a full executable path in the command tree, no canonical summary carries forward-looking vocabulary or any adjudicated-and-retired string, the two remaining target-state summaries (`delete pane`, `restore snapshot`) are pinned verbatim with a named owning track and must stay absent from every command-tree node, and the separate shortcut gaps are enumerated as a two-way diff so a future change cannot drop a mapping unadjudicated; config and workflow routes are also asserted to have no cardinality-matrix row because they resolve no resource set.
|
|
184
|
+
- `make test` also covers singular and plural kind spellings on the four resource verbs: `Route.Aliases` in `internal/cli/catalog.go` is the single declaration, `cli.CanonicalChildToken` normalizes an alias to its canonical token before `get`/`describe`/`delete`/`rename` dispatch, and the unknown-kind refusals are rendered from `cli.ChildSpellings` so an accepted spelling can never be missing from the list they print. `TestKindSpellingAliasesAreByteIdenticalToTheCanonicalSpelling` runs all 17 canonical/alias pairs -- including the two forwarded parity kinds per verb, whose forwarded argv is compared as well -- and requires identical stdout, identical stderr, and an identical error, with the canonical run required to succeed so an all-failing pair cannot satisfy byte-equality vacuously; `TestEveryManifestKindHasAParityCase` derives the matrix from the manifest so a kind added later cannot escape coverage, and `TestKindSpellingAliasesNeverReachAnotherRoute` proves each singular `get` alias answers its own inventory and is distinguishable from every sibling kind. On the manifest side `TestCanonicalKindSpellingsSurviveTheAliasContract` pins the canonical kind token of every resource-verb child so an alias can never replace a shipped spelling, `TestNoChildAliasShadowsACanonicalSpelling` walks the whole tree for alias/name collisions and duplicate aliases, and `TestResourceVerbsAcceptBothFormsOfEveryKind` asserts zero missing singular/plural combinations with `get pane`/`get panes` as the one enumerated divergent pair. That exception is the product decision the track recorded and is held by `TestGetPaneKeepsItsOwnRouteUnderBothSpellings` and `TestGetPaneSpellingIsUnchanged`: `get pane` stays the exact-one Pane read that owns `--current -o cwd`, `get panes` stays the 0..N inventory, and neither aliases onto the other. `rename` no longer special-cases the `agent` token by hand -- the manifest has no Agent child, so `agent` and `agents` both reach the ordinary refusal.
|
|
185
|
+
- `make test-integration` / `make test-e2e` / `make test-install-smoke`: suite containers still run with `--network none`, so `scripts/test-docker-run.sh` prefetches the checked-in module graph once per `go.sum` into a host-side Go module cache outside the repository and mounts it into the isolated run; `test/lib/smoke.sh` honors that inherited `GOMODCACHE` instead of forcing an empty run-local one.
|
|
186
|
+
- `make test-integration`: Docker-backed Linux integration smoke with real `tmux`, `git`, and `stty`; covers Doctor schema 2 missing/corrupt/permission degradation, runtime socket/config current/stale findings against a guarded run-unique `-L` socket, source byte/mode/mtime/inventory no-repair evidence, explicit support-report no-request/preview/private archive and Doctor-schema inspection, missing/corrupt/permission-denied source manifest reasons with no source-mode repair, preview-writer failure before output creation, collision byte/mode preservation and temp cleanup, tmux config render/install/apply including stale live `C-t` pane-label retirement, current `M-p` preservation, current `C-t` reassignment, repeated apply/keymap byte preservation, and unrelated live/current binding preservation, default-off/on live resource config plus two-sample procfs status rendering, notify queue CRUD against isolated HOME/XDG paths, private operational-log persistence/mode repair/readback/hot-path exclusion/best-effort write failure, and built-CLI propagation of a fake tmux `split-window -P -F "#{pane_id}"` result to `--print-pane-id` stdout. The generated config is also audited for the CLI internal-namespace relocation: it must contain the `internal status`/`internal statusbar`/`internal tmux` spellings and no `'<bin>' <route>` invocation of any of the 7 removed pre-namespace plumbing tokens; invoking any removed token directly is separately pinned to the root unknown-command contract. Root containers run the permission case through `runuser`+`nobody`; environments without that adapter take an explicit asserted skip instead of treating root chmod access as denial.
|
|
187
|
+
- `make test-install-smoke`: Docker-backed source install smoke; covers `make install`, atomic binary replacement, `config apply` against a live `projmux` socket, post-install notify queue initialization, the installed `~/.config/projmux/tmux.conf` carrying the relocated `internal status`/`internal statusbar` spellings and no pre-namespace `status`/`statusbar`/`tmux` invocation of the installed binary, and installed-binary temporary HOME/XDG support-report preview → explicit private archive → manifest/Doctor schema inspection with exact smoke-root cleanup.
|
|
188
|
+
- `make test-e2e`: Docker-backed real-tmux workflow smoke for session/pane setup, a direct shell `--print-pane-id` split whose returned `%N` handle is verified against the isolated live server, an attached-client `rename-pane-label` command-prompt flow covering current-label initial value, Enter confirm, native Esc cancel, empty clear, and AI topic/manual/raw-title non-mutation, app config sourcing, reply-state notify reconciliation, focus notify fallback, canonical `internal status notify` rendering with contextual project/state/agent badges, and an isolated attached-client `display-popup` Settings recorder flow against a temporary HOME/keymap: one Add binding recorder saves a single C-r after one confirm, Esc cancels another draft with zero mutation, the same still-open reader records visible `C-o,o`, pops/re-adds its last stroke with Backspace, writes canonical `C-o o`, applies the live root-table trie, renders comma-form detail, and removes the sequence without stale tables; stale retired picker env/file values remain inert, unchanged, and silent. The reused FIFO/attached-client Notify Clear All flow has command markers and queue JSON proving cancel no-write, INFO/WARN/CRIT confirm clear, and pane focus restoration. Host-only terminal, WSL, macOS, and GUI notification behavior remains outside Docker; see [docs/testing.md](testing.md).
|
|
126
189
|
|
|
127
190
|
## When To Update This List
|
|
128
191
|
- A feature moves between unit, integration, and e2e coverage levels.
|