Token导航 LogoToken导航TokenDH.com
研究检索操作浏览器github未标认证来源可访问许可证需确认审计提醒

electrobun-window-managementElectrobun 窗口管理

Agent Skill

electrobun-window-management 用于查找、检索和筛选相关信息,适合在 Codex、Claude、Cursor、Gemini CLI 中需要根据关键词、任务场景或来源线索快速定位候选结果时使用。可结合来源仓库、安装命令和原始 README 继续核验具体用法。安装前建议确认权限范围、维护状态,以及是否会触发联网、命令执行或文件读写。

总安装

1,483

周安装

60

GitHub Stars

6

下载量

466
CodexClaudeCursorGemini CLI

安装说明

本站只整理中文说明和来源信息,不托管安装包,也不代用户安装。

GitHub

来源数

2

许可证

unknown

最后核验

2026-05-01

来源状态

来源可访问

安装方式

通过对话安装

复制提示词发给支持本地命令或 Skills 的 AI 助手,先确认命令和权限,再让它执行。

请帮我安装这个 Agent Skill:electrobun-window-management(Electrobun 窗口管理)
来源仓库:https://github.com/rajavijayach/electrobun-skills
仓库路径:skills/electrobun-window-management
安装命令:
npx skills add https://github.com/rajavijayach/electrobun-skills --skill electrobun-window-management
安装前请先检查当前环境是否支持对应 CLI,并向我确认将要执行的命令、安装目录、联网范围和文件读写权限;确认后再执行。

命令行安装

复制命令到本机终端执行。该命令会通过 npx skills 从第三方来源获取 Skill;本站只展示命令,不托管安装包,也不自动执行。

skills.shnpx skills
npx skills add https://github.com/rajavijayach/electrobun-skills --skill electrobun-window-management

简介

electrobun-window-management 用于在 Electrobun 应用中管理窗口和视图,支持多窗口应用开发。

  • 适用于构建需要多个浏览器窗口或复杂视图布局的桌面应用,提供窗口创建、管理和事件处理功能。
  • 通过类和方法组织窗口逻辑,支持窗口生命周期管理和跨进程通信,适合 Electron 风格应用架构。
  • 安装需确认权限范围和维护状态,注意是否会触发文件读写或命令执行等敏感操作。
  • 适用宿主包括 Codex、Claude、Cursor、Gemini CLI,接入前应确认版本、权限和运行环境要求。

SKILL.md

Electrobun Window Management

Advanced patterns for managing windows and views in Electrobun applications.

Multi-Window Applications

Basic Window Manager

import { BrowserWindow } from "electrobun/bun";

class WindowManager {
  private windows = new Map<string, BrowserWindow>();

  createWindow(id: string, options: any) {
    const win = new BrowserWindow(options);
    this.windows.set(id, win);

    win.on("close", () => {
      this.windows.delete(id);
    });

    return win;
  }

  getWindow(id: string) {
    return this.windows.get(id);
  }

  getAllWindows() {
    return Array.from(this.windows.values());
  }

  closeWindow(id: string) {
    const win = this.windows.get(id);
    if (win) {
      win.close();
    }
  }

  closeAllWindows() {
    this.windows.forEach(win => win.close());
    this.windows.clear();
  }
}

const windowManager = new WindowManager();

Window Factory Pattern

type WindowType = "main" | "settings" | "editor" | "preview";

interface WindowConfig {
  type: WindowType;
  url: string;
  width: number;
  height: number;
  frame?: boolean;
  parent?: BrowserWindow;
}

class WindowFactory {
  private configs: Record<WindowType, Partial<WindowConfig>> = {
    main: {
      url: "views://main/index.html",
      width: 1200,
      height: 800,
      frame: true,
    },
    settings: {
      url: "views://settings/index.html",
      width: 600,
      height: 500,
      frame: true,
    },
    editor: {
      url: "views://editor/index.html",
      width: 1000,
      height: 700,
    },
    preview: {
      url: "views://preview/index.html",
      width: 800,
      height: 600,
      frame: false,
    }
  };

  create(type: WindowType, overrides?: Partial<WindowConfig>) {
    const config = { ...this.configs[type], ...overrides };
    return new BrowserWindow(config);
  }
}

const factory = new WindowFactory();
const mainWindow = factory.create("main");
const settingsWindow = factory.create("settings", { width: 700 });

BrowserView

BrowserView allows embedding webviews within a window without creating a separate window.

Basic BrowserView

import { BrowserWindow, BrowserView } from "electrobun/bun";

const win = new BrowserWindow({
  title: "Browser App",
  width: 1200,
  height: 800,
});

const view = new BrowserView({
  bounds: { x: 0, y: 60, width: 1200, height: 740 }
});

win.addBrowserView(view);
view.loadURL("https://example.com");

// Update bounds on window resize
win.on("resize", ({ width, height }) => {
  view.setBounds({ x: 0, y: 60, width, height: height - 60 });
});

Tab System with BrowserView

class TabManager {
  private tabs: Map<string, BrowserView> = new Map();
  private activeTab: string | null = null;
  private window: BrowserWindow;

  constructor(window: BrowserWindow) {
    this.window = window;
  }

  createTab(id: string, url: string) {
    const view = new BrowserView({
      bounds: this.getViewBounds()
    });

    view.loadURL(url);
    this.tabs.set(id, view);

    if (!this.activeTab) {
      this.activateTab(id);
    }

    return view;
  }

  activateTab(id: string) {
    const view = this.tabs.get(id);
    if (!view) return;

    // Hide current tab
    if (this.activeTab) {
      const currentView = this.tabs.get(this.activeTab);
      if (currentView) {
        this.window.removeBrowserView(currentView);
      }
    }

    // Show new tab
    this.window.addBrowserView(view);
    this.activeTab = id;
  }

  closeTab(id: string) {
    const view = this.tabs.get(id);
    if (!view) return;

    if (this.activeTab === id) {
      this.window.removeBrowserView(view);
      this.activeTab = null;

      // Activate another tab
      const otherTab = Array.from(this.tabs.keys()).find(k => k !== id);
      if (otherTab) {
        this.activateTab(otherTab);
      }
    }

    this.tabs.delete(id);
  }

  private getViewBounds() {
    const { width, height } = this.window.getBounds();
    return { x: 0, y: 60, width, height: height - 60 };
  }

  updateBounds() {
    const bounds = this.getViewBounds();
    this.tabs.forEach(view => {
      view.setBounds(bounds);
    });
  }
}

// Usage
const tabManager = new TabManager(mainWindow);

tabManager.createTab("tab1", "https://example.com");
tabManager.createTab("tab2", "https://github.com");
tabManager.activateTab("tab2");

mainWindow.on("resize", () => {
  tabManager.updateBounds();
});

Window Lifecycle Management

Window State Persistence

import { paths } from "electrobun/bun";
import { join } from "path";

interface WindowState {
  x: number;
  y: number;
  width: number;
  height: number;
  maximized: boolean;
}

class WindowStateManager {
  private stateFile: string;

  constructor(windowId: string) {
    this.stateFile = join(paths.userData, `window-state-${windowId}.json`);
  }

  async save(state: WindowState) {
    await Bun.write(this.stateFile, JSON.stringify(state, null, 2));
  }

  async load(): Promise<WindowState | null> {
    try {
      const content = await Bun.file(this.stateFile).text();
      return JSON.parse(content);
    } catch {
      return null;
    }
  }

  async restore(window: BrowserWindow) {
    const state = await this.load();
    if (!state) return false;

    window.move({ x: state.x, y: state.y });
    window.resize({ width: state.width, height: state.height });

    if (state.maximized) {
      window.maximize();
    }

    return true;
  }

  startTracking(window: BrowserWindow) {
    let saveTimeout: Timer;

    const saveState = () => {
      clearTimeout(saveTimeout);
      saveTimeout = setTimeout(async () => {
        const bounds = window.getBounds();
        await this.save({
          x: bounds.x,
          y: bounds.y,
          width: bounds.width,
          height: bounds.height,
          maximized: window.isMaximized(),
        });
      }, 500);
    };

    window.on("move", saveState);
    window.on("resize", saveState);
  }
}

// Usage
const stateManager = new WindowStateManager("main");
const win = new BrowserWindow({ width: 1200, height: 800 });

await stateManager.restore(win);
stateManager.startTracking(win);

Window Groups & Parent-Child

class WindowGroup {
  private parent: BrowserWindow;
  private children: BrowserWindow[] = [];

  constructor(parent: BrowserWindow) {
    this.parent = parent;

    // Close children when parent closes
    parent.on("close", () => {
      this.closeAllChildren();
    });
  }

  addChild(options: any) {
    const child = new BrowserWindow({
      ...options,
      parent: this.parent,
    });

    this.children.push(child);

    child.on("close", () => {
      const index = this.children.indexOf(child);
      if (index > -1) {
        this.children.splice(index, 1);
      }
    });

    return child;
  }

  closeAllChildren() {
    this.children.forEach(child => child.close());
    this.children = [];
  }

  showAll() {
    this.parent.show();
    this.children.forEach(child => child.show());
  }

  hideAll() {
    this.parent.hide();
    this.children.forEach(child => child.hide());
  }
}

// Usage
const mainWindow = new BrowserWindow({ width: 1200, height: 800 });
const group = new WindowGroup(mainWindow);

const palette = group.addChild({
  url: "views://palette/index.html",
  width: 250,
  height: 600,
  frame: false,
});

const inspector = group.addChild({
  url: "views://inspector/index.html",
  width: 300,
  height: 400,
});

Window Orchestration

Broadcasting to All Windows

class WindowBroadcaster {
  private windows: Set<BrowserWindow> = new Set();

  register(window: BrowserWindow) {
    this.windows.add(window);

    window.on("close", () => {
      this.windows.delete(window);
    });
  }

  async broadcast(method: string, ...args: any[]) {
    const promises = Array.from(this.windows).map(win =>
      win.rpc[method](...args).catch(err => {
        console.error(`Broadcast to window failed:`, err);
      })
    );

    await Promise.allSettled(promises);
  }
}

const broadcaster = new WindowBroadcaster();

// Register windows
broadcaster.register(mainWindow);
broadcaster.register(settingsWindow);

// Broadcast to all
await broadcaster.broadcast("updateTheme", { theme: "dark" });

Window Communication Hub

class WindowHub {
  private windows = new Map<string, BrowserWindow>();

  register(id: string, window: BrowserWindow) {
    this.windows.set(id, window);

    // Setup RPC handler for messaging
    window.defineRpc({
      handlers: {
        sendToWindow: async (targetId: string, method: string, ...args: any[]) => {
          return this.send(targetId, method, ...args);
        }
      }
    });
  }

  async send(targetId: string, method: string, ...args: any[]) {
    const target = this.windows.get(targetId);
    if (!target) {
      throw new Error(`Window ${targetId} not found`);
    }

    return await target.rpc[method](...args);
  }

  async broadcast(method: string, ...args: any[]) {
    const results = new Map();

    for (const [id, window] of this.windows) {
      try {
        const result = await window.rpc[method](...args);
        results.set(id, result);
      } catch (err) {
        results.set(id, { error: err.message });
      }
    }

    return results;
  }
}

const hub = new WindowHub();
hub.register("main", mainWindow);
hub.register("editor", editorWindow);

// Send from main to editor
await hub.send("editor", "updateContent", { text: "Hello" });

// Broadcast to all
await hub.broadcast("refreshData");

Floating Windows & Overlays

Always-on-Top Window

const floatingWindow = new BrowserWindow({
  url: "views://floating/index.html",
  width: 300,
  height: 200,
  frame: false,
  alwaysOnTop: true,
  skipTaskbar: true,
});

// Toggle always-on-top
floatingWindow.setAlwaysOnTop(!floatingWindow.isAlwaysOnTop());

Picture-in-Picture Mode

class PictureInPicture {
  private pipWindow: BrowserWindow | null = null;
  private sourceWindow: BrowserWindow;

  constructor(sourceWindow: BrowserWindow) {
    this.sourceWindow = sourceWindow;
  }

  enter(url: string) {
    if (this.pipWindow) return;

    this.pipWindow = new BrowserWindow({
      url,
      width: 400,
      height: 300,
      frame: false,
      alwaysOnTop: true,
      resizable: true,
    });

    this.pipWindow.on("close", () => {
      this.pipWindow = null;
    });
  }

  exit() {
    if (this.pipWindow) {
      this.pipWindow.close();
      this.pipWindow = null;
    }
  }

  toggle(url: string) {
    if (this.pipWindow) {
      this.exit();
    } else {
      this.enter(url);
    }
  }
}

const pip = new PictureInPicture(mainWindow);
pip.enter("views://video-player/index.html");

Advanced Patterns

Modal Dialogs

function showModal(parent: BrowserWindow, options: any) {
  const modal = new BrowserWindow({
    ...options,
    parent,
    modal: true,
    frame: false,
  });

  // Disable parent interaction
  parent.setEnabled(false);

  modal.on("close", () => {
    parent.setEnabled(true);
    parent.focus();
  });

  return modal;
}

// Usage
const confirmDialog = showModal(mainWindow, {
  url: "views://confirm/index.html",
  width: 400,
  height: 200,
});

Window Positioning

function centerWindow(window: BrowserWindow) {
  const { screen } = require("electrobun/bun");
  const display = screen.getPrimaryDisplay();
  const { width: screenWidth, height: screenHeight } = display.workArea;
  const { width, height } = window.getBounds();

  const x = Math.floor((screenWidth - width) / 2);
  const y = Math.floor((screenHeight - height) / 2);

  window.move({ x, y });
}

function cascadeWindows(windows: BrowserWindow[]) {
  const offset = 30;
  windows.forEach((win, index) => {
    win.move({
      x: 100 + (index * offset),
      y: 100 + (index * offset)
    });
  });
}

Resources

For more on Electrobun:

  • Core skill: electrobun - Basic window creation and APIs
  • RPC patterns: electrobun-rpc-patterns - Window-to-window RPC
  • Native UI: electrobun-native-ui - Menus and tray integration

适合场景

01

用户想查找某类 Agent Skill 时

02

需要根据任务场景推荐可安装能力包时

03

需要对比不同来源的安装命令和来源信息时

能力概览

能力 1

按任务关键词查找相关 Skills

能力 2

展示可复制的安装命令

能力 3

保留来源站点、仓库和原始说明,方便继续核验

能力 4

展示第三方安全扫描或审计结果

安装后应在对应宿主中按原始 README 的触发条件使用;具体调用方式请以来源页面和 README 为准。

平台分布

Codex

34.73%
按下载量换算162

Claude

30.54%
按下载量换算142

Cursor

21.06%
按下载量换算98

Gemini CLI

10.29%
按下载量换算48

安全审计

Gen Agent Trust Hub

通过

Socket

可疑

Snyk

可疑

权限和风险

操作浏览器

该 Skill 可能涉及浏览器控制能力,使用时可能读取或操作网页内容,需要在受控环境中确认权限边界。

安装前确认

本站仅展示第三方公开信息,不托管安装包,不提供自动安装或运行环境。安装前应自行审查源码、依赖和命令行为。来源安全扫描存在 warning/failed 结果,不能写成本站确认安全。当前只有一个来源,正式发布前建议补源仓库或其他目录站核验。

来源信息

继续浏览同类 Skills