- scripts/v0.9.1: split README for users; real public zip distribution Reported ("answerhub-extension是公開給人下載的怎麼一堆給自己看的東西"): the README was full of maintainer-only content — a user just needs install/usage instructions. Split into README.md (download, install, configure, use, FAQ) and DEVELOPMENT.md (architecture, selector trust notes, debugging flows, release checklist). Also reported ("git clone跑得通嗎?或是我也沒有看到Download to zip啊"): is the pushed SiaoHub repo actually reachable? Checked properly — git.siao.ai is real and public, but git clone over it fails ("Authentication required") and there's no archive/zip endpoint; SiaoHub requires login for git operations on public repos, confirmed as deliberate. README's download link now points at a static zip on apps.siao.ai (already public, no login) instead of the SiaoHub URL. This repo still pushes to SiaoHub for source control/history — it's just not the distribution channel end users hit. New scripts/package.js builds that zip from exactly background.js's own HASHED_FILES list (no separately-maintained file list to drift). dist/ gitignored — build artifact, not tracked. Verified end to end: downloaded the public URL from outside, unzipped, confirmed manifest.json parses and all 8 files sit flat at the archive root. Co-Authored-By: Claude Sonnet 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01MDq26pQUZki77xe2zBvDas35 天前
- .gitignorev0.9.1: split README for users; real public zip distribution Reported ("answerhub-extension是公開給人下載的怎麼一堆給自己看的東西"): the README was full of maintainer-only content — a user just needs install/usage instructions. Split into README.md (download, install, configure, use, FAQ) and DEVELOPMENT.md (architecture, selector trust notes, debugging flows, release checklist). Also reported ("git clone跑得通嗎?或是我也沒有看到Download to zip啊"): is the pushed SiaoHub repo actually reachable? Checked properly — git.siao.ai is real and public, but git clone over it fails ("Authentication required") and there's no archive/zip endpoint; SiaoHub requires login for git operations on public repos, confirmed as deliberate. README's download link now points at a static zip on apps.siao.ai (already public, no login) instead of the SiaoHub URL. This repo still pushes to SiaoHub for source control/history — it's just not the distribution channel end users hit. New scripts/package.js builds that zip from exactly background.js's own HASHED_FILES list (no separately-maintained file list to drift). dist/ gitignored — build artifact, not tracked. Verified end to end: downloaded the public URL from outside, unzipped, confirmed manifest.json parses and all 8 files sit flat at the archive root. Co-Authored-By: Claude Sonnet 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01MDq26pQUZki77xe2zBvDas35 天前
- background.jsv0.9.10: call woqu.siao.ai directly — the old prefix now 301s apps.siao.ai/answerhub answers a 301 to woqu.siao.ai since the rebrand. A cross-origin redirect drops Authorization and landed on a host this extension had no permission for, so every call in v0.9.9 — lookup, key test, version check — failed as "Failed to fetch". The server now serves those three old paths in place for older copies (apps-siao-ai proxy.ts, EXTENSION_ENDPOINTS); this release stops depending on that. - API_BASE / VALIDATE_URL / VERSION_CHECK_URL → https://woqu.siao.ai/api/… - host_permissions: woqu.siao.ai replaces apps.siao.ai/answerhub - README settings link → woqu.siao.ai/settings; DEVELOPMENT paths updated Verified by loading the extension in Chromium and fetching from its own service worker: lookup/validate reach the route (401 for a fake key), version check 200. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01U86fDQbfN9KcLDdJ2brdqT2 天前
- content.jsv0.9.9: debounce could starve forever under continuous DOM churn Reported live: processCurrentQuestion() logged "no question element matched" exactly once right after a subject switch, then nothing at all — not even the retry a live header clock ticking once a second should have produced, for 17+ seconds, on a page that had visibly finished rendering the question in that time. Went looking for a missing special-case in NetHoAuto.py's own answering flow first (not the separate harvest_answers scraper, which does use an explicit Selenium wait) — its selectors are the same ones content.js already has, tried once, with no retry loop either. Confirmed: there is nothing missing there, so the bug had to be in this rewrite's own code. debounce() had no ceiling: every mutation's clearTimeout resets the 400ms window, so any page with something mutating more often than that, continuously, would starve processCurrentQuestion() from ever running again once fired that way — not a one-off timing miss, a structural starvation bug. This page has more than just the clock: a hidden #publicBusyIcon and an "上線人數" counter are both candidates. Added maxWaitMs (2000): a periodic ceiling on top of the normal trailing-debounce behaviour, so processCurrentQuestion() is guaranteed to run at least every 2s even under continuous churn. Verified standalone (not just read) with a synthetic 200ms-interval churn test: the old debounce would fire zero times during 5s of that and once at the end; this one fires roughly every 2s throughout and still debounces normally once churn stops. node --test: 8/8 pass.34 天前
- DEVELOPMENT.mdv0.9.10: call woqu.siao.ai directly — the old prefix now 301s apps.siao.ai/answerhub answers a 301 to woqu.siao.ai since the rebrand. A cross-origin redirect drops Authorization and landed on a host this extension had no permission for, so every call in v0.9.9 — lookup, key test, version check — failed as "Failed to fetch". The server now serves those three old paths in place for older copies (apps-siao-ai proxy.ts, EXTENSION_ENDPOINTS); this release stops depending on that. - API_BASE / VALIDATE_URL / VERSION_CHECK_URL → https://woqu.siao.ai/api/… - host_permissions: woqu.siao.ai replaces apps.siao.ai/answerhub - README settings link → woqu.siao.ai/settings; DEVELOPMENT paths updated Verified by loading the extension in Chromium and fetching from its own service worker: lookup/validate reach the route (401 for a fake key), version check 200. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01U86fDQbfN9KcLDdJ2brdqT2 天前
- hash-consistency.test.jsv0.4.3: fix the real version-check bug (join separator, not caching) Reported twice: the update banner showed "outdated" even when both version numbers matched (v0.4.2 → v0.4.2). Both prior fixes ({cache: "no-store"}, then a plan to cache-bust with a query string) were solving the wrong problem. Actual bug: background.js's computeSelfHash joined file contents with a literal "\x00", while scripts/compute-hash.js — the release script that computes the value AnswerHub publishes — joined with a plain space " ". The two hashes could never have matched, all the way back to v0.2.0; nothing about caching was ever involved. Fixed the separator and added hash-consistency.test.js, which extracts and compares the two files' literal .join(...) argument by regex. Verified it actually fails when the bug is reintroduced (temporarily restored the "\x00" locally, confirmed the test catches it, restored the fix) before trusting it as a regression guard — not just written and assumed correct. Co-Authored-By: Claude Sonnet 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01MDq26pQUZki77xe2zBvDas35 天前
- manifest.jsonv0.9.10: call woqu.siao.ai directly — the old prefix now 301s apps.siao.ai/answerhub answers a 301 to woqu.siao.ai since the rebrand. A cross-origin redirect drops Authorization and landed on a host this extension had no permission for, so every call in v0.9.9 — lookup, key test, version check — failed as "Failed to fetch". The server now serves those three old paths in place for older copies (apps-siao-ai proxy.ts, EXTENSION_ENDPOINTS); this release stops depending on that. - API_BASE / VALIDATE_URL / VERSION_CHECK_URL → https://woqu.siao.ai/api/… - host_permissions: woqu.siao.ai replaces apps.siao.ai/answerhub - README settings link → woqu.siao.ai/settings; DEVELOPMENT paths updated Verified by loading the extension in Chromium and fetching from its own service worker: lookup/validate reach the route (401 for a fake key), version check 200. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01U86fDQbfN9KcLDdJ2brdqT2 天前
- netholiday-reh-scraper.jsv0.6.0: replace popup with a side panel + live activity feed Requested: a sidebar form so the UI can stay open while watching the page auto-answer ("一邊查詢一邊自動做"), with "insert into the page itself" offered as an alternative. Chrome's native Side Panel API fits this exactly and is far less fragile than injecting a widget into someone else's site's DOM, so that's what got built. manifest.json: dropped action.default_popup, added side_panel.default_path, added the "sidePanel" permission. background.js calls chrome.sidePanel.setPanelBehavior({ openPanelOnActionClick: true}) once at startup so the toolbar icon opens the panel directly. sidepanel.html/sidepanel.js carry over every popup feature unchanged (API key, level picker + description, level-4 warning/ack/start, manual retrigger, version-check banner) — same element IDs, same logic, just a persistent container instead of one that closes the instant focus leaves it. New: a live activity feed, which is the part that actually answers "一邊查詢一邊自動做" rather than just moving the same static form somewhere else. content.js, background.js, and netholiday-reh-scraper.js each broadcast a fire-and-forget {type:"ACTIVITY", text} message alongside every existing console.debug call; the panel listens and renders a scrolling, timestamped, 200-entry-capped log. Not tab-filtered — acceptable for solo use, noted in the ticket rather than silently assumed fine. popup.html/popup.js deleted, not left dead in the tree. Implements ticket 10 of apps-siao-ai/.scratch/answerhub-answer-lookup/. Co-Authored-By: Claude Sonnet 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01MDq26pQUZki77xe2zBvDas35 天前
- README.mdv0.9.10: call woqu.siao.ai directly — the old prefix now 301s apps.siao.ai/answerhub answers a 301 to woqu.siao.ai since the rebrand. A cross-origin redirect drops Authorization and landed on a host this extension had no permission for, so every call in v0.9.9 — lookup, key test, version check — failed as "Failed to fetch". The server now serves those three old paths in place for older copies (apps-siao-ai proxy.ts, EXTENSION_ENDPOINTS); this release stops depending on that. - API_BASE / VALIDATE_URL / VERSION_CHECK_URL → https://woqu.siao.ai/api/… - host_permissions: woqu.siao.ai replaces apps.siao.ai/answerhub - README settings link → woqu.siao.ai/settings; DEVELOPMENT paths updated Verified by loading the extension in Chromium and fetching from its own service worker: lookup/validate reach the route (401 for a fake key), version check 200. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01U86fDQbfN9KcLDdJ2brdqT2 天前
- shared.cssv0.8.0: split settings into an Options page; add direct search to the panel Two things requested together: - "把這些拖到設定頁面" — API Key, automation level picker/description, and the level-4 risk warning+ack move out of the side panel into a dedicated Chrome extension Options page (options.html/options.js, manifest's options_ui with open_in_tab). The panel isn't cluttered with settings touched once; both surfaces read/write the same chrome.storage.local keys and stay in sync live via storage.onChanged, no reload needed either way. - "側邊展開也可以直接像是在AnswerHub一樣查詢" — the panel gets a search box: paste any question, get the same single-answer lookup the automation itself uses (own site, then rival-site fallback), without needing netholiday.kh.edu.tw open at all. Reuses the existing LOOKUP_ANSWER message as-is — background.js's handler was never sender-restricted, so no new message type or endpoint. New shared.css factors out the design tokens and base components (inputs, buttons, status pills, warning box) both pages need, so they don't visually drift apart from independent edits. HASHED_FILES (background.js + scripts/compute-hash.js) updated to include options.html, options.js, shared.css. Confirmed both the settings destination (in-extension Options page, not AnswerHub's own website settings) and the search implementation (lightweight single-answer query, not an embedded AnswerHub iframe) before building — both were genuine architecture forks, not obvious from the request alone. Implements ticket 14 of apps-siao-ai/.scratch/answerhub-answer-lookup/. Co-Authored-By: Claude Sonnet 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01MDq26pQUZki77xe2zBvDas35 天前
- sidepanel.htmlv0.9.3: remove the manual "paste a question and search" feature The side panel's main view had two ways to get an answer: automatic detection on netholiday.kh.edu.tw, and a standalone search box where you could paste any question text and query AnswerHub directly, no netholiday page needed. Owner asked to drop the second one. Removed: #searchInput/#search/#search-status/#search-result and their markup, describeSearchResult()/runSearch() and their event listeners, and the now-dead #search-result CSS block. The quota display, "重新查詢 目前題目", and the level-4 "開始答題" row all stay — they're independent of the search box and still belong on the main view. Renamed the main view for what's actually left in it: #show-search → #show-status, #search-view → #status-view, setView("search") → setView("status"), tab label "查詢" → "狀態". Updated every place that told the user to click "查詢" to get back to the main screen (sidepanel.html's settings hint, sidepanel.js's level-4 description), plus README.md and DEVELOPMENT.md's now-stale references to the search box. LOOKUP_ANSWER itself is untouched — content.js's automatic detection still uses it, this only removed the side panel's second caller. node --test: 8/8 pass. Checked visually by serving the directory over a plain HTTP server (chrome.runtime is undefined outside a real extension context, but that only affects data population, not layout/toggle behaviour) and clicking through both views — no leftover search UI, both tab labels correct, the settings hint's "狀態" reference renders right.34 天前
- sidepanel.jsv0.9.3: remove the manual "paste a question and search" feature The side panel's main view had two ways to get an answer: automatic detection on netholiday.kh.edu.tw, and a standalone search box where you could paste any question text and query AnswerHub directly, no netholiday page needed. Owner asked to drop the second one. Removed: #searchInput/#search/#search-status/#search-result and their markup, describeSearchResult()/runSearch() and their event listeners, and the now-dead #search-result CSS block. The quota display, "重新查詢 目前題目", and the level-4 "開始答題" row all stay — they're independent of the search box and still belong on the main view. Renamed the main view for what's actually left in it: #show-search → #show-status, #search-view → #status-view, setView("search") → setView("status"), tab label "查詢" → "狀態". Updated every place that told the user to click "查詢" to get back to the main screen (sidepanel.html's settings hint, sidepanel.js's level-4 description), plus README.md and DEVELOPMENT.md's now-stale references to the search box. LOOKUP_ANSWER itself is untouched — content.js's automatic detection still uses it, this only removed the side panel's second caller. node --test: 8/8 pass. Checked visually by serving the directory over a plain HTTP server (chrome.runtime is undefined outside a real extension context, but that only affects data population, not layout/toggle behaviour) and clicking through both views — no leftover search UI, both tab labels correct, the settings hint's "狀態" reference renders right.34 天前
- similarity.jsAnswerHub 自動作答: Chrome extension MVP Manifest V3 extension that looks up answers on netholiday.kh.edu.tw via AnswerHub's answer-lookup API and auto-selects the matching option. Rewrite of NetHoHpRdlAuto's Selenium logic (question/#topic, options/#answer .radio, 0.8-threshold bigram similarity) for a content-script context — the Python tool itself is untouched. - background.js: the only place that calls fetch(); holds the stored sk_live_ key, never exposed to the netholiday.kh.edu.tw page context - content.js: detects the current question, never overrides an answer the student already picked, caches per-question results so revisiting a question doesn't re-spend the 100/day quota - similarity.js: pure matching logic, factored out so it's actually unit-testable without a browser (node --test, 7 passing) - options.html/js: paste + test an API key, stored in chrome.storage.local only Implements tickets 03-04 of apps-siao-ai/.scratch/answerhub-answer-lookup/. Co-Authored-By: Claude Sonnet 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01MDq26pQUZki77xe2zBvDas35 天前
- similarity.test.jsAnswerHub 自動作答: Chrome extension MVP Manifest V3 extension that looks up answers on netholiday.kh.edu.tw via AnswerHub's answer-lookup API and auto-selects the matching option. Rewrite of NetHoHpRdlAuto's Selenium logic (question/#topic, options/#answer .radio, 0.8-threshold bigram similarity) for a content-script context — the Python tool itself is untouched. - background.js: the only place that calls fetch(); holds the stored sk_live_ key, never exposed to the netholiday.kh.edu.tw page context - content.js: detects the current question, never overrides an answer the student already picked, caches per-question results so revisiting a question doesn't re-spend the 100/day quota - similarity.js: pure matching logic, factored out so it's actually unit-testable without a browser (node --test, 7 passing) - options.html/js: paste + test an API key, stored in chrome.storage.local only Implements tickets 03-04 of apps-siao-ai/.scratch/answerhub-answer-lookup/. Co-Authored-By: Claude Sonnet 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01MDq26pQUZki77xe2zBvDas35 天前
README.md
AnswerHub 自動作答
Chrome 擴充功能。在「高雄市網路假期」(netholiday.kh.edu.tw)自動查詢並填入
AnswerHub 上的答案,可以設定不同程度的自動化。
下載安裝
- 下載:answerhub-extension.zip
- 解壓縮到一個資料夾(之後不要刪除或搬動這個資料夾)。
- Chrome 網址列輸入
chrome://extensions,右上角打開「開發人員模式」。 - 點「載入未封裝項目」,選擇剛剛解壓縮出來的資料夾。
- 工具列會出現擴充功能圖示,點一下打開側邊欄。
設定
到 我去不早說的「設定」頁面產生一支自己的
sk_live_...API Key。側邊欄右上角點「設定」,貼上金鑰,按「測試金鑰」確認顯示「金鑰有效」。
選「自動化程度」(預設 1,最保守),按「儲存設定」:
等級 行為 0 關閉 完全不動作 1 只選答案(預設) 自動選出答案,換題、換科目都要自己來 2 自動換題 選完自動跳下一題,跳完本科目所有題目為止 3 自動換題+自動進入下一科 跟等級 2 一樣自動換題;人在科目列表畫面時,會自動點進下一個未完成的科目,但不會幫你離開目前這科(網站要求全部答完才給離開)——一科一科接力,你自己按離開,它接著挑下一科 4 全自動跨科目+自動送出 對沒有答案的題目隨機猜一個選項讓每一科都能答完,答完自動按「結束離開」換到下一科,直到所有科目跑過一輪——唯一會做出不可逆動作的等級,選它時要先勾選風險確認才能儲存 按「狀態」切換回主畫面,打開 netholiday.kh.edu.tw 進行作答。
等級 4 存好設定後不會自動開始——回主畫面按一次「開始答題(等級 4)」才會真的動作; 重新整理頁面、關掉分頁重開,都要再按一次,避免不小心刷新就整科自動送出去。
使用
- 重新查詢目前題目:如果自動偵測沒跟上頁面切換,按這個手動重新查一次當下這一題。
- 今日查詢額度:會顯示還剩多少次(每支金鑰每日 100 次,隔天重置)。
- 即時動態:側邊欄下半部會即時顯示偵測到的題目、查詢結果、換題/換科目/送出的過程。
常見問題
點了「開始答題」或「重新查詢」說「目前分頁還沒載入擴充功能的偵測程式」 剛更新完擴充功能時會這樣——把 netholiday.kh.edu.tw 那個分頁重新整理一次就好。
側邊欄頂端出現紅色「有新版本可用」
去 chrome://extensions 點這個擴充功能卡片右下角的重新整理圖示,再重新下載
最新的 zip 重新載入。
測試金鑰或查詢一直失敗
先確認 API Key 貼對(sk_live_ 開頭)、AnswerHub 帳號沒被停權。如果側邊欄的訊息說背景
服務可能還在跑舊版,一樣去 chrome://extensions 點重新整理。
想改程式碼、想知道內部怎麼運作、想發新版,看 DEVELOPMENT.md。