Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion termdeck/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
__version__ = "0.14.0"
__version__ = "0.15.0"
9 changes: 4 additions & 5 deletions termdeck/static/app_markdown_files.js
Original file line number Diff line number Diff line change
Expand Up @@ -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());
Expand Down Expand Up @@ -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;
Expand Down
20 changes: 20 additions & 0 deletions termdeck/static/app_search_git.js
Original file line number Diff line number Diff line change
Expand Up @@ -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";
},


Expand All @@ -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);
},


Expand Down
4 changes: 2 additions & 2 deletions termdeck/static/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -623,8 +623,8 @@
<!-- One class, split across files: app.js declares TermdeckApp (constants, constructor, core);
the app_*.js files attach method groups to its prototype; app_boot.js instantiates. Order matters. -->
<script src="/static/app.js?v=20260912-remember-address"></script>
<script src="/static/app_search_git.js?v=20260912-group-plus"></script>
<script src="/static/app_markdown_files.js?v=20260912-keyboard-focus"></script>
<script src="/static/app_search_git.js?v=20260914-submenu-position"></script>
<script src="/static/app_markdown_files.js?v=20260914-agent-paste"></script>
<script src="/static/app_terminal.js?v=20260903-claude-renderer-resume"></script>
<script src="/static/app_settings_ui.js?v=20260909-compact-update"></script>
<script src="/static/app_misc_ui.js?v=20260911-update-safety"></script>
Expand Down