Skip to content

feat(drive): search the whole Workspace with optional id and --path-prefix - #139

Merged
pocketsharkk merged 6 commits into
mainfrom
claude/ship-wspc-todo-9596a3
Oct 7, 2026
Merged

pocketsharkk merged 6 commits into
mainfrom
claude/ship-wspc-todo-9596a3

Conversation

@pocketsharkk

@pocketsharkk pocketsharkk commented Oct 7, 2026 •

Copy link
Copy Markdown
Collaborator

使用者遇到的問題

wspc drive search 一定要先給 library ID,沒辦法一次搜整個 Workspace,也沒有 --path-prefix 可以限定資料夾。Backend 早就支援這兩件事,CLI 卻跟不上。

更糟的是,Release workflow 現在每次都會中止:它會先同步 live OpenAPI 再 regenerate,接著跑 typecheck,結果失敗:

src/generated/cli/index.ts(39,10): error TS2305: Module '"./drive/search.js"' has no exported member 'driveSearchCommand'

背景

問題出在哪裡

Live spec 裡兩個 op 的 x-cli.command 都是 drive search,差別只在 per-library 那個有 positional: ["id"]。codegen 把 command path 當檔名,每個 op 各寫一次:

const parts = op["x-cli"].command.split(/\s+/)
const relFile = `${parts.join("/")}.ts`
await fs.writeFile(filePath, code)

於是兩個 op 都寫進 drive/search.ts,後寫的蓋掉先寫的,index.ts 卻仍 import 兩個名字,typecheck 因此失敗。以前所有 command 名都不重複,「一個 op 對應一個檔」跟「一個 command 對應一個檔」是同一件事,所以一直沒人發現。

修法

main.ts 新增 groupCommands:先收集所有 op,再依 x-cli.command 分組。

  • 單一 op:照舊。
  • 恰好兩個 op、只有一個有 path param:組成 Paired Command。有 path param 的當主體,另一個當 fallback。
  • 其他重名(三個同名、兩個都有或都沒有 path param):直接 throw,錯誤訊息列出所有 operationId。這個 guard 是必要的,今天的 silent overwrite 就是少了它。

emitCommand 收到 fallback 時:

  • positional 改宣告成 optional [id]
  • flag 取兩個 op query field 的聯集,同名以主體為準;本案兩邊完全相同,所以不需要去重或處理衝突
  • summary、description、examples 取自 fallback op(Workspace 搜尋是主要用法)
  • action 開頭插入一段分支:
if (id === undefined) {
  await runSdkCommand({
    operation: driveWorkspaceSearch,
    input: { query: { query: opts.query, limit: opts.limit, cursor: opts.cursor, path_prefix: opts.pathPrefix } },
    context: { kind: "drive_workspace_search", display: {...columns: ["library_id","path","snippet"]} },
  })
  return
}

有 id 時走原本的 driveSearch,kind: "drive_search" 與 columns ["path","snippet"] 跟 0.14.0 相同。

與 spec 的差異(已同步更新 spec): spec 原本寫死 argument 說明為 library ID; omit to search every library in the Workspace。但 id path param 在 OpenAPI 沒有 description,要做到這行字,就得在通用 codegen 裡寫死一段 drive 專屬文字。改成由 codegen 用 <name>; omit to <fallback summary 首字小寫> 產生,實際輸出為 id; omit to search drive text across the Workspace。spec 的 --help 列在第一個 commit(e25d1b5)一併更新。這是設計判斷,請 reviewer 確認。

最後執行 npm run sync-spec && npm run generate,提交 regenerated 結果。

已知副作用

無。對 committed(舊)spec 重新跑 generate 的 diff 為空,其他 78 個 command 的產物不變。

測試

  • tools/cli-codegen/main.test.ts:pair、不同名、非 pair 重名 throw(含兩個 operationId)、三個同名 throw。改動前紅:groupCommands is not a function。
  • tools/cli-codegen/emit.test.ts(AC4):[id]、--path-prefix <value>、兩個 operation、兩個 kind、id === undefined 分支、fallback summary。改動前 2 個測試紅(輸出沒有 [id],也沒有第二個 operation)。
  • test/generated/drive.test.ts(AC1–AC3、AC5):省略 id 時只呼叫 driveWorkspaceSearch、給 id 時只呼叫 driveSearch(未被呼叫的那個斷言 0 次)、path/query/kind/columns、--path-prefix 與 --cursor 原樣送出、helpInformation() 含 [id]、--path-prefix <value>、--cursor 說明含 path_prefix。把 drive/search.ts 換回 0.14.0 的產物後,4 個測試全紅:process.exit unexpectedly called with "1"(缺 <id>/未知 option)、expected 'Usage: search [options] <id>…' to contain '[id]'。
  • npm run typecheck、npm test(68 files / 826 tests)、npm run build 全綠。

AC5(npm run build 後 node dist/cli.js drive search --help,採自動化,另貼輸出):

Usage: wspc drive search [options] [id]

Search drive text across the Workspace

Arguments:
  id                     id; omit to search drive text across the Workspace

Options:
  --query <value>        query
  --limit <value>        limit
  --cursor <value>       Opaque Search Cursor from next_cursor; reuse with the
                         same query, library and path_prefix. No TTL.
  --path-prefix <value>  path_prefix

AC6:spec/openapi.json 含 /drive/search;src/generated/cli/index.ts 只有一行 import { driveSearchCommand } from "./drive/search.js"。

AC7 readback(乾淨 working tree):

$ npm run sync-spec && npm run generate && git status --porcelain spec src/generated
(空)
$ npm run typecheck   # ok

Live spec 與先前 committed spec 的 path 差異只有新增 /drive/search,沒有 search 以外的 drift。

AC8 live transcript(node dist/cli.js,已登入帳號;只留欄位與 status,查詢詞與內容省略):

步驟 結果
drive search --query <term> --limit 2 --json exit 0,2 筆,欄位 library_id, path, snippet,有 next_cursor
drive search <lib> --query <term> --path-prefix <folder>/ --json exit 0,2 筆,全部 path 都以該前綴開頭
以第一頁 next_cursor 加 --cursor 續頁 exit 0,1 筆,與第一頁無重疊
--cursor old-string-cursor exit 1,HTTP 400,body error.code = "VALIDATION_ERROR"

Review 結果

  • Repo 規範(CLAUDE.md):無違規。TDD 先紅後綠、conventional 小 commit、src/generated/ 只由 pipeline 產生、未碰 spec 列為「不要碰」的檔案。
  • 權威 spec:AC1–AC8 皆有佐證;唯一差異是上述 argument 說明文字(設計判斷,spec 已同步更新),沒有缺漏,也沒有 spec 以外的行為。
  • Over-engineering review:沒有需要刪的東西。

未完成驗收

  • AC9:Release 後 npx -y -p @wspc/cli@latest wspc drive search --help 應顯示 [id] 與 --path-prefix。屬 post-release 手動驗收,Release workflow 由使用者手動觸發(spec Out of Scope),不是 merge gate。

🤖 Generated with Claude Code


View with [code]smith Autofix with [code]smith
Need help on this PR? Tag @codesmith-bot with what you need. Autofix is disabled.

@pocketsharkk
pocketsharkk merged commit c48dd2b into main Oct 7, 2026
2 checks passed
@pocketsharkk
pocketsharkk deleted the claude/ship-wspc-todo-9596a3 branch October 7, 2026 03:39
@pocketsharkk

pocketsharkk commented Oct 7, 2026 •

Copy link
Copy Markdown
Collaborator Author

驗收報告

編號 結果 佐證
AC1 通過 test/generated/drive.test.ts「searches the Workspace when the library id is omitted」
AC2 通過 同檔「searches one library with --path-prefix when the id is given」
AC3 通過 同檔「passes --path-prefix and --cursor through in Workspace scope」,以及 AC1 斷言 path_prefix === undefined
AC4 通過 tools/cli-codegen/emit.test.ts「paired command fallback」、tools/cli-codegen/main.test.ts「groupCommands」
AC5 通過 同檔「documents the optional id and --path-prefix in --help」;node dist/cli.js drive search --help 輸出已貼在 PR 描述
AC6 通過 CI PR check success(exact head);index.ts 只有一行 driveSearchCommand import
AC7 通過 乾淨 working tree 執行 sync-spec && generate 後,git status --porcelain spec src/generated 為空,typecheck 通過
AC8 通過 Live transcript 見 PR 描述:Workspace 搜尋結果含 library_id;--path-prefix 結果全部在前綴之下;next_cursor 續頁成功;舊 cursor 回 HTTP 400 VALIDATION_ERROR,exit 1
AC9 通過 Release run 37568121812 發布 @wspc/cli@0.15.0(latest,附 provenance)。npx -y -p @wspc/cli@latest wspc --version 回 wspc 0.15.0,drive search --help 顯示 Usage: wspc drive search [options] [id] 與 --path-prefix <value>

AC1–AC9 全部通過,Todo tod_01M4A59S2BYHGHEB5GWTCVCVCS 已結案。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant