feat(pi-soul): configurable persistence, CLI flags, interactive picker#7
Open
titosemi wants to merge 11 commits into
Open
feat(pi-soul): configurable persistence, CLI flags, interactive picker#7titosemi wants to merge 11 commits into
titosemi wants to merge 11 commits into
Conversation
Add piSoul.persistence (global|session|none) and piSoul.autoLoad config read from Pi settings files. Add --soul and --soul-level CLI flags via pi.registerFlag. Add /soul status command. Emit soul:activated and soul:deactivated lifecycle events on pi.events bus. - shared/soul-config.ts: loadPiSoulConfig, ActiveSoulStore interface, GlobalFileActiveSoulStore, SessionActiveSoulStore, MemoryActiveSoulStore, isSoulClearValue, createActiveSoulStore factory - shared/package.json: export ./soul-config - extensions/soul.ts: replace local persistence helpers with store abstraction; add flag registration; rewrite session_start handler (all reasons: startup/new/resume/fork; skip reload); update /soul command (add status, events, store-based persistence) - tests/soul.test.ts: unit tests for all soul-config helpers (31 tests) - individual-packages/pi-soul/README.md: document config, CLI flags, /soul status, lifecycle events, companion extension pattern - CHANGELOG.md: document new features under [Unreleased] Missing config defaults to current behavior: persistence=global, autoLoad=true. No migration required for existing users.
Add three tests for the clarified autoLoad rule: - global+autoLoad=true → loads on startup ✓ - global+autoLoad=false → skips on startup ✓ - session+autoLoad=true → skips on startup (autoLoad only applies to global) ✓
…rites Config (persistence mode) lives in soul-config.json. Do not duplicate it in the runtime state file.
Also corrects autoLoad semantics description (only applies to global).
Add minimal hooks to soul.ts and put all new logic in soul-core.ts: - Config in soul-config.json (dedicated file, not settings.json) - Persistence modes: global, session, none (via shared/soul-config.ts) - --soul and --soul-level CLI flags - Interactive /soul picker with disclosure level selection - /soul status command - soul:activated / soul:deactivated lifecycle events - Powerline integration via ctx.ui.setStatus - autoLoad only applies to global persistence Existing soul.ts changes are minimal: ~60 lines of additions. All new logic lives in extensions/soul-core.ts (260 lines).
…n startup) TDD: updated test from 'skips autoLoad in session' to 'autoLoads in session+autoLoad=true with store entry'. Also updates docs and CHANGELOG.
- Fix success→info notify type, catch(error)→catch(error:any) - Fix sensor/actuator type parsing with explicit Record casts - Fix enum index type assertions - Add @ts-ignore for pre-existing AgentToolResult peer-dep conflicts - Add --experimental-test-module-mocks to npm test script - Convert tab indentation to 2-space to match upstream
…h to usage error
When selecting 'status' in the /soul interactive picker, the handler
returned { type: 'none' } which caused the caller to fall through to
the text-based usage/help message. Now the picker always returns
cleanly — the picker handles the interaction completely regardless
of the chosen action.
Adds a regression test verifying no 'Usage:' message leaks through
after selecting status in the interactive picker.
09eeac7 to
8f9ab2f
Compare
Contributor
Author
|
Hey 👋 bumping this — just squashed a bug where the interactive picker's status option fell through to the usage error.
58 tests, zero failures. No breaking changes — defaults match the original behavior exactly. Would love a review when you have a moment. Happy to address any feedback. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Tl;dr: you can now choose where your active soul is stored, activate one at startup with
--soul, and get a much nicer/soulexperience — while keeping everything backwards compatible.Here's what changed and why.
1. New config file
A dedicated config file to control where your active soul is stored and whether it auto-loads:
Auto-created with defaults on first extension load. No manual setup needed. You can also override per-project in
.pi/soul-config.json.Backward compatibility: if you don't add this file, the defaults match the original behavior exactly.
2. Three persistence modes
/new?global(default).active-soul.jsonsessionprocess.cwd()noneSession mode is handy if you switch between projects:
/soul davein project A,/soul irisin project B, and each keeps its own active soul. On/new, Pi restores the right soul for the directory you're in.3.
autoLoad— what it does per modeControls whether the persisted soul is auto-applied on fresh Pi startup.
globalmode +autoLoad: true→ loads the single active soulsessionmode +autoLoad: true→ loads the soul mapped to current project directorynonemode → ignored (no storage to load from)autoLoad: false→ no auto-load on startup (explicit/soul <name>or--soul <name>needed)/new,/reload,/resume, and/forkalways restore regardless ofautoLoadorpersistencemode — the soul was explicitly activated within this Pi process.4.
--souland--soul-levelCLI flagsFlags are processed before
autoLoad, so--soulalways wins. Handy for scripting or one-shot sessions.5. Enhanced
/soulcommand/soul status— shows what soul is currently active (name + level)/soul(no args) — opens an interactive picker to choose a soul, then asks for the disclosure level (1-3)The interactive picker respects terminal UIs that support
ctx.ui.select()— no UI, no picker, just the familiar text list.6. Lifecycle events
Companion extensions can react to soul changes:
This lets companion extensions (like Telegram autoconnect) react without polling.
7. Status bar
Pi's standard
ctx.ui.setStatus("pi-soul", displayName)API is called on activation and cleared on deactivation. The soul name shows in Pi's built-in TUI footer automatically. If pi-powerline-footer is installed, it also appears in the status bar — no config needed, the default preset includesextension_statuses.Breaking changes?
None. If you don't add
soul-config.json, the extension behaves exactly as before:persistence: "global",autoLoad: true(original upstream behavior).active-soul.jsonformat unchanged/soul <name>and/soul offwork identicallyHow the code changed
The approach was to keep changes to existing files as small as possible:
extensions/soul-core.tsextensions/soul.tsshared/soul-config.tsloadPiSoulConfig,createActiveSoulStore, persistence store classestests/soul.test.tstests/extension-soul.test.tsindividual-packages/pi-soul/README.mdextensions/soul.tswent from 1064 lines to ~1120 — the ~60 added lines are hooks that delegate tosoul-core.ts. An additional ~100 lines changed to fix 33 pre-existing TypeScript errors (sensor/actuator types, enum index types, error type narrowing, AgentToolResult peer-dep conflicts — all upstream issues surfaced by running tsc on the imported file). No reformatting or restructuring of existing logic.Tests
58 tests, 0 failures:
tests/soul.test.ts— config parsing, all three persistence stores, edge cases (malformed JSON, invalid values, file auto-creation)tests/extension-soul.test.ts— extension registration, session lifecycle (reload/new/startup), commands (status, off, interactive picker), lifecycle events, powerline status