diff --git a/CHANGELOG.md b/CHANGELOG.md index b9e5842..85c5e19 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,8 +6,14 @@ All notable changes to this project are documented here. The format follows ## [Unreleased] +## [0.15.0] — 2026-09-14 + ### Fixed +- Agent and other context submenus expand upward near the bottom edge instead of clipping the available list. + +- “Ask an agent” pastes into the receiving tab's current composer or terminal, including running agents that are still producing output. + - Automatic PyPI publication uses the registered publishing workflow directly, avoiding the signing-identity mismatch that required a manual retry. ## [0.14.0] — 2026-09-12 @@ -786,7 +792,8 @@ First public release. nothing compiles; `uv`/`pipx` from the GitHub release everywhere else. Apache 2.0 license; full README, installation, configuration, troubleshooting, and architecture documentation. -[Unreleased]: https://github.com/danialfarid/termdeck/compare/v0.14.0...HEAD +[Unreleased]: https://github.com/danialfarid/termdeck/compare/v0.15.0...HEAD +[0.15.0]: https://github.com/danialfarid/termdeck/compare/v0.14.0...v0.15.0 [0.14.0]: https://github.com/danialfarid/termdeck/compare/v0.13.0...v0.14.0 [0.13.0]: https://github.com/danialfarid/termdeck/compare/v0.12.3...v0.13.0 [0.12.3]: https://github.com/danialfarid/termdeck/compare/v0.12.2...v0.12.3 diff --git a/termdeck/__init__.py b/termdeck/__init__.py index 9e78220..9da2f8f 100644 --- a/termdeck/__init__.py +++ b/termdeck/__init__.py @@ -1 +1 @@ -__version__ = "0.14.0" +__version__ = "0.15.0" diff --git a/termdeck/static/app_markdown_files.js b/termdeck/static/app_markdown_files.js index bafe3e1..1b74703 100644 --- a/termdeck/static/app_markdown_files.js +++ b/termdeck/static/app_markdown_files.js @@ -2879,6 +2879,7 @@ Object.assign(TermdeckApp.prototype, { schedulePendingAgentPaste(view, delay = 0) { if (!view || view.closed || !view.pendingAgentPaste) return; + if (view.pendingAgentPasteTimer && !view.pendingAgentPasteRequireComposer) return; if (!view.pendingAgentPasteStartedAt) view.pendingAgentPasteStartedAt = Date.now(); clearTimeout(view.pendingAgentPasteTimer); const readyDelay = Math.max(0, (view.pendingAgentPasteReadyAt || 0) - Date.now()); @@ -6243,17 +6244,15 @@ Object.assign(TermdeckApp.prototype, { const session = this.session(sessionId); if (!value || !session || !session.agent_kind || session.agent_kind === "none" || (!session.running && !session.dormant)) return false; - const useHistoryComposer = this.historyOpen; this.hideSelectionActions(true); this.activate(sessionId, { reveal: true }); - const view = this.views.get(sessionId) || this.ensureView(sessionId); - if (useHistoryComposer && this.sessionSupportsTranscript(session)) { - if (!this.historyOpen) this.setHistoryMode(true); + if (this.historyOpen && this.sessionSupportsTranscript(session)) { this.appendTextToHistoryPrompt(value); this.$("status-name").textContent = "selected text added to transcript composer for " + this.agentSessionContextLabel(session); return true; } - if (!this.queuePendingAgentPaste(view, value)) return false; + const view = this.views.get(sessionId) || this.ensureView(sessionId); + if (!this.queuePendingAgentPaste(view, value, { requireComposer: !!session.dormant })) return false; if (!view.ws) this.connect(sessionId, view); this.$("status-name").textContent = "selected text queued for " + this.agentSessionContextLabel(session); return true; diff --git a/termdeck/static/app_search_git.js b/termdeck/static/app_search_git.js index 1fe8358..12e7e96 100644 --- a/termdeck/static/app_search_git.js +++ b/termdeck/static/app_search_git.js @@ -3949,6 +3949,25 @@ Object.assign(TermdeckApp.prototype, { } wrapper.appendChild(submenu); menu.appendChild(wrapper); + wrapper.addEventListener("mouseenter", () => this.positionContextSubmenu(wrapper)); + wrapper.addEventListener("focusin", () => this.positionContextSubmenu(wrapper)); + }, + + + positionContextSubmenu(wrapper) { + const submenu = wrapper.querySelector(":scope > .context-submenu-menu"); + if (!submenu || !submenu.offsetHeight) return; + const anchor = wrapper.getBoundingClientRect(); + submenu.style.maxHeight = Math.max(0, Math.min(420, window.innerHeight - 16)) + "px"; + submenu.style.maxWidth = Math.max(0, window.innerWidth - 16) + "px"; + submenu.style.minWidth = Math.min(190, window.innerWidth - 16) + "px"; + const height = submenu.offsetHeight; + const width = submenu.offsetWidth; + const top = Math.max(8, Math.min(anchor.top - 4, window.innerHeight - height - 8)); + const preferredLeft = anchor.right + width <= window.innerWidth - 8 ? anchor.right - 1 : anchor.left - width + 1; + const left = Math.max(8, Math.min(preferredLeft, window.innerWidth - width - 8)); + submenu.style.top = top - anchor.top + "px"; + submenu.style.left = left - anchor.left + "px"; }, @@ -3961,6 +3980,7 @@ Object.assign(TermdeckApp.prototype, { const top = y + height > window.innerHeight - 10 && above >= 8 ? above : y; menu.style.left = Math.max(8, Math.min(x, window.innerWidth - menu.offsetWidth - 10)) + "px"; menu.style.top = Math.max(8, Math.min(top, window.innerHeight - height - 10)) + "px"; + for (const wrapper of menu.querySelectorAll(".context-submenu")) this.positionContextSubmenu(wrapper); }, diff --git a/termdeck/static/index.html b/termdeck/static/index.html index dee89eb..1875d55 100644 --- a/termdeck/static/index.html +++ b/termdeck/static/index.html @@ -623,8 +623,8 @@ - - + +