研发效能 Vibe Coding:从灵感到分钟级实现的 Nova(浏览器插件) 开发之旅

Ayo · 2025年06月06日 · 101 次阅读

Vibe Coding - Nova

前景介绍

故事开始于一个平凡的午后,当阳光透过窗户洒在代码编辑器上,前端开发小 A 忽然眼前一亮,情不自禁地大声赞叹:"Cursor 真是太好用了!"这款 AI 驱动的编辑器让他的代码效率翻倍,但一个棘手的问题却在他脑海中盘旋:他究竟如何才能把 Swagger 中指定模块的 API 接口定义导入到 Cursor 中,让 AI 助手直接基于这些定义来生成和实现代码?

开发时间
MVP 可用 一个小时左右,当前版本 2 天。

开发人员
Cursor Version: Version: 1.0.0 (Universal)

工具形态
悬浮框 +AIChat 对话框

步骤实现
优先考虑通过 MCP 调用 Swagger 并解析特定模块的接口提供给 Cursor,这个方案的优势在于我们已有现成实现,将其注册为 MCP 工具只需简单添加一个装饰器即可完成转换。

然而,实践中发现这种方式对语义解析的要求极高,尤其在模块匹配和模块下接口的精准识别方面。若不进行多轮深度对话,AI 生成的结果往往不尽如人意。为解决这一痛点,我转向了更直观的解决方案——开发浏览器插件实现页面接口的直接选择与抓取,从而获取更精准的结构化数据,大幅提升接口解析的准确性和开发体验。

令人啼笑皆非的是,就在团队还在为接口集成方案激烈讨论时,我们的"外包伙伴" Cursor 默默地等待着指令。短短几分钟的对话和指导后,它就交出了一份令人惊艳的答卷。
所有人好奇地凑到屏幕前,只见一个简洁优雅的操作:鼠标轻轻一划,Swagger 页面上的接口就被选中了,紧接着——砰!Cursor 编辑器自动弹出,接口定义完美呈现。这个看似简单的功能,却恰到好处地解决了团队一直纠结的难题。
"这...这也太快了吧?"有人惊讶地说。
"这就是 Cursor 的魅力,"团队负责人笑着说,"它就像一位得力的外包伙伴,只需简单的指令,就能快速理解需求并交付成果。"
这一刻,办公室里响起了一片赞叹声。谁能想到困扰团队的难题,竟被这位 AI 助手用如此优雅的方式解决了。这或许就是 AI 时代的魅力——有时候,最好的解决方案不在于复杂的架构设计,而是找到一个懂你的好搭档。而 Cursor,正是这样一位既懂技术又懂团队的完美伙伴。

诶~突然灵光一闪! 我们这不是已经整了个剪贴板功能嘛。转念一想...哎哟我去,那些设了权限的机密文档...该不会也能被'顺手牵羊'了吧? 这可是个'神奇的发现'啊,要是真能复制出来,那可就有点意思了~

出来吧,我的如意神剑 Cursor!
......
果不其然,一分钟后,尘埃落定。任务完美达成

卧槽,这威力简直了! 让我们掀开它的神秘面纱,一探究竟... 不得不说,这操作属实秀到我了,高手在民间啊~

// Text selection utilities

export function getSelectedText() {
  const selection = window.getSelection();
  let text = selection.toString().trim();

  // First method: standard selection
  if (text && text.length > 0) {
    return text;
  }

  try {
    // Second method: extract from range contents
    if (selection.rangeCount > 0) {
      const range = selection.getRangeAt(0);
      const container = range.commonAncestorContainer;

      // Create a temporary div to extract text
      const tempDiv = document.createElement('div');
      tempDiv.appendChild(range.cloneContents());

      // Get the text content and clean it
      text = (tempDiv.innerText || tempDiv.textContent || '').trim();
      text = text.replace(/\u200B/g, '').trim(); // Remove zero-width spaces

      if (text && text.length > 0) {
        return text;
      }

      // Third method: try to get text from the element itself
      if (container) {
        // If selection is within a special element
        const targetElement = 
          container.nodeType === Node.TEXT_NODE ? 
          container.parentNode : 
          container;

        // Check for special elements
        if (targetElement) {
          // Try to get text content in various ways
          text = targetElement.innerText || 
                 targetElement.textContent || 
                 targetElement.getAttribute('data-text') || 
                 targetElement.value || 
                 targetElement.getAttribute('value') || 
                 '';

          text = text.trim();
          if (text && text.length > 0) {
            return text;
          }

          // If still no text, try to get from parent elements
          let parent = targetElement.parentElement;
          while (parent && !text) {
            text = parent.innerText || 
                   parent.textContent || 
                   parent.getAttribute('data-text') || 
                   parent.value || 
                   parent.getAttribute('value') || 
                   '';
            text = text.trim();
            if (text && text.length > 0) {
              return text;
            }
            parent = parent.parentElement;
          }
        }
      }
    }
  } catch (e) {
    console.error('Error extracting text:', e);
  }

  return text || '';
}

export function disableCopyProtection() {
  // Remove all copy protections
  const protectionRemover = () => {
    // Enable selection
    document.designMode = 'on';
    setTimeout(() => {
      document.designMode = 'off';
    }, 100);

    // Remove common protection attributes
    document.querySelectorAll('*').forEach(el => {
      if (el.style) {
        if (el.style.userSelect === 'none') {
          el.style.userSelect = 'auto';
        }
        if (el.style.webkitUserSelect === 'none') {
          el.style.webkitUserSelect = 'auto';
        }
      }

      // Remove protection attributes
      el.removeAttribute('unselectable');
      el.removeAttribute('onselectstart');
      el.removeAttribute('oncontextmenu');
      el.removeAttribute('oncopy');
      el.removeAttribute('oncut');
    });

    // Allow right-click
    document.oncontextmenu = null;

    // Allow selection
    document.onselectstart = null;
  };

  // Run protection remover immediately and periodically
  protectionRemover();
  setInterval(protectionRemover, 1000);

  // Override common protection methods
  const originalAddEventListener = EventTarget.prototype.addEventListener;
  EventTarget.prototype.addEventListener = function(type, listener, options) {
    if (type === 'copy' || type === 'cut' || type === 'contextmenu' || 
        type === 'selectstart' || type === 'mousedown' || 
        type === 'keydown' || type === 'dragstart') {
      // Skip adding these protection event listeners
      console.log(`Blocked protection: ${type}`);
      return;
    }
    return originalAddEventListener.call(this, type, listener, options);
  };
} 

等等...灵光乍现! 既然能复制,那岂不是...嘿嘿,直接请 AI 大神帮忙解惑也不是不可以? 这波操作可以啊~
咱给团队配个 CTO 当技术马仔~
再怼上满血 DeepSeek V3 引擎 ——
代码跑得比奶茶外卖还快,算法 buff 直接拉满,
CTO 举着键盘喊:"这算力咱可叠明白了!"(狗头)

咱得给 CTO 加个 "防秃金钟罩"~ 免得被累死....

再让我们的 Cursor 员工实现一下 ChatBot 引入逻辑...依然是那么的速度....等等...既然是插件那岂不是...在任何页面都可以无侵入的加载...我好像想到了什么....基于 RAG 岂不是可以做个业务问答?

基于已有的精准测试岂不是可以分析 URL 对应的业务代码?.... 这....

未完待续。。。下班了。。。

暂无回复。
需要 登录 后方可回复, 如果你还没有账号请点击这里 注册