Communitygithub.com

ssunduko/product-video

將流水線 .demo 腳本中的自然語言 `ask "..."` 選擇器,透過 Claude in Chrome 擴充功能對應到實際應用程式,並寫入 <script>.selectors.json 側車檔案。當腳本中有未解析的意圖、編譯或錄製失敗顯示「選擇器仍在陳述意圖」,或重新設計導致原本可用的選擇器失效時使用。

product-video 是什麼?

這個技能的核心是解析 `.demo` 腳本中自然語言描述的選擇器(例如 `ask "聊天室底部的訊息方塊"`),並將其轉換為持久、穩定的 DOM 選擇器。它透過 Claude in Chrome 擴充功能在實際的瀏覽器環境中執行,而非依靠 LLM 模型即時推斷,因為選擇器解析只需要進行一次,但錄製影片的時機非常敏感。系統支援多種選擇器策略,優先使用 `data-testid`、`aria-label` 等屬性,並透過逐步執行腳本的「節拍」來確保只在元素實際出現在畫面上時才進行解析。這項技能對於確保自動化影片錄製的可靠性至關重要,因為它避免了在執行期間因模型延遲而產生的「靜默時間」,並透過側車檔案將解析結果持久化,讓腳本編譯器 (`script.mjs`) 可以直接使用,從而實現可重複、穩定的錄製流程。

相容平台✓Claude Code~Codex CLI~Cursor
npx skills add https://github.com/ssunduko/product-video/tree/HEAD/.claude/skills/resolve-selectors

在你喜歡的 AI 中提問

開啟一個已預先載入此 Agent Skill 的新對話。

說明文件

解析自然語言選擇器

.demo 腳本會以自然語言描述其意圖:

selectors:
  composer = ask "the message box at the bottom of the chat"

您的工作是找出這個元素在實際 DOM 中的位置,並將其寫入 scripts/<name>.selectors.json,如此 script.mjs 才能將其編譯為一般的選擇器, 而 driver.mjs 才能錄製出確定的拍攝內容。

您是解析器。 流水線中沒有任何部分會呼叫模型 — script.mjs 會讀取側車檔案,若沒有該檔案則拒絕編譯。解析在這裡執行, 且僅執行一次,在錄製之前進行,因為拍攝的時機就是影片的時間軸, 如果在執行過程中進行模型往返,會導致完成的影片中出現靜默時間。

開始之前

  • 應用程式必須可連線,且如果需要登入,必須已在使用者的 Chrome 中登入。 這就是使用擴充功能的重點:它能夠存取真實的會話,因此不需要 SSO 流程, 也不需要填寫電子郵件驗證碼。
  • 請先閱讀腳本。您需要 app:/target: 標頭來取得 URL, 以及各個節拍,因為選擇器必須依照流程順序解析(詳見下文)。

程序

  1. 取得工作清單。

    cd pipeline
    node script.mjs ../scripts/<name>.demo --intents
    

    stdout 會輸出 JSON:每個 ask 選擇器、其意圖及其目前的解析結果 (若未解析則為 null)。解析那些 null。僅在使用者表示流程已損壞時, 才重新解析其餘部分。

  2. 在單一次 ToolSearch 呼叫中載入瀏覽器工具,然後在執行任何其他操作之前 先呼叫 tabs_context_mcp。除非使用者指定了現有的分頁,否則使用 tabs_create_mcp 建立一個新的分頁。

  3. 按照節拍順序逐步執行流程。 這是最容易出錯的部分: 許多選擇器在登陸頁面上並不存在。結果表格只會在送出問題後出現; 「停止」控制項只在有內容生成時存在。因此,請依照腳本的節拍逐步執行, 在每個 ask 的元素出現在畫面上的那一刻進行解析。

    即時資料。在任何會建立、修改、傳送或刪除任何內容的步驟之前, 請暫停並詢問使用者。 feature.demo 會向真實的 Salesmessage 帳戶傳送四則訊息。 如果只需要定位某個東西,請使用懸停而非點擊,且絕對不要點擊破壞性控制項來「看看它是什麼」。

  4. 找到元素並選擇最耐用的控制代碼。 偏好順序如下:

    偏好原因
    [data-testid=...]、data-test、data-qa專為被選取而設計;能經得起重新設計
    穩定的 id良好,除非看起來是自動產生的(:r3a:、id-1a2b)
    按精確可存取名稱的按鈕/連結 → btn:Name驅動程式的 btn: 會比對文字、aria-label 和內部的 img[alt]
    [aria-label=...]、[role=...]穩定,且通常具有語義
    語義結構(main table、nav a[href="/teams"])能經得起樣式更迭

    絕對不要使用:nth-child 鏈、自動產生的類別名稱(css-1a2b3c、 很長的 Tailwind 堆疊),或任何以產生的內容為鍵值的東西。 最後一項正是此功能存在所要避免的陷阱 — 模型的答案每次執行措辭都不同, 因此與其文字相符的選擇器就如同擲硬幣。請改為定位容器或完成訊號。

  5. 在寫入之前先驗證。 針對每個候選項,使用 javascript_tool 確認它 比對到恰好一個元素,且該元素是可見的:

    const q = 'div[data-testid="chat-input"]';
    const n = document.querySelectorAll(q);
    console.log(JSON.stringify({
      q, count: n.length,
      visible: n[0] ? !!(n[0].offsetWidth || n[0].offsetHeight) : false,
      tag: n[0]?.tagName, editable: n[0]?.isContentEditable,
    }));
    

    使用 read_console_messages 讀回結果。如果比對到超過一個,或零個, 則表示需要繼續尋找 — 請勿寫入您尚未看到實際比對的選擇器。

  6. 寫入側車檔案 scripts/<name>.selectors.json:

    {
      "resolvedAgainst": "https://claude.ai/new",
      "resolvedAt": "2026-08-10T09:00:00Z",
      "resolvedBy": "claude-in-chrome",
      "selectors": {
        "the message box at the bottom of the chat": {
          "spec": "div[data-testid=\"chat-input\"]",
          "evidence": "contenteditable tiptap div, aria-label 'Write a message', 1 match, visible"
        }
      }
    }
    

    以意圖文字為鍵值,必須與腳本中的完全相同 — 重新命名選擇器 或重新排序區塊不得使解析結果孤立。spec 是驅動程式可接受的任何格式: 原始 puppeteer 選擇器、btn:Text|Alt、或 ::-p-text(substring)。evidence 是您實際觀察到的內容;請寫下來, 以便其他人可以判斷此選擇器是否仍然有效。

  7. 確認並交回。

    node script.mjs ../scripts/<name>.demo --intents   # 期望 0 個未解析
    node script.mjs ../scripts/<name>.demo --print     # 編譯
    

    報告您解析了哪些內容、您在哪些部分必須做出猜測,以及任何 因為需要破壞性步驟而跳過的項目。

當您無法解析時

請直接說明並停止;請不要虛構一個選擇器。未解析的意圖在 Chrome 啟動之前 就會產生乾淨的編譯錯誤。錯誤的選擇器則會在拍攝中途失敗,也就是在錄製 開始之後 — 這是最昂貴的失敗點。如果兩個元素同樣符合描述,請詢問使用者 他們指的是哪一個,而不是自行選擇。

注意事項

症狀原因 / 修正
元素不在頁面上它會在流程的後續階段出現。請依序逐步執行節拍;在元素實際出現在畫面上時,再解析每個意圖
兩個元素相符描述不夠明確。請先與使用者確認,然後也修改腳本中的 ask,使下一次解析不會有歧義
選擇器現在可用,下次執行卻壞了它是以產生的內容或產生的類別為鍵值。請重新定位到 testid、role 或容器上
wait ... gone 錨點這些本質上是暫時性的(例如生成時的停止按鈕)。請在元素顯示於畫面上時解析,並優先使用 aria-label — 它比文字更不容易改變
重新設計後解析結果偏移請只刪除側車檔案中的該鍵值並重新執行。.demo 不會改變;這就是重點
對話框封鎖了擴充功能請不要點擊會開啟 confirm/alert 的東西。模態對話框會凍結擴充功能,直到手動關閉

相關技能