Skip to content

Merge dev → main (automated)#2010

Merged
SorraTheOrc merged 27 commits into
mainfrom
release/dev-to-main-20260711204949
Jul 11, 2026
Merged

Merge dev → main (automated)#2010
SorraTheOrc merged 27 commits into
mainfrom
release/dev-to-main-20260711204949

Conversation

@SorraTheOrc

Copy link
Copy Markdown
Member

Automated release created by ship skill.\n\nIncludes CHANGELOG.md with work-item summaries from this release.

Sorra the Orc added 27 commits July 9, 2026 09:52
…-git-branch guard

Changes:
- .githooks/post-merge: Fix hardcoded /tmp/Worklog/... path to use $(dirname "$0")
- .githooks/post-rewrite: Fix hardcoded /tmp/Worklog/... path to use $(dirname "$0")
- .githooks/post-checkout: Add --git-branch refs/worklog/data to wl sync call
- .githooks/worklog-post-pull: Add --git-branch refs/worklog/data to wl sync call
- src/commands/init.ts: All 5 inline hook generation patterns now use --git-branch refs/worklog/data
- docs/branch-protection.md: Document required branch protection rules for dev and main

All hooks now explicitly use --git-branch refs/worklog/data to prevent
accidental pushes to standard branches (refs/heads/, refs/tags/).
The src/sync.ts guard (gitPushDataFileToBranch) already blocks such pushes.
The pre-push hook was already fixed to use worktree isolation + --git-branch.
… from .githooks

Extend the  command to detect and replace outdated
git hooks installed in .git/hooks/ from the committed safe versions
in .githooks/. This ensures existing installations automatically get
the safe hook patterns (using --git-branch refs/worklog/data) without
manual re-installation.

Changes:
- New src/doctor/hook-upgrade.ts module for hook detection and upgrade
- Updated doctor upgrade command to check/upgrade hooks alongside
  database migrations
- CLI: dry-run reports outdated hooks, --confirm applies upgrades
- JSON output includes hooks info alongside migrations
- Unit tests (21 tests) and CLI integration tests (5 tests)
- Updated docs/migrations.md with hook upgrade documentation
- Created packages/tui/extensions/Worklog/session-health.ts with:
  - SessionHealthState type and state management
  - Event handlers for turn_start, message_end, tool_execution_start/end,
    model_select, session_start, session_shutdown
  - Footer renderer showing status marker (○/●/⚡), elapsed time
    (colour-coded), token counts (↑input ↓output), context usage
    (percent/window), model ID, and turn count (#N)
  - 1-second setInterval ticker for elapsed time updates
  - Graceful degradation in non-TUI modes
  - Token extraction from session entries, k-suffix formatting
  - Truncation for narrow terminals via terminal-utils

- Created session-health.test.ts with 46 tests covering:
  - Export constants (SESSION_HEALTH_STATUS_KEY, STATUS_*)
  - Event registration (7 lifecycle events)
  - Time formatting (elapsed, colour thresholds)
  - Token formatting (k/M suffixes)
  - Context usage formatting
  - Token extraction from session entries
  - Footer rendering (idle/streaming/tool/model/turn)
  - Integration scenarios
  - Edge cases (boundaries, null handling, narrow terminals)

- Updated index.ts: import and call registerSessionHealth(pi)
- Updated README.md: added Session Health Footer documentation
…ealth

The updateState() function was calling registerSessionHealth(pi) which
re-registered ALL event listeners via pi.on() each time any event fired.
This caused exponential listener growth and OOM crash on pi startup.

Fix:
- Removed the recursive registerSessionHealth() call from updateState()
- Changed updateState() to just mutate state and call requestRender()
- Stored a requestRender reference from the footer factory's tui param
- Merged the duplicate session_start listeners into one
- Proper dispose() in the footer component cleans up ticker + branch listener
…in session health footer and move #N before timer

Fixes audit rejection: 'The new footer prevents the old footer information from
being displayed... There is also no description of what is happening... Move the
step number to before the timer'

Changes:
- Move turn count (#N) from right section to left section, before the elapsed
  time (so layout reads: marker #N time tokens context model instead of
  marker time tokens context model #N)
- Include extension status entries (from footerData.getExtensionStatuses()) as
  the first line of the rendered footer, ensuring that ctx.ui.setStatus()
  entries (model-display provider/model, activity indicator, etc.) remain
  visible when the custom session health footer is active
- Updated README.md documentation to reflect the new two-line footer layout
  and the position of the turn count
…health footer

- Add lastChunkTime property to SessionHealthState, updated on message_update
- Add message_update event handler to track last chunk arrival time
- Refactor footer into three-section layout:
  Left: [marker] [#turn] (Last Chunk: Xs ago) [streaming only]
  Center: [elapsed since stage start]
  Right: ↑input ↓output [context%/window] [model]
- Add formatShortElapsedTime utility for last-chunk timer display
- Update tests: 56 existing + 4 new test cases (60 total)
- Update README with new three-section layout and message_update event
Add a dedicated third line to the TUI footer showing the provider/model
in grey (dim) text, below the session health details.

Changes:
- model-display.ts: Export getResolvedModel() and getSelectedModel()
  getters; stop using setStatus() (model now shown on its own line);
  add onModelChange() callback for reactive updates
- session-health.ts: Import model state from model-display; add Line 3
  to footer render showing provider/model in grey text (or (pending));
  remove ctx.model?.id from session health line (right section); fix
  pre-existing off-by-one in layout width calculation; add
  after_provider_response listener to trigger re-render
- Updated tests to verify new behavior (23 model-display + 64
  session-health tests all pass)
… footer line 3

Changes:
- Footer Line 3 now shows both the selected Pi model alias AND the
  resolved provider/model, e.g. 'code -> openai/gpt-4' (addresses
  regression where the selected model was no longer visible after
  removal from the session health line)
- When no router-assigned model yet, shows just the alias (e.g. 'code')
  instead of '(pending)' for more informative feedback
- Updated tests to verify the new format
- The model/provider line on the footer is now always visible: shows
  a grey '—' when no alias or resolved model is available
- Replaced '->' with Unicode '→' arrow character for cleaner display
- Updated tests to expect the new format and always-present dash
…footer display

- Added session_start listener to model-display.ts that reads the Pi model
  alias from ctx.model?.id and populates _selectedModel. This ensures
  getSelectedModel() returns the alias even when no model_select event has
  fired yet (e.g. at startup with a default model).
- Guard: only populates if model_select hasn't already set _selectedModel,
  so explicit user selections take priority.
- Added 4 new tests: session_start listener registration, session_start
  captures alias, session_start does not overwrite model_select, and
  onModelChange fires on session_start. Total: 91 tests passing.
Add a truncated preview of the session's first user message to Line 3
of the footer alongside the model/provider info.

Changes:
- Add extractInitialPrompt(entries) to extract first user message text
- Add initialPrompt to SessionHealthState for ticker population
- Update line 3 render to show both model info and quoted prompt preview
- Add 7 unit tests for extractInitialPrompt edge cases
- Add 3 integration tests for the prompt display in footer (resolved,
  alias-only, no-prompt)
- 101 total tests passing (27 model-display + 74 session-health)
…te()

The ticker's refreshState() captures the initial prompt via
extractInitialPrompt(entries) but never calls requestRender(),
so the TUI footer is never redrawn with the captured prompt
value. This is a one-line fix to add requestRender?.() after
the capture.

Fixes the bug where the initial prompt preview was captured
correctly but never appeared in the TUI footer.

Related: WL-0MRF6JXMD003KHLQ (original implementation)
…sed content format

Pi stores user message content as an array of content parts
([{ type: "text", text: "..." }, ...]) — see agent-session.js:788-795.
extractInitialPrompt() only handled string format, so it returned null
for all real Pi session entries and the initial prompt preview never
captured any text.

Fix: handle both string format (backward compat) and array format
by extracting text parts from the array, same approach used by
Pi's own _getUserMessageText() and activity-indicator.ts.

Adds 6 new tests for array content format.
All 80 tests pass (74 existing + 6 new).

Related: WL-0MRF6JR7P005TJU9
When a user invokes /skill:name, Pi expands it to an XML block:
<skill name="..." location="...">...</skill>

extractInitialPrompt() now detects skill blocks and returns a compact
preview like '[skill:audit] WL-123' instead of the raw XML first line.

Also refactored to use a helper extractMessageText(content) that
matches Pi's own extractTextContent approach (session-manager.js),
keeping the skill block logic cleanly separated.

Adds 5 new tests for skill block detection.
All 85 tests pass (80 existing + 5 new).

Related: WL-0MRFH8W4J007HIY5
…remove quotes

Two improvements to the initial prompt preview in the footer:

1. Work item title resolution: When the prompt contains a work item ID
   (e.g. '[skill:audit] WL-0MRF6JXMD003KHLQ'), asynchronously resolve
   the title via 'wl show' and enrich the preview to
   '[skill:audit] WL-0MRF6JXMD003KHLQ Show initial prompt...'. Uses
   fire-and-forget pattern (same as activity-indicator) so the UI
   shows the raw ID first, then updates once the title arrives.

2. Drop surrounding quotes: The quotes consumed precious character
   space on the footer line. The preview is now unquoted.

3. Dynamic preview width: Instead of a fixed 40-char limit, calculate
   available space as Math.max(15, width - 38) so wider terminals show
   more prompt text. The line is still ultimately truncated to terminal
   width by truncateToTerminalWidth.

Imports added: detectWorkItemId from activity-indicator, runWl from
wl-integration.

Updates 3 existing tests for quote removal and dynamic truncation.
All 85 tests pass.

Related: WL-0MRF6JR7P005TJU9
Changes:
- Added sessionStartTime field to SessionHealthState interface
- Set sessionStartTime=Date.now() in session_start handler
- Added formatTotalSessionTime() function for 'Total: Xm Ys' display
- Moved elapsed time (color-coded) from center to left section, after state marker
- Center section now shows total wall-clock session duration
- Right section unchanged
- Updated all tests to verify new layout
- Added new formatTotalSessionTime tests

Acceptance criteria:
1. Center: Total: 5m 42s (or Total: — before session starts)
2. Left: ○ Idle 30s #1 (elapsed time after state label)
3. Right: unchanged
4. Total: updates every second via existing ticker
5. Documentation: code comments updated
6. Tests: all session-health tests pass
…n close

Add lease-release module that detects when a new Pi session is created
(reason 'new') and sends a best-effort POST to the Local Proxy's
{baseUrl}/leases/release endpoint to release the previous session's
model lease, speeding up model reclamation.

Changes:
- New lease-release.ts module:
  - Reads ~/.pi/agent/models.json to find Local Proxy baseUrl
  - Sends fire-and-forget POST {baseUrl}/leases/release
  - Error handling via console.debug (no user-visible errors)
  - Caches baseUrl per extension lifecycle
  - Exports registerLeaseRelease() for integration
- New lease-release.test.ts with 17 tests covering:
  - Happy path (correct endpoint, session ID in body)
  - Network failure (no crash, debug log)
  - Non-2xx response (no crash, debug log)
  - Missing Local Proxy provider (no request sent)
  - Missing models.json (no request sent)
  - Non-'new' reasons (startup, resume, fork, reload)
  - Missing previousSessionFile
  - Empty session ID
- Modified index.ts: imports and registers registerLeaseRelease()
- Updated README.md with lease release feature documentation
…r layout

The README at packages/tui/extensions/README.md still described the old
footer layout (elapsed time in center as 'Stage elapsed time'). Updated:
- Section descriptions to show elapsed time in left section
- Center section now documents 'total session duration'
- Table rows: 'Stage elapsed' → 'Response elapsed', added 'Total session time'
- Layout diagram: moved elapsed time (45s) to left, shows Total: 5m 42s in center
- Event tracking: 'set stage-start timer' → 'set last-response timer'
- Technical notes updated for the three-section layout
Summary of changes:
- tests/extensions/worklog-browse-extension.test.ts: Fix 16 emoji icon
  expectations from ❓ (U+2753) to ❔ (U+2754) to match src/icons.ts
- packages/shared/src/persistent-store.ts: Add commentsForItem_ cache prefix
  invalidation to invalidateWorkItemCaches; add clearCommentCaches() public
  wrapper method to support cross-connection cache coherence
- packages/shared/src/database.ts: Call clearCommentCaches() after
  triggerSemanticIndex() in create() to prevent stale cached empty comment
  lists from persisting across database connections
- tests/cli/status.test.ts: Update version expectation from 1.0.1 to 1.0.2
- ~/.pi/agent/skills/ralph/SKILL.md (system): Replace 6 legacy skill/plan/
  path refs with ../plan/ relative paths
- ~/.pi/agent/skills/ship/SKILL.md (system): Replace 1 legacy skill/audit/
  path ref with ../audit/ relative path

All 165 test files pass (3035 tests), 1 skipped (long-running load test).
…indicators and truncated work item IDs

Changes:
- session-health.ts: Changed extractInitialPrompt skill format from
  [skill:name] to name: (e.g., [skill:implement] → implement:)
- terminal-utils.ts: Added truncateWorkItemId() utility that replaces
  full-length IDs (WL-0MQK0OM6I00168HD) with truncated form (WL...68HD)
- session-health.ts: Applied truncateWorkItemId to Line 3 prompt preview
- activity-indicator.ts: Applied truncateWorkItemId to displayed work
  item IDs in showActivityWithTitleLookup
- Updated all relevant tests to expect new formats
- All 3043 tests pass
@SorraTheOrc
SorraTheOrc merged commit 28aac53 into main Jul 11, 2026
2 of 5 checks passed
@SorraTheOrc
SorraTheOrc deleted the release/dev-to-main-20260711204949 branch July 11, 2026 20:51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant