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.
74 lines
2.5 KiB
TypeScript
74 lines
2.5 KiB
TypeScript
import {
|
|
JupyterFrontEnd,
|
|
JupyterFrontEndPlugin
|
|
} from '@jupyterlab/application';
|
|
|
|
import { Widget } from '@lumino/widgets';
|
|
|
|
import { OpenCodeFloatingPanel } from './components/opencode_floating_panel';
|
|
import { requestAPI } from './request';
|
|
import { callOpenCodeProviders } from './api/opencode_client';
|
|
|
|
/**
|
|
* Initialization data for the opencode_bridge extension.
|
|
*
|
|
* v5-floating: the per-cell AI button is gone. A single
|
|
* OpenCodeFloatingPanel is attached to document.body and operates
|
|
* against the JupyterLab shell's currently-active notebook. The model
|
|
* is picked dynamically in the inline prompt.
|
|
*/
|
|
const plugin: JupyterFrontEndPlugin<void> = {
|
|
id: 'opencode_bridge:plugin',
|
|
description: 'A JupyterLab extension bridging the UI to OpenCode Serve.',
|
|
autoStart: true,
|
|
activate: (app: JupyterFrontEnd) => {
|
|
console.log('JupyterLab extension opencode_bridge is activated!');
|
|
|
|
// Mount the floating AI button on the body. The panel itself is
|
|
// hidden until the user clicks the button.
|
|
const floating = new OpenCodeFloatingPanel({
|
|
app,
|
|
serverSettings: app.serviceManager.serverSettings,
|
|
providers: null
|
|
});
|
|
Widget.attach(floating, document.body);
|
|
|
|
// Fetch available providers once at activation and cache them for
|
|
// the inline prompt's model picker. Failure is non-fatal (the
|
|
// picker hides). Also push the payload into the floating panel so
|
|
// the prompt can render selects without an extra round trip.
|
|
void callOpenCodeProviders(app.serviceManager.serverSettings)
|
|
.then(data => {
|
|
floating.setProviders(data);
|
|
const lines: string[] = [
|
|
'[opencode_bridge] Available OpenCode providers:'
|
|
];
|
|
for (const p of data.providers) {
|
|
const models = Object.values(p.models)
|
|
.map(m => m.id)
|
|
.join(', ');
|
|
lines.push(` - ${p.id}: ${models || '(no models)'}`);
|
|
}
|
|
console.log(lines.join('\n'));
|
|
})
|
|
.catch(reason => {
|
|
console.warn(
|
|
'[opencode_bridge] Could not fetch providers (is the opencode-bridge server extension enabled and opencode serve running?):',
|
|
reason
|
|
);
|
|
});
|
|
|
|
requestAPI<unknown>('hello', app.serviceManager.serverSettings)
|
|
.then(data => {
|
|
console.log('hello endpoint:', data);
|
|
})
|
|
.catch(reason => {
|
|
console.error(
|
|
`The opencode_bridge server extension appears to be missing.\n${reason}`
|
|
);
|
|
});
|
|
}
|
|
};
|
|
|
|
export default plugin;
|