@wport/cli 0.9.3 → 0.10.0

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/dist/index.js CHANGED
@@ -387,7 +387,7 @@ function registerJobsSearch(parent) {
387
387
  baseUrl: ctx.baseUrl,
388
388
  locale: ctx.locale,
389
389
  timeoutMs: ctx.timeoutMs,
390
- userAgent: (0, import_core2.buildUserAgent)("wport-cli", "0.9.3"),
390
+ userAgent: (0, import_core2.buildUserAgent)("wport-cli", "0.10.0"),
391
391
  source: CLI_SOURCE
392
392
  });
393
393
  const { data, error, response } = await client.GET("/api/jobs/search", {
@@ -632,7 +632,7 @@ function registerJobsView(parent) {
632
632
  baseUrl: ctx.baseUrl,
633
633
  locale: ctx.locale,
634
634
  timeoutMs: ctx.timeoutMs,
635
- userAgent: (0, import_core3.buildUserAgent)("wport-cli", "0.9.3"),
635
+ userAgent: (0, import_core3.buildUserAgent)("wport-cli", "0.10.0"),
636
636
  source: CLI_SOURCE
637
637
  });
638
638
  if (flags.batch) {
@@ -1073,7 +1073,7 @@ async function oauthPost(opts, path, body) {
1073
1073
  method: "POST",
1074
1074
  headers: {
1075
1075
  "Accept-Language": opts.locale,
1076
- "User-Agent": (0, import_core5.buildUserAgent)("wport-cli", "0.9.3"),
1076
+ "User-Agent": (0, import_core5.buildUserAgent)("wport-cli", "0.10.0"),
1077
1077
  "X-Source": CLI_SOURCE,
1078
1078
  Accept: "application/json",
1079
1079
  "Content-Type": "application/json"
@@ -1156,7 +1156,7 @@ function registerDoctorCommand(program2) {
1156
1156
  }
1157
1157
  async function runDoctor(ctx) {
1158
1158
  const line = (s = "") => process.stdout.write(s + "\n");
1159
- line(`wport-cli ${"0.9.3"}`);
1159
+ line(`wport-cli ${"0.10.0"}`);
1160
1160
  line(` bundled schema fingerprint: ${"839e8a891dfb"}`);
1161
1161
  line("");
1162
1162
  line("Resolved configuration:");
@@ -1216,7 +1216,7 @@ async function probeServer(ctx, line) {
1216
1216
  baseUrl: ctx.baseUrl,
1217
1217
  locale: ctx.locale,
1218
1218
  timeoutMs: ctx.timeoutMs,
1219
- userAgent: (0, import_core7.buildUserAgent)("wport-cli", "0.9.3"),
1219
+ userAgent: (0, import_core7.buildUserAgent)("wport-cli", "0.10.0"),
1220
1220
  source: CLI_SOURCE
1221
1221
  });
1222
1222
  const { response } = await client.GET("/api/jobs/search", { params: { query: { pageSize: 1 } } });
@@ -1246,11 +1246,61 @@ async function probeAuthServer(ctx, line) {
1246
1246
  var import_core8 = require("@wport/core");
1247
1247
  var transport = __toESM(require("@wport/core"));
1248
1248
  function withUserAgent(opts) {
1249
- return { ...opts, userAgent: (0, import_core8.buildUserAgent)("wport-cli", "0.9.3"), source: CLI_SOURCE };
1249
+ return { ...opts, userAgent: (0, import_core8.buildUserAgent)("wport-cli", "0.10.0"), source: CLI_SOURCE };
1250
+ }
1251
+ function extractErrorCodeBody(body) {
1252
+ if (!body || typeof body !== "object") return void 0;
1253
+ const b = body;
1254
+ const code = b.error_code;
1255
+ if (code !== "block_max_exceeded" && code !== "unsupported_video_provider" && code !== "block_item_forbidden" && code !== "profile_revision_conflict" && code !== "profile_revision_required") {
1256
+ return void 0;
1257
+ }
1258
+ return {
1259
+ error_code: code,
1260
+ block: typeof b.block === "string" ? b.block : void 0,
1261
+ limit: typeof b.limit === "number" ? b.limit : void 0,
1262
+ current_revision: typeof b.current_revision === "string" ? b.current_revision : void 0
1263
+ };
1264
+ }
1265
+ function decorateByErrorCode(base, err, info) {
1266
+ switch (info.error_code) {
1267
+ case "block_max_exceeded":
1268
+ return new import_core8.WportHttpError(
1269
+ `${base} \u2014 Block "${info.block ?? "unknown"}" exceeds its item limit` + (info.limit !== void 0 ? ` (max ${info.limit})` : "") + ". Run `wport enterprise company view --output json` to see the current items before replacing.",
1270
+ err.status,
1271
+ err.body
1272
+ );
1273
+ case "unsupported_video_provider":
1274
+ return new import_core8.WportHttpError(
1275
+ `${base} \u2014 Unsupported video URL. Accepted forms: https://www.youtube.com/watch?v=<id>, https://youtu.be/<id>, https://vimeo.com/<id>, https://player.vimeo.com/video/<id>.`,
1276
+ err.status,
1277
+ err.body
1278
+ );
1279
+ case "block_item_forbidden":
1280
+ return new import_core8.WportHttpError(
1281
+ `${base} \u2014 This enc_id (block "${info.block ?? "unknown"}") does not belong to your company or no longer exists. Run \`wport enterprise company view\` to get the latest enc_id list.`,
1282
+ err.status,
1283
+ err.body
1284
+ );
1285
+ case "profile_revision_conflict":
1286
+ return new import_core8.WportHttpError(
1287
+ `${base} \u2014 Block "${info.block ?? "unknown"}" changed since you last read it` + (info.current_revision ? ` (current revision: ${info.current_revision})` : "") + ". This CLI will not auto-retry: re-run `wport enterprise company view` to see the latest state, then confirm again.",
1288
+ err.status,
1289
+ err.body
1290
+ );
1291
+ case "profile_revision_required":
1292
+ return new import_core8.WportHttpError(
1293
+ `${base} \u2014 This request needs an If-Match revision (block "${info.block ?? "unknown"}") and none was recognized. This usually means the CLI is out of date \u2014 upgrade it, or re-run \`wport enterprise company view\` to fetch a fresh revision before retrying.`,
1294
+ err.status,
1295
+ err.body
1296
+ );
1297
+ }
1250
1298
  }
1251
1299
  function decorateEnterpriseError(err) {
1252
1300
  if (!(err instanceof import_core8.WportHttpError)) return err;
1253
1301
  const base = err.message;
1302
+ const errorCodeInfo = extractErrorCodeBody(err.body);
1303
+ if (errorCodeInfo) return decorateByErrorCode(base, err, errorCodeInfo);
1254
1304
  if (err.status === 401) {
1255
1305
  return new import_core8.WportHttpError(
1256
1306
  `${base} \u2014 If your key has expired, rotate it in place: \`wport enterprise keys rotate <enc_id>\` (an expired key is still accepted for rotate). If it was revoked or is incorrect, obtain a valid key and run \`wport enterprise login\`.`,
@@ -1311,6 +1361,9 @@ function enterprisePost2(opts, path, body, extra) {
1311
1361
  function enterprisePatch2(opts, path, body, extra) {
1312
1362
  return wrap(transport.enterprisePatch(withUserAgent(opts), path, body, extra));
1313
1363
  }
1364
+ function enterprisePut2(opts, path, body, extra) {
1365
+ return wrap(transport.enterprisePut(withUserAgent(opts), path, body, extra));
1366
+ }
1314
1367
  function enterpriseDelete2(opts, path, extra) {
1315
1368
  return wrap(transport.enterpriseDelete(withUserAgent(opts), path, extra));
1316
1369
  }
@@ -1921,6 +1974,15 @@ function renderDetailLines2(company) {
1921
1974
  }
1922
1975
  return lines;
1923
1976
  }
1977
+ var BLOCK_SUMMARY_FIELDS = ["pain_points", "awards", "milestones", "qa_items", "video_links"];
1978
+ function renderBlockSummaryLines(company) {
1979
+ const width = Math.max(...BLOCK_SUMMARY_FIELDS.map((f) => f.length)) + 3;
1980
+ return BLOCK_SUMMARY_FIELDS.map((field) => {
1981
+ const value = company[field];
1982
+ const count = Array.isArray(value) ? value.length : 0;
1983
+ return `${(field + ":").padEnd(width)}${count}`;
1984
+ });
1985
+ }
1924
1986
  async function runCompanyView(ctx, apiKey, flags) {
1925
1987
  const { body } = await enterpriseGet2(
1926
1988
  { baseUrl: ctx.baseUrl, locale: ctx.locale, timeoutMs: ctx.timeoutMs, apiKey },
@@ -1935,7 +1997,8 @@ async function runCompanyView(ctx, apiKey, flags) {
1935
1997
  printJson(company);
1936
1998
  return;
1937
1999
  }
1938
- process.stdout.write(renderDetailLines2(company).join("\n") + "\n");
2000
+ const lines = [...renderDetailLines2(company), "", ...renderBlockSummaryLines(company)];
2001
+ process.stdout.write(lines.join("\n") + "\n");
1939
2002
  }
1940
2003
  function registerEnterpriseCompanyView(parent) {
1941
2004
  parent.command("view").description("View your company information").option("--fields <list>", "output selected fields as JSON (comma-separated dotted paths)").action(async (flags, command) => {
@@ -1950,6 +2013,52 @@ function registerEnterpriseCompanyView(parent) {
1950
2013
  var import_node_crypto5 = require("crypto");
1951
2014
  var import_core19 = require("@wport/core");
1952
2015
 
2016
+ // src/commands/enterprise/company/block-replace-shared.ts
2017
+ function assertValidSubmittedItems(value, label) {
2018
+ if (!Array.isArray(value)) {
2019
+ throw new InvalidArgumentError(
2020
+ `"${label}" must be a JSON array, got ${value === null ? "null" : typeof value}`
2021
+ );
2022
+ }
2023
+ value.forEach((item, index) => {
2024
+ if (item === null || typeof item !== "object" || Array.isArray(item)) {
2025
+ throw new InvalidArgumentError(
2026
+ `"${label}[${index}]" must be a JSON object, got ` + (item === null ? "null" : Array.isArray(item) ? "an array" : typeof item)
2027
+ );
2028
+ }
2029
+ });
2030
+ return value;
2031
+ }
2032
+ function previewDeletions(current, submitted, summarize) {
2033
+ const submittedIds = new Set(
2034
+ submitted.filter((i) => typeof i.enc_id === "string").map((i) => i.enc_id)
2035
+ );
2036
+ return current.filter((item) => !submittedIds.has(item.enc_id)).map((item) => ({ enc_id: item.enc_id, summary: summarize(item) }));
2037
+ }
2038
+ function enforceDeletionConfirmation(label, deletions, confirm, color) {
2039
+ if (deletions.length === 0) return;
2040
+ printWarn(
2041
+ `This replace will delete ${deletions.length} existing "${label}" item(s): ` + deletions.map((d) => `${d.enc_id} (${d.summary || "untitled"})`).join("; "),
2042
+ color
2043
+ );
2044
+ if (!confirm) {
2045
+ throw new InvalidArgumentError(
2046
+ `Refusing to replace "${label}" without --confirm: ${deletions.length} existing item(s) would be deleted (see the warning above for the enc_id list). Re-run with --confirm to proceed.`
2047
+ );
2048
+ }
2049
+ }
2050
+ function summarizeItemsDiff(before, after) {
2051
+ const beforeIds = new Set(before.map((i) => i.enc_id));
2052
+ const afterIds = new Set(after.map((i) => i.enc_id));
2053
+ const added = after.filter((i) => !beforeIds.has(i.enc_id)).map((i) => i.enc_id);
2054
+ const removed = before.filter((i) => !afterIds.has(i.enc_id)).map((i) => i.enc_id);
2055
+ const parts = [];
2056
+ if (added.length > 0) parts.push(`added since your read: ${added.join(", ")}`);
2057
+ if (removed.length > 0) parts.push(`removed since your read: ${removed.join(", ")}`);
2058
+ if (parts.length === 0) parts.push("item content or order changed (enc_id set unchanged)");
2059
+ return parts.join("; ");
2060
+ }
2061
+
1953
2062
  // src/commands/enterprise/company/types.ts
1954
2063
  var BASIC_FIELDS = [
1955
2064
  "name",
@@ -1961,24 +2070,25 @@ var BASIC_FIELDS = [
1961
2070
  "capital_show_status",
1962
2071
  "website",
1963
2072
  "area_code",
1964
- "address"
2073
+ "address",
2074
+ "representative_name",
2075
+ "establishment_date",
2076
+ "directors",
2077
+ "is_representative_visible",
2078
+ "is_establishment_date_visible",
2079
+ "is_directors_visible"
1965
2080
  ];
1966
- var DESCRIPTION_FIELDS = ["description", "products_services", "latest_news"];
2081
+ var DESCRIPTION_FIELDS = ["description", "products_services", "latest_news", "video_links"];
1967
2082
  var FORBIDDEN_FIELDS = [
1968
2083
  "uniform_number",
2084
+ "is_uniform_number_visible",
1969
2085
  "banner_url",
1970
2086
  "photo_1",
1971
2087
  "photo_2",
1972
2088
  "photo_3",
1973
2089
  "video_1",
1974
2090
  "video_2",
1975
- "video_3",
1976
- "foundation_date",
1977
- "representative",
1978
- "directors",
1979
- "milestones",
1980
- "awards",
1981
- "qa"
2091
+ "video_3"
1982
2092
  ];
1983
2093
 
1984
2094
  // src/commands/enterprise/company/update.ts
@@ -2046,12 +2156,25 @@ async function buildCompanyUpdatePayloads(input, ctx, apiKey) {
2046
2156
  }
2047
2157
  let descriptions = null;
2048
2158
  if (inputHasDescriptionField) {
2049
- descriptions = {};
2159
+ const partial = {};
2050
2160
  for (const field of DESCRIPTION_FIELDS) {
2051
- if (field in input) descriptions[field] = input[field];
2161
+ if (field in input) partial[field] = input[field];
2162
+ }
2163
+ descriptions = partial;
2164
+ }
2165
+ let videoLinksRevision;
2166
+ let currentVideoLinks;
2167
+ if ("video_links" in input) {
2168
+ currentVideoLinks = current.video_links ?? [];
2169
+ videoLinksRevision = current.block_revisions?.video_links;
2170
+ if (!videoLinksRevision) {
2171
+ throw new CliError(
2172
+ "Backend contract appears broken: GET /company response is missing block_revisions.video_links",
2173
+ ExitCode.ServerOrNetworkError
2174
+ );
2052
2175
  }
2053
2176
  }
2054
- return { basic, descriptions };
2177
+ return { basic, descriptions, videoLinksRevision, currentVideoLinks };
2055
2178
  }
2056
2179
  function isDescriptionsPartialFailureBody(body) {
2057
2180
  return !!body && typeof body === "object" && Array.isArray(body.updated_sections) && typeof body.failed_section === "string";
@@ -2076,12 +2199,21 @@ function resolveUpdateIdempotencyKeys(needsBasic, needsDescriptions, flags) {
2076
2199
  descriptionsKey: needsDescriptions ? flags.descriptionsIdempotencyKey ?? flags.idempotencyKey ?? (0, import_node_crypto5.randomUUID)() : void 0
2077
2200
  };
2078
2201
  }
2079
- async function runCompanyUpdate(ctx, apiKey, source, idempotencyFlags, options = {}) {
2202
+ async function runCompanyUpdate(ctx, apiKey, source, idempotencyFlags, options = {}, confirm = false) {
2080
2203
  const input = readJsonObject(source, options);
2081
2204
  const needsBasic = BASIC_FIELDS.some((f) => f in input);
2082
2205
  const needsDescriptions = DESCRIPTION_FIELDS.some((f) => f in input);
2206
+ const needsVideoLinks = "video_links" in input;
2207
+ if (needsVideoLinks) {
2208
+ assertValidSubmittedItems(input.video_links, "video_links");
2209
+ }
2083
2210
  const { basicKey, descriptionsKey } = resolveUpdateIdempotencyKeys(needsBasic, needsDescriptions, idempotencyFlags);
2084
2211
  const payloads = await buildCompanyUpdatePayloads(input, ctx, apiKey);
2212
+ if (needsVideoLinks) {
2213
+ const submitted = payloads.descriptions?.video_links ?? [];
2214
+ const deletions = previewDeletions(payloads.currentVideoLinks ?? [], submitted, (item) => String(item.url ?? ""));
2215
+ enforceDeletionConfirmation("video_links", deletions, confirm, ctx.color ?? false);
2216
+ }
2085
2217
  const requestOpts = { baseUrl: ctx.baseUrl, locale: ctx.locale, timeoutMs: ctx.timeoutMs, apiKey };
2086
2218
  let basicResultCompany;
2087
2219
  if (needsBasic) {
@@ -2099,11 +2231,43 @@ async function runCompanyUpdate(ctx, apiKey, source, idempotencyFlags, options =
2099
2231
  requestOpts,
2100
2232
  "/company/descriptions",
2101
2233
  payloads.descriptions,
2102
- { idempotencyKey: descriptionsKey }
2234
+ {
2235
+ idempotencyKey: descriptionsKey,
2236
+ // 只有輸入帶 video_links 時才附 If-Match——後端只在這種情況要求它(spec §3.2.2);
2237
+ // 沒帶 video_links 時絕不能傳這個 key(用條件式 spread,不是傳 `undefined`)。
2238
+ ...needsVideoLinks ? { ifMatch: payloads.videoLinksRevision } : {}
2239
+ }
2103
2240
  );
2104
2241
  const result = (0, import_core19.unwrapDataResponse)(body);
2105
2242
  printCompanyResult(result.company, ctx.format);
2106
2243
  } catch (err) {
2244
+ if (needsVideoLinks && err instanceof ServerClientHttpError && err.status === 409) {
2245
+ const { body: freshBody } = await enterpriseGet2(requestOpts, "/company");
2246
+ const freshCurrent = (0, import_core19.unwrapDataResponse)(freshBody);
2247
+ const freshVideoLinks = freshCurrent.video_links ?? [];
2248
+ const diff = summarizeItemsDiff(payloads.currentVideoLinks ?? [], freshVideoLinks);
2249
+ const partialBody = isDescriptionsPartialFailureBody(err.body) ? err.body : void 0;
2250
+ printWarn(`Server state for "video_links" changed since your read: ${diff}.`, ctx.color ?? false);
2251
+ const descriptionsError = {
2252
+ updated_sections: partialBody?.updated_sections ?? [],
2253
+ failed_section: partialBody?.failed_section ?? "video_links",
2254
+ video_links_diff: diff
2255
+ };
2256
+ if (ctx.format === "json") {
2257
+ printJson(
2258
+ needsBasic ? { basic_updated: true, basic_company: basicResultCompany, descriptions_error: descriptionsError } : { descriptions_error: descriptionsError }
2259
+ );
2260
+ } else {
2261
+ if (needsBasic) process.stdout.write("Basic company info was updated successfully.\n");
2262
+ process.stdout.write(
2263
+ `Updated sections before failure: ${descriptionsError.updated_sections.join(", ")}; failed section: ${descriptionsError.failed_section}
2264
+ `
2265
+ );
2266
+ }
2267
+ throw new InvalidArgumentError(
2268
+ `Refusing to auto-retry "video_links" update after a stale revision conflict (409). ${diff}. Re-run \`wport enterprise company view\` and retry \`company update --confirm\` against the current state.`
2269
+ );
2270
+ }
2107
2271
  if (!needsBasic) {
2108
2272
  throw err;
2109
2273
  }
@@ -2134,10 +2298,13 @@ async function runCompanyUpdate(ctx, apiKey, source, idempotencyFlags, options =
2134
2298
  }
2135
2299
  function registerEnterpriseCompanyUpdate(parent) {
2136
2300
  parent.command("update").description(
2137
- "Update your company basic info and/or descriptions from a JSON file (uniform_number is read-only and cannot be changed via this command)"
2301
+ "Update your company basic info and/or descriptions from a JSON file (uniform_number is read-only and cannot be changed via this command). is_representative_visible / is_establishment_date_visible / is_directors_visible default to 0 (hidden) when not set. video_links (in descriptions) uses optimistic locking (If-Match, handled automatically from your latest `company view`); removing any existing video requires --confirm."
2138
2302
  ).requiredOption("--file <path>", 'path to a partial JSON company body, or "-" for stdin').option("--idempotency-key <key>", "single-section update only: reuse across retries (default: a fresh UUID)").option("--basic-idempotency-key <key>", "two-section update: idempotency key for PATCH /company/basic").option(
2139
2303
  "--descriptions-idempotency-key <key>",
2140
2304
  "two-section update: idempotency key for PATCH /company/descriptions"
2305
+ ).option(
2306
+ "--confirm",
2307
+ "confirm deletion of existing video_links items not present in the input (required when video_links is provided and would remove any existing item)"
2141
2308
  ).action(async (flags, command) => {
2142
2309
  const ctx = resolveContext(command);
2143
2310
  const globals = command.optsWithGlobals();
@@ -2151,7 +2318,8 @@ function registerEnterpriseCompanyUpdate(parent) {
2151
2318
  basicIdempotencyKey: flags.basicIdempotencyKey,
2152
2319
  descriptionsIdempotencyKey: flags.descriptionsIdempotencyKey
2153
2320
  },
2154
- { timeoutMs: ctx.timeoutMs }
2321
+ { timeoutMs: ctx.timeoutMs },
2322
+ flags.confirm === true
2155
2323
  );
2156
2324
  });
2157
2325
  }
@@ -2247,16 +2415,122 @@ function registerEnterpriseCompanyLogo(parent) {
2247
2415
  });
2248
2416
  }
2249
2417
 
2418
+ // src/commands/enterprise/company/replace.ts
2419
+ var import_node_crypto7 = require("crypto");
2420
+ var import_core21 = require("@wport/core");
2421
+ var REPLACE_SECTIONS = ["pain-points", "awards", "milestones", "qa-items"];
2422
+ var SECTION_CONFIG = {
2423
+ "pain-points": {
2424
+ path: "/company/pain-points",
2425
+ dataKey: "pain_points",
2426
+ summarize: (i) => String(i.title ?? "")
2427
+ },
2428
+ awards: {
2429
+ path: "/company/awards",
2430
+ dataKey: "awards",
2431
+ summarize: (i) => String(i.name ?? "")
2432
+ },
2433
+ milestones: {
2434
+ path: "/company/milestones",
2435
+ dataKey: "milestones",
2436
+ summarize: (i) => String(i.title ?? "")
2437
+ },
2438
+ "qa-items": {
2439
+ path: "/company/qa-items",
2440
+ dataKey: "qa_items",
2441
+ summarize: (i) => String(i.question ?? "")
2442
+ }
2443
+ };
2444
+ function isReplaceSection(v) {
2445
+ return REPLACE_SECTIONS.includes(v);
2446
+ }
2447
+ function printReplaceResult(result, config, format, color) {
2448
+ if (format === "json") {
2449
+ printJson(result);
2450
+ return;
2451
+ }
2452
+ printTable(
2453
+ result.items ?? [],
2454
+ [
2455
+ { header: "enc_id", value: (r) => String(r.enc_id ?? "") },
2456
+ { header: "summary", value: (r) => config.summarize(r) }
2457
+ ],
2458
+ color
2459
+ );
2460
+ process.stdout.write(`revision: ${result.revision ?? ""}
2461
+ `);
2462
+ }
2463
+ async function runCompanyReplace(ctx, apiKey, section, source, confirm, idempotencyKey, options = {}) {
2464
+ if (!isReplaceSection(section)) {
2465
+ throw new InvalidArgumentError(`Invalid section "${section}". Allowed: ${REPLACE_SECTIONS.join(", ")}`);
2466
+ }
2467
+ const config = SECTION_CONFIG[section];
2468
+ const input = readJsonObject(source, options);
2469
+ if (!Array.isArray(input.items)) {
2470
+ throw new InvalidArgumentError('Input must be a JSON object of the form { "items": [...] }');
2471
+ }
2472
+ const items = assertValidSubmittedItems(input.items, "items");
2473
+ const requestOpts = { baseUrl: ctx.baseUrl, locale: ctx.locale, timeoutMs: ctx.timeoutMs, apiKey };
2474
+ const { body: getBody } = await enterpriseGet2(requestOpts, "/company");
2475
+ const current = (0, import_core21.unwrapDataResponse)(getBody);
2476
+ const currentItems = current[config.dataKey] ?? [];
2477
+ const revision = current.block_revisions?.[config.dataKey];
2478
+ if (!revision) {
2479
+ throw new CliError(
2480
+ `Backend contract appears broken: GET /company response is missing block_revisions.${config.dataKey}`,
2481
+ ExitCode.ServerOrNetworkError
2482
+ );
2483
+ }
2484
+ const deletions = previewDeletions(currentItems, items, config.summarize);
2485
+ enforceDeletionConfirmation(section, deletions, confirm, ctx.color);
2486
+ try {
2487
+ const { body } = await enterprisePut2(requestOpts, config.path, { items }, { idempotencyKey, ifMatch: revision });
2488
+ const result = (0, import_core21.unwrapDataResponse)(body);
2489
+ printReplaceResult(result, config, ctx.format, ctx.color);
2490
+ } catch (err) {
2491
+ if (err instanceof import_core21.WportHttpError && err.status === 409) {
2492
+ const { body: freshBody } = await enterpriseGet2(requestOpts, "/company");
2493
+ const freshCurrent = (0, import_core21.unwrapDataResponse)(freshBody);
2494
+ const freshItems = freshCurrent[config.dataKey] ?? [];
2495
+ const diff = summarizeItemsDiff(currentItems, freshItems);
2496
+ printWarn(`Server state for "${section}" changed since your read: ${diff}.`, ctx.color);
2497
+ throw new InvalidArgumentError(
2498
+ `Refusing to auto-retry "${section}" replace after a stale revision conflict (409). ${diff}. Re-run \`wport enterprise company view\` and retry \`company replace --confirm\` against the current state.`
2499
+ );
2500
+ }
2501
+ throw err;
2502
+ }
2503
+ }
2504
+ function registerEnterpriseCompanyReplace(parent) {
2505
+ parent.command("replace <section>").description(
2506
+ `Replace an entire company profile block from a JSON file. <section> is one of: ${REPLACE_SECTIONS.join("|")}. This is a full replacement, not an add/update: any existing item not listed in the input is deleted.`
2507
+ ).requiredOption("--file <path>", 'path to a JSON body { "items": [...] }, or "-" for stdin').option("--confirm", "confirm deletion of existing items that are not present in the input").option("--idempotency-key <key>", "reuse across retries (default: a fresh UUID)").action(async (section, flags, command) => {
2508
+ const ctx = resolveContext(command);
2509
+ const globals = command.optsWithGlobals();
2510
+ const { key } = resolveApiKey(globals.apiKey);
2511
+ await runCompanyReplace(
2512
+ ctx,
2513
+ key,
2514
+ section,
2515
+ flags.file,
2516
+ flags.confirm === true,
2517
+ flags.idempotencyKey ?? (0, import_node_crypto7.randomUUID)(),
2518
+ { timeoutMs: ctx.timeoutMs }
2519
+ );
2520
+ });
2521
+ }
2522
+
2250
2523
  // src/commands/enterprise/company/index.ts
2251
2524
  function registerEnterpriseCompanyCommand(parent) {
2252
2525
  const company = parent.command("company").description("View and manage your company information");
2253
2526
  registerEnterpriseCompanyView(company);
2254
2527
  registerEnterpriseCompanyUpdate(company);
2255
2528
  registerEnterpriseCompanyLogo(company);
2529
+ registerEnterpriseCompanyReplace(company);
2256
2530
  }
2257
2531
 
2258
2532
  // src/commands/enterprise/talents/list.ts
2259
- var import_core21 = require("@wport/core");
2533
+ var import_core22 = require("@wport/core");
2260
2534
  var DEFAULT_PAGE_SIZE = 20;
2261
2535
  var MINIMAL_LIST_FIELDS2 = ["enc_resume_id", "candidate_name", "applied_job_title", "applied_at"];
2262
2536
  function formatDate4(value) {
@@ -2279,7 +2553,7 @@ async function runEnterpriseTalentsList(ctx, apiKey, flags) {
2279
2553
  pageSize: flags.pageSize ?? DEFAULT_PAGE_SIZE
2280
2554
  }
2281
2555
  );
2282
- const paged = (0, import_core21.asPaginatedBody)(body);
2556
+ const paged = (0, import_core22.asPaginatedBody)(body);
2283
2557
  const projection = flags.minimal ? MINIMAL_LIST_FIELDS2 : flags.fields ? parseFieldsList(flags.fields) : void 0;
2284
2558
  if (projection || ctx.format === "json") {
2285
2559
  printJson(projection ? { ...paged, data: paged.data.map((row) => pickPaths(row, projection)) } : paged);
@@ -2312,7 +2586,7 @@ function registerEnterpriseTalentsList(parent) {
2312
2586
  }
2313
2587
 
2314
2588
  // src/commands/enterprise/talents/view.ts
2315
- var import_core22 = require("@wport/core");
2589
+ var import_core23 = require("@wport/core");
2316
2590
  async function runEnterpriseTalentsView(ctx, apiKey, encResumeId, flags) {
2317
2591
  const trimmed = encResumeId.trim();
2318
2592
  if (!trimmed) {
@@ -2322,7 +2596,7 @@ async function runEnterpriseTalentsView(ctx, apiKey, encResumeId, flags) {
2322
2596
  { baseUrl: ctx.baseUrl, locale: ctx.locale, timeoutMs: ctx.timeoutMs, apiKey },
2323
2597
  `/talents/${encodeURIComponent(trimmed)}`
2324
2598
  );
2325
- const resume = (0, import_core22.unwrapDataResponse)(body);
2599
+ const resume = (0, import_core23.unwrapDataResponse)(body);
2326
2600
  if (flags.fields) {
2327
2601
  printJson(pickPaths(resume, parseFieldsList(flags.fields)));
2328
2602
  return;
@@ -2339,8 +2613,8 @@ function registerEnterpriseTalentsView(parent) {
2339
2613
  }
2340
2614
 
2341
2615
  // src/commands/enterprise/talents/respond.ts
2342
- var import_node_crypto7 = require("crypto");
2343
- var import_core23 = require("@wport/core");
2616
+ var import_node_crypto8 = require("crypto");
2617
+ var import_core24 = require("@wport/core");
2344
2618
  function resolveRespondBody(flags, options = {}) {
2345
2619
  const hasBody = flags.body !== void 0;
2346
2620
  const hasBodyFile = flags.bodyFile !== void 0;
@@ -2372,7 +2646,7 @@ async function runEnterpriseTalentsRespond(ctx, apiKey, encResumeId, flags, idem
2372
2646
  payload,
2373
2647
  { idempotencyKey }
2374
2648
  );
2375
- const result = (0, import_core23.unwrapDataResponse)(respBody);
2649
+ const result = (0, import_core24.unwrapDataResponse)(respBody);
2376
2650
  if (ctx.format === "json") {
2377
2651
  printJson(result);
2378
2652
  return;
@@ -2385,7 +2659,7 @@ function registerEnterpriseTalentsRespond(parent) {
2385
2659
  const ctx = resolveContext(command);
2386
2660
  const globals = command.optsWithGlobals();
2387
2661
  const { key } = resolveApiKey(globals.apiKey);
2388
- await runEnterpriseTalentsRespond(ctx, key, encResumeId, flags, flags.idempotencyKey ?? (0, import_node_crypto7.randomUUID)());
2662
+ await runEnterpriseTalentsRespond(ctx, key, encResumeId, flags, flags.idempotencyKey ?? (0, import_node_crypto8.randomUUID)());
2389
2663
  });
2390
2664
  }
2391
2665
 
@@ -2400,8 +2674,8 @@ function registerEnterpriseTalentsCommand(parent) {
2400
2674
  }
2401
2675
 
2402
2676
  // src/commands/enterprise/campaigns/create.ts
2403
- var import_node_crypto8 = require("crypto");
2404
- var import_core24 = require("@wport/core");
2677
+ var import_node_crypto9 = require("crypto");
2678
+ var import_core25 = require("@wport/core");
2405
2679
  async function runCampaignCreate(ctx, apiKey, source, idempotencyKey) {
2406
2680
  const campaignBody = readJsonObject(source, { timeoutMs: ctx.timeoutMs });
2407
2681
  const { body } = await enterprisePost2(
@@ -2410,7 +2684,7 @@ async function runCampaignCreate(ctx, apiKey, source, idempotencyKey) {
2410
2684
  campaignBody,
2411
2685
  { idempotencyKey }
2412
2686
  );
2413
- const created = (0, import_core24.unwrapDataResponse)(body);
2687
+ const created = (0, import_core25.unwrapDataResponse)(body);
2414
2688
  if (ctx.format === "json") {
2415
2689
  printJson(created);
2416
2690
  return;
@@ -2423,12 +2697,12 @@ function registerEnterpriseCampaignsCreate(parent) {
2423
2697
  const ctx = resolveContext(command);
2424
2698
  const globals = command.optsWithGlobals();
2425
2699
  const { key } = resolveApiKey(globals.apiKey);
2426
- await runCampaignCreate(ctx, key, flags.file, flags.idempotencyKey ?? (0, import_node_crypto8.randomUUID)());
2700
+ await runCampaignCreate(ctx, key, flags.file, flags.idempotencyKey ?? (0, import_node_crypto9.randomUUID)());
2427
2701
  });
2428
2702
  }
2429
2703
 
2430
2704
  // src/commands/enterprise/campaigns/list.ts
2431
- var import_core25 = require("@wport/core");
2705
+ var import_core26 = require("@wport/core");
2432
2706
  var STATUS_MAP2 = { open: 1, closed: 0 };
2433
2707
  var MINIMAL_LIST_FIELDS3 = ["enc_id", "name", "status", "job_count"];
2434
2708
  function mapStatusFlag2(raw) {
@@ -2458,7 +2732,7 @@ async function runEnterpriseCampaignsList(ctx, apiKey, flags) {
2458
2732
  status: mapStatusFlag2(flags.status)
2459
2733
  }
2460
2734
  );
2461
- const paged = (0, import_core25.asPaginatedBody)(body);
2735
+ const paged = (0, import_core26.asPaginatedBody)(body);
2462
2736
  const projection = flags.minimal ? MINIMAL_LIST_FIELDS3 : flags.fields ? parseFieldsList(flags.fields) : void 0;
2463
2737
  if (projection || ctx.format === "json") {
2464
2738
  printJson(projection ? { ...paged, data: paged.data.map((row) => pickPaths(row, projection)) } : paged);
@@ -2490,8 +2764,8 @@ function registerEnterpriseCampaignsList(parent) {
2490
2764
  }
2491
2765
 
2492
2766
  // src/commands/enterprise/campaigns/lifecycle.ts
2493
- var import_node_crypto9 = require("crypto");
2494
- var import_core26 = require("@wport/core");
2767
+ var import_node_crypto10 = require("crypto");
2768
+ var import_core27 = require("@wport/core");
2495
2769
  async function runCampaignTransition(ctx, apiKey, encId, action, idempotencyKey) {
2496
2770
  const trimmed = requireEncId(encId);
2497
2771
  const { body } = await enterprisePatch2(
@@ -2500,7 +2774,7 @@ async function runCampaignTransition(ctx, apiKey, encId, action, idempotencyKey)
2500
2774
  {},
2501
2775
  { idempotencyKey }
2502
2776
  );
2503
- const result = (0, import_core26.unwrapDataResponse)(body);
2777
+ const result = (0, import_core27.unwrapDataResponse)(body);
2504
2778
  if (ctx.format === "json") {
2505
2779
  printJson(result);
2506
2780
  return;
@@ -2513,20 +2787,20 @@ function registerEnterpriseCampaignsPublish(parent) {
2513
2787
  parent.command("publish <enc_id>").description("Publish (activate) a recruitment campaign").option("--idempotency-key <key>", "reuse across retries (default: a fresh UUID)").action(async (encId, flags, command) => {
2514
2788
  const ctx = resolveContext(command);
2515
2789
  const { key } = resolveApiKey(command.optsWithGlobals().apiKey);
2516
- await runCampaignTransition(ctx, key, encId, "publish", flags.idempotencyKey ?? (0, import_node_crypto9.randomUUID)());
2790
+ await runCampaignTransition(ctx, key, encId, "publish", flags.idempotencyKey ?? (0, import_node_crypto10.randomUUID)());
2517
2791
  });
2518
2792
  }
2519
2793
  function registerEnterpriseCampaignsUnpublish(parent) {
2520
2794
  parent.command("unpublish <enc_id>").description("Unpublish (deactivate) a recruitment campaign").option("--idempotency-key <key>", "reuse across retries (default: a fresh UUID)").action(async (encId, flags, command) => {
2521
2795
  const ctx = resolveContext(command);
2522
2796
  const { key } = resolveApiKey(command.optsWithGlobals().apiKey);
2523
- await runCampaignTransition(ctx, key, encId, "unpublish", flags.idempotencyKey ?? (0, import_node_crypto9.randomUUID)());
2797
+ await runCampaignTransition(ctx, key, encId, "unpublish", flags.idempotencyKey ?? (0, import_node_crypto10.randomUUID)());
2524
2798
  });
2525
2799
  }
2526
2800
 
2527
2801
  // src/commands/enterprise/campaigns/update.ts
2528
- var import_node_crypto10 = require("crypto");
2529
- var import_core27 = require("@wport/core");
2802
+ var import_node_crypto11 = require("crypto");
2803
+ var import_core28 = require("@wport/core");
2530
2804
  async function runCampaignUpdate(ctx, apiKey, encId, source, idempotencyKey) {
2531
2805
  const trimmed = requireEncId(encId);
2532
2806
  const campaignBody = readJsonObject(source, { timeoutMs: ctx.timeoutMs });
@@ -2536,7 +2810,7 @@ async function runCampaignUpdate(ctx, apiKey, encId, source, idempotencyKey) {
2536
2810
  campaignBody,
2537
2811
  { idempotencyKey }
2538
2812
  );
2539
- const updated = (0, import_core27.unwrapDataResponse)(body);
2813
+ const updated = (0, import_core28.unwrapDataResponse)(body);
2540
2814
  if (ctx.format === "json") {
2541
2815
  printJson(updated);
2542
2816
  return;
@@ -2549,12 +2823,12 @@ function registerEnterpriseCampaignsUpdate(parent) {
2549
2823
  const ctx = resolveContext(command);
2550
2824
  const globals = command.optsWithGlobals();
2551
2825
  const { key } = resolveApiKey(globals.apiKey);
2552
- await runCampaignUpdate(ctx, key, encId, flags.file, flags.idempotencyKey ?? (0, import_node_crypto10.randomUUID)());
2826
+ await runCampaignUpdate(ctx, key, encId, flags.file, flags.idempotencyKey ?? (0, import_node_crypto11.randomUUID)());
2553
2827
  });
2554
2828
  }
2555
2829
 
2556
2830
  // src/commands/enterprise/campaigns/view.ts
2557
- var import_core28 = require("@wport/core");
2831
+ var import_core29 = require("@wport/core");
2558
2832
  async function runEnterpriseCampaignsView(ctx, apiKey, encId, flags) {
2559
2833
  const trimmed = encId.trim();
2560
2834
  if (!trimmed) {
@@ -2564,7 +2838,7 @@ async function runEnterpriseCampaignsView(ctx, apiKey, encId, flags) {
2564
2838
  { baseUrl: ctx.baseUrl, locale: ctx.locale, timeoutMs: ctx.timeoutMs, apiKey },
2565
2839
  `/campaigns/${encodeURIComponent(trimmed)}`
2566
2840
  );
2567
- const campaign = (0, import_core28.unwrapDataResponse)(body);
2841
+ const campaign = (0, import_core29.unwrapDataResponse)(body);
2568
2842
  if (flags.fields) {
2569
2843
  printJson(pickPaths(campaign, parseFieldsList(flags.fields)));
2570
2844
  return;
@@ -2709,10 +2983,10 @@ function registerLoginCommand(program2) {
2709
2983
  }
2710
2984
 
2711
2985
  // src/commands/auth/whoami.ts
2712
- var import_core30 = require("@wport/core");
2986
+ var import_core31 = require("@wport/core");
2713
2987
 
2714
2988
  // src/lib/personal-client.ts
2715
- var import_core29 = require("@wport/core");
2989
+ var import_core30 = require("@wport/core");
2716
2990
  var EXPIRY_SKEW_MS = 3e4;
2717
2991
  var NOT_LOGGED_IN_MESSAGE = "Not logged in. Run `wport login`.";
2718
2992
  async function ensureFreshCredentials(opts) {
@@ -2741,7 +3015,7 @@ async function attemptRequest(opts, method, path, accessToken, body, query, extr
2741
3015
  const headers = {
2742
3016
  Authorization: `Bearer ${accessToken}`,
2743
3017
  "Accept-Language": opts.locale,
2744
- "User-Agent": (0, import_core29.buildUserAgent)("wport-cli", "0.9.3"),
3018
+ "User-Agent": (0, import_core30.buildUserAgent)("wport-cli", "0.10.0"),
2745
3019
  "X-Source": CLI_SOURCE,
2746
3020
  Accept: "application/json"
2747
3021
  };
@@ -2752,7 +3026,7 @@ async function attemptRequest(opts, method, path, accessToken, body, query, extr
2752
3026
  headers,
2753
3027
  body: body !== void 0 ? JSON.stringify(body) : void 0
2754
3028
  });
2755
- const res = await (0, import_core29.fetchWithTimeout)(request, opts.timeoutMs);
3029
+ const res = await (0, import_core30.fetchWithTimeout)(request, opts.timeoutMs);
2756
3030
  const respBody = await res.json().catch(() => null);
2757
3031
  return { status: res.status, body: respBody, headers: res.headers };
2758
3032
  }
@@ -2784,13 +3058,13 @@ function personalDelete(opts, path, extra) {
2784
3058
  }
2785
3059
  function throwPersonalHttpError(status, body) {
2786
3060
  if (status === 401) {
2787
- const base = (0, import_core29.extractErrorMessage)(body) ?? `HTTP ${status}`;
3061
+ const base = (0, import_core30.extractErrorMessage)(body) ?? `HTTP ${status}`;
2788
3062
  throw new CliError(
2789
3063
  `${base} \u2014 Your session may have expired or the request was rejected. Run \`wport login\` to sign in again.`,
2790
3064
  ExitCode.ServerClientError
2791
3065
  );
2792
3066
  }
2793
- (0, import_core29.throwForHttpStatus)(status, body);
3067
+ (0, import_core30.throwForHttpStatus)(status, body);
2794
3068
  }
2795
3069
  function warnIfRateLimitLow2(headers) {
2796
3070
  const remaining = Number(headers.get("x-ratelimit-remaining"));
@@ -2801,7 +3075,7 @@ function warnIfRateLimitLow2(headers) {
2801
3075
  }
2802
3076
 
2803
3077
  // src/commands/auth/whoami.ts
2804
- var import_core31 = require("@wport/core");
3078
+ var import_core32 = require("@wport/core");
2805
3079
  var PLACEHOLDER = "\u2014";
2806
3080
  function display(value) {
2807
3081
  const clean = sanitizeForTerminal(value ?? "");
@@ -2809,8 +3083,8 @@ function display(value) {
2809
3083
  }
2810
3084
  async function performWhoami(ctx) {
2811
3085
  const opts = { baseUrl: ctx.baseUrl, locale: ctx.locale, timeoutMs: ctx.timeoutMs };
2812
- const { body } = await personalGet(opts, import_core31.OAUTH_SESSIONS_BASE);
2813
- const sessions = (0, import_core30.unwrapDataArray)(body);
3086
+ const { body } = await personalGet(opts, import_core32.OAUTH_SESSIONS_BASE);
3087
+ const sessions = (0, import_core31.unwrapDataArray)(body);
2814
3088
  const current = sessions.find((s) => s.is_current);
2815
3089
  const localLoginAt = loadPersonalCredentials()?.session_created_at ?? null;
2816
3090
  if (ctx.format === "json") {
@@ -2862,15 +3136,15 @@ function registerLogoutCommand(program2) {
2862
3136
  }
2863
3137
 
2864
3138
  // src/commands/sessions/list.ts
2865
- var import_core32 = require("@wport/core");
2866
3139
  var import_core33 = require("@wport/core");
3140
+ var import_core34 = require("@wport/core");
2867
3141
  function formatDate5(value) {
2868
3142
  return value ? String(value).slice(0, 10) : "";
2869
3143
  }
2870
3144
  async function runSessionsList(ctx) {
2871
3145
  const opts = { baseUrl: ctx.baseUrl, locale: ctx.locale, timeoutMs: ctx.timeoutMs };
2872
- const { body } = await personalGet(opts, import_core33.OAUTH_SESSIONS_BASE);
2873
- const sessions = (0, import_core32.unwrapDataArray)(body);
3146
+ const { body } = await personalGet(opts, import_core34.OAUTH_SESSIONS_BASE);
3147
+ const sessions = (0, import_core33.unwrapDataArray)(body);
2874
3148
  if (ctx.format === "json") {
2875
3149
  printJson(sessions);
2876
3150
  return;
@@ -2894,8 +3168,8 @@ function registerSessionsList(parent) {
2894
3168
  }
2895
3169
 
2896
3170
  // src/commands/sessions/revoke.ts
2897
- var import_core34 = require("@wport/core");
2898
3171
  var import_core35 = require("@wport/core");
3172
+ var import_core36 = require("@wport/core");
2899
3173
  async function runSessionsRevoke(ctx, encId, allOthers) {
2900
3174
  const hasEncId = encId !== void 0;
2901
3175
  if (hasEncId === allOthers) {
@@ -2903,8 +3177,8 @@ async function runSessionsRevoke(ctx, encId, allOthers) {
2903
3177
  }
2904
3178
  const opts = { baseUrl: ctx.baseUrl, locale: ctx.locale, timeoutMs: ctx.timeoutMs };
2905
3179
  if (allOthers) {
2906
- const { body } = await personalDelete(opts, `${import_core34.OAUTH_SESSIONS_BASE}/others`);
2907
- const result = (0, import_core35.unwrapDataResponse)(body);
3180
+ const { body } = await personalDelete(opts, `${import_core35.OAUTH_SESSIONS_BASE}/others`);
3181
+ const result = (0, import_core36.unwrapDataResponse)(body);
2908
3182
  if (ctx.format === "json") {
2909
3183
  printJson(result);
2910
3184
  return;
@@ -2915,7 +3189,7 @@ async function runSessionsRevoke(ctx, encId, allOthers) {
2915
3189
  }
2916
3190
  const trimmed = encId.trim();
2917
3191
  if (!trimmed) throw new CliError("enc_id must not be empty", ExitCode.InvalidArgument);
2918
- await personalDelete(opts, `${import_core34.OAUTH_SESSIONS_BASE}/${encodeURIComponent(trimmed)}`);
3192
+ await personalDelete(opts, `${import_core35.OAUTH_SESSIONS_BASE}/${encodeURIComponent(trimmed)}`);
2919
3193
  if (ctx.format === "json") {
2920
3194
  printJson({ enc_id: trimmed, revoked: true });
2921
3195
  return;
@@ -2938,18 +3212,18 @@ function registerSessionsCommand(program2) {
2938
3212
  }
2939
3213
 
2940
3214
  // src/commands/personal/resumes/schema.ts
2941
- var import_core36 = require("@wport/core");
3215
+ var import_core37 = require("@wport/core");
2942
3216
  function registerPersonalResumesSchema(parent) {
2943
3217
  parent.command("schema").description("Print the resume aggregate JSON Schema (offline, no login required)").option("--section <name>", "print only the given section (e.g. education, work_experience)").action((opts) => {
2944
- printJson((0, import_core36.buildAggregateJsonSchema)(opts.section));
3218
+ printJson((0, import_core37.buildAggregateJsonSchema)(opts.section));
2945
3219
  });
2946
3220
  }
2947
3221
 
2948
3222
  // src/commands/personal/resumes/validate.ts
2949
- var import_core37 = require("@wport/core");
3223
+ var import_core38 = require("@wport/core");
2950
3224
  function runResumesValidate(ctx, filePath) {
2951
3225
  const input = readJsonInput(filePath, { timeoutMs: ctx.timeoutMs });
2952
- const issues = (0, import_core37.validateAggregate)(input);
3226
+ const issues = (0, import_core38.validateAggregate)(input);
2953
3227
  if (issues.length === 0) {
2954
3228
  if (ctx.format === "json") {
2955
3229
  printJson({ valid: true });
@@ -2977,9 +3251,9 @@ function registerPersonalResumesValidate(parent) {
2977
3251
 
2978
3252
  // src/commands/personal/resumes/template.ts
2979
3253
  var import_node_fs8 = require("fs");
2980
- var import_core38 = require("@wport/core");
3254
+ var import_core39 = require("@wport/core");
2981
3255
  function runResumesTemplate(outPath) {
2982
- const template = (0, import_core38.buildTemplate)();
3256
+ const template = (0, import_core39.buildTemplate)();
2983
3257
  if (outPath === void 0) {
2984
3258
  printJson(template);
2985
3259
  return;
@@ -3003,8 +3277,8 @@ function registerPersonalResumesTemplate(parent) {
3003
3277
  }
3004
3278
 
3005
3279
  // src/commands/personal/resumes/list.ts
3006
- var import_core39 = require("@wport/core");
3007
3280
  var import_core40 = require("@wport/core");
3281
+ var import_core41 = require("@wport/core");
3008
3282
  var MINIMAL_LIST_FIELDS4 = ["enc_id", "name", "updated_at", "is_complete", "is_published"];
3009
3283
  function formatDate6(value) {
3010
3284
  return value ? String(value).slice(0, 10) : "";
@@ -3014,8 +3288,8 @@ function formatQuotaLine(quota) {
3014
3288
  return `${quota.used}/${quota.max_resumes} used, ${status}.`;
3015
3289
  }
3016
3290
  async function fetchResumeList(opts) {
3017
- const { body } = await personalGet(opts, import_core40.PERSONAL_RESUMES_BASE);
3018
- return (0, import_core39.unwrapDataResponse)(body);
3291
+ const { body } = await personalGet(opts, import_core41.PERSONAL_RESUMES_BASE);
3292
+ return (0, import_core40.unwrapDataResponse)(body);
3019
3293
  }
3020
3294
  async function runResumesList(ctx, flags) {
3021
3295
  if (flags.fields && flags.minimal) {
@@ -3048,20 +3322,20 @@ function registerPersonalResumesList(parent) {
3048
3322
  }
3049
3323
 
3050
3324
  // src/commands/personal/resumes/view.ts
3051
- var import_core41 = require("@wport/core");
3052
3325
  var import_core42 = require("@wport/core");
3053
3326
  var import_core43 = require("@wport/core");
3327
+ var import_core44 = require("@wport/core");
3054
3328
  async function fetchResumeAggregate(opts, encId) {
3055
3329
  const trimmed = encId.trim();
3056
3330
  if (!trimmed) {
3057
3331
  throw new CliError("enc_id must not be empty", ExitCode.InvalidArgument);
3058
3332
  }
3059
- const { body } = await personalGet(opts, `${import_core42.PERSONAL_RESUMES_BASE}/${encodeURIComponent(trimmed)}`);
3060
- return (0, import_core41.unwrapDataResponse)(body);
3333
+ const { body } = await personalGet(opts, `${import_core43.PERSONAL_RESUMES_BASE}/${encodeURIComponent(trimmed)}`);
3334
+ return (0, import_core42.unwrapDataResponse)(body);
3061
3335
  }
3062
3336
  function summarizeSections(resume) {
3063
3337
  const rows = [{ section: "name", summary: resume.name }];
3064
- for (const def of import_core43.SECTIONS) {
3338
+ for (const def of import_core44.SECTIONS) {
3065
3339
  rows.push({ section: def.key, summary: summarizeSection(def, resume) });
3066
3340
  }
3067
3341
  return rows;
@@ -3139,15 +3413,15 @@ function registerPersonalResumesExport(parent) {
3139
3413
  }
3140
3414
 
3141
3415
  // src/commands/personal/resumes/create.ts
3142
- var import_core47 = require("@wport/core");
3416
+ var import_core48 = require("@wport/core");
3143
3417
 
3144
3418
  // src/lib/resume-orchestrator.ts
3145
- var import_node_crypto11 = require("crypto");
3146
- var import_core44 = require("@wport/core");
3419
+ var import_node_crypto12 = require("crypto");
3147
3420
  var import_core45 = require("@wport/core");
3148
3421
  var import_core46 = require("@wport/core");
3422
+ var import_core47 = require("@wport/core");
3149
3423
  function freshIdempotencyKey() {
3150
- return { idempotencyKey: (0, import_node_crypto11.randomUUID)() };
3424
+ return { idempotencyKey: (0, import_node_crypto12.randomUUID)() };
3151
3425
  }
3152
3426
  function describeError(err) {
3153
3427
  return err instanceof Error ? err.message : String(err);
@@ -3160,8 +3434,8 @@ function extractErrorCode(body) {
3160
3434
  }
3161
3435
  async function createShell(opts) {
3162
3436
  try {
3163
- const { body } = await personalPost(opts, import_core45.PERSONAL_RESUMES_BASE, {}, freshIdempotencyKey());
3164
- return (0, import_core44.unwrapDataResponse)(body).enc_id;
3437
+ const { body } = await personalPost(opts, import_core46.PERSONAL_RESUMES_BASE, {}, freshIdempotencyKey());
3438
+ return (0, import_core45.unwrapDataResponse)(body).enc_id;
3165
3439
  } catch (err) {
3166
3440
  if (err instanceof ServerClientHttpError) {
3167
3441
  const code = extractErrorCode(err.body);
@@ -3182,7 +3456,7 @@ async function createShell(opts) {
3182
3456
  }
3183
3457
  }
3184
3458
  async function renameResume(opts, encId, name) {
3185
- await personalPut(opts, `${import_core45.PERSONAL_RESUMES_BASE}/${encodeURIComponent(encId)}/name`, { name }, freshIdempotencyKey());
3459
+ await personalPut(opts, `${import_core46.PERSONAL_RESUMES_BASE}/${encodeURIComponent(encId)}/name`, { name }, freshIdempotencyKey());
3186
3460
  }
3187
3461
  function toWorkExperienceWriteItem(item) {
3188
3462
  const { is_current, ...rest } = item;
@@ -3194,8 +3468,8 @@ function splitItemEncId(item) {
3194
3468
  return [valid, rest];
3195
3469
  }
3196
3470
  async function writeSection(opts, encId, key, value, mode) {
3197
- const plan = import_core45.SECTION_WRITE_PLAN[key];
3198
- const base = `${import_core45.PERSONAL_RESUMES_BASE}/${encodeURIComponent(encId)}`;
3471
+ const plan = import_core46.SECTION_WRITE_PLAN[key];
3472
+ const base = `${import_core46.PERSONAL_RESUMES_BASE}/${encodeURIComponent(encId)}`;
3199
3473
  switch (plan.kind) {
3200
3474
  case "per-item-post": {
3201
3475
  for (const item of value) {
@@ -3262,7 +3536,7 @@ async function createAggregate(opts, aggregate) {
3262
3536
  if (aggregate.name !== void 0) {
3263
3537
  reports.push(await attemptStep("name", () => renameResume(opts, encId, aggregate.name)));
3264
3538
  }
3265
- for (const section of import_core46.SECTIONS) {
3539
+ for (const section of import_core47.SECTIONS) {
3266
3540
  const value = aggregate[section.key];
3267
3541
  if (value === void 0) continue;
3268
3542
  reports.push(await attemptStep(section.key, () => writeSection(opts, encId, section.key, value, "create")));
@@ -3272,9 +3546,9 @@ async function createAggregate(opts, aggregate) {
3272
3546
  async function updateAggregate(opts, encId, aggregate, onlySection) {
3273
3547
  const reports = [];
3274
3548
  if (onlySection !== void 0) {
3275
- const section = (0, import_core46.getSection)(onlySection);
3549
+ const section = (0, import_core47.getSection)(onlySection);
3276
3550
  if (!section) {
3277
- const allowed = import_core46.SECTIONS.map((s) => s.key).join(", ");
3551
+ const allowed = import_core47.SECTIONS.map((s) => s.key).join(", ");
3278
3552
  throw new CliError(`Unknown section "${onlySection}". Allowed: ${allowed}`, ExitCode.InvalidArgument);
3279
3553
  }
3280
3554
  const value = aggregate[onlySection];
@@ -3287,7 +3561,7 @@ async function updateAggregate(opts, encId, aggregate, onlySection) {
3287
3561
  if (aggregate.name !== void 0) {
3288
3562
  reports.push(await attemptStep("name", () => renameResume(opts, encId, aggregate.name)));
3289
3563
  }
3290
- for (const section of import_core46.SECTIONS) {
3564
+ for (const section of import_core47.SECTIONS) {
3291
3565
  const value = aggregate[section.key];
3292
3566
  if (value === void 0) continue;
3293
3567
  reports.push(await attemptStep(section.key, () => writeSection(opts, encId, section.key, value, "update")));
@@ -3298,7 +3572,7 @@ async function updateAggregate(opts, encId, aggregate, onlySection) {
3298
3572
  // src/commands/personal/resumes/create.ts
3299
3573
  async function runResumesCreate(ctx, filePath) {
3300
3574
  const input = readJsonObject(filePath, { timeoutMs: ctx.timeoutMs });
3301
- const issues = (0, import_core47.validateAggregate)(input);
3575
+ const issues = (0, import_core48.validateAggregate)(input);
3302
3576
  if (issues.length > 0) {
3303
3577
  if (ctx.format === "json") {
3304
3578
  printJson({ valid: false, issues });
@@ -3390,9 +3664,9 @@ function registerPersonalResumesUpdate(parent) {
3390
3664
  }
3391
3665
 
3392
3666
  // src/commands/personal/resumes/copy.ts
3393
- var import_node_crypto12 = require("crypto");
3394
- var import_core48 = require("@wport/core");
3667
+ var import_node_crypto13 = require("crypto");
3395
3668
  var import_core49 = require("@wport/core");
3669
+ var import_core50 = require("@wport/core");
3396
3670
  function requireEncId3(encId) {
3397
3671
  const trimmed = encId.trim();
3398
3672
  if (!trimmed) {
@@ -3411,12 +3685,12 @@ function printCopyResult(ctx, sourceEncId, newEncId) {
3411
3685
  async function runResumesCopy(ctx, encId, name) {
3412
3686
  const trimmed = requireEncId3(encId);
3413
3687
  const opts = { baseUrl: ctx.baseUrl, locale: ctx.locale, timeoutMs: ctx.timeoutMs };
3414
- const { body } = await personalPost(opts, `${import_core49.PERSONAL_RESUMES_BASE}/${encodeURIComponent(trimmed)}/duplicate`, {}, { idempotencyKey: (0, import_node_crypto12.randomUUID)() });
3415
- const { enc_id: newEncId } = (0, import_core48.unwrapDataResponse)(body);
3688
+ const { body } = await personalPost(opts, `${import_core50.PERSONAL_RESUMES_BASE}/${encodeURIComponent(trimmed)}/duplicate`, {}, { idempotencyKey: (0, import_node_crypto13.randomUUID)() });
3689
+ const { enc_id: newEncId } = (0, import_core49.unwrapDataResponse)(body);
3416
3690
  printCopyResult(ctx, trimmed, newEncId);
3417
3691
  if (name === void 0) return;
3418
3692
  try {
3419
- await personalPut(opts, `${import_core49.PERSONAL_RESUMES_BASE}/${encodeURIComponent(newEncId)}/name`, { name }, { idempotencyKey: (0, import_node_crypto12.randomUUID)() });
3693
+ await personalPut(opts, `${import_core50.PERSONAL_RESUMES_BASE}/${encodeURIComponent(newEncId)}/name`, { name }, { idempotencyKey: (0, import_node_crypto13.randomUUID)() });
3420
3694
  } catch (err) {
3421
3695
  const reason = err instanceof Error ? err.message : String(err);
3422
3696
  throw new CliError(
@@ -3432,9 +3706,9 @@ function registerPersonalResumesCopy(parent) {
3432
3706
  }
3433
3707
 
3434
3708
  // src/commands/personal/resumes/publish.ts
3435
- var import_node_crypto13 = require("crypto");
3436
- var import_core50 = require("@wport/core");
3709
+ var import_node_crypto14 = require("crypto");
3437
3710
  var import_core51 = require("@wport/core");
3711
+ var import_core52 = require("@wport/core");
3438
3712
  function requireEncId4(encId) {
3439
3713
  const trimmed = encId.trim();
3440
3714
  if (!trimmed) {
@@ -3448,11 +3722,11 @@ async function runResumesPublishTransition(ctx, encId, action) {
3448
3722
  const targetStatus = action === "publish";
3449
3723
  const { body } = await personalPatch(
3450
3724
  opts,
3451
- `${import_core51.PERSONAL_RESUMES_BASE}/${encodeURIComponent(trimmed)}/published-status`,
3725
+ `${import_core52.PERSONAL_RESUMES_BASE}/${encodeURIComponent(trimmed)}/published-status`,
3452
3726
  { target_status: targetStatus },
3453
- { idempotencyKey: (0, import_node_crypto13.randomUUID)() }
3727
+ { idempotencyKey: (0, import_node_crypto14.randomUUID)() }
3454
3728
  );
3455
- const result = (0, import_core50.unwrapDataResponse)(body);
3729
+ const result = (0, import_core51.unwrapDataResponse)(body);
3456
3730
  if (ctx.format === "json") {
3457
3731
  printJson({ enc_id: trimmed, is_published: result.is_published });
3458
3732
  return;
@@ -3473,8 +3747,8 @@ function registerPersonalResumesUnpublish(parent) {
3473
3747
  }
3474
3748
 
3475
3749
  // src/commands/personal/resumes/delete.ts
3476
- var import_node_crypto14 = require("crypto");
3477
- var import_core52 = require("@wport/core");
3750
+ var import_node_crypto15 = require("crypto");
3751
+ var import_core53 = require("@wport/core");
3478
3752
  function requireEncId5(encId) {
3479
3753
  const trimmed = encId.trim();
3480
3754
  if (!trimmed) {
@@ -3488,7 +3762,7 @@ async function runResumesDelete(ctx, encId, confirm) {
3488
3762
  }
3489
3763
  const trimmed = requireEncId5(encId);
3490
3764
  const opts = { baseUrl: ctx.baseUrl, locale: ctx.locale, timeoutMs: ctx.timeoutMs };
3491
- await personalDelete(opts, `${import_core52.PERSONAL_RESUMES_BASE}/${encodeURIComponent(trimmed)}`, { idempotencyKey: (0, import_node_crypto14.randomUUID)() });
3765
+ await personalDelete(opts, `${import_core53.PERSONAL_RESUMES_BASE}/${encodeURIComponent(trimmed)}`, { idempotencyKey: (0, import_node_crypto15.randomUUID)() });
3492
3766
  if (ctx.format === "json") {
3493
3767
  printJson({ enc_id: trimmed, deleted: true });
3494
3768
  return;
@@ -3520,9 +3794,9 @@ function registerPersonalResumesCommand(parent) {
3520
3794
  }
3521
3795
 
3522
3796
  // src/commands/personal/apply/index.ts
3523
- var import_node_crypto15 = require("crypto");
3797
+ var import_node_crypto16 = require("crypto");
3524
3798
  var import_node_fs11 = require("fs");
3525
- var import_core53 = require("@wport/core");
3799
+ var import_core54 = require("@wport/core");
3526
3800
 
3527
3801
  // src/commands/personal/apply/message-input.ts
3528
3802
  var import_node_fs10 = require("fs");
@@ -3604,7 +3878,7 @@ async function runPersonalApply(ctx, args) {
3604
3878
  const body = { enc_job_id: args.encJobId, enc_resume_id: args.encResumeId, application_message: args.message };
3605
3879
  let result;
3606
3880
  try {
3607
- result = await personalPost(opts, import_core53.PERSONAL_APPLICATIONS_BASE, body, { idempotencyKey: (0, import_node_crypto15.randomUUID)() });
3881
+ result = await personalPost(opts, import_core54.PERSONAL_APPLICATIONS_BASE, body, { idempotencyKey: (0, import_node_crypto16.randomUUID)() });
3608
3882
  } catch (err) {
3609
3883
  rethrowApplyError(err);
3610
3884
  }
@@ -3655,7 +3929,7 @@ async function runPersonalApplyBatch(ctx, args) {
3655
3929
  const opts = { baseUrl: ctx.baseUrl, locale: ctx.locale, timeoutMs: ctx.timeoutMs };
3656
3930
  let result;
3657
3931
  try {
3658
- result = await personalPost(opts, `${import_core53.PERSONAL_APPLICATIONS_BASE}/batch`, { applications: items }, { idempotencyKey: (0, import_node_crypto15.randomUUID)() });
3932
+ result = await personalPost(opts, `${import_core54.PERSONAL_APPLICATIONS_BASE}/batch`, { applications: items }, { idempotencyKey: (0, import_node_crypto16.randomUUID)() });
3659
3933
  } catch (err) {
3660
3934
  rethrowApplyError(err);
3661
3935
  }
@@ -3683,7 +3957,7 @@ function registerPersonalCommand(program2) {
3683
3957
 
3684
3958
  // src/index.ts
3685
3959
  var program = new import_commander.Command();
3686
- program.name("wport").description("wport CLI \u2014 terminal interface to the W101 Talent Search Hub public API").version("0.9.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));
3960
+ program.name("wport").description("wport CLI \u2014 terminal interface to the W101 Talent Search Hub public API").version("0.10.0", "-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));
3687
3961
  registerJobsCommand(program);
3688
3962
  registerConfigCommand(program);
3689
3963
  registerDoctorCommand(program);