Bug: clicking the floating button after the first time caused the panel
content to multiply — every hide+show cycle appended a new prompt while
the previous one stayed in the DOM.
Root cause: the prompt's Lumino parent is null (it's attached to a raw
HTMLDivElement, not a Widget, so neither appendChild nor
Widget.attach(widget, HTMLElement) sets a Lumino parent). The
defensive DOM cleanup in _hidePrompt now removes the prompt's node
explicitly before nulling the reference, so no residual nodes linger
across show+hide cycles. Also use Widget.attach in _showPrompt for the
before-attach / after-attach lifecycle messages the prompt may rely on.
Added a regression test that toggles 5 times and asserts the panel
contains exactly one .opencode-inline-prompt node.
Files:
- src/components/opencode_floating_panel.ts — defensive cleanup + attach
- src/__tests__/opencode_floating_panel.spec.ts — regression test
The per-cell toolbar AI button (OpenCodeCellActions) is removed. A
single round button is mounted on document.body at the bottom-right of
the JupyterLab shell; clicking it opens a floating panel containing
the same OpenCodeInlinePrompt widget. Clicking again closes it.
The panel resolves the active notebook from app.shell.currentWidget
at open time and re-resolves it whenever currentChanged fires while
the panel is open. The active cell (used by the 📋 插入单元格内容,
↪ Insert, and ⟳ Replace cell actions) is resolved via a new
getActiveCell callback in OpenCodeInlinePrompt, decoupling the prompt
itself from any specific CodeCell instance.
Files:
- src/components/opencode_floating_panel.ts (new) — global panel
- src/components/opencode_cell_actions.ts (deleted) — logic moved up
- src/components/opencode_inline_prompt.ts — getActiveCell option
- src/index.ts — wire floating panel, drop toolbar factory
- style/base.css — .opencode-floating-* styles
- src/__tests__/opencode_floating_panel.spec.ts — new tests (renamed)
All existing functionality preserved: multi-session UI, SSE
streaming, permission/question interaction, history reload.