journal: managed wrapper bootstrap, rename env var, two-branch resolver
Replace the ~/.local/bin/sol symlink with a managed POSIX shell wrapper
that embeds the journal path and the venv binary path as install-time
literals. The wrapper becomes the canonical setter for SOLSTONE_JOURNAL
on installed runs — services no longer carry a journal env key, and the
resolver's branch-1 reads SOLSTONE_JOURNAL set by the wrapper or by the
test autouse fixture.
Why this matters: the journal path needs one source of truth that
survives packaged installs (where there is no source tree to fall back
to) and tracks user reconfiguration cleanly. The wrapper does both —
sol config journal <path> rewrites it atomically under flock — and gets
the env-var coupling out of the service files where it didn't belong.
Resolver collapses to two branches: SOLSTONE_JOURNAL → source-tree
fallback (project root has both pyproject.toml and .git) → typed
SolstoneNotConfigured. Source labels become {"env", "source"}.
The env var is renamed from _SOLSTONE_JOURNAL_OVERRIDE to SOLSTONE_JOURNAL
across all 161 tracked files (1020 line hits) — clean break, no
backwards-compat alias.
Adds:
- think/install_guard.py: render/parse/atomic-write/flock helpers,
AliasState.FOREIGN, dual-OWNED state, --force, current/upgrade tokens
- think/config_cli.py: sol config show / sol config journal <path>
- think/utils.py: SolstoneNotConfigured, two-branch resolver
- think/service.py: services invoke ~/.local/bin/sol; no journal env
key in generated env blocks
- scripts/doctor.py: resolve_alias_target reads managed wrappers
- Makefile: current) no-op case in install-service
- Tests: install-guard wrapper round-trips, resolver branches,
config_cli show/journal, autouse fixture sentinel, service-file
shape
- Docs: docs/environment.md, AGENTS.md §3/§6/§8, docs/CORTEX.md, et al.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>