Skip to content

Releases: Jeshii/iterm2axis

iTerm2Axis v0.1.3

Choose a tag to compare

@Jeshii Jeshii released this 18 Jun 06:59
9659473

2026-06-18

  • Claude Code sidebar now shows model name, no Python dependency — fetchClaudeAgentsData runs claude agents --json directly via /usr/bin/env, parses JSON with hs.json.decode, and reads the session's .jsonl file in pure Lua to extract modelID. Removed RESOLVE_PYTHON_PATH(), buildCCModelCmd(), and the pythonPath config option. The entire enrichment pipeline is now implemented in Lua using io.open and hs.json.decode. Displayed as a DETAIL_COLOR row under the "claude" header. Also fixed a string.format error caused by an unescaped % in the old Python inline script.
  • Claude CLI path auto-resolution — replaces the broken which claude async check with RESOLVE_CLAUDE_PATH() that probes ~/.local/bin/claude, /opt/homebrew/bin/claude, and /usr/local/bin/claude at startup. The claude binary is invoked via /bin/sh -c with the full resolved path.
  • Parsed-agents log gated behind debug config, SHORT_MODEL_NAME strips claude- prefix.

2026-06-16

  • Removed tiling on/off feature (_tilingEnabled, toggleTiling(), ⌘⇧T hotkey) — hiding the sidebar already disables tiling, making a separate toggle misleading. Tiling is now always active when the sidebar is visible. The tiling cascade guard (_tilingInProgress, _withTilingGuard) is preserved as a stability mechanism. Removed: _tilingEnabled state var and all 4 guard conditions across windows.lua/render.lua/watchers.lua, toggleTiling() function, toggleTiling from ACTION_LABELS and bindHotkeys(), and the Phase 3 "sidebar follows focus when tiling off" block in windowFocused handler.

  • Cleaned up _sidebarEnabled dead code — this variable was initialized to true and never mutated. Removed from init(), syncCanvasLevel(), refreshSleepWake(), _setupSpaceWatcher(), and 5 async callback guards in fetchers.lua.

  • Fixed sidebar-hidden dead-end state where _sidebarVisible could only be recovered via explicit toggle — _doBuildSidebar() was setting _sidebarVisible = false in two non-user-intent paths: (1) the #wins == 0 branch (no iTerm windows), and (2) the pcall error handler. Once _sidebarVisible was false, the early if not self._sidebarVisible then return end guard prevented ALL future rebuilds through watchers/refresh — only toggleSidebar() could recover it. Fixed by removing both _sidebarVisible = false assignments — the system now only hides/deletes the canvas without overwriting user intent. toggleSidebar() no longer calls tileITermWindows() on hide (canvas just hides, windows keep their positions). Added pcall error capture (local ok, err = pcall(...)) with print() in the error handler so the root cause of any "sidebar disappears on refresh" crash can be diagnosed.

  • macOS native full-screen (green button) now hides sidebar and excludes full-screened windows from tiling — Space watcher calls _checkFullScreenAndAdjust() on every Space switch; when hs.spaces.spaceType() returns "fullscreen", the sidebar canvas is hidden (removed from full-screen Spaces for other apps and full-screened iTerm windows). _doBuildSidebar() also checks _isCurrentSpaceFullScreen() as a guard on every rebuild. Full-screened iTerm windows are filtered from getITermWindows() via w:isFullScreen(), keeping them out of the tiling pool. Option-click (Zoom/fill) is unaffected — isFullScreen() returns false and no Space change occurs.

  • Added screensDidWake / screensDidUnlock to sleep watcher — refreshSleepWake() now also fires when the display wakes or the user unlocks the computer (not just system sleep wake), re-creating event taps and rebuilding the sidebar to fix unresponsive clicks after sleep/lock.

2026-06-15

  • Fixed sidebar not showing on build and eliminated double-resize — reordered _doBuildSidebar so that _sidebarVisible = true and tileITermWindows(sb) run before syncCanvasLevel() and show(). Previously windows were tiled after the canvas appeared, causing: (a) two visual transitions (canvas shows, then windows resize); (b) setFrame reshuffling z-order and burying the just-shown canvas. Now windows resize first while the canvas is still hidden, then the canvas appears already at the correct level above the tiled windows — single visual transition.

2026-06-12

  • Tiling cascade guard — added _tilingInProgress flag set before any setFrame loop (via _withTilingGuard) and cleared after settleDelay + 0.1s. handleWindowMoveOrResize checks and bails early if a tile is in flight, breaking the setFrame → windowMoved → retile cascade. Also guards the drift-path setFrame loop in handleWindowMoveOrResize. Cleaned up in stop()/init().
  • Eliminated double-tile on sidebar show — show path in toggleSidebar now inlines anchor computation and calls buildSidebar() directly (no synchronous tileITermWindows), letting _doBuildSidebar be the sole tile trigger. refreshLayout sets _skipTileOnThisBuild = true after its sync tile to prevent _doBuildSidebar from tiling again.
  • Guard watchers during hide — _rebuildAfterSettle now checks _toggleLock before scheduling any rebuild, preventing stale work during the 0.5s hide/show lock window.
  • Reload hygiene — stop() now cleans up _resizeDebounceTimer, _tilingClearTimer, _tilingInProgress, _pendingSidebarFrame, and _currentScreen. init() initializes _tilingInProgress and _tilingClearTimer.

2026-06-09

  • Phase 1: Decouple tiling from sidebar — added _tilingEnabled state variable (init'd true), toggleTiling() function, and ⌘⇧T hotkey. No behavioral change yet — the toggle flips state and re-tiles when re-enabled, but nothing is gated behind it (Phase 2 adds the actual guards).
  • Phase 2: Gate all window frame manipulation behind _tilingEnabled — tileITermWindows(), the setFrame() loop in handleWindowMoveOrResize(), the retile guard in _doBuildSidebar(), and _rebuildAfterSettle() all check _tilingEnabled before touching any window frame. Toggling tiling OFF now actually prevents window layout changes; the sidebar repositions itself to the focused window but does not resize/move any iTerm windows.
  • Phase 3: Sidebar follows focused window when tiling is off — windowFocused handler repositions the sidebar canvas to the newly focused iTerm window using direct canvas:setFrame() instead of going through the buildSidebar() pipeline. This bypasses the snapshot-check/debounce/rebuild machinery and moves the canvas instantly. Only fires when position actually differs (avoids redundant calls on stacked windows).

2026-06-06

  • Fixed canvas unresponsive after sleep/wake — added hs.caffeinate.watcher (_setupSleepWatcher) that re-creates the click and drag event taps and rebuilds the sidebar canvas on wake from sleep, since hs.eventtap instances can be silently invalidated by the system after macOS sleep. Added refreshSleepWake() helper that invalidates all state, re-creates event taps, and conditionally rebuilds if the sidebar was visible.
  • Attempted to fix sidebar toggle reliability — _sidebarVisible is now the single source of truth in toggleSidebar (decoupled from sidebarCanvas existence). Screen watcher (_setupScreenWatcher) no longer forces _sidebarVisible = true and only rebuilds if the sidebar was already visible. Space watcher (_setupSpaceWatcher) now checks _sidebarVisible before rebuilding. Added _toggleLock to the show path for consistency with the hide path. Added _sidebarVisible guards to all async fetcher callbacks to prevent unnecessary rebuilds when the sidebar is hidden.
  • Attempted to fix tiling never firing after first build — _doBuildSidebar body is now wrapped in pcall so _buildPending is always reset (preventing the "stuck" state where any Lua error silently blocks all future rebuilds and tiling). Added tileITermWindows() call directly in refreshLayout so tiling always fires on explicit layout commands regardless of _doBuildSidebar's snapshot-based early-exit logic.

2026-06-05

  • Fixed sidebar context loss on focused Claude Code window during spinner animation — when the focused iTerm2 window had a Claude Code session running, every spinner tick in the title (⠋ /path, ⠙ /path, etc.) triggered windowTitleChanged. The stableCore() comparison was intended to detect these as no-ops, but lastRawTitle was never seeded on windowFocused — it was only written by windowTitleChanged itself. So the very first spinner frame after focusing always diffed against a nil/stale baseline, newCore != prevCore, which invalidated wd/tabInfo and fired FETCH_WINDOW_INFO with the spinning title. The AppleScript first window whose name = "⠋ /path" failed to match, leaving tabInfo as MISSING and the sidebar falling back to parts.basename (the last word of the title). Fixed by seeding CACHE.wc(winId).lastRawTitle = win:title() in the windowFocused handler so the first spinner diff always has a clean baseline. The bug only manifested on the focused window because unfocused windows don't receive windowFocused and their lastRawTitle was already populated from prior title changes.

  • Attempts to fix sidebar cache corruption during Claude Code spinner animation — CC's dynamic spinner frames (braille U+2800-U+28FF) in the window title lacked the ✳/·/🔔 prefix, so windowTitleChanged treated them as real navigation events, calling CACHE.invalidateWindow which wiped wd/tabInfo before the async AppleScript could re-populate them. The AppleScript then failed because the spinner-frame title didn't match any iTerm window name. Replaced the fragile CC-prefix-based invalidation gate with a stableCore() comparison — strips all stable CC decorations (✳, ·, 🔔, braille U+2800-U+28FF, trailing resolution suffix) and only invalidates when the meaningful path portion actually...

Read more

iTerm2Axis v0.1.2

Choose a tag to compare

@Jeshii Jeshii released this 31 May 05:54
afb60b2

Bug Fixes

  • Sidebar no longer disrupts other apps. Clicks in the sidebar region are only intercepted when iTerm2 is the frontmost application and the sidebar is visible. Previously, the canvas silently absorbed clicks across all apps.
  • Sidebar visibility properly tracked. Replaced unreliable hs.canvas:isVisible() with an explicit _sidebarVisible flag, fixing the bug where the hidden canvas still consumed mouse events.
  • Sidebar z-order restored on focus return. Uses hs.application.watcher to set the canvas to floating level when iTerm activates and drop to normal level when another app takes focus. Previously, switching away and back via Mission Control left the canvas stuck behind other windows.
  • Graceful error handling. Wrapped isITerm(), buildSidebar(), and filesystem operations in pcall to prevent cascading failures.

New Features

  • Bell flash notification. Windows with a bell indicator (🔔) now flash with a separate configurable color and interval (config.bell). Previously, only Claude Code "waiting" state triggered a flash with a hardcoded color.
  • Consolidated flash timer. Replaced per-window flash timers with a single shared timer, reducing resource usage.
  • Path-keyed custom names. Window renames can now be keyed by working directory path, so the same name persists across sessions for the same project even if the window ID changes.
  • Persistent window ordering and names. Custom window order and renames are saved to hs.settings and restored across reloads and restarts.
  • Space change handling. Added hs.spaces.watcher to detect macOS Space changes and rebuild/retile accordingly.
  • Canvas level polling. Periodic 1-second timer ensures the canvas level stays correct even when Hammerspoon misses a focus event.
  • Sidebar build optimization. Snapshot diffing avoids full canvas rebuilds when window structure hasn't changed; uses in-place element attribute updates instead. Debounced rebuilds coalesce rapid successive events.

Refactoring

  • buildSidebar split into public buildSidebar (snapshot + debounce) and private _doBuildSidebar (actual canvas manipulation).
  • startFlashing now accepts a flashType parameter ("waiting" or "bell") instead of having a single hardcoded behavior.
  • OpenCode data finalization extracted into _finalizeOpenCodeData().

iTerm2Axis v0.1.1

Choose a tag to compare

@Jeshii Jeshii released this 28 May 09:22
ea3734a

See AGENTS.md for usage instructions.

To install: unzip and copy iTerm2Axis.spoon to ~/.hammerspoon/Spoons/, then add hs.loadSpoon("iTerm2Axis") to your init.lua.

iTerm2Axis v0.1.0

Choose a tag to compare

@Jeshii Jeshii released this 27 May 01:35
f62633b

See AGENTS.md for usage instructions.

To install: unzip and copy iTerm2Axis.spoon to ~/.hammerspoon/Spoons/, then add hs.loadSpoon("iTerm2Axis") to your init.lua.