4f52797
handoff: Fix countdown and extract model helper
Click to expand commit body
Cancel the countdown on any terminal input, not just "editable" keys.
Arrow keys and other navigation are escape sequences that
isEditableInput() explicitly rejected, so navigating the handoff draft
didn't stop the auto-submit timer.
Extract parseAndSetModel() into model-utils.ts to deduplicate the
model-parsing logic shared between the agent_end handler in index.ts and
the /handoff command. The shared helper also wraps pi.setModel() in
try/catch, surfacing failures as user-visible warnings instead of
unhandled promise rejections.
Amolith
created
4586179
handoff: Add countdown to tool-path handoff
Click to expand commit body
The tool-path handoff (agent calling the handoff tool) bypassed the
pause-to-edit countdown and sent the prompt immediately via
sendUserMessage. Replace that with setEditorText + startCountdown so
both paths give the user a 10-second window to review and edit the
handoff draft before it's submitted.
Set editor text before awaiting setModel to avoid a race where slow
model setup could clobber user edits.
Rename the package directory, npm package name, slash command, on-disk
paths, XML tags, and all internal references from "personality" /
"personalities" to "persona" / "personas".
All four packages used "*" for their pi SDK and typebox peer
dependencies, which accepts any version including ones with breaking API
changes.
Pin to >=0.65.0 for the pi packages (pi-ai, pi-coding-agent, pi-tui)
since the current code relies on APIs introduced in that release
(session_start event, AgentToolResult.details, SessionManager.open). Pin
typebox to >=0.34.0 as the Type.Object/Array/String/Optional API is
stable across the 0.34.x line.
Break the 776-line single file into four modules along natural
boundaries:
- prompt.ts: extraction system prompt, few-shot examples, tool schema,
and shared types (ExtractedQuestion, ExtractionResult)
- extract.ts: model resolution, tool call parsing, XML escaping
- QnAComponent.ts: full interactive TUI component
- index.ts: command/shortcut registration and extraction orchestration
No behavioral changes.
Break the 905-line single file into six modules along natural
boundaries:
- session-paths.ts: path utilities (getSessionsRoot,
getFallbackSessionsRoot, normalizeSessionPath, sessionPathAllowed)
- session-analysis.ts: extractCandidateFiles, extractLoadedSkills,
resolveExtractionModel
- handoff-extraction.ts: extraction prompts, tool schema,
extractHandoffContext, assembleHandoffDraft
- session-query-tool.ts: session_query tool registration
- handoff-tool.ts: handoff tool registration
- handoff-command.ts: /handoff command registration
- index.ts: wiring, event handlers, shared state, countdown logic
No behavioral changes. Each module has a narrow interface with the rest
of the system — shared state is threaded through callbacks rather than
module-level globals.
Escape <, >, and & in question text, user answers, and notes before
embedding them in pseudo-XML tags. Without this, literal angle brackets
in content could confuse model parsing of the <qna> block.
Wrap the done() callback in a finished-flag guard so only the first
completion takes effect. The loader.onAbort handler and the in-flight
extraction promise could both call done() on user cancellation,
producing a double-completion race.
Amolith
created
f83b5aa
handoff: Fix session_query signal and path checks
Click to expand commit body
The signal guard `if (!signal || signal.aborted)` treated a missing
signal as cancelled, preventing session_query from running when the SDK
passes no AbortSignal. Change to `if (signal?.aborted)` so only an
actually-aborted signal triggers cancellation.
sessionPathAllowed() returned true when sessionsRoot was undefined,
allowing any absolute path to pass validation. Flip the default to false
so queries fail closed when the sessions root cannot be determined.
Amolith
created
a099639
questionnaire: Guard empty options and dedup IDs
Click to expand commit body
When a question has no options and allowOther is false, the opts array
is empty but optionIndex is 0. Accessing opts[0].isOther crashes with a
TypeError on undefined. Add an early return when the selected option
does not exist.
Deduplicate question IDs at normalization time by appending _2, _3, etc.
to collisions. Duplicate IDs caused answer map overwrites where only the
last answer for a given ID survived.
Wrap all filesystem calls (readdirSync, readFileSync, writeFileSync,
unlinkSync) in try/catch with graceful fallbacks — return empty/null
instead of crashing the extension.
Validate the persisted personality name against listPersonalities()
before loading it. A tampered persistence file containing a path like
../../etc/something would previously be passed straight to readFileSync;
now it is rejected if not in the available list.
Amolith
created
e3b6594
personality: Lock system prompt at session start
Click to expand commit body
The old code injected a system-reminder custom message every turn after
the first, creating a persisted entry in the session file each time.
Long conversations accumulated dozens of personality blobs, wasting
tokens and cluttering session history.
Lock the personality into the system prompt at session start via the
ephemeral systemPrompt return from before_agent_start (never persisted,
same content each turn so provider cache stays valid). Mid-session
switches queue a single one-shot message instead of touching the system
prompt — once a conversation exists, its system prompt is immutable.
Fix ~15 type errors and 3 noExplicitAny lint warnings caused by SDK API
drift in the handoff extension.
- Replace session_switch/session_fork events with session_start (the
old events no longer exist in the SDK); use event.reason to distinguish
switch, resume, and fork
- Cast sessionManager to SessionManager instead of any for newSession()
- Type the context event handler properly instead of casting to any
- Change label from dynamic function to static string
- Add details property to all AgentToolResult returns
- Guard signal-possibly-undefined with optional chaining
- Accept string | undefined for apiKey in extractHandoffContext
- Handle getSessionFile() returning undefined in command handler
- Fix race condition: call newSession() before setting
handoffTimestamp so session_start clears stale values first
Amolith
created
bdcf05f
handoff: Fix lint in file-pattern extraction
Click to expand commit body
- Remove useless regex escape on closing paren
- Replace while/exec loop with for/matchAll to avoid assignment in
expression and implicit-any let
- Change trailing boundary group from consuming to lookahead so
adjacent files separated by a single space are no longer skipped
- Align EditorTheme.selectList with current SelectListTheme API
(selectedPrefix, selectedText, description, scrollInfo, noMatch)
- Replace non-null assertions on ctx.model and lastAssistantText with
captured locals after the early-return guards so closures see narrowed
types
- Add explicit fallback parameter to resolveExtractionModel instead
of asserting ctx.model inside the function
- Convert remaining string concatenations to template literals
- Remove unused private allQuestionsAnswered method
Code inside markdown headings can't be linked, so replace the linked
header style with plain code headings and shields.io NPM version badges
underneath.
Switchable agent personalities stored as markdown files, injected into
the system prompt. Includes a /personality command for interactive
switching and persistence across sessions.
Licensed under the Unlicense.
Multi-question interactive prompts with tab-based navigation, from Mario
Zechner's pi-mono examples. Changes from upstream:
- Added a free-text notes editor (press 'n') available on any tab
- Custom answers and notes are sent as a steering user message so
the model sees them as user content, not just tool results
- Added word wrapping for long question prompts via wrapTextWithAnsi
- Updated tool description to mention the notes feature
Licensed MIT per the upstream.
Interactive Q&A extraction from assistant responses with a custom TUI
for navigating and answering questions. Based on Armin Ronacher's answer
extension from agent-stuff, with several changes:
- Replaced responseFormat-based extraction with a structured
tool call (extract_questions), which models handle more reliably
- Rewrote the system prompt with detailed few-shot examples
including deduplication and standalone-question rules
- Changed model selection to prefer nemotron-3-super-120b-a12b
instead of codex-mini/haiku
- Added a notes editor (Alt+N) for attaching free-text context
alongside answers
- Added fallback extraction with current model when the preferred
model fails
Licensed Apache-2.0 per the upstream.
Context-preserving session handoff with LLM-based extraction of relevant
files, skills, and open items. Derived from Petr Baudis' pi-amplike
handoff and session-query extensions, substantially reworked with
structured tool-call extraction, auto-submit countdown, and an
integrated session query tool.
Licensed MIT per the upstream.
Amolith
created
d5bb747
Add monorepo scaffold with tooling and REUSE
Click to expand commit body
Bun workspaces monorepo for Pi extensions published under the @amolith
npm scope. Includes:
- Biome for linting and formatting (tabs, double quotes, 120-col)
- TypeScript for type checking (noEmit only, Pi loads .ts via jiti)
- mise tasks as thin wrappers around bun run scripts
- REUSE 3.3 compliance with per-file SPDX headers
- CC0-1.0 for ancillary files, code licenses per-package