Jeffery jiantw83

@jiantw83/cliproxy (0.0.6)

Published 2026-08-23 15:44:02 +00:00 by jiantw83

Installation

@jiantw83:registry=https://gitea.jsc.idv.tw/api/packages/jiantw83/npm/
npm install @jiantw83/cliproxy@0.0.6
"@jiantw83/cliproxy": "0.0.6"

About this package

CLIProxy 管理介面:OpenAI 相容派工端點、多 Worker 監控、金鑰管理、派工紀錄

CLIProxy

CLIProxy 是分散式派工系統的管理端:提供 OpenAI 相容的派工端點 (/api/v1/chat/completions、/v1/completions、/v1/responses), 監控多台 CLIProxyWorker,並提供一個繁體中文的 管理介面(金鑰管理、派工紀錄、系統日誌、CLI 工具狀態、模型路由、 測試呼叫)。管理介面與管理 API 一律要求以 Gitea OAuth2 登入且僅限 系統管理員(is_admin)使用。

系統需求

  • Node.js ≥ 20.11.0
  • 一個資料庫:SQLite(預設,免安裝)/PostgreSQL/SQL Server
  • 一個 Gitea 站台(供 OAuth2 登入),以及一個對該站台有效的 Personal Access Token(僅首次設定時使用一次)

安裝

CLIProxy 發布在本組織 Gitea 的 npm package registry(非公開的 npmjs.com),安裝前要先讓 npm 知道去哪裡拉套件、並帶上有讀取權限的 Gitea token。

方式一:npm 安裝(推薦)

  1. 設定 registry 與認證(擇一即可):

    • 全域設定(寫進 ~/.npmrc,之後每次安裝/更新都不用再帶):
      npm config set @jiantw83:registry https://gitea.jsc.idv.tw/api/packages/jiantw83/npm/
      npm config set //gitea.jsc.idv.tw/api/packages/jiantw83/npm/:_authToken <你的 Gitea token>
      
    • 或單次安裝時用參數帶入(不寫進任何設定檔):
      npm install -g @jiantw83/cliproxy \
        --@jiantw83:registry=https://gitea.jsc.idv.tw/api/packages/jiantw83/npm/ \
        --//gitea.jsc.idv.tw/api/packages/jiantw83/npm/:_authToken=<你的 Gitea token>
      
  2. 全域安裝:

    npm install -g @jiantw83/cliproxy
    

    安裝完成後可直接用 cliproxy 指令(scope 只影響套件名稱,不影響 指令名稱);前端靜態檔已預先建置並隨套件發布,不需要另外 cd web && npm install && npm run build。

  3. 依 DATABASE_PROVIDER(未設定則預設 sqlite)產生 schema 並套用 migration:

    cliproxy migrate
    

    非 sqlite 的 provider 必須先設定 DATABASE_URL 才能執行本指令 (見下方「環境變數」)。

  4. 啟動服務:

    cliproxy start   # 監聽 PORT(預設 3000),前端由同一個服務靜態提供
    

Gitea token 需具備該 repo 的讀取權限,向管理員索取或在 Gitea 「設定 → 應用程式」自行建立(read:package 權限即可)。

首次啟動後,用瀏覽器開啟 http://<host>:<port>/,會看到「首次設定」 畫面:貼上 Gitea 站台網址與 Personal Access Token 後送出,系統會 自動在該 Gitea 站台建立一個 OAuth 應用程式並算出回呼網址,接著導向 Gitea 完成登入(僅 is_admin 帳號能登入成功)。

完成設定後的登入頁會多一個「重設 Gitea OAuth 設定」入口,需要一把 對該站台有效且擁有者為系統管理員的 PAT,送出後會刪除 Gitea 端的 CLIProxy OAuth 應用程式與本機設定、所有登入 session 一併失效,畫面 回到「首次設定」,用於 OAuth 應用程式被刪、client_secret 不符或 回呼網址變更導致登入卡死時自救。

方式二:從原始碼建置

git clone https://gitea.jsc.idv.tw/jiantw83/CLIProxy.git
cd CLIProxy
npm install
npm run prisma:generate  # 產生 Prisma Client
npm run prisma:migrate   # 依 DATABASE_PROVIDER 產生對應 schema 並套用 migration
cd web && npm install && npm run build && cd ..
npm run build
npm start                 # 監聽 PORT(預設 3000),前端由同一個服務靜態提供

首次啟動後的設定步驟同「方式一」。

首次啟動後,用瀏覽器開啟 http://<host>:<port>/,會看到「首次設定」 畫面:貼上 Gitea 站台網址與 Personal Access Token 後送出,系統會 自動在該 Gitea 站台建立一個 OAuth 應用程式並算出回呼網址,接著導向 Gitea 完成登入(僅 is_admin 帳號能登入成功)。

完成設定後的登入頁會多一個「重設 Gitea OAuth 設定」入口,需要一把 對該站台有效且擁有者為系統管理員的 PAT,送出後會刪除 Gitea 端的 CLIProxy OAuth 應用程式與本機設定、所有登入 session 一併失效,畫面 回到「首次設定」,用於 OAuth 應用程式被刪、client_secret 不符或 回呼網址變更導致登入卡死時自救。

更新

方式一:npm 更新

npm update -g @jiantw83/cliproxy
cliproxy migrate   # 有新 migration 時套用

若要指定更新到某個版本,改用 npm install -g @jiantw83/cliproxy@<版本號>。

方式二:從原始碼更新

git pull
npm install
npm run prisma:generate    # 重新產生 Prisma Client
npm run prisma:migrate     # 有新 migration 時套用
cd web && npm install && npm run build && cd ..
npm run build

不論哪種方式,重新啟動服務即可;Gitea OAuth 設定與 Session 皆存在 資料庫/記憶體中不受影響,Worker 端不需重新註冊。

移除

方式一:npm 解除安裝

npm uninstall -g @jiantw83/cliproxy

方式二:從原始碼安裝時的移除

停掉服務後,刪除整個資料夾即可。

兩種方式都一樣:資料庫檔案(SQLite 預設在 prisma/sqlite/dev.db, 或依你設定的 DATABASE_URL)需另外手動刪除;若要順手撤銷 Gitea 端 建立的 OAuth 應用程式,有兩條路:在登入頁以具系統管理員身分的 PAT 執行「重設 Gitea OAuth 設定」,CLIProxy 會一併刪除 Gitea 端名稱為 CLIProxy 的 OAuth 應用程式;或直接到 Gitea 後台手動刪除(直接刪掉 資料庫檔的情境只能走這條,CLIProxy 沒有機會反向刪除)。

環境變數

變數 預設值 說明
PORT 3000 HTTP 監聽埠號
DATABASE_PROVIDER sqlite sqlite/postgresql/sqlserver 三選一,決定套用哪個 prisma/providers/<provider>.prisma 與 migration 目錄
DATABASE_URL provider 為 sqlite 時預設 file:prisma/sqlite/dev.db,其餘 provider 必填 Prisma 連線字串
WORKER_OFFLINE_MS 300000(5 分鐘) 超過多久沒收到心跳視為 Worker 離線
WORKER_CONCURRENCY_LIMIT 4 健康分數 C 因子計算壓力時,假設每台 Worker 的可並行任務數上限;與 Worker 端 TASK_CONCURRENCY 預設值一致
HEARTBEAT_INTERVAL_MS 30000 期望的心跳間隔,用於健康分數 Q 因子的新鮮度判斷
CLI_LIFECYCLE_TASK_TIMEOUT_MS 300000 安裝/解除安裝/啟用/停用任務的逾時秒數
RETENTION_METRIC_SAMPLE_MAX_COUNT / _MAX_DAYS — 時序樣本環狀保留策略(近 N 筆/近 N 天)
RETENTION_SYSTEM_LOG_MAX_COUNT / _MAX_DAYS — 系統日誌環狀保留策略
TASK_CLAIM_POLL_INTERVAL_MS 150(下限 50) Worker 長輪詢向佇列嘗試認領任務的間隔;低於下限會被夾到下限,避免打成緊迴圈
TASK_CLAIM_MAX_BATCH 4 一次長輪詢最多能認領的任務筆數上限,預設與 Worker 端 TASK_CONCURRENCY 一致;Worker 端可用 max query 要更少,但不能超過這個上限
TASK_PREFETCH_GRACE_MS 60000 已認領但尚未開始執行(被預取)的任務,等多久才視為逾時;任務真的開始執行後改以 timeoutMs 起算
CREDENTIAL_REFRESH_CHECK_INTERVAL_MS 300000(5 分鐘) 自動憑證刷新排程的掃描間隔
CREDENTIAL_REFRESH_LEAD_MS 1800000(30 分鐘) 登入到期前多久開始自動送出刷新任務
CREDENTIAL_REFRESH_MIN_INTERVAL_MS 600000(10 分鐘) 同一工具兩次自動刷新之間的最短間隔,避免刷不動時打成迴圈
SQLITE_BUSY_TIMEOUT_MS 15000 SQLite PRAGMA busy_timeout:併發寫入互搶檔案鎖時的重試等待上限,只在 DATABASE_PROVIDER=sqlite 生效
GITEA_CA_CERT 無 指向 PEM 檔(可為含多張憑證的 bundle)路徑,把該 CA 加入信任清單後仍完整驗證對 Gitea 的 9 個出站呼叫(OAuth 應用程式管理、登入回呼、清除設定);檔案無法讀取時 fail-closed,記一則 ERR 並維持預設驗證,不會自動退化成忽略驗證
GITEA_TLS_INSECURE 0 設為 1/true 時,對 Gitea 的出站呼叫不驗證 TLS 憑證;只作用於這 9 個呼叫,不影響 CLIProxy 其他任何 TLS 連線;與 GITEA_CA_CERT 同時設定時以後者為準;啟動時記一則 WRN、管理介面全站顯示警示標誌,僅適合在可信任網路使用

Gitea OAuth2 設定不透過環境變數,而是透過管理介面「首次設定」 畫面呼叫 POST /api/auth/register(giteaBaseUrl/ personalAccessToken/選填的 clientSecret)在啟動後設定一次, 設定結果存在資料庫的 GiteaAuthConfig 表,可隨時用新的 PAT 再次呼叫 該端點覆蓋設定。

Worker 註冊流程

  1. 系統在啟動或首次讀取時會自動建立一組一次性註冊 token;管理介面 的「註冊 token 管理」區塊可檢視、複製與重新產生。
  2. 在要跑 CLIProxyWorker 的機器上安裝並執行:
    cliproxyworker register --server https://<CLIProxy 位址> --token <剛才產生的註冊 token>
    
    成功後會在 ~/.config/cliproxyworker/config.json(權限 600)寫入 workerId/workerToken;同一台機器只需註冊一次。
  3. 執行 cliproxyworker daemon 啟動常駐程序,開始每隔 HEARTBEAT_INTERVAL_MS 上報系統資訊與 CLI 工具狀態、以 socket 優先領取任務; socket 不可用時會自動回退長輪詢。
  4. 回到管理介面「總覽」頁應該立刻看到該 Worker 上線;「CLI 工具」頁 可對它下發安裝/啟用等操作。

已知限制

  • 三 provider 驗證(I-2):scripts/prisma-cli.mjs 已針對 postgresql/sqlserver 產生對應 schema 並以 prisma validate 確認語法正確(含 @LongText 依 provider 置換為 @db.Text/ @db.NVarChar(Max)),但目前的開發環境沒有 Docker 也沒有可連線的 PostgreSQL/SQL Server 執行個體,因此尚未實際執行過這兩個 provider 的 migrate deploy 與一次完整派工。SQLite 這條路徑已由完整測試 套件(真的 SQLite,涵蓋 migration/心跳/派工/健康分數/模型 路由等)反覆驗證。若要補齊,需要一個可連線的 PostgreSQL 或 SQL Server 執行個體,設定 DATABASE_PROVIDER/DATABASE_URL 後跑 npm run prisma:migrate 即可沿用同一套流程驗證。
  • F-8/F-9 的模型選擇已支援 model: "auto" 或省略 model 時由 AutoModelSelectorService 依提示內容自動挑選(需求 6),挑選理由會 回傳於回應的 autoReason 欄位;測試呼叫頁的執行者/工具/模型皆可 選「自動」。
  • E-1 的註冊 token 目前僅保留列出、複製、重新產生與撤銷;首次建立 由系統自動處理,管理介面「註冊 token 管理」頁可直接操作。
  • PROTOCOL_VERSION 已 bump 至 1.3.0(模型 Tag 語意變更: CliToolModelInfo.tag 由「CLI 別名」改為 formatModelTag() 產生的正規化模型 Tag,派工與 CLI 呼叫一律以此為準):舊版 CLIProxyWorker 回報 1.2.0 以下心跳時會被 ProtocolVersionGuard 以 409 拒絕,必須同時升級 CLIProxyWorker 到含本次變更的版本才能 繼續運作,不支援新舊版本混跑。
  • 模型 Tag 正規化規則:formatModelTag()(contracts/cli-tool.ts) 把 CLI 工具回報的原始模型 id 正規化成對外唯一的模型 Tag—— trim+小寫 → 去除供應商前綴(openai//anthropic//google// github//models/) → 版本段以點號合併(-4-5 → -4.5)直到 字串不再變化;不同 CLI 工具對同一模型的不同寫法(例如 claude-haiku-4-5 與 claude-haiku-4.5)會合併成同一個 Tag, 之後派工、健康分數、管理介面一律以 Tag 稱呼模型。
  • 模型實測結論僅供顯示、不影響派工:ModelProbe 的實測結論 (available/temporary-failure/permanent-failure)不再壓低 或排除任何 {模型}-{執行者}-{工具} 組合的派工資格,只出現在 ModelSummary.status/routes[].probeConclusion 供前端顯示; GateState 已移除 probe-temporary-failure/probe-permanent-failure 兩個狀態。
  • 模型路由頁的啟用/停用以顏色反映狀態:「模型操作」欄的按鈕改為 狀態色——啟用中為綠底白字「● 已啟用」,停用中為灰底深灰字 「○ 已停用」,點擊即切換;顏色之外仍保留文字與符號,避免只靠顏色 辨識造成色覺障礙使用者無法分辨。
  • PROTOCOL_VERSION 已 bump 至 1.4.0(新增 CLI 工具版本檢查相關 欄位:CliToolStatus.latestVersion/updateCheckSupported): Worker 端會在心跳裡順便回報每個 CLI 工具目前是否有新版可用,管理 介面「CLI 工具」頁只會顯示提示(工具名稱後標記 •、卡片內顯示 「有新版 x.y.z 可更新」、詳細清單新增「最新版本」欄),不會 自動送出更新任務,是否更新仍由使用者手動按下既有的「更新」按鈕 決定。與先前的 PROTOCOL_VERSION bump 相同,isProtocolVersionCompatible() 是嚴格相等比對,Worker 與 CLIProxy 必須同時升級到含本次變更的版本 才能繼續運作,不支援新舊版本混跑。
  • 「CLI 工具」頁的「開新視窗」與「登入」是兩種不同用途的互動終端: 「開新視窗」開出一般互動終端(purpose=shell),對 kiro 而言會直接 進入聊天 TUI;「登入」開出登入專用終端(purpose=login),對有設定 auth.loginArgs 的工具(目前僅 kiro)會執行該工具自身的登入子指令 (例如 kiro-cli login),其餘工具的「登入」目前仍是裸指令,與「開 新視窗」行為一致。兩者各自以獨立瀏覽器視窗開啟,視窗名稱依 worker、工具、purpose 區分,不會互相覆蓋彼此的視窗。
  • 企業防火牆重簽 TLS 時 Gitea 登入失敗(NODE_EXTRA_CA_CERTS/GITEA_CA_CERT/GITEA_TLS_INSECURE): 若站台憑證被企業防火牆重簽(例如 issuer 為 O=Fortinet, CN=FG6H1ETB21900327 這類設備憑證),對 Gitea 的出站呼叫(OAuth 應用程式管理、登入回呼)會以 TypeError: fetch failed(cause SELF_SIGNED_CERT_IN_CHAIN)失敗, 伺服器日誌顯示「登入回呼發生非預期例外」,因為 Node 的 fetch 不使用 系統 CA store。判斷方式:curl 打得通同一個 URL、但 node -e "fetch(...)" 打不通,即為此問題。三者的關係與適用時機:
    • NODE_EXTRA_CA_CERTS:作用於整個 Node 行程的所有 TLS 連線,適合 「除了 Gitea 之外,行程本身還有其他站台也被同一個防火牆攔截」的情況; 例如:
      NODE_EXTRA_CA_CERTS=/etc/ssl/certs/ca-certificates.crt npm run dev
      
    • GITEA_CA_CERT:只作用於 gitea-auth.service.ts 對 Gitea 的 9 個出站 呼叫,仍完整驗證憑證,範圍比 NODE_EXTRA_CA_CERTS 更收斂,一般 情況下優先使用這個;指到系統 CA bundle(例如 /etc/ssl/certs/ca-certificates.crt)或匯出的防火牆設備憑證皆可。
    • GITEA_TLS_INSECURE:最後手段,明示對 Gitea 呼叫不驗證憑證, 等同關掉這 9 個呼叫的中間人攻擊防護(client_secret、authorization code、access token 皆可能被攔截竄改),只在真的無法取得可用 CA 檔時 才使用,且僅限於可信任網路;開啟後管理介面全站會顯示「目前未驗證 Gitea TLS 憑證」警示,日誌也會記一則 WRN。 三者可以並存:GITEA_CA_CERT 與 GITEA_TLS_INSECURE 同時設定時以 GITEA_CA_CERT 為準,並多記一則 WRN 說明 GITEA_TLS_INSECURE 本次 被忽略;NODE_EXTRA_CA_CERTS 不受這兩個變數影響,仍可單獨沿用。 (2026/08/19)
  • 派工紀錄頁「嘗試次數」欄語意(原「嘗試順序」):一次派工的 attemptSequence 是總嘗試次數,不是第幾次成功的順序——分類 階段(判斷該提示屬於哪種問題類別)與處理階段(實際呼叫 CLI)各算 一次,因此一次零失敗的正常派工也會顯示 2。展開列不再只限失敗的 紀錄,成功的紀錄也能展開查看每一次嘗試明細,並在每一列標示該次是 「分類階段」或「處理階段」(依 problemCategory 是否為 null 判斷)。(2026/08/19)
  • 派工紀錄頁「嘗試次數」欄只計處理階段:上一項讓「嘗試次數」欄 正名,但顯示值仍是分類+處理兩階段加總的 attemptSequence,把 「跑完 2 個階段」誤講成「重試過 1 次」。現在該欄改顯示 DispatchRecord.processAttemptCount——只計處理階段(problemCategory 非 null)的嘗試次數,分類階段不計入但展開明細仍完整看得到、並 維持原本的「分類階段/處理階段」標示;attemptSequence(總呼叫 次數)本身不變,仍是判斷是否可展開(> 0)的依據。既有 438 筆 舊資料已一次性回填 processAttemptCount;回填不到的歷史紀錄(例如 完全沒有嘗試明細、或當時仍是 pending)該欄顯示 —,不會顯示成 0。(2026/08/20)
  • 總覽頁面板的資料來源與空狀態:金鑰統計只納入未撤銷(revokedAt 為 null)的金鑰,已撤銷金鑰的歷史統計仍留在金鑰管理頁查看; 「資源走勢」與「CLI 資源占用」兩個面板改為區分「載入失敗」與 「目前真的沒有樣本」兩種空狀態——端點回應非 2xx 時顯示紅字載入 失敗訊息(含 HTTP 狀態碼),不再與正常的空樣本狀態混淆。 (2026/08/19)
  • 派工端點的 executor 必須填 workerId,不是執行者的人類可讀名稱: POST /api/v1/chat/completions(及 /v1/completions、/v1/responses) 選填的 executor 欄位,在 DispatchService.buildFilteredChain() 是拿去跟 RankedComboDetail.executor(即 ChainBuilderService.buildChain() 產出的 row.workerId)做字串全等 比對;因此 executor 必須傳「Worker 註冊流程」取得的 workerId (例如 cmswwqhf10004blp0eax80vu0),而不是 CLI 工具或執行者的名稱 (例如 claude)。三欄位(model+executor+tool)齊帶時,若 executor 填成非 workerId 的字串,篩選鏈必為空、固定回應 { "message": "沒有任何可用的 {模型}-{執行者}-{工具} 組合" } (HTTP 503);這是預期行為,不是 bug。要固定使用某台 Worker 派工時, 請到管理介面「總覽」或「CLI 工具」頁複製該 Worker 的 workerId, tool 才是 CLI 工具名稱(例如 claude/copilot/kiro/ antigravity)。(2026/08/20)
  • 併發 16 崩潰的真正根因是單台 Worker 容量不足,不是已知失效候選混入 推薦鏈:壓測報告(P1/P2-重測)原判斷併發 16 效能崩潰是因為 auto 推薦鏈仍會嘗試 copilot(未登入)/antigravity(憑證刷新失效)這類 已知失效候選,但該判斷已過期——not-logged-in/ credential-refresh-ineffective 兩個閘門狀態已於 2026/08/19(commit 7b9ba1e)納入 SKIP_DISPATCH_GATE_STATES(src/routing/chain-builder.service.ts), 早於 P2-重測執行時間。實際核對 P2-重測期間(2026/08/20 09:14~11:01) 資料庫裡全部 24 筆「分類階段全部失敗」紀錄的 DispatchAttempt 明細, 48 筆嘗試全部是 timeout,執行者/工具皆為 claude/kiro(同一 台 Worker),沒有任何 copilot/antigravity 嘗試紀錄。真正瓶頸是:某些 模型 Tag(如 claude-haiku-4.5)在本機只有 2 個可用組合(claude/ kiro),且兩者都指向同一台 Worker(TASK_CONCURRENCY=4),併發 16 時這些組合的等待時間超過 CLASSIFY_TIMEOUT_MS(30,000ms)而逾時失敗, 與候選是否「已知失效」無關——這些組合本身是健康、已登入的正常候選。 依此結論,不在 buildFilteredChain()/ChainBuilderService 加入 候選健康度快取或跳過機制(該類機制對應到已在 commit 76635c4(2026/08/14)刻意移除的 K 失敗冷卻因子,重新加入 需要重新評估是否違反 I.7「健康分數只影響排序、不剔除任何組合」的既有 設計原則,且對本次觀察到的逾時模式沒有直接幫助)。後續若要真正緩解, 建議方向為調高 CLASSIFY_TIMEOUT_MS、調高 TASK_CONCURRENCY、或增加 可承載該模型 Tag 的 Worker/CLI 工具數量,三者皆屬容量規劃決策,需 另行裁示與驗證,不在本次代辦處理範圍內。(2026/08/20)
  • 併發 8 表現不一致,重跑後確認並非 SQLite 版本差異造成:壓測報告 記載併發 8 的成功率在 P0-重測(60.0%)與 P1-重測(100.0%)間差異極大, 當時懷疑是 connection_limit=1 修復(commit 909dd15)前後版本差異。 以修復後版本(a9adbcb 加上群組 A 的文件/註解修正,未改動派工邏輯) 重跑一次併發 8(20 次請求,scripts/stress-results/followup-c8.jsonl), 結果成功率仍為 60.0%(12/20),e2e p95 為 121,497ms(基準線 33,938ms 的約 3.58 倍,超過「≤ 3 倍」門檻),皆未達 §1.3 門檻;失敗 的 8 筆全部一樣是 claude-haiku-4.5/gpt-5.4-mini 這類只有 1~2 個 可用組合的模型在同一台 Worker 上逾時(與上一條「併發 16 崩潰」同根因)。 由於 SQLite 修復已經在本次測試版本中、仍重現與 P0-重測相同的 60.0%,可排除「SQLite 版本差異」這個假設;原本 P0/P1 兩次併發 8 結果不一致,更可能是每次執行時 AutoModelSelectorService 挑到的 模型 Tag 恰好有多少可用組合(進而是否會撞上單一 Worker 容量瓶頸) 批次間隨機波動所致,而不是版本或程式碼差異。(2026/08/20)
  • WORKER_OFFLINE_MS/TASK_PREFETCH_GRACE_MS 不是聊天派工端點實際生效 的失敗判定門檻:這兩個環境變數分別用於「判定 Worker 整體離線」與 「判定已認領但尚未開始執行的任務逾時」,但 POST /api/v1/chat/completions 等聊天派工端點在分類階段與處理階段各自以程式碼常數 CLASSIFY_TIMEOUT_MS(30,000ms)/PROCESS_TIMEOUT_MS(120,000ms) 為單一 combo 的等待上限(DispatchService.awaitTaskResult 再加 10 秒 寬限才回報逾時),兩者皆早於 WORKER_OFFLINE_MS 預設的 300,000ms 觸發, 目前也不可用環境變數調整。實測對照:Worker daemon 整台停止時, 推薦鏈會對鏈上每個 combo 依序等滿「分類階段 40 秒」才換下一組,總計 140~160 秒即對應多個 combo 依序逾時的加總;模擬單一 CLI 呼叫卡住 (SIGSTOP)時,只有當下那個 combo 受影響,40 秒(分類階段)左右即 回報逾時,與實測的約 42.5 秒相符。(2026/08/20)

開發

npm run dev          # NestJS 熱重載
npm run test          # 後端測試(真的 SQLite,不用 mock)
npm run lint
cd web && npm run dev # 前端獨立開發伺服器(另開一個終端)

更新時間:2026/08/20 17:45:47(Asia/Taipei)

Dependencies

Dependencies

ID Version
@nestjs/common ^11.0.0
@nestjs/core ^11.0.0
@nestjs/platform-express ^11.0.0
@nestjs/platform-socket.io ^11.2.1
@nestjs/serve-static ^5.0.0
@nestjs/websockets ^11.2.1
@prisma/client ^6.0.0
commander ^12.1.0
cookie-parser ^1.4.7
prisma ^6.0.0
reflect-metadata ^0.2.2
rxjs ^7.8.1
socket.io ^4.8.3

Development Dependencies

ID Version
@eslint/js ^9.9.0
@nestjs/cli ^11.0.0
@nestjs/testing ^11.0.0
@types/cookie-parser ^1.4.10
@types/express ^5.0.6
@types/jest ^29.5.0
@types/node ^20.11.0
eslint ^9.0.0
eslint-config-prettier ^9.1.0
jest ^29.7.0
prettier ^3.3.0
source-map-support ^0.5.21
ts-jest ^29.1.0
ts-node ^10.9.2
typescript ^5.5.0
typescript-eslint ^8.0.0
Details
npm
2026-08-23 15:44:02 +00:00
2
MIT
474 KiB
Assets (1)
Versions (17) View all
0.1.9 2026-09-14
0.1.8 2026-09-07
0.1.6 2026-08-25
0.1.4 2026-08-25
0.1.3 2026-08-25