@wport/cli 0.1.2 → 0.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md ADDED
@@ -0,0 +1,99 @@
1
+ # Changelog
2
+
3
+ `@wport/cli` 變更紀錄。格式參考 [Keep a Changelog](https://keepachangelog.com/),
4
+ 版號遵循 [Semantic Versioning](https://semver.org/)。
5
+
6
+ ---
7
+
8
+ ## [Unreleased]
9
+
10
+ 下一輪變更會寫在這裡。
11
+
12
+ ---
13
+
14
+ ## [0.1.3] — 2026-06-02
15
+
16
+ npm 頁面呈現優化,**無 CLI 邏輯/原始碼變動**(`src/` 行為與 0.1.2 相同)。唯一的執行層差異是版號字串:`tsup.config.ts` 在 build 時把 `pkg.version` 經 `__CLI_VERSION__` define 嵌入 `dist/index.js`,故重 build 後 `wport --version` 會印 `0.1.3`、`dist` 非與 0.1.2 二進位一致(除版號字串外行為相同,比照 0.1.1 的描述)。因 npm 已發布版本不可覆寫、需 republish 才會反映到 npmjs.com,故 bump PATCH。
17
+
18
+ ### Docs
19
+
20
+ - **`package.json` metadata 補齊**:新增 `repository`(含 `directory: apps/cli`)、`homepage`、`author`、`bugs`(email channel,與 README `## Support` 一致),讓 npmjs.com sidebar 連結與署名完整。`keywords` 擴充(`ndjson` / `jq` / `agent` / `terminal` / `wport-cli` / `job-search-api`)。
21
+ - **`files` 加入 `CHANGELOG.md`**:changelog 一併進 tarball。
22
+ - **README**:標題下加 npm version / node / license badge;Quick start 後新增 Example output(table + JSON)區塊;開頭 pre-release 免責濃縮;修正 `CHANGELOG.md` 相對連結為絕對 GitHub URL(原連結在 npmjs.com 上 404)。
23
+
24
+ ---
25
+
26
+ ## [0.1.2] — 2026-05-29
27
+
28
+ agent-ready + contract-hardened 一輪。版號維持 PATCH(0.x 階段 SemVer §4 不保證穩定、實際使用者趨近零、移除項有 graceful degradation),但下方 ⚠️ BREAKING 仍明確標注。
29
+
30
+ ### ⚠️ BREAKING
31
+
32
+ - **移除 `api_base_url` config key**。改用 `WPORT_API_BASE` 環境變數或 `--api` flag 覆寫 base URL。
33
+ - 理由:把可變 base URL 持久化在磁碟上是 SSRF / credential-exfil 攻擊面,外部使用者並不需要(沒有 localhost / staging 場景);未來加入登入後風險更高。
34
+ - **不會 hard-fail**:既有 config 仍含 `api_base_url` 時,CLI 在載入時印一次 deprecation 警告並忽略該 key(不會 crash)。
35
+ - `wport config set api_base_url <x>` 會明確報錯並引導改用 `WPORT_API_BASE`。
36
+
37
+ ### Added
38
+
39
+ - **`jobs search --fields <list>` / `--minimal`**:JSON 輸出時只保留指定欄位(comma-separated dotted paths)。`--minimal` 是 `enc_id,title,company_name,area_display,salary_display` 的捷徑。大幅降低 agent 讀取 response 的 token 量(client-side 過濾,省 token 非省 bytes-on-wire)。`--fields` 與 `--minimal` 互斥;table 模式不受影響並會提示改用 `--output json`。
40
+ - **`jobs view --fields <list>`**:多欄位投影成 JSON object(既有 `--field` 單欄位純值輸出保留)。`--field` 與 `--fields` 互斥。
41
+ - **`jobs view --batch [--concurrency <n>]`**:從 stdin 讀 newline-separated enc_ids(需以 `-` 作 enc_id 參數),bounded 並行(預設 5、最大 20)逐筆查詢,輸出 ND-JSON(每行 `{ enc_id, ok, data? , error? }`)。單筆失敗不影響其餘,輸出順序對齊輸入順序。一個 process 處理多筆,省去 N 次 Node cold start。
42
+ - **`wport doctor`**:診斷指令,列出 resolved config(base URL / locale / timeout / config 檔位置)、server 連通性探測、bundled schema fingerprint,以及「server 會 silent ignore `orderBy` / `order`」等 agent 需知的行為。連不上 server 時 exit `ServerOrNetworkError`(4),其餘 exit 0。
43
+ - **bundled schema fingerprint(`__SCHEMA_HASH__`)**:build 時對 `src/generated/schema.d.ts` 取 SHA-256 前 12 字嵌入,供 `wport doctor` 顯示以人工比對 schema drift(自動偵測待後端提供 schema-version endpoint)。
44
+
45
+ ### Changed
46
+
47
+ - **`jobs search --help` 文案**:明講 sort 由 server 控制、`orderBy` / `order` 會被 silently ignored,故 CLI 不開排序 flag。
48
+ - **移除未使用的 `ora` 依賴**(dead dependency;程式碼無任何 import)。
49
+ - **HTTP 連線重用**:明確記錄「交給 Node 內建 fetch(undici)的 global dispatcher connection pooling」,刻意不 ship 自訂 `undici` Agent(near-zero 收益、避免新增 runtime dependency)。
50
+
51
+ ### Fixed
52
+
53
+ - **piped stdin 讀取的 EAGAIN**:`jobs view -`(與 `--batch`)改用可重試的 `readPipedStdin`,解決上游為另一個 process 時(如 `search | jq | view - --batch`)`readFileSync(0)` 偶發 `EAGAIN: resource temporarily unavailable` 而中斷的問題。
54
+
55
+ ---
56
+
57
+ ## [0.1.1] — 2026-05-27
58
+
59
+ ### Changed
60
+
61
+ - **README `## Support` 段聯絡 email**:從 `a39795979@gmail.com`(個人 Gmail,0.1.0 誤用)改成 `yao@wport.me`(公司 email)。`0.1.0` 已 published 到 npm registry、無法事後修改 README 內容,故 bump 0.1.1 republish。
62
+ - PUBLISH-CHECKLIST 與 ROADMAP 對應 §「對外支援 channel」決策紀錄同步修正。
63
+
64
+ ### Notes
65
+
66
+ - `0.1.0` 在 npm registry 上仍存在但 README 含 personal Gmail。建議使用者直接 `npm install @wport/cli@0.1.1` 或不指定版本(會解析到 latest = 0.1.1)。維護者後續可能 unpublish `0.1.0`(72h 內、無依賴限制下允許)以完整移除 Gmail 痕跡。
67
+ - 沒有程式碼變更;`dist/index.js` 內容跟 0.1.0 二進位一致(除版號字串)。
68
+
69
+ ---
70
+
71
+ ## [0.1.0] — TBD(pre-release)
72
+
73
+ 對應 PR [#15](https://github.com/w101-admin/W101-TalentSearchHub/pull/15)。
74
+
75
+ ### Added
76
+
77
+ - `wport jobs search` — 對接公開 `GET /api/jobs/search`:keyword、location、category、page、page-size、`--json-query` 進階逃生口。
78
+ - `wport jobs view <enc_id>` — 對接 `GET /api/jobs/{encId}/view`。支援 `--field <dotted.path>`(例 `--field job_info.salary_display`)、stdin (`-`) 取 enc_id。
79
+ - `wport config <set|get|path|reset>` — 持久化 `locale` / `api_base_url` / `output` / `timeout_ms`。Config 檔權限 0600,位置依 `env-paths` 跨平台。
80
+ - 全域 flags:`--lang`(Accept-Language)、`--api`、`--output`(TTY 偵測 table/json)、`--no-color`、`--timeout`、`-v/--version`、`-h/--help`。
81
+ - OpenAPI codegen pipeline(`gen:openapi:prod` / `gen:openapi:remote`):透過 `scripts/gen-from-remote.cjs` filter `KEEP_PATHS`,跳過 upstream 不相關端點的壞 `$ref`。
82
+ - Typed `paths` schema 從 prod swagger 產生;query 型別取自 `operations['JobsController_searchJobs']['parameters']['query']`,後端 DTO 變動會在 CLI 端 surface 成 TS error。
83
+ - Pagination 對齊 `PaginatedResponse` 扁平結構:`{ success, statusCode, message, data: T[], currentPage, totalPages, pageSize, totalCount }`。
84
+
85
+ ### Security
86
+
87
+ - Terminal escape / control-character sanitization,分兩級:
88
+ - `sanitizeForTerminal`(strict,單行):剝全部 C0(含 `\t \n \r`)、DEL、C1、ESC-initiated 序列。printTable cells、`view` 各欄位標題、error/warning 訊息走這條。
89
+ - `sanitizeForTerminalMultiline`(描述本文、`--field` 字串輸出):保留 `\n`,正規化 `\r\n` / lone `\r` 為 `\n`,剝其他控制字元。
90
+ - JSON 模式不需 sanitize:`JSON.stringify` 自動 escape `< 0x20` 字元成 `\uXXXX`。
91
+ - 防禦的攻擊:CSI clear-screen / OSC 0 set-window-title / OSC 8 phishing hyperlink / SGR 偽造 error 訊息 / NUL DEL C1 / CR overwrite / LF row injection / TAB align break。
92
+
93
+ ### Notes
94
+
95
+ - 預設 API base URL:`https://api.wport.me`。本機開發用 `wport config set api_base_url http://localhost:3000` 或 `--api` flag 覆寫。
96
+ - 預設 page size:10(對齊後端 `PaginationDto`)。Server 端強制上限 100。
97
+ - 排序由 server 決定:filter 搜尋按 publish date desc、keyword 搜尋按 relevance score。CLI 不暴露 sort flag(後端 service hardcode 不讀 client `orderBy` / `order`)。
98
+ - Rate limit:1200 req/min/IP(read-heavy throttle)。互動使用足夠;不要 scripted multi-process scraping。
99
+ - `--field <path>` 支援 dotted path 因為 `JobViewVM` 是嵌套(`job_info.{job_title,area_display,salary_display,...}` / `company_header_info.company_name` / `job_description`)。
package/README.md CHANGED
@@ -1,15 +1,12 @@
1
1
  # @wport/cli
2
2
 
3
- `wport` — terminal interface to the W101 Talent Search Hub public API. Query public job listings from your shell, pipe results to `jq`, scriptable end-to-end.
3
+ ![npm](https://img.shields.io/npm/v/@wport/cli)
4
+ ![node](https://img.shields.io/node/v/@wport/cli)
5
+ ![license](https://img.shields.io/npm/l/@wport/cli)
4
6
 
5
- > **Status**: 0.1.x pre-release.
6
- >
7
- > The default API base `https://api.wport.me` and the npm scope `@wport` are
8
- > **not yet publicly committed contracts**. Both may change before the first
9
- > public 0.1.0 release. Local development should override via the
10
- > `WPORT_API_BASE` env var or `--api <url>`.
11
- >
12
- > Scope: read-only public job search & view. No login. No employer-side commands yet.
7
+ `wport` terminal interface to the W101 Talent Search Hub public API. Query public job listings from your shell, pipe results to `jq`, scriptable end-to-end. Read-only public job search & view — no login, no employer-side commands yet.
8
+
9
+ > **Status**: 0.1.x pre-release. The default API base `https://api.wport.me` and the npm scope `@wport` are **not yet publicly committed contracts** and may change before the public 0.1.0 release. Override locally via the `WPORT_API_BASE` env var or `--api <url>`.
13
10
 
14
11
  ## Install
15
12
 
@@ -51,6 +48,28 @@ wport jobs search --keyword backend --api http://localhost:3000
51
48
  wport doctor
52
49
  ```
53
50
 
51
+ ## Example output
52
+
53
+ Default `table` output in a TTY (`wport jobs search --keyword backend`):
54
+
55
+ ```text
56
+ ┌────────────────┬──────────────────────────────────────┬──────────────────────┬────────────────────┬────────────────────┬──────────────┐
57
+ │ ENC_ID │ TITLE │ COMPANY │ LOCATION │ SALARY │ UPDATED │
58
+ ├────────────────┼──────────────────────────────────────┼──────────────────────┼────────────────────┼────────────────────┼──────────────┤
59
+ │ a1B2c3D4e5F6g… │ Senior Backend Engineer (Node.js) │ Acme Cloud Inc. │ Taipei City │ TWD 1.2M–1.8M / yr │ 2026-05-28 │
60
+ │ h7I8j9K0l1M2n… │ Backend Developer — Go / gRPC │ Penguin Labs │ Remote (TW) │ Negotiable │ 2026-05-27 │
61
+ └────────────────┴──────────────────────────────────────┴──────────────────────┴────────────────────┴────────────────────┴──────────────┘
62
+ Showing page 1/5 (10 of 47 results). Next: wport jobs search --page 2
63
+ ```
64
+
65
+ Same query as `--output json` (auto-selected when piped), trimmed to two fields for agents:
66
+
67
+ ```console
68
+ $ wport jobs search --keyword backend --fields enc_id,title --output json | jq '.data[]'
69
+ { "enc_id": "a1B2c3D4e5F6g7", "title": "Senior Backend Engineer (Node.js)" }
70
+ { "enc_id": "h7I8j9K0l1M2n3", "title": "Backend Developer — Go / gRPC" }
71
+ ```
72
+
54
73
  ## Commands
55
74
 
56
75
  ### `wport jobs search [options]`
@@ -206,7 +225,7 @@ A public issue tracker (GitHub Issues under [`w101-admin/W101-TalentSearchHub`](
206
225
 
207
226
  This CLI tracks the `api.wport.me` public job endpoints (`GET /api/jobs/search`, `GET /api/jobs/{encId}/view`).
208
227
 
209
- **Pre-1.0 (0.x.y) — soft compatibility**: During the `0.x.y` phase the upstream API and the CLI may evolve without strict semver guarantees. Backward-incompatible changes can land in any `0.x` minor release. Pin to a specific version (`@wport/cli@0.1.0`) if you script against this CLI in production. Each release pins the server version range it has been tested against (see [`CHANGELOG.md`](CHANGELOG.md)).
228
+ **Pre-1.0 (0.x.y) — soft compatibility**: During the `0.x.y` phase the upstream API and the CLI may evolve without strict semver guarantees. Backward-incompatible changes can land in any `0.x` minor release. Pin to a specific version (`@wport/cli@0.1.0`) if you script against this CLI in production. Each release pins the server version range it has been tested against (see [`CHANGELOG.md`](https://github.com/w101-admin/W101-TalentSearchHub/blob/main/apps/cli/CHANGELOG.md)).
210
229
 
211
230
  **Post-1.0 (1.x.y and beyond) — firm semver**: The `1.0.0` release will commit to standard semver. Any breaking server-side change that affects the CLI surface will be released as a CLI **major** bump (`2.0.0`, `3.0.0`, ...). Additive changes (new flags, new fields) → minor; bug fixes → patch.
212
231
 
package/dist/index.js CHANGED
@@ -179,7 +179,7 @@ function isTimeoutAbort(err) {
179
179
  return false;
180
180
  }
181
181
  function buildUserAgent() {
182
- return `wport-cli/${"0.1.2"} (node ${process.version}; ${process.platform})`;
182
+ return `wport-cli/${"0.1.3"} (node ${process.version}; ${process.platform})`;
183
183
  }
184
184
  function unwrapDataResponse(body) {
185
185
  if (body && typeof body === "object" && "success" in body && "data" in body) {
@@ -878,7 +878,7 @@ function registerDoctorCommand(program2) {
878
878
  ).action(async (_opts, command) => {
879
879
  const ctx = resolveContext(command);
880
880
  const line = (s = "") => process.stdout.write(s + "\n");
881
- line(`wport-cli ${"0.1.2"}`);
881
+ line(`wport-cli ${"0.1.3"}`);
882
882
  line(` bundled schema fingerprint: ${"839e8a891dfb"}`);
883
883
  line("");
884
884
  line("Resolved configuration:");
@@ -923,7 +923,7 @@ async function probeServer(ctx, line) {
923
923
 
924
924
  // src/index.ts
925
925
  var program = new import_commander.Command();
926
- program.name("wport").description("wport CLI \u2014 terminal interface to the W101 Talent Search Hub public API").version("0.1.2", "-v, --version", "output the CLI version").option("--lang <locale>", "Accept-Language locale: zh-TW | en-US | vi-VN | th-TH | id-ID").option("--api <url>", "override API base URL").option("--output <fmt>", "output format: table | json").option("--no-color", "disable color output").option("--timeout <ms>", "HTTP timeout in milliseconds", (v) => Number(v));
926
+ program.name("wport").description("wport CLI \u2014 terminal interface to the W101 Talent Search Hub public API").version("0.1.3", "-v, --version", "output the CLI version").option("--lang <locale>", "Accept-Language locale: zh-TW | en-US | vi-VN | th-TH | id-ID").option("--api <url>", "override API base URL").option("--output <fmt>", "output format: table | json").option("--no-color", "disable color output").option("--timeout <ms>", "HTTP timeout in milliseconds", (v) => Number(v));
927
927
  registerJobsCommand(program);
928
928
  registerConfigCommand(program);
929
929
  registerDoctorCommand(program);
package/package.json CHANGED
@@ -1,7 +1,17 @@
1
1
  {
2
2
  "name": "@wport/cli",
3
- "version": "0.1.2",
3
+ "version": "0.1.3",
4
4
  "description": "wport CLI — terminal interface to the W101 Talent Search Hub public API",
5
+ "repository": {
6
+ "type": "git",
7
+ "url": "git+https://github.com/w101-admin/W101-TalentSearchHub.git",
8
+ "directory": "apps/cli"
9
+ },
10
+ "homepage": "https://github.com/w101-admin/W101-TalentSearchHub/tree/main/apps/cli#readme",
11
+ "author": "YAO <yao@wport.me>",
12
+ "bugs": {
13
+ "email": "yao@wport.me"
14
+ },
5
15
  "bin": {
6
16
  "wport": "bin/wport.js"
7
17
  },
@@ -14,6 +24,7 @@
14
24
  "bin/",
15
25
  "dist/",
16
26
  "README.md",
27
+ "CHANGELOG.md",
17
28
  "LICENSE"
18
29
  ],
19
30
  "scripts": {
@@ -33,11 +44,17 @@
33
44
  },
34
45
  "keywords": [
35
46
  "wport",
47
+ "wport-cli",
36
48
  "w101",
37
49
  "jobs",
38
50
  "cli",
39
51
  "talent",
40
- "job-search"
52
+ "job-search",
53
+ "job-search-api",
54
+ "ndjson",
55
+ "jq",
56
+ "agent",
57
+ "terminal"
41
58
  ],
42
59
  "license": "MIT",
43
60
  "dependencies": {