siluzan-website-cli 1.0.1-beta.1 → 1.0.1-beta.10

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
@@ -1960,6 +1960,7 @@ import * as fs from "fs";
1960
1960
  import * as path from "path";
1961
1961
  import * as os from "os";
1962
1962
  import lockfile from "proper-lockfile";
1963
+ import { randomBytes } from "crypto";
1963
1964
  import * as https from "https";
1964
1965
  import * as http from "http";
1965
1966
  import * as zlib from "zlib";
@@ -2460,7 +2461,13 @@ function rawRequest(url, options) {
2460
2461
  }
2461
2462
  reject(err);
2462
2463
  });
2463
- if (options.body) req.write(options.body);
2464
+ if (options.body !== void 0) {
2465
+ const payload = typeof options.body === "string" ? Buffer.from(options.body) : options.body;
2466
+ if (!headers["Content-Length"] && !headers["content-length"]) {
2467
+ req.setHeader("Content-Length", payload.length);
2468
+ }
2469
+ req.write(payload);
2470
+ }
2464
2471
  req.end();
2465
2472
  });
2466
2473
  }
@@ -2557,6 +2564,54 @@ function formatHttpError(status, rawBody, opts) {
2557
2564
  function buildAuthHeaders(config) {
2558
2565
  return buildSiluzanAuthHeaders(config);
2559
2566
  }
2567
+ function buildMultipartBody(fields, files) {
2568
+ const boundary = `----SiluzanForm${randomBytes(16).toString("hex")}`;
2569
+ const chunks = [];
2570
+ for (const [name, value] of Object.entries(fields)) {
2571
+ chunks.push(
2572
+ Buffer.from(
2573
+ `--${boundary}\r
2574
+ Content-Disposition: form-data; name="${name}"\r
2575
+ \r
2576
+ ${value}\r
2577
+ `
2578
+ )
2579
+ );
2580
+ }
2581
+ for (const file of files) {
2582
+ chunks.push(
2583
+ Buffer.from(
2584
+ `--${boundary}\r
2585
+ Content-Disposition: form-data; name="${file.field}"; filename="${file.filename}"\r
2586
+ Content-Type: ${file.contentType}\r
2587
+ \r
2588
+ `
2589
+ )
2590
+ );
2591
+ chunks.push(file.data);
2592
+ chunks.push(Buffer.from("\r\n"));
2593
+ }
2594
+ chunks.push(Buffer.from(`--${boundary}--\r
2595
+ `));
2596
+ return {
2597
+ body: Buffer.concat(chunks),
2598
+ contentType: `multipart/form-data; boundary=${boundary}`
2599
+ };
2600
+ }
2601
+ async function parseApiResponse(status, text, verbose) {
2602
+ if (status < 200 || status >= 300) {
2603
+ throw new Error(formatHttpError(status, text, { verbose }));
2604
+ }
2605
+ if (!text.trim()) return null;
2606
+ try {
2607
+ return parseJsonWithStringIds(text);
2608
+ } catch {
2609
+ if (verbose) {
2610
+ console.error(` \u26A0\uFE0F \u54CD\u5E94\u975E JSON\uFF0C\u539F\u59CB\u5185\u5BB9\uFF1A${redactSensitive(text).slice(0, 200)}`);
2611
+ }
2612
+ return text;
2613
+ }
2614
+ }
2560
2615
  async function apiFetch(url, config, options = {}, verbose = false) {
2561
2616
  const method = options.method ?? "GET";
2562
2617
  const reqHeaders = {
@@ -2575,19 +2630,23 @@ async function apiFetch(url, config, options = {}, verbose = false) {
2575
2630
  headers: reqHeaders,
2576
2631
  body
2577
2632
  });
2578
- const text = res.text;
2579
- if (res.status < 200 || res.status >= 300) {
2580
- throw new Error(formatHttpError(res.status, text, { verbose }));
2581
- }
2582
- if (!text.trim()) return null;
2583
- try {
2584
- return parseJsonWithStringIds(text);
2585
- } catch {
2586
- if (verbose) {
2587
- console.error(` \u26A0\uFE0F \u54CD\u5E94\u975E JSON\uFF0C\u539F\u59CB\u5185\u5BB9\uFF1A${redactSensitive(text).slice(0, 200)}`);
2588
- }
2589
- return text;
2590
- }
2633
+ return parseApiResponse(res.status, res.text, verbose);
2634
+ }
2635
+ async function apiFetchMultipart(url, config, payload, verbose = false) {
2636
+ const packed = buildMultipartBody(payload.fields ?? {}, payload.files);
2637
+ const reqHeaders = {
2638
+ "Content-Type": packed.contentType,
2639
+ "Accept-Language": "zh-CN",
2640
+ "Accept-Encoding": "gzip, deflate, br",
2641
+ ...buildAuthHeaders(config),
2642
+ Datapermission: config.dataPermission ?? ""
2643
+ };
2644
+ const res = await rawRequest(url, {
2645
+ method: "POST",
2646
+ headers: reqHeaders,
2647
+ body: packed.body
2648
+ });
2649
+ return parseApiResponse(res.status, res.text, verbose);
2591
2650
  }
2592
2651
  function getCurrentVersion(importMetaUrl) {
2593
2652
  try {
@@ -3258,7 +3317,9 @@ import { spawnSync } from "child_process";
3258
3317
  var BUILD_ENV = "test";
3259
3318
  var DEFAULT_API_BASE = "https://api-ci.siluzan.com";
3260
3319
  var DEFAULT_CSO_BASE = "https://cso-ci.siluzan.com";
3320
+ var DEFAULT_CSO_PLUGIN_API = "https://cso-api-ci.siluzan.com";
3261
3321
  var DEFAULT_WEB_BASE = "https://www-ci.siluzan.com";
3322
+ var DEFAULT_SITEMAN_BASE = "https://api-ussiteman-ci.mysiluzan.com";
3262
3323
  var DEFAULT_SITE_STAGE = "ci";
3263
3324
 
3264
3325
  // src/utils/version.ts
@@ -3668,6 +3729,7 @@ function loadConfig() {
3668
3729
  }
3669
3730
  const apiBaseUrl = process.env.SILUZAN_WEBSITE_API_BASE ?? DEFAULT_API_BASE;
3670
3731
  const csoBaseUrl = process.env.SILUZAN_CSO_BASE ?? DEFAULT_CSO_BASE;
3732
+ const csoPluginApiBaseUrl = process.env.SILUZAN_CSO_PLUGIN_API ?? DEFAULT_CSO_PLUGIN_API;
3671
3733
  const apiErr = validateBaseUrl(apiBaseUrl);
3672
3734
  if (apiErr) {
3673
3735
  console.error(`
@@ -3680,9 +3742,16 @@ function loadConfig() {
3680
3742
  \u274C csoBaseUrl \u4E0D\u5408\u6CD5\uFF1A${csoErr}`);
3681
3743
  process.exit(1);
3682
3744
  }
3745
+ const pluginApiErr = validateBaseUrl(csoPluginApiBaseUrl);
3746
+ if (pluginApiErr) {
3747
+ console.error(`
3748
+ \u274C csoPluginApiBaseUrl \u4E0D\u5408\u6CD5\uFF1A${pluginApiErr}`);
3749
+ process.exit(1);
3750
+ }
3683
3751
  return {
3684
3752
  apiBaseUrl,
3685
3753
  csoBaseUrl,
3754
+ csoPluginApiBaseUrl,
3686
3755
  authToken: "",
3687
3756
  apiKey,
3688
3757
  dataPermission: process.env.SILUZAN_DATA_PERMISSION ?? shared.dataPermission
@@ -3691,6 +3760,9 @@ function loadConfig() {
3691
3760
  function apiFetch2(url, config, options = {}, verbose = false) {
3692
3761
  return apiFetch(url, config, options, verbose);
3693
3762
  }
3763
+ function apiFetchMultipart2(url, config, payload, verbose = false) {
3764
+ return apiFetchMultipart(url, config, payload, verbose);
3765
+ }
3694
3766
 
3695
3767
  // src/utils/site-url.ts
3696
3768
  function normalizeRegion(raw) {
@@ -3834,256 +3906,2202 @@ async function runSitesList(options) {
3834
3906
  console.log("\n\u540E\u7EED\uFF1Asiluzan-website pages list --site <guid>\n");
3835
3907
  }
3836
3908
  function register5(program2) {
3837
- const sites = program2.command("sites").description("WordPress \u7AD9\u70B9\u67E5\u8BE2");
3909
+ const sites = program2.command("sites").description("WordPress \u7AD9\u70B9\u67E5\u8BE2\u4E0E\u5F00\u901A");
3838
3910
  sites.command("list").description("\u5217\u51FA\u5F53\u524D\u8D26\u53F7\u4E0B\u7684 WordPress \u7AD9\u70B9").option("-q, --query <keyword>", "\u6309\u540D\u79F0\u641C\u7D22").option("--json", "\u8F93\u51FA JSON", false).option("--verbose", "\u8F93\u51FA\u8BF7\u6C42\u8BE6\u60C5", false).action(async (opts) => {
3839
3911
  await runSitesList(opts);
3840
3912
  });
3913
+ sites.command("create").description("\u805A\u5408\u521B\u5EFA\u7AD9\u70B9\uFF08website-provision\uFF0C\u5199\u64CD\u4F5C\uFF0CAgent \u987B\u5148\u83B7\u7528\u6237\u786E\u8BA4\uFF09").option("--name <advertiserName>", "\u7AD9\u70B9\u540D\u79F0").option("--region <US|CN>", "\u533A\u57DF", "US").option("--package <packageId>", "\u5957\u9910 ID").option("--template <siteTemplateId>", "\u6A21\u677F ID").option("--site-lang <lang>", "\u524D\u53F0\u8BED\u8A00\uFF0C\u5982 en_US / zh_CN").option("--admin-lang <lang>", "\u540E\u53F0\u8BED\u8A00").option("--bill <packageBillId>", "\u5DF2\u4ED8\u8D26\u5355\u53F7\uFF08\u4ED8\u8D39\u8DEF\u5F84\uFF1B\u8BD5\u7528\u53EF\u4E0D\u4F20\uFF09").option("--wait", "\u521B\u5EFA\u540E\u8F6E\u8BE2\u81F3 Online", false).option("--timeout <seconds>", "wait \u8D85\u65F6\u79D2\u6570", "600").option("--json", "\u8F93\u51FA JSON", false).option("--verbose", "\u8F93\u51FA\u8BF7\u6C42\u8BE6\u60C5", false).action(async (opts) => {
3914
+ await runSitesCreate(opts);
3915
+ });
3916
+ sites.command("status").description("\u67E5\u8BE2\u5EFA\u7AD9\u72B6\u6001\uFF08website-provision\uFF09").option("--site <siteGuid>", "\u7AD9\u70B9 guid").option("--region <US|CN>", "\u533A\u57DF", "US").option("--json", "\u8F93\u51FA JSON", false).option("--verbose", "\u8F93\u51FA\u8BF7\u6C42\u8BE6\u60C5", false).action(async (opts) => {
3917
+ await runSitesStatus(opts);
3918
+ });
3919
+ sites.command("bind").description("\u8D26\u53F7\u6302\u63A5\u8865\u507F\uFF08SiteMan \u5DF2\u6210\u529F\u4F46 list \u4E0D\u53EF\u89C1\u65F6\uFF09").option("--site <siteGuid>", "\u7AD9\u70B9 guid").option("--region <US|CN>", "\u533A\u57DF", "US").option("--name <advertiserName>", "\u7AD9\u70B9\u540D\u79F0\uFF08\u7528\u4E8E\u67E5\u627E/\u521B\u5EFA Mag\uFF09").option("--mag <magKey>", "\u5DF2\u6709 Mag Key\uFF08\u53EF\u9009\uFF09").option("--json", "\u8F93\u51FA JSON", false).option("--verbose", "\u8F93\u51FA\u8BF7\u6C42\u8BE6\u60C5", false).action(async (opts) => {
3920
+ await runSitesBind(opts);
3921
+ });
3841
3922
  }
3842
-
3843
- // src/commands/pages.ts
3844
- import * as fs6 from "fs";
3845
- function pageTitle(page) {
3846
- if (typeof page.title === "string") return page.title;
3847
- return page.title?.rendered ?? "";
3923
+ function asRecordLocal(value) {
3924
+ return value && typeof value === "object" ? value : null;
3848
3925
  }
3849
- function readTextOption(inline, filePath) {
3850
- if (filePath) {
3851
- try {
3852
- return fs6.readFileSync(filePath, "utf8");
3853
- } catch (e) {
3854
- console.error(`
3855
- \u274C \u65E0\u6CD5\u8BFB\u53D6\u6587\u4EF6 ${filePath}\uFF1A${e.message}
3856
- `);
3857
- process.exit(1);
3858
- }
3859
- }
3860
- return inline ?? "";
3926
+ function readStr2(obj, key) {
3927
+ if (!obj) return "";
3928
+ const v = obj[key];
3929
+ return typeof v === "string" ? v : v == null ? "" : String(v);
3861
3930
  }
3862
- async function runPagesList(opts) {
3931
+ async function runSitesCreate(opts) {
3932
+ const name = opts.name?.trim();
3933
+ const packageId = opts.package?.trim();
3934
+ const templateId = opts.template?.trim();
3935
+ const region = (opts.region || "US").trim();
3936
+ const siteLang = opts.siteLang?.trim() || (region.toUpperCase() === "CN" ? "zh_CN" : "en_US");
3937
+ const adminLang = opts.adminLang?.trim() || siteLang;
3938
+ if (!name || !packageId || !templateId) {
3939
+ console.error("\n\u274C \u8BF7\u63D0\u4F9B --name --package --template\uFF08\u4EE5\u53CA\u53EF\u9009 --bill / --region / --site-lang / --admin-lang\uFF09\n");
3940
+ process.exit(1);
3941
+ }
3942
+ console.log("\n\u5373\u5C06\u521B\u5EFA WordPress \u7AD9\u70B9\uFF08\u4E3B\u7AD9 website-provision\uFF0C\u4E0D\u53EF\u76F2\u76EE\u91CD\u8BD5\uFF09\uFF1A");
3943
+ console.log(` name : ${name}`);
3944
+ console.log(` region : ${region}`);
3945
+ console.log(` packageId : ${packageId}`);
3946
+ console.log(` templateId : ${templateId}`);
3947
+ console.log(` siteLang : ${siteLang}`);
3948
+ console.log(` adminLang : ${adminLang}`);
3949
+ console.log(` billId : ${opts.bill?.trim() || "(\u8BD5\u7528)"}`);
3863
3950
  const config = loadConfig();
3864
- const site = await resolveSite(config, opts);
3865
- const base = trimTrailingSlash(site.url);
3866
- const api = `${base}/wp-json/wp/v2/pages?per_page=100&status=publish,draft,private,pending`;
3867
- let pages;
3951
+ const body = {
3952
+ advertiserName: name,
3953
+ region,
3954
+ packageId,
3955
+ siteTemplateId: templateId,
3956
+ siteLang,
3957
+ adminLang,
3958
+ packageBillId: opts.bill?.trim() || void 0
3959
+ };
3960
+ const url = `${config.apiBaseUrl}/website-provision/sites`;
3961
+ let raw;
3868
3962
  try {
3869
- pages = await apiFetch2(api, config, {}, opts.verbose);
3963
+ raw = await apiFetch2(
3964
+ url,
3965
+ config,
3966
+ { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(body) },
3967
+ opts.verbose
3968
+ );
3870
3969
  } catch (e) {
3871
3970
  console.error(`
3872
- \u274C \u83B7\u53D6\u9875\u9762\u5931\u8D25\uFF1A${e.message}`);
3873
- console.error(` \u7AD9\u70B9\uFF1A${base}`);
3971
+ \u274C \u521B\u5EFA\u7AD9\u70B9\u5931\u8D25\uFF1A${e.message}`);
3874
3972
  process.exit(1);
3875
3973
  return;
3876
3974
  }
3877
- if (!Array.isArray(pages)) {
3878
- console.error("\n\u274C \u7AD9\u70B9\u8FD4\u56DE\u7684\u9875\u9762\u5217\u8868\u683C\u5F0F\u5F02\u5E38\n");
3879
- process.exit(1);
3880
- }
3975
+ const obj = asRecordLocal(raw);
3976
+ const siteGuid = readStr2(obj, "siteGuid") || readStr2(obj, "SiteGuid");
3977
+ const bound = obj?.bound === true || obj?.Bound === true;
3978
+ const code = readStr2(obj, "code") || readStr2(obj, "Code") || "ok";
3881
3979
  if (opts.json) {
3882
- console.log(
3883
- JSON.stringify(
3884
- {
3885
- site: { guid: site.guid, name: site.name, url: site.url },
3886
- total: pages.length,
3887
- pages: pages.map((p) => ({
3888
- id: p.id,
3889
- title: pageTitle(p),
3890
- slug: p.slug ?? "",
3891
- status: p.status ?? "",
3892
- link: p.link ?? "",
3893
- modified: p.modified ?? ""
3894
- }))
3895
- },
3896
- null,
3897
- 2
3898
- )
3899
- );
3900
- return;
3980
+ console.log(JSON.stringify(raw, null, 2));
3981
+ } else {
3982
+ console.log(code === "site_created_unbound" ? "\n\u26A0\uFE0F \u7AD9\u70B9\u5DF2\u521B\u5EFA\u4F46\u8D26\u53F7\u6302\u63A5\u672A\u5B8C\u6210\n" : "\n\u2705 \u7AD9\u70B9\u521B\u5EFA\u8BF7\u6C42\u5DF2\u53D7\u7406\n");
3983
+ console.log(` siteGuid : ${siteGuid}`);
3984
+ console.log(` region : ${readStr2(obj, "region") || region}`);
3985
+ console.log(` state : ${readStr2(obj, "state") || readStr2(obj, "State") || "-"}`);
3986
+ console.log(` platformUrl : ${readStr2(obj, "platformUrl") || readStr2(obj, "PlatformUrl") || "-"}`);
3987
+ console.log(` bound : ${bound}`);
3988
+ console.log(` magKey : ${readStr2(obj, "magKey") || readStr2(obj, "MagKey") || "-"}`);
3989
+ console.log(` code : ${code}`);
3990
+ if (code === "site_created_unbound") {
3991
+ console.log(`
3992
+ \u8865\u507F\uFF1Asiluzan-website sites bind --site ${siteGuid} --region ${region} --name "${name}"
3993
+ `);
3994
+ }
3901
3995
  }
3902
- if (pages.length === 0) {
3996
+ if (opts.wait && siteGuid) {
3997
+ await pollUntilOnline(config, siteGuid, region, Number(opts.timeout) || 600, opts.verbose);
3998
+ } else if (siteGuid && !opts.json) {
3903
3999
  console.log(`
3904
- \u7AD9\u70B9 ${site.name} \u6682\u65E0\u9875\u9762\u3002\u53EF\u7528 pages add \u65B0\u589E\u3002
4000
+ \u8F6E\u8BE2\u72B6\u6001\uFF1Asiluzan-website sites status --site ${siteGuid} --region ${region}`);
4001
+ console.log(`\u5217\u8868\u6838\u5BF9\uFF1Asiluzan-website sites list -q ${siteGuid}
3905
4002
  `);
4003
+ }
4004
+ }
4005
+ async function runSitesStatus(opts) {
4006
+ const siteGuid = opts.site?.trim();
4007
+ const region = (opts.region || "US").trim();
4008
+ if (!siteGuid) {
4009
+ console.error("\n\u274C \u8BF7\u63D0\u4F9B --site <siteGuid>\n");
4010
+ process.exit(1);
4011
+ }
4012
+ const config = loadConfig();
4013
+ const url = `${config.apiBaseUrl}/website-provision/sites/${encodeURIComponent(region)}/${encodeURIComponent(siteGuid)}/status`;
4014
+ let raw;
4015
+ try {
4016
+ raw = await apiFetch2(url, config, {}, opts.verbose);
4017
+ } catch (e) {
4018
+ console.error(`
4019
+ \u274C \u67E5\u8BE2\u72B6\u6001\u5931\u8D25\uFF1A${e.message}`);
4020
+ process.exit(1);
3906
4021
  return;
3907
4022
  }
3908
- const columns = [
3909
- { key: "id", header: "id" },
3910
- { key: "title", header: "\u6807\u9898" },
3911
- { key: "status", header: "\u72B6\u6001" },
3912
- { key: "link", header: "\u94FE\u63A5" }
3913
- ];
3914
- console.log(`
3915
- ${site.name} \u9875\u9762\uFF08${pages.length}\uFF09
3916
- `);
3917
- printCliTable(
3918
- pages.map((p) => ({
3919
- id: String(p.id),
3920
- title: pageTitle(p) || "(\u65E0\u6807\u9898)",
3921
- status: p.status ?? "-",
3922
- link: p.link ?? "-"
3923
- })),
3924
- columns
3925
- );
4023
+ if (opts.json) {
4024
+ console.log(JSON.stringify(raw, null, 2));
4025
+ return;
4026
+ }
4027
+ const obj = asRecordLocal(raw);
4028
+ console.log("\n\u5EFA\u7AD9\u72B6\u6001\n");
4029
+ console.log(` siteGuid : ${readStr2(obj, "siteGuid") || siteGuid}`);
4030
+ console.log(` region : ${readStr2(obj, "region") || region}`);
4031
+ console.log(` statusCode : ${String(obj?.statusCode ?? obj?.StatusCode ?? "-")}`);
4032
+ console.log(` online : ${String(obj?.online ?? obj?.Online ?? "-")}`);
4033
+ console.log(` url : ${readStr2(obj, "url") || readStr2(obj, "Url") || "-"}`);
3926
4034
  console.log();
3927
4035
  }
3928
- async function runPagesWrite(mode, opts) {
3929
- const config = loadConfig();
3930
- const site = await resolveSite(config, opts);
3931
- const base = trimTrailingSlash(site.url);
3932
- const title = opts.title?.trim() ?? "";
3933
- const content = readTextOption(opts.content, opts.contentFile);
3934
- if (mode === "add" && !title) {
3935
- console.error("\n\u274C \u65B0\u589E\u9875\u9762\u5FC5\u987B\u63D0\u4F9B --title\n");
4036
+ async function runSitesBind(opts) {
4037
+ const siteGuid = opts.site?.trim();
4038
+ if (!siteGuid) {
4039
+ console.error("\n\u274C \u8BF7\u63D0\u4F9B --site <siteGuid>\n");
3936
4040
  process.exit(1);
3937
4041
  }
3938
- if (!content.trim()) {
3939
- console.error("\n\u274C \u8BF7\u7528 --content \u6216 --content-file \u63D0\u4F9B HTML \u6B63\u6587\n");
4042
+ if (!opts.name?.trim() && !opts.mag?.trim()) {
4043
+ console.error("\n\u274C \u8BF7\u63D0\u4F9B --name <advertiserName> \u6216 --mag <magKey>\n");
3940
4044
  process.exit(1);
3941
4045
  }
4046
+ const config = loadConfig();
3942
4047
  const body = {
3943
- content,
3944
- import_mode: "preserve"
4048
+ region: opts.region || "US",
4049
+ advertiserName: opts.name?.trim(),
4050
+ magKey: opts.mag?.trim()
3945
4051
  };
3946
- if (title) body.title = title;
3947
- const css = readTextOption(opts.css, opts.cssFile);
3948
- if (css) body._custom_css = css;
3949
- const js = readTextOption(opts.js, opts.jsFile);
3950
- if (js) body._custom_javascript = js;
3951
- if (mode === "add") body.post_type = opts.postType?.trim() || "page";
3952
- const api = mode === "add" ? `${base}/wp-json/zionbuilder/v1/pages/add-visual-edit` : `${base}/wp-json/zionbuilder/v1/pages/${opts.id}/save-visual-edit`;
3953
- if (mode === "update" && !opts.id) {
3954
- console.error("\n\u274C \u66F4\u65B0\u9875\u9762\u5FC5\u987B\u63D0\u4F9B --id\uFF08\u5148 pages list \u67E5 id\uFF09\n");
3955
- process.exit(1);
3956
- }
3957
- let result;
4052
+ const url = `${config.apiBaseUrl}/website-provision/sites/${encodeURIComponent(siteGuid)}/bind`;
4053
+ let raw;
3958
4054
  try {
3959
- result = await apiFetch2(
3960
- api,
4055
+ raw = await apiFetch2(
4056
+ url,
3961
4057
  config,
3962
- { method: "POST", body: JSON.stringify(body) },
4058
+ { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(body) },
3963
4059
  opts.verbose
3964
4060
  );
3965
4061
  } catch (e) {
3966
4062
  console.error(`
3967
- \u274C ${mode === "add" ? "\u65B0\u589E" : "\u66F4\u65B0"}\u9875\u9762\u5931\u8D25\uFF1A${e.message}
3968
- `);
4063
+ \u274C \u6302\u63A5\u5931\u8D25\uFF1A${e.message}`);
3969
4064
  process.exit(1);
3970
4065
  return;
3971
4066
  }
3972
- if (result.error || result.success === false) {
3973
- console.error(`
3974
- \u274C ${result.error || result.message || "\u7AD9\u70B9\u62D2\u7EDD\u4FDD\u5B58"}
3975
- `);
3976
- process.exit(1);
4067
+ if (opts.json) {
4068
+ console.log(JSON.stringify(raw, null, 2));
4069
+ return;
3977
4070
  }
3978
- console.log(mode === "add" ? "\n\u2705 \u9875\u9762\u5DF2\u521B\u5EFA" : "\n\u2705 \u9875\u9762\u5DF2\u66F4\u65B0");
3979
- if (result.post_id) console.log(` post_id : ${result.post_id}`);
3980
- if (result.url) console.log(` url : ${result.url}`);
3981
- console.log(` \u7AD9\u70B9 : ${base}
3982
- `);
4071
+ const obj = asRecordLocal(raw);
4072
+ console.log("\n\u2705 \u6302\u63A5\u5B8C\u6210\n");
4073
+ console.log(` siteGuid : ${readStr2(obj, "siteGuid") || siteGuid}`);
4074
+ console.log(` bound : ${String(obj?.bound ?? true)}`);
4075
+ console.log(` magKey : ${readStr2(obj, "magKey") || "-"}`);
4076
+ console.log("\n\u8BF7\u518D\u8DD1 siluzan-website sites list \u6838\u5BF9\u3002\n");
3983
4077
  }
3984
- function register6(program2) {
3985
- const pages = program2.command("pages").description("WordPress \u9875\u9762\uFF08zionbuilder visual-edit\uFF09");
3986
- pages.command("list").description("\u5217\u51FA\u7AD9\u70B9\u9875\u9762").option("-s, --site <guidOrName>", "\u7AD9\u70B9 guid \u6216\u540D\u79F0").option("--url <url>", "\u76F4\u63A5\u6307\u5B9A\u7AD9\u70B9\u5730\u5740\uFF08\u8DF3\u8FC7 all-sites\uFF09").option("--json", "\u8F93\u51FA JSON", false).option("--verbose", "\u8F93\u51FA\u8BF7\u6C42\u8BE6\u60C5", false).action(async (opts) => {
3987
- await runPagesList(opts);
3988
- });
3989
- pages.command("add").description("\u7528 HTML \u65B0\u589E\u9875\u9762\uFF08\u8D70 add-visual-edit\uFF0C\u4F1A\u76F4\u63A5\u53D1\u5E03\uFF09").option("-s, --site <guidOrName>", "\u7AD9\u70B9 guid \u6216\u540D\u79F0").option("--url <url>", "\u76F4\u63A5\u6307\u5B9A\u7AD9\u70B9\u5730\u5740").option("-t, --title <title>", "\u9875\u9762\u6807\u9898").option("-c, --content <html>", "HTML \u6B63\u6587").option("--content-file <path>", "\u4ECE\u6587\u4EF6\u8BFB\u53D6 HTML \u6B63\u6587").option("--css <css>", "\u9644\u52A0 CSS").option("--css-file <path>", "\u4ECE\u6587\u4EF6\u8BFB\u53D6 CSS").option("--js <js>", "\u9644\u52A0 JS").option("--js-file <path>", "\u4ECE\u6587\u4EF6\u8BFB\u53D6 JS").option("--post-type <type>", "\u6587\u7AE0\u7C7B\u578B\uFF0C\u9ED8\u8BA4 page", "page").option("--verbose", "\u8F93\u51FA\u8BF7\u6C42\u8BE6\u60C5", false).action(async (opts) => {
3990
- await runPagesWrite("add", opts);
3991
- });
3992
- pages.command("update").description("\u7528 HTML \u8986\u76D6\u5DF2\u6709\u9875\u9762\uFF08\u8D70 save-visual-edit\uFF0C\u4F1A\u76F4\u63A5\u53D1\u5E03\uFF09").option("-s, --site <guidOrName>", "\u7AD9\u70B9 guid \u6216\u540D\u79F0").option("--url <url>", "\u76F4\u63A5\u6307\u5B9A\u7AD9\u70B9\u5730\u5740").requiredOption("--id <id>", "\u9875\u9762 ID").option("-t, --title <title>", "\u65B0\u6807\u9898\uFF08\u53EF\u7701\u7565\uFF09").option("-c, --content <html>", "HTML \u6B63\u6587").option("--content-file <path>", "\u4ECE\u6587\u4EF6\u8BFB\u53D6 HTML \u6B63\u6587").option("--css <css>", "\u9644\u52A0 CSS").option("--css-file <path>", "\u4ECE\u6587\u4EF6\u8BFB\u53D6 CSS").option("--js <js>", "\u9644\u52A0 JS").option("--js-file <path>", "\u4ECE\u6587\u4EF6\u8BFB\u53D6 JS").option("--verbose", "\u8F93\u51FA\u8BF7\u6C42\u8BE6\u60C5", false).action(async (opts) => {
3993
- await runPagesWrite("update", opts);
3994
- });
4078
+ async function pollUntilOnline(config, siteGuid, region, timeoutSec, verbose) {
4079
+ const deadline = Date.now() + timeoutSec * 1e3;
4080
+ console.log(`
4081
+ \u7B49\u5F85\u7AD9\u70B9 Online\uFF08\u6700\u957F ${timeoutSec}s\uFF09\u2026`);
4082
+ while (Date.now() < deadline) {
4083
+ try {
4084
+ const url = `${config.apiBaseUrl}/website-provision/sites/${encodeURIComponent(region)}/${encodeURIComponent(siteGuid)}/status`;
4085
+ const raw = await apiFetch2(url, config, {}, verbose);
4086
+ const obj = asRecordLocal(raw);
4087
+ const online = Boolean(obj?.online ?? obj?.Online);
4088
+ const code = obj?.statusCode ?? obj?.StatusCode;
4089
+ process.stdout.write(` statusCode=${code} online=${online}
4090
+ `);
4091
+ if (online) {
4092
+ console.log("\n\u2705 \u7AD9\u70B9\u5DF2\u53EF\u8BBF\u95EE\uFF08Online\uFF09\n");
4093
+ return;
4094
+ }
4095
+ } catch (e) {
4096
+ process.stdout.write(` \u8F6E\u8BE2\u5F02\u5E38\uFF1A${e.message}
4097
+ `);
4098
+ }
4099
+ await new Promise((r) => setTimeout(r, 1e4));
4100
+ }
4101
+ console.error("\n\u26A0\uFE0F \u7B49\u5F85\u8D85\u65F6\uFF0C\u7AD9\u70B9\u53EF\u80FD\u4ECD\u5728\u521B\u5EFA\u4E2D\u3002\u8BF7\u7A0D\u540E siluzan-website sites status \u518D\u67E5\u3002\n");
3995
4102
  }
3996
4103
 
3997
- // src/commands/plugins.ts
3998
- function pluginName(item) {
3999
- if (typeof item.name === "string") return item.name;
4000
- return item.name?.raw || item.name?.rendered || item.plugin || "";
4104
+ // src/commands/packages.ts
4105
+ function asRecord2(value) {
4106
+ return value && typeof value === "object" ? value : null;
4001
4107
  }
4002
- async function resolveTarget(opts) {
4003
- const config = loadConfig();
4004
- const site = await resolveSite(config, opts);
4005
- return { config, site, base: trimTrailingSlash(site.url) };
4108
+ function readString2(obj, key) {
4109
+ if (!obj) return "";
4110
+ const v = obj[key];
4111
+ return typeof v === "string" ? v : v == null ? "" : String(v);
4006
4112
  }
4007
- async function runPluginsList(opts) {
4008
- const { config, site, base } = await resolveTarget(opts);
4009
- const api = `${base}/wp-json/wp/v2/plugins`;
4010
- let plugins;
4113
+ function unwrapList(raw) {
4114
+ if (Array.isArray(raw)) {
4115
+ return raw.map(asRecord2).filter((x) => Boolean(x));
4116
+ }
4117
+ const obj = asRecord2(raw);
4118
+ if (!obj) return [];
4119
+ if (Array.isArray(obj.data)) {
4120
+ return obj.data.map(asRecord2).filter((x) => Boolean(x));
4121
+ }
4122
+ return [];
4123
+ }
4124
+ async function runPackagesList(opts) {
4125
+ const config = loadConfig();
4126
+ const url = `${config.apiBaseUrl}/website-provision/packages`;
4127
+ let raw;
4011
4128
  try {
4012
- plugins = await apiFetch2(api, config, {}, opts.verbose);
4129
+ raw = await apiFetch2(url, config, {}, opts.verbose);
4013
4130
  } catch (e) {
4014
4131
  console.error(`
4015
- \u274C \u83B7\u53D6\u5DF2\u88C5\u63D2\u4EF6\u5931\u8D25\uFF1A${e.message}
4016
- `);
4132
+ \u274C \u83B7\u53D6\u5957\u9910\u5217\u8868\u5931\u8D25\uFF1A${e.message}`);
4133
+ if (!opts.verbose) console.error(" \u52A0 --verbose \u53EF\u67E5\u770B\u8BE6\u7EC6\u9519\u8BEF");
4017
4134
  process.exit(1);
4018
4135
  return;
4019
4136
  }
4020
- if (!Array.isArray(plugins)) {
4021
- console.error("\n\u274C \u7AD9\u70B9\u8FD4\u56DE\u7684\u63D2\u4EF6\u5217\u8868\u683C\u5F0F\u5F02\u5E38\n");
4022
- process.exit(1);
4023
- }
4137
+ const list = unwrapList(raw);
4024
4138
  if (opts.json) {
4025
- console.log(
4026
- JSON.stringify(
4027
- {
4028
- site: { guid: site.guid, name: site.name, url: site.url },
4029
- total: plugins.length,
4030
- plugins: plugins.map((p) => ({
4031
- plugin: p.plugin ?? "",
4032
- name: pluginName(p),
4033
- status: p.status ?? "",
4034
- version: p.version ?? ""
4035
- }))
4036
- },
4037
- null,
4038
- 2
4039
- )
4040
- );
4139
+ console.log(JSON.stringify({ total: list.length, packages: list }, null, 2));
4041
4140
  return;
4042
4141
  }
4043
- if (plugins.length === 0) {
4044
- console.log(`
4045
- \u7AD9\u70B9 ${site.name} \u672A\u8FD4\u56DE\u63D2\u4EF6\u3002
4046
- `);
4142
+ if (list.length === 0) {
4143
+ console.log("\n\u6682\u65E0\u53EF\u7528\u5957\u9910\u3002\n");
4047
4144
  return;
4048
4145
  }
4049
4146
  const columns = [
4050
- { key: "plugin", header: "plugin" },
4051
- { key: "name", header: "\u540D\u79F0" },
4052
- { key: "status", header: "\u72B6\u6001" },
4053
- { key: "version", header: "\u7248\u672C" }
4147
+ { key: "packageId", header: "packageId" },
4148
+ { key: "packageName", header: "\u540D\u79F0" },
4149
+ { key: "monthUsd", header: "\u6708\u4ED8(USD)" },
4150
+ { key: "yearUsd", header: "\u5E74\u4ED8\u6708\u4EF7(USD)" },
4151
+ { key: "enabled", header: "\u542F\u7528" },
4152
+ { key: "sunset", header: "\u4E0B\u67B6" }
4054
4153
  ];
4154
+ const rows = list.map((p) => ({
4155
+ packageId: readString2(p, "packageId") || readString2(p, "PackageId"),
4156
+ packageName: readString2(p, "packageName") || readString2(p, "PackageName"),
4157
+ monthUsd: readString2(p, "monthPriceUSD") || readString2(p, "MonthPriceUSD") || "-",
4158
+ yearUsd: readString2(p, "yearlyPriceUSD") || readString2(p, "YearlyPriceUSD") || "-",
4159
+ enabled: String(p.enabled ?? p.Enabled ?? "-"),
4160
+ sunset: String(p.sunset ?? p.Sunset ?? "-")
4161
+ }));
4055
4162
  console.log(`
4056
- ${site.name} \u5DF2\u88C5\u63D2\u4EF6\uFF08${plugins.length}\uFF09
4163
+ \u5957\u9910\u5217\u8868\uFF08\u5171 ${list.length} \u4E2A\uFF09
4057
4164
  `);
4058
- printCliTable(
4059
- plugins.map((p) => ({
4060
- plugin: p.plugin ?? "-",
4061
- name: pluginName(p) || "-",
4062
- status: p.status ?? "-",
4063
- version: p.version ?? "-"
4064
- })),
4165
+ printCliTable(rows, columns);
4166
+ console.log("\n\u4E0B\u4E00\u6B65\uFF1Asiluzan-website templates list --package <packageId>\n");
4167
+ }
4168
+ function register6(program2) {
4169
+ const packages = program2.command("packages").description("\u5EFA\u7AD9\u5957\u9910\uFF08website-provision\uFF09");
4170
+ packages.command("list").description("\u5217\u51FA\u53EF\u552E\u5957\u9910").option("--json", "\u8F93\u51FA JSON", false).option("--verbose", "\u8F93\u51FA\u8BF7\u6C42\u8BE6\u60C5", false).action(async (opts) => {
4171
+ await runPackagesList(opts);
4172
+ });
4173
+ }
4174
+
4175
+ // src/commands/templates.ts
4176
+ import fs6 from "fs";
4177
+ import path6 from "path";
4178
+ function resolveJsonOutFile(jsonOut) {
4179
+ const raw = jsonOut.trim();
4180
+ if (!raw) {
4181
+ throw new Error("--json-out \u8DEF\u5F84\u4E0D\u80FD\u4E3A\u7A7A");
4182
+ }
4183
+ const abs = path6.resolve(raw);
4184
+ if (abs.toLowerCase().endsWith(".json")) {
4185
+ fs6.mkdirSync(path6.dirname(abs), { recursive: true });
4186
+ return abs;
4187
+ }
4188
+ fs6.mkdirSync(abs, { recursive: true });
4189
+ return path6.join(abs, "template-catalog.json");
4190
+ }
4191
+ function slimCatalogGroups(groups) {
4192
+ return groups.map((g) => {
4193
+ const templates = Array.isArray(g.templates) ? g.templates : [];
4194
+ return {
4195
+ packageId: readString3(g, "packageId") || readString3(g, "PackageId"),
4196
+ packageName: readString3(g, "packageName") || readString3(g, "PackageName"),
4197
+ monthPriceUSD: g.monthPriceUSD ?? g.MonthPriceUSD ?? "-",
4198
+ yearlyPriceUSD: g.yearlyPriceUSD ?? g.YearlyPriceUSD ?? "-",
4199
+ templates: templates.map((item) => {
4200
+ const t = asRecord3(item) ?? {};
4201
+ const p = pickPreviewFields(t);
4202
+ return {
4203
+ siteTemplateId: p.id,
4204
+ name: p.name,
4205
+ industry: p.industry,
4206
+ coverUrl: p.coverUrl,
4207
+ previewUrl: p.previewUrl,
4208
+ hotTag: Boolean(t.hotTag ?? t.HotTag),
4209
+ newTag: Boolean(t.newTag ?? t.NewTag)
4210
+ };
4211
+ })
4212
+ };
4213
+ });
4214
+ }
4215
+ function asRecord3(value) {
4216
+ return value && typeof value === "object" ? value : null;
4217
+ }
4218
+ function readString3(obj, key) {
4219
+ if (!obj) return "";
4220
+ const v = obj[key];
4221
+ return typeof v === "string" ? v : v == null ? "" : String(v);
4222
+ }
4223
+ function unwrapList2(raw) {
4224
+ if (Array.isArray(raw)) {
4225
+ return raw.map(asRecord3).filter((x) => Boolean(x));
4226
+ }
4227
+ const obj = asRecord3(raw);
4228
+ if (!obj) return [];
4229
+ if (Array.isArray(obj.data)) {
4230
+ return obj.data.map(asRecord3).filter((x) => Boolean(x));
4231
+ }
4232
+ if (Array.isArray(obj.items)) {
4233
+ return obj.items.map(asRecord3).filter((x) => Boolean(x));
4234
+ }
4235
+ return [];
4236
+ }
4237
+ function siteManBase() {
4238
+ return (process.env.SILUZAN_SITEMAN_BASE ?? DEFAULT_SITEMAN_BASE).replace(/\/+$/, "");
4239
+ }
4240
+ function enrichTemplatePreview(t) {
4241
+ const out = { ...t };
4242
+ const base = siteManBase();
4243
+ const coverId = readString3(t, "cover") || readString3(t, "Cover");
4244
+ const imageId = readString3(t, "image") || readString3(t, "Image");
4245
+ if (!readString3(t, "coverUrl") && coverId) out.coverUrl = `${base}/api/Attachments/${coverId}`;
4246
+ if (!readString3(t, "imageUrl") && imageId) out.imageUrl = `${base}/api/Attachments/${imageId}`;
4247
+ const colors = Array.isArray(t.colors) ? t.colors : Array.isArray(t.Colors) ? t.Colors : [];
4248
+ const first = asRecord3(colors[0]);
4249
+ const preview = readString3(first, "colorSchemePreview") || readString3(first, "ColorSchemePreview");
4250
+ if (!readString3(t, "previewUrl") && preview) out.previewUrl = preview;
4251
+ const colorPreviewId = readString3(first, "colorPreview") || readString3(first, "ColorPreview");
4252
+ if (!readString3(t, "colorPreviewUrl") && colorPreviewId) {
4253
+ out.colorPreviewUrl = `${base}/api/Attachments/${colorPreviewId}`;
4254
+ }
4255
+ return out;
4256
+ }
4257
+ function templateBelongsToPackage(t, packageId) {
4258
+ const packages = readString3(t, "packages") || readString3(t, "Packages");
4259
+ if (!packages) return false;
4260
+ if (packages.toLowerCase().includes(`|${packageId.toLowerCase()}|`)) return true;
4261
+ return packages.split(/[|,;]/).map((s) => s.trim()).some((p) => p.toLowerCase() === packageId.toLowerCase());
4262
+ }
4263
+ function pickPreviewFields(t) {
4264
+ const e = enrichTemplatePreview(t);
4265
+ return {
4266
+ id: readString3(e, "siteTemplateId") || readString3(e, "SiteTemplateId"),
4267
+ name: readString3(e, "name") || readString3(e, "Name"),
4268
+ industry: readString3(e, "industrys") || readString3(e, "Industrys") || "-",
4269
+ coverUrl: readString3(e, "coverUrl") || readString3(e, "CoverUrl") || "",
4270
+ previewUrl: readString3(e, "previewUrl") || readString3(e, "PreviewUrl") || "",
4271
+ hot: String(e.hotTag ?? e.HotTag ?? "-"),
4272
+ neu: String(e.newTag ?? e.NewTag ?? "-"),
4273
+ version: readString3(e, "version") || readString3(e, "Version") || "-"
4274
+ };
4275
+ }
4276
+ async function composeCatalogLocally(config, verbose) {
4277
+ const [pkgRaw, tplRaw] = await Promise.all([
4278
+ apiFetch2(`${config.apiBaseUrl}/website-provision/packages`, config, {}, verbose),
4279
+ apiFetch2(
4280
+ `${config.apiBaseUrl}/website-provision/templates?pageSize=500&pageIndex=1`,
4281
+ config,
4282
+ {},
4283
+ verbose
4284
+ )
4285
+ ]);
4286
+ const packages = unwrapList2(pkgRaw).filter((p) => !(p.sunset === true || p.Sunset === true));
4287
+ const templates = unwrapList2(tplRaw).map(enrichTemplatePreview);
4288
+ const groups = packages.map((p) => {
4289
+ const packageId = readString3(p, "packageId") || readString3(p, "PackageId");
4290
+ const matched = templates.filter((t) => templateBelongsToPackage(t, packageId));
4291
+ return {
4292
+ packageId,
4293
+ packageName: readString3(p, "packageName") || readString3(p, "PackageName"),
4294
+ monthPriceUSD: p.monthPriceUSD ?? p.MonthPriceUSD,
4295
+ yearlyPriceUSD: p.yearlyPriceUSD ?? p.YearlyPriceUSD,
4296
+ templates: matched,
4297
+ templateCount: matched.length
4298
+ };
4299
+ });
4300
+ return {
4301
+ packages,
4302
+ groups,
4303
+ totalTemplates: templates.length,
4304
+ source: "cli-fallback"
4305
+ };
4306
+ }
4307
+ async function runTemplatesList(opts) {
4308
+ const config = loadConfig();
4309
+ const params = new URLSearchParams({ pageSize: "100", pageIndex: "1" });
4310
+ if (opts.package) params.set("package", opts.package);
4311
+ if (opts.industry) params.set("industry", opts.industry);
4312
+ if (opts.keyword) params.set("keyword", opts.keyword);
4313
+ const url = `${config.apiBaseUrl}/website-provision/templates?${params.toString()}`;
4314
+ let raw;
4315
+ try {
4316
+ raw = await apiFetch2(url, config, {}, opts.verbose);
4317
+ } catch (e) {
4318
+ console.error(`
4319
+ \u274C \u83B7\u53D6\u6A21\u677F\u5217\u8868\u5931\u8D25\uFF1A${e.message}`);
4320
+ if (!opts.verbose) console.error(" \u52A0 --verbose \u53EF\u67E5\u770B\u8BE6\u7EC6\u9519\u8BEF");
4321
+ process.exit(1);
4322
+ return;
4323
+ }
4324
+ const list = unwrapList2(raw).map(enrichTemplatePreview);
4325
+ if (opts.json) {
4326
+ console.log(JSON.stringify({ total: list.length, templates: list }, null, 2));
4327
+ return;
4328
+ }
4329
+ if (list.length === 0) {
4330
+ console.log("\n\u6682\u65E0\u5339\u914D\u6A21\u677F\u3002\u8BF7\u68C0\u67E5 --package \u662F\u5426\u6B63\u786E\u3002\n");
4331
+ return;
4332
+ }
4333
+ const columns = [
4334
+ { key: "id", header: "siteTemplateId" },
4335
+ { key: "name", header: "\u540D\u79F0" },
4336
+ { key: "industry", header: "\u884C\u4E1A" },
4337
+ { key: "preview", header: "\u9884\u89C8" },
4338
+ { key: "hot", header: "\u70ED\u95E8" },
4339
+ { key: "neu", header: "\u65B0\u54C1" }
4340
+ ];
4341
+ const rows = list.map((t) => {
4342
+ const p = pickPreviewFields(t);
4343
+ return {
4344
+ id: p.id,
4345
+ name: p.name,
4346
+ industry: p.industry,
4347
+ preview: p.previewUrl || (p.coverUrl ? "(\u6709\u5C01\u9762)" : "-"),
4348
+ hot: p.hot,
4349
+ neu: p.neu
4350
+ };
4351
+ });
4352
+ console.log(`
4353
+ \u6A21\u677F\u5217\u8868\uFF08\u5171 ${list.length} \u4E2A\uFF09
4354
+ `);
4355
+ printCliTable(rows, columns);
4356
+ console.log("\n\u6A21\u677F\u76EE\u5F55\uFF1Asiluzan-website templates catalog");
4357
+ console.log("\u8BE6\u60C5\uFF1Asiluzan-website templates get --id <siteTemplateId>\n");
4358
+ }
4359
+ async function runTemplatesCatalog(opts) {
4360
+ const config = loadConfig();
4361
+ const url = `${config.apiBaseUrl}/website-provision/template-catalog`;
4362
+ let raw;
4363
+ let usedFallback = false;
4364
+ try {
4365
+ raw = await apiFetch2(url, config, {}, opts.verbose);
4366
+ } catch (e) {
4367
+ const msg = e.message || "";
4368
+ if (/HTTP 404/.test(msg)) {
4369
+ console.error("\u2139\uFE0F \u4E3B\u7AD9\u5C1A\u672A\u90E8\u7F72 template-catalog\uFF0C\u6539\u7528 packages+templates \u672C\u5730\u62FC\u88C5\u76EE\u5F55\u2026");
4370
+ try {
4371
+ raw = await composeCatalogLocally(config, opts.verbose);
4372
+ usedFallback = true;
4373
+ } catch (e2) {
4374
+ console.error(`
4375
+ \u274C \u62FC\u88C5\u6A21\u677F\u76EE\u5F55\u5931\u8D25\uFF1A${e2.message}`);
4376
+ process.exit(1);
4377
+ return;
4378
+ }
4379
+ } else {
4380
+ console.error(`
4381
+ \u274C \u83B7\u53D6\u6A21\u677F\u76EE\u5F55\u5931\u8D25\uFF1A${msg}`);
4382
+ if (!opts.verbose) console.error(" \u52A0 --verbose \u53EF\u67E5\u770B\u8BE6\u7EC6\u9519\u8BEF");
4383
+ process.exit(1);
4384
+ return;
4385
+ }
4386
+ }
4387
+ const root = asRecord3(raw);
4388
+ let groups = (Array.isArray(root?.groups) ? root.groups : []).map(asRecord3).filter((x) => Boolean(x)).map((g) => ({
4389
+ ...g,
4390
+ templates: Array.isArray(g.templates) ? g.templates.map((t) => enrichTemplatePreview(asRecord3(t) ?? {})) : []
4391
+ }));
4392
+ if (opts.package?.trim()) {
4393
+ const pkg = opts.package.trim();
4394
+ groups = groups.filter((g) => readString3(g, "packageId") === pkg);
4395
+ }
4396
+ const slimGroups = slimCatalogGroups(groups);
4397
+ const totalTemplates = Number(root?.totalTemplates) || slimGroups.reduce(
4398
+ (n, g) => n + (Array.isArray(g.templates) ? g.templates.length : 0),
4399
+ 0
4400
+ );
4401
+ const source = usedFallback ? "cli-fallback" : root?.source ?? "api";
4402
+ const payload = {
4403
+ totalGroups: slimGroups.length,
4404
+ totalTemplates,
4405
+ source,
4406
+ groups: slimGroups
4407
+ };
4408
+ if (opts.jsonOut?.trim()) {
4409
+ const outFile = resolveJsonOutFile(opts.jsonOut);
4410
+ fs6.writeFileSync(outFile, JSON.stringify(payload, null, 2), "utf8");
4411
+ console.log(
4412
+ JSON.stringify({
4413
+ ok: true,
4414
+ path: outFile,
4415
+ totalGroups: payload.totalGroups,
4416
+ totalTemplates: payload.totalTemplates,
4417
+ source: payload.source,
4418
+ next: "present_website_templates(groups_path=<path>)"
4419
+ })
4420
+ );
4421
+ return;
4422
+ }
4423
+ if (!opts.table) {
4424
+ console.log(JSON.stringify(payload, null, 2));
4425
+ return;
4426
+ }
4427
+ for (const g of groups) {
4428
+ const pkgId = readString3(g, "packageId");
4429
+ const pkgName = readString3(g, "packageName") || pkgId;
4430
+ const templates = Array.isArray(g.templates) ? g.templates : [];
4431
+ console.log(`
4432
+ ## ${pkgName} (${pkgId}) \u2014 ${templates.length} \u4E2A\u6A21\u677F
4433
+ `);
4434
+ const columns = [
4435
+ { key: "id", header: "siteTemplateId" },
4436
+ { key: "name", header: "\u540D\u79F0" },
4437
+ { key: "industry", header: "\u884C\u4E1A" },
4438
+ { key: "preview", header: "\u9884\u89C8URL" }
4439
+ ];
4440
+ const rows = templates.map((item) => {
4441
+ const t = asRecord3(item) ?? {};
4442
+ const p = pickPreviewFields(t);
4443
+ return { id: p.id, name: p.name, industry: p.industry, preview: p.previewUrl || "-" };
4444
+ });
4445
+ printCliTable(rows, columns);
4446
+ }
4447
+ console.log();
4448
+ }
4449
+ async function runTemplatesGet(opts) {
4450
+ const id = opts.id?.trim();
4451
+ if (!id) {
4452
+ console.error("\n\u274C \u8BF7\u63D0\u4F9B --id <siteTemplateId>\n");
4453
+ process.exit(1);
4454
+ }
4455
+ const config = loadConfig();
4456
+ const url = `${config.apiBaseUrl}/website-provision/templates/${encodeURIComponent(id)}`;
4457
+ let raw;
4458
+ try {
4459
+ raw = await apiFetch2(url, config, {}, opts.verbose);
4460
+ } catch (e) {
4461
+ console.error(`
4462
+ \u274C \u83B7\u53D6\u6A21\u677F\u8BE6\u60C5\u5931\u8D25\uFF1A${e.message}`);
4463
+ process.exit(1);
4464
+ return;
4465
+ }
4466
+ const enriched = enrichTemplatePreview(asRecord3(raw) ?? {});
4467
+ if (opts.json) {
4468
+ console.log(JSON.stringify(enriched, null, 2));
4469
+ return;
4470
+ }
4471
+ const p = pickPreviewFields(enriched);
4472
+ console.log("\n\u6A21\u677F\u8BE6\u60C5\n");
4473
+ console.log(` siteTemplateId : ${p.id || id}`);
4474
+ console.log(` name : ${p.name}`);
4475
+ console.log(` description : ${readString3(enriched, "description") || readString3(enriched, "Description") || "-"}`);
4476
+ console.log(` industrys : ${p.industry}`);
4477
+ console.log(` version : ${p.version}`);
4478
+ console.log(` hasTheme : ${String(enriched.hasTheme ?? "-")}`);
4479
+ console.log(` coverUrl : ${p.coverUrl || "-"}`);
4480
+ console.log(` previewUrl : ${p.previewUrl || "-"}`);
4481
+ if (p.coverUrl) console.log(`
4482
+ ![${p.name || p.id}](${p.coverUrl})`);
4483
+ console.log("\n\uFF08\u5B89\u88C5\u5305\u5730\u5740\u5DF2\u8131\u654F\uFF0C\u4E0D\u4F1A\u8F93\u51FA\uFF09\n");
4484
+ }
4485
+ function register7(program2) {
4486
+ const templates = program2.command("templates").description("\u5EFA\u7AD9\u6A21\u677F\uFF08website-provision\uFF09");
4487
+ templates.command("catalog").description("\u5957\u9910+\u6A21\u677F\u76EE\u5F55 JSON\uFF08\u4F9B DeerFlow present_website_templates\uFF1B\u5F00\u7AD9\u7B2C\u4E00\u6B65\uFF09").option("--package <packageId>", "\u53EA\u8FD4\u56DE\u67D0\u4E00\u5957\u9910").option("--json", "\u8F93\u51FA JSON\uFF08\u9ED8\u8BA4\u5DF2\u662F JSON\uFF0C\u4FDD\u7559\u517C\u5BB9\uFF09", false).option("--json-out <path>", "\u843D\u76D8 template-catalog.json\uFF08\u76EE\u5F55\u6216 *.json\uFF09\uFF1Bstdout \u4EC5\u4E00\u884C\u6458\u8981").option("--table", "\u7EC8\u7AEF\u8868\u683C\u8F93\u51FA\uFF08\u8C03\u8BD5\u7528\uFF09", false).option("--verbose", "\u8F93\u51FA\u8BF7\u6C42\u8BE6\u60C5", false).action(async (opts) => {
4488
+ await runTemplatesCatalog({
4489
+ package: opts.package,
4490
+ json: true,
4491
+ table: opts.table,
4492
+ jsonOut: opts.jsonOut,
4493
+ verbose: opts.verbose
4494
+ });
4495
+ });
4496
+ templates.command("list").description("\u6309\u5957\u9910\u7B49\u6761\u4EF6\u5217\u51FA\u6A21\u677F").option("--package <packageId>", "\u5957\u9910 ID \u8FC7\u6EE4").option("--industry <industry>", "\u884C\u4E1A\u8FC7\u6EE4").option("--keyword <keyword>", "\u5173\u952E\u8BCD").option("--json", "\u8F93\u51FA JSON", false).option("--verbose", "\u8F93\u51FA\u8BF7\u6C42\u8BE6\u60C5", false).action(async (opts) => {
4497
+ await runTemplatesList(opts);
4498
+ });
4499
+ templates.command("get").description("\u6A21\u677F\u8BE6\u60C5\uFF08\u4E0D\u542B\u5B89\u88C5\u5305 URI\uFF09").option("--id <siteTemplateId>", "\u6A21\u677F ID").option("--json", "\u8F93\u51FA JSON", false).option("--verbose", "\u8F93\u51FA\u8BF7\u6C42\u8BE6\u60C5", false).action(async (opts) => {
4500
+ await runTemplatesGet(opts);
4501
+ });
4502
+ }
4503
+
4504
+ // src/commands/trial.ts
4505
+ function asRecord4(value) {
4506
+ return value && typeof value === "object" ? value : null;
4507
+ }
4508
+ async function runTrialStatus(opts) {
4509
+ const config = loadConfig();
4510
+ const url = `${config.apiBaseUrl}/website-provision/trial-count`;
4511
+ let raw;
4512
+ try {
4513
+ raw = await apiFetch2(url, config, {}, opts.verbose);
4514
+ } catch (e) {
4515
+ console.error(`
4516
+ \u274C \u83B7\u53D6\u8BD5\u7528\u6B21\u6570\u5931\u8D25\uFF1A${e.message}`);
4517
+ process.exit(1);
4518
+ return;
4519
+ }
4520
+ if (opts.json) {
4521
+ console.log(JSON.stringify(raw, null, 2));
4522
+ return;
4523
+ }
4524
+ const obj = asRecord4(raw);
4525
+ const used = Number(obj?.used ?? obj?.Used ?? 0);
4526
+ const limit = Number(obj?.limit ?? obj?.Limit ?? 3);
4527
+ const remaining = Number(obj?.remaining ?? obj?.Remaining ?? Math.max(0, limit - used));
4528
+ console.log("\n\u8BD5\u7528\u5EFA\u7AD9\u989D\u5EA6\n");
4529
+ console.log(` \u5DF2\u7528 : ${used}`);
4530
+ console.log(` \u4E0A\u9650 : ${limit}`);
4531
+ console.log(` \u5269\u4F59 : ${remaining}`);
4532
+ console.log();
4533
+ }
4534
+ function register8(program2) {
4535
+ const trial = program2.command("trial").description("\u8BD5\u7528\u5EFA\u7AD9\u989D\u5EA6\uFF08website-provision\uFF09");
4536
+ trial.command("status").description("\u67E5\u770B\u5F53\u524D\u8D26\u53F7\u8BD5\u7528\u5DF2\u7528\u6B21\u6570\u4E0E\u4E0A\u9650").option("--json", "\u8F93\u51FA JSON", false).option("--verbose", "\u8F93\u51FA\u8BF7\u6C42\u8BE6\u60C5", false).action(async (opts) => {
4537
+ await runTrialStatus(opts);
4538
+ });
4539
+ }
4540
+
4541
+ // src/commands/bills.ts
4542
+ function asRecord5(value) {
4543
+ return value && typeof value === "object" ? value : null;
4544
+ }
4545
+ function readString4(obj, key) {
4546
+ if (!obj) return "";
4547
+ const v = obj[key];
4548
+ return typeof v === "string" ? v : v == null ? "" : String(v);
4549
+ }
4550
+ async function runBillsCreate(opts) {
4551
+ const packageId = opts.package?.trim();
4552
+ if (!packageId) {
4553
+ console.error("\n\u274C \u8BF7\u63D0\u4F9B --package <packageId>\n");
4554
+ process.exit(1);
4555
+ }
4556
+ const config = loadConfig();
4557
+ const body = {
4558
+ packageId,
4559
+ payChannel: opts.channel || "Monthly",
4560
+ currency: opts.currency || "USD",
4561
+ successUrl: opts.successUrl || "",
4562
+ cancelUrl: opts.cancelUrl || ""
4563
+ };
4564
+ console.log("\n\u5373\u5C06\u521B\u5EFA\u5957\u9910\u8D26\u5355\uFF08\u4E0D\u4F1A\u81EA\u52A8\u6263\u6B3E\uFF0C\u7528\u6237\u9700\u6253\u5F00\u6536\u94F6\u53F0\u5B8C\u6210\u652F\u4ED8\uFF09\uFF1A");
4565
+ console.log(` packageId : ${body.packageId}`);
4566
+ console.log(` payChannel : ${body.payChannel}`);
4567
+ console.log(` currency : ${body.currency}`);
4568
+ const url = `${config.apiBaseUrl}/website-provision/bills`;
4569
+ let raw;
4570
+ try {
4571
+ raw = await apiFetch2(
4572
+ url,
4573
+ config,
4574
+ { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(body) },
4575
+ opts.verbose
4576
+ );
4577
+ } catch (e) {
4578
+ console.error(`
4579
+ \u274C \u521B\u5EFA\u8D26\u5355\u5931\u8D25\uFF1A${e.message}`);
4580
+ process.exit(1);
4581
+ return;
4582
+ }
4583
+ if (opts.json) {
4584
+ console.log(JSON.stringify(raw, null, 2));
4585
+ return;
4586
+ }
4587
+ const obj = asRecord5(raw);
4588
+ const billId = readString4(obj, "billId") || readString4(obj, "BillId");
4589
+ const checkoutUrl = readString4(obj, "checkoutUrl") || readString4(obj, "CheckoutUrl");
4590
+ console.log("\n\u2705 \u8D26\u5355\u5DF2\u521B\u5EFA\n");
4591
+ console.log(` billId : ${billId}`);
4592
+ console.log(` state : ${readString4(obj, "state") || readString4(obj, "State") || "-"}`);
4593
+ console.log(` checkoutUrl : ${checkoutUrl || "(\u65E0\uFF0C\u8BF7\u68C0\u67E5 Stripe \u914D\u7F6E)"}`);
4594
+ console.log("\n\u8BF7\u5C06\u6536\u94F6\u53F0\u94FE\u63A5\u53D1\u7ED9\u7528\u6237\u5B8C\u6210\u652F\u4ED8\uFF0C\u7136\u540E\uFF1A");
4595
+ console.log(` siluzan-website bills get --id ${billId}`);
4596
+ console.log(` \u652F\u4ED8\u6210\u529F\u540E\u521B\u5EFA\u7AD9\u70B9\u65F6\u5E26 --bill ${billId}
4597
+ `);
4598
+ }
4599
+ async function runBillsGet(opts) {
4600
+ const id = opts.id?.trim();
4601
+ if (!id) {
4602
+ console.error("\n\u274C \u8BF7\u63D0\u4F9B --id <billId>\n");
4603
+ process.exit(1);
4604
+ }
4605
+ const config = loadConfig();
4606
+ const url = `${config.apiBaseUrl}/website-provision/bills/${encodeURIComponent(id)}`;
4607
+ let raw;
4608
+ try {
4609
+ raw = await apiFetch2(url, config, {}, opts.verbose);
4610
+ } catch (e) {
4611
+ console.error(`
4612
+ \u274C \u67E5\u8BE2\u8D26\u5355\u5931\u8D25\uFF1A${e.message}`);
4613
+ process.exit(1);
4614
+ return;
4615
+ }
4616
+ if (opts.json) {
4617
+ console.log(JSON.stringify(raw, null, 2));
4618
+ return;
4619
+ }
4620
+ const obj = asRecord5(raw);
4621
+ console.log("\n\u8D26\u5355\u72B6\u6001\n");
4622
+ console.log(` billId : ${readString4(obj, "billId") || id}`);
4623
+ console.log(` state : ${readString4(obj, "state") || readString4(obj, "State")}`);
4624
+ console.log(` paid : ${String(obj?.paid ?? obj?.Paid ?? "-")}`);
4625
+ console.log(` packageId : ${readString4(obj, "packageId") || readString4(obj, "PackageId") || "-"}`);
4626
+ console.log(` siteId : ${readString4(obj, "siteId") || readString4(obj, "SiteId") || "(\u672A\u7ED1\u5B9A)"}`);
4627
+ console.log();
4628
+ }
4629
+ function register9(program2) {
4630
+ const bills = program2.command("bills").description("\u5EFA\u7AD9\u5957\u9910\u8D26\u5355 / \u652F\u4ED8\uFF08website-provision\uFF09");
4631
+ bills.command("create").description("\u521B\u5EFA\u5957\u9910\u8D26\u5355\u5E76\u8FD4\u56DE\u6536\u94F6\u53F0 URL\uFF08\u5199\u64CD\u4F5C\uFF0CAgent \u987B\u5148\u83B7\u7528\u6237\u786E\u8BA4\uFF09").option("--package <packageId>", "\u5957\u9910 ID").option("--channel <Monthly|Yearly>", "\u4ED8\u8D39\u5468\u671F", "Monthly").option("--currency <code>", "\u5E01\u79CD", "USD").option("--success-url <url>", "\u652F\u4ED8\u6210\u529F\u56DE\u8DF3 URL").option("--cancel-url <url>", "\u652F\u4ED8\u53D6\u6D88\u56DE\u8DF3 URL").option("--json", "\u8F93\u51FA JSON", false).option("--verbose", "\u8F93\u51FA\u8BF7\u6C42\u8BE6\u60C5", false).action(async (opts) => {
4632
+ await runBillsCreate(opts);
4633
+ });
4634
+ bills.command("get").description("\u67E5\u8BE2\u8D26\u5355\u652F\u4ED8\u4E0E\u7ED1\u5B9A\u72B6\u6001").option("--id <billId>", "\u8D26\u5355\u53F7").option("--json", "\u8F93\u51FA JSON", false).option("--verbose", "\u8F93\u51FA\u8BF7\u6C42\u8BE6\u60C5", false).action(async (opts) => {
4635
+ await runBillsGet(opts);
4636
+ });
4637
+ }
4638
+
4639
+ // src/commands/pages.ts
4640
+ import * as fs7 from "fs";
4641
+
4642
+ // src/utils/wp-site.ts
4643
+ async function resolveTarget(opts) {
4644
+ const config = loadConfig();
4645
+ const site = await resolveSite(config, opts);
4646
+ return { config, site, base: trimTrailingSlash(site.url) };
4647
+ }
4648
+ function wpV2(base, path7) {
4649
+ const suffix = path7.startsWith("/") ? path7 : `/${path7}`;
4650
+ return `${base}/wp-json/wp/v2${suffix}`;
4651
+ }
4652
+ async function resolveTypeRestBase(target, typeArg, verbose = false) {
4653
+ const needle = typeArg.trim().toLowerCase();
4654
+ if (!needle) {
4655
+ throw new Error("\u8BF7\u63D0\u4F9B --type\uFF08\u5148 content types \u770B rest_base\uFF09");
4656
+ }
4657
+ const types = await apiFetch2(
4658
+ wpV2(target.base, "/types?context=edit"),
4659
+ target.config,
4660
+ {},
4661
+ verbose
4662
+ );
4663
+ for (const [slug, info] of Object.entries(types || {})) {
4664
+ const restBase = (info.rest_base || slug).toLowerCase();
4665
+ if (slug.toLowerCase() === needle || restBase === needle) {
4666
+ return info.rest_base || slug;
4667
+ }
4668
+ }
4669
+ return typeArg.trim();
4670
+ }
4671
+ async function resolveTaxonomyRestBase(target, taxonomyArg, verbose = false) {
4672
+ const needle = taxonomyArg.trim().toLowerCase();
4673
+ if (!needle) {
4674
+ throw new Error("\u8BF7\u63D0\u4F9B --taxonomy\uFF08\u5982 category\u3001post_tag\uFF09");
4675
+ }
4676
+ const taxes = await apiFetch2(
4677
+ wpV2(target.base, "/taxonomies?context=edit"),
4678
+ target.config,
4679
+ {},
4680
+ verbose
4681
+ );
4682
+ for (const [slug, info] of Object.entries(taxes || {})) {
4683
+ const restBase = (info.rest_base || slug).toLowerCase();
4684
+ if (slug.toLowerCase() === needle || restBase === needle) {
4685
+ return info.rest_base || slug;
4686
+ }
4687
+ }
4688
+ return taxonomyArg.trim();
4689
+ }
4690
+
4691
+ // src/commands/pages.ts
4692
+ function pageTitle(page) {
4693
+ if (typeof page.title === "string") return page.title;
4694
+ return page.title?.rendered ?? "";
4695
+ }
4696
+ function readTextOption(inline, filePath) {
4697
+ if (filePath) {
4698
+ try {
4699
+ return fs7.readFileSync(filePath, "utf8");
4700
+ } catch (e) {
4701
+ console.error(`
4702
+ \u274C \u65E0\u6CD5\u8BFB\u53D6\u6587\u4EF6 ${filePath}\uFF1A${e.message}
4703
+ `);
4704
+ process.exit(1);
4705
+ }
4706
+ }
4707
+ return inline ?? "";
4708
+ }
4709
+ async function runPagesList(opts) {
4710
+ const config = loadConfig();
4711
+ const site = await resolveSite(config, opts);
4712
+ const base = trimTrailingSlash(site.url);
4713
+ const api = `${base}/wp-json/wp/v2/pages?per_page=100&status=publish,draft,private,pending`;
4714
+ let pages;
4715
+ try {
4716
+ pages = await apiFetch2(api, config, {}, opts.verbose);
4717
+ } catch (e) {
4718
+ console.error(`
4719
+ \u274C \u83B7\u53D6\u9875\u9762\u5931\u8D25\uFF1A${e.message}`);
4720
+ console.error(` \u7AD9\u70B9\uFF1A${base}`);
4721
+ process.exit(1);
4722
+ return;
4723
+ }
4724
+ if (!Array.isArray(pages)) {
4725
+ console.error("\n\u274C \u7AD9\u70B9\u8FD4\u56DE\u7684\u9875\u9762\u5217\u8868\u683C\u5F0F\u5F02\u5E38\n");
4726
+ process.exit(1);
4727
+ }
4728
+ if (opts.json) {
4729
+ console.log(
4730
+ JSON.stringify(
4731
+ {
4732
+ site: { guid: site.guid, name: site.name, url: site.url },
4733
+ total: pages.length,
4734
+ pages: pages.map((p) => ({
4735
+ id: p.id,
4736
+ title: pageTitle(p),
4737
+ slug: p.slug ?? "",
4738
+ status: p.status ?? "",
4739
+ link: p.link ?? "",
4740
+ modified: p.modified ?? ""
4741
+ }))
4742
+ },
4743
+ null,
4744
+ 2
4745
+ )
4746
+ );
4747
+ return;
4748
+ }
4749
+ if (pages.length === 0) {
4750
+ console.log(`
4751
+ \u7AD9\u70B9 ${site.name} \u6682\u65E0\u9875\u9762\u3002\u53EF\u7528 pages add \u65B0\u589E\u3002
4752
+ `);
4753
+ return;
4754
+ }
4755
+ const columns = [
4756
+ { key: "id", header: "id" },
4757
+ { key: "title", header: "\u6807\u9898" },
4758
+ { key: "status", header: "\u72B6\u6001" },
4759
+ { key: "slug", header: "slug" },
4760
+ { key: "link", header: "\u94FE\u63A5" }
4761
+ ];
4762
+ console.log(`
4763
+ ${site.name} \u9875\u9762\uFF08${pages.length}\uFF09
4764
+ `);
4765
+ printCliTable(
4766
+ pages.map((p) => ({
4767
+ id: String(p.id),
4768
+ title: pageTitle(p) || "(\u65E0\u6807\u9898)",
4769
+ status: p.status ?? "-",
4770
+ slug: p.slug ?? "-",
4771
+ link: p.link ?? "-"
4772
+ })),
4773
+ columns
4774
+ );
4775
+ console.log();
4776
+ }
4777
+ async function runPagesWrite(mode, opts) {
4778
+ const config = loadConfig();
4779
+ const site = await resolveSite(config, opts);
4780
+ const base = trimTrailingSlash(site.url);
4781
+ const title = opts.title?.trim() ?? "";
4782
+ const content = readTextOption(opts.content, opts.contentFile);
4783
+ if (mode === "add" && !title) {
4784
+ console.error("\n\u274C \u65B0\u589E\u9875\u9762\u5FC5\u987B\u63D0\u4F9B --title\n");
4785
+ process.exit(1);
4786
+ }
4787
+ if (!content.trim()) {
4788
+ console.error("\n\u274C \u8BF7\u7528 --content \u6216 --content-file \u63D0\u4F9B HTML \u6B63\u6587\n");
4789
+ process.exit(1);
4790
+ }
4791
+ const body = {
4792
+ content,
4793
+ import_mode: "preserve"
4794
+ };
4795
+ if (title) body.title = title;
4796
+ const css = readTextOption(opts.css, opts.cssFile);
4797
+ if (css) body._custom_css = css;
4798
+ const js = readTextOption(opts.js, opts.jsFile);
4799
+ if (js) body._custom_javascript = js;
4800
+ if (mode === "add") body.post_type = opts.postType?.trim() || "page";
4801
+ const api = mode === "add" ? `${base}/wp-json/zionbuilder/v1/pages/add-visual-edit` : `${base}/wp-json/zionbuilder/v1/pages/${opts.id}/save-visual-edit`;
4802
+ if (mode === "update" && !opts.id) {
4803
+ console.error("\n\u274C \u66F4\u65B0\u9875\u9762\u5FC5\u987B\u63D0\u4F9B --id\uFF08\u5148 pages list \u67E5 id\uFF09\n");
4804
+ process.exit(1);
4805
+ }
4806
+ let result;
4807
+ try {
4808
+ result = await apiFetch2(
4809
+ api,
4810
+ config,
4811
+ { method: "POST", body: JSON.stringify(body) },
4812
+ opts.verbose
4813
+ );
4814
+ } catch (e) {
4815
+ console.error(`
4816
+ \u274C ${mode === "add" ? "\u65B0\u589E" : "\u66F4\u65B0"}\u9875\u9762\u5931\u8D25\uFF1A${e.message}
4817
+ `);
4818
+ process.exit(1);
4819
+ return;
4820
+ }
4821
+ if (result.error || result.success === false) {
4822
+ console.error(`
4823
+ \u274C ${result.error || result.message || "\u7AD9\u70B9\u62D2\u7EDD\u4FDD\u5B58"}
4824
+ `);
4825
+ process.exit(1);
4826
+ }
4827
+ console.log(mode === "add" ? "\n\u2705 \u9875\u9762\u5DF2\u521B\u5EFA" : "\n\u2705 \u9875\u9762\u5DF2\u66F4\u65B0");
4828
+ if (result.post_id) console.log(` post_id : ${result.post_id}`);
4829
+ if (result.url) console.log(` url : ${result.url}`);
4830
+ console.log(` \u7AD9\u70B9 : ${base}
4831
+ `);
4832
+ }
4833
+ async function runPagesGet(opts) {
4834
+ const id = Number(opts.id);
4835
+ if (!Number.isFinite(id) || id <= 0) {
4836
+ console.error("\n\u274C \u8BF7\u63D0\u4F9B --id\n");
4837
+ process.exit(1);
4838
+ }
4839
+ const target = await resolveTarget(opts);
4840
+ const page = await apiFetch2(
4841
+ wpV2(target.base, `/pages/${id}?context=edit`),
4842
+ target.config,
4843
+ {},
4844
+ opts.verbose
4845
+ ).catch((e) => {
4846
+ console.error(`
4847
+ \u274C \u83B7\u53D6\u9875\u9762\u5931\u8D25\uFF1A${e.message}
4848
+ `);
4849
+ process.exit(1);
4850
+ });
4851
+ if (opts.json) {
4852
+ console.log(JSON.stringify(page, null, 2));
4853
+ return;
4854
+ }
4855
+ console.log(`
4856
+ \u9875\u9762 #${page.id}`);
4857
+ console.log(` \u6807\u9898 : ${pageTitle(page) || "-"}`);
4858
+ console.log(` \u72B6\u6001 : ${page.status || "-"}`);
4859
+ console.log(` slug : ${page.slug || "-"}`);
4860
+ console.log(` \u94FE\u63A5 : ${page.link || "-"}`);
4861
+ if (page.parent) console.log(` \u7236\u9875 : ${page.parent}`);
4862
+ if (page.featured_media) console.log(` \u7279\u8272\u56FE : ${page.featured_media}`);
4863
+ console.log();
4864
+ }
4865
+ async function runPagesMeta(opts) {
4866
+ const id = Number(opts.id);
4867
+ if (!Number.isFinite(id) || id <= 0) {
4868
+ console.error("\n\u274C \u8BF7\u63D0\u4F9B --id\n");
4869
+ process.exit(1);
4870
+ }
4871
+ const body = {};
4872
+ if (opts.title?.trim()) body.title = opts.title.trim();
4873
+ if (opts.slug?.trim()) body.slug = opts.slug.trim();
4874
+ if (opts.status?.trim()) body.status = opts.status.trim();
4875
+ const parent = Number(opts.parent);
4876
+ if (opts.parent !== void 0 && Number.isFinite(parent)) body.parent = parent;
4877
+ const featured = Number(opts.featuredMedia);
4878
+ if (Number.isFinite(featured) && featured > 0) body.featured_media = featured;
4879
+ if (Object.keys(body).length === 0) {
4880
+ console.error("\n\u274C \u6CA1\u6709\u8981\u6539\u7684\u5B57\u6BB5\u3002\u6B63\u6587\u8BF7\u7528 pages update\u3002\n");
4881
+ process.exit(1);
4882
+ }
4883
+ const target = await resolveTarget(opts);
4884
+ const page = await apiFetch2(
4885
+ wpV2(target.base, `/pages/${id}`),
4886
+ target.config,
4887
+ { method: "POST", body: JSON.stringify(body) },
4888
+ opts.verbose
4889
+ ).catch((e) => {
4890
+ console.error(`
4891
+ \u274C \u66F4\u65B0\u9875\u9762\u5143\u6570\u636E\u5931\u8D25\uFF1A${e.message}
4892
+ `);
4893
+ process.exit(1);
4894
+ });
4895
+ console.log(`
4896
+ \u2705 \u9875\u9762 #${page.id} \u5143\u6570\u636E\u5DF2\u66F4\u65B0`);
4897
+ console.log(` \u6807\u9898 : ${pageTitle(page) || "-"}`);
4898
+ console.log(` \u72B6\u6001 : ${page.status || "-"}`);
4899
+ console.log(` slug : ${page.slug || "-"}`);
4900
+ if (page.link) console.log(` \u94FE\u63A5 : ${page.link}`);
4901
+ console.log();
4902
+ }
4903
+ async function runPagesTrash(opts) {
4904
+ const id = Number(opts.id);
4905
+ if (!Number.isFinite(id) || id <= 0) {
4906
+ console.error("\n\u274C \u8BF7\u63D0\u4F9B --id\n");
4907
+ process.exit(1);
4908
+ }
4909
+ const target = await resolveTarget(opts);
4910
+ const qs = opts.force ? "?force=true" : "";
4911
+ const page = await apiFetch2(
4912
+ wpV2(target.base, `/pages/${id}${qs}`),
4913
+ target.config,
4914
+ { method: "DELETE" },
4915
+ opts.verbose
4916
+ ).catch((e) => {
4917
+ console.error(`
4918
+ \u274C \u5220\u9664\u9875\u9762\u5931\u8D25\uFF1A${e.message}
4919
+ `);
4920
+ process.exit(1);
4921
+ });
4922
+ console.log(
4923
+ opts.force ? `
4924
+ \u2705 \u5DF2\u6C38\u4E45\u5220\u9664\u9875\u9762 #${id}
4925
+ ` : `
4926
+ \u2705 \u9875\u9762 #${id} \u5DF2\u8FDB\u56DE\u6536\u7AD9\uFF08status=${page.status || "trash"}\uFF09
4927
+ `
4928
+ );
4929
+ }
4930
+ function register10(program2) {
4931
+ const pages = program2.command("pages").description("WordPress \u9875\u9762\uFF08zionbuilder visual-edit\uFF09");
4932
+ pages.command("list").description("\u5217\u51FA\u7AD9\u70B9\u9875\u9762").option("-s, --site <guidOrName>", "\u7AD9\u70B9 guid \u6216\u540D\u79F0").option("--url <url>", "\u76F4\u63A5\u6307\u5B9A\u7AD9\u70B9\u5730\u5740\uFF08\u8DF3\u8FC7 all-sites\uFF09").option("--json", "\u8F93\u51FA JSON", false).option("--verbose", "\u8F93\u51FA\u8BF7\u6C42\u8BE6\u60C5", false).action(async (opts) => {
4933
+ await runPagesList(opts);
4934
+ });
4935
+ pages.command("add").description("\u7528 HTML \u65B0\u589E\u9875\u9762\uFF08\u8D70 add-visual-edit\uFF0C\u4F1A\u76F4\u63A5\u53D1\u5E03\uFF09").option("-s, --site <guidOrName>", "\u7AD9\u70B9 guid \u6216\u540D\u79F0").option("--url <url>", "\u76F4\u63A5\u6307\u5B9A\u7AD9\u70B9\u5730\u5740").option("-t, --title <title>", "\u9875\u9762\u6807\u9898").option("-c, --content <html>", "HTML \u6B63\u6587").option("--content-file <path>", "\u4ECE\u6587\u4EF6\u8BFB\u53D6 HTML \u6B63\u6587").option("--css <css>", "\u9644\u52A0 CSS").option("--css-file <path>", "\u4ECE\u6587\u4EF6\u8BFB\u53D6 CSS").option("--js <js>", "\u9644\u52A0 JS").option("--js-file <path>", "\u4ECE\u6587\u4EF6\u8BFB\u53D6 JS").option("--post-type <type>", "\u6587\u7AE0\u7C7B\u578B\uFF0C\u9ED8\u8BA4 page", "page").option("--verbose", "\u8F93\u51FA\u8BF7\u6C42\u8BE6\u60C5", false).action(async (opts) => {
4936
+ await runPagesWrite("add", opts);
4937
+ });
4938
+ pages.command("update").description("\u7528 HTML \u8986\u76D6\u5DF2\u6709\u9875\u9762\uFF08\u8D70 save-visual-edit\uFF0C\u4F1A\u76F4\u63A5\u53D1\u5E03\uFF09").option("-s, --site <guidOrName>", "\u7AD9\u70B9 guid \u6216\u540D\u79F0").option("--url <url>", "\u76F4\u63A5\u6307\u5B9A\u7AD9\u70B9\u5730\u5740").requiredOption("--id <id>", "\u9875\u9762 ID").option("-t, --title <title>", "\u65B0\u6807\u9898\uFF08\u53EF\u7701\u7565\uFF09").option("-c, --content <html>", "HTML \u6B63\u6587").option("--content-file <path>", "\u4ECE\u6587\u4EF6\u8BFB\u53D6 HTML \u6B63\u6587").option("--css <css>", "\u9644\u52A0 CSS").option("--css-file <path>", "\u4ECE\u6587\u4EF6\u8BFB\u53D6 CSS").option("--js <js>", "\u9644\u52A0 JS").option("--js-file <path>", "\u4ECE\u6587\u4EF6\u8BFB\u53D6 JS").option("--verbose", "\u8F93\u51FA\u8BF7\u6C42\u8BE6\u60C5", false).action(async (opts) => {
4939
+ await runPagesWrite("update", opts);
4940
+ });
4941
+ pages.command("get").description("\u67E5\u770B\u5355\u4E2A\u9875\u9762\u7684\u5143\u6570\u636E").option("-s, --site <guidOrName>", "\u7AD9\u70B9 guid \u6216\u540D\u79F0").option("--url <url>", "\u76F4\u63A5\u6307\u5B9A\u7AD9\u70B9\u5730\u5740").requiredOption("--id <id>", "\u9875\u9762 ID").option("--json", "\u8F93\u51FA JSON", false).option("--verbose", "\u8F93\u51FA\u8BF7\u6C42\u8BE6\u60C5", false).action(async (opts) => {
4942
+ await runPagesGet(opts);
4943
+ });
4944
+ pages.command("meta").description("\u6539\u9875\u9762 slug / \u72B6\u6001 / \u7236\u9875 / \u7279\u8272\u56FE\uFF08\u4E0D\u6539 Zion \u6B63\u6587\uFF09").option("-s, --site <guidOrName>", "\u7AD9\u70B9 guid \u6216\u540D\u79F0").option("--url <url>", "\u76F4\u63A5\u6307\u5B9A\u7AD9\u70B9\u5730\u5740").requiredOption("--id <id>", "\u9875\u9762 ID").option("-t, --title <title>", "\u6807\u9898").option("--slug <slug>", "\u522B\u540D").option("--status <status>", "publish / draft / private / pending").option("--parent <id>", "\u7236\u9875\u9762 ID\uFF0C0 \u8868\u793A\u53D6\u6D88").option("--featured-media <id>", "\u7279\u8272\u56FE\u5A92\u4F53 ID").option("--verbose", "\u8F93\u51FA\u8BF7\u6C42\u8BE6\u60C5", false).action(async (opts) => {
4945
+ await runPagesMeta(opts);
4946
+ });
4947
+ pages.command("trash").description("\u9875\u9762\u8FDB\u56DE\u6536\u7AD9\uFF1B\u52A0 --force \u6C38\u4E45\u5220\u9664").option("-s, --site <guidOrName>", "\u7AD9\u70B9 guid \u6216\u540D\u79F0").option("--url <url>", "\u76F4\u63A5\u6307\u5B9A\u7AD9\u70B9\u5730\u5740").requiredOption("--id <id>", "\u9875\u9762 ID").option("--force", "\u6C38\u4E45\u5220\u9664", false).option("--verbose", "\u8F93\u51FA\u8BF7\u6C42\u8BE6\u60C5", false).action(async (opts) => {
4948
+ await runPagesTrash(opts);
4949
+ });
4950
+ }
4951
+
4952
+ // src/commands/plugins.ts
4953
+ import { readFileSync as readFileSync7, existsSync as existsSync3 } from "fs";
4954
+ import { basename as basename2, resolve as resolve2 } from "path";
4955
+
4956
+ // src/utils/wp-plugin-catalog.ts
4957
+ import * as http2 from "http";
4958
+ import * as https2 from "https";
4959
+ function trimSlash(url) {
4960
+ return url.replace(/\/+$/, "");
4961
+ }
4962
+ function pluginApiBases(config) {
4963
+ const seen = /* @__PURE__ */ new Set();
4964
+ const out = [];
4965
+ for (const raw of [config.csoPluginApiBaseUrl, config.csoBaseUrl]) {
4966
+ const base = trimSlash(raw || "");
4967
+ if (!base || seen.has(base)) continue;
4968
+ seen.add(base);
4969
+ out.push(base);
4970
+ }
4971
+ return out;
4972
+ }
4973
+ function isNetworkish(err) {
4974
+ const msg = err.message || "";
4975
+ return /fetch failed|ENOTFOUND|ECONNREFUSED|ETIMEDOUT|ECONNRESET|EPROTO|TLS|socket disconnected|certificate|HTTP 5\d\d/i.test(
4976
+ msg
4977
+ );
4978
+ }
4979
+ function compareVersion(a, b) {
4980
+ const pa = a.split(".").map((p) => Number(p) || 0);
4981
+ const pb = b.split(".").map((p) => Number(p) || 0);
4982
+ const n = Math.max(pa.length, pb.length);
4983
+ for (let i = 0; i < n; i++) {
4984
+ const da = pa[i] ?? 0;
4985
+ const db = pb[i] ?? 0;
4986
+ if (da !== db) return da - db;
4987
+ }
4988
+ return 0;
4989
+ }
4990
+ function versionFromPath(path7, filename) {
4991
+ const parts = path7.replace(/\\/g, "/").split("/").filter(Boolean);
4992
+ if (parts.length >= 2) return parts[1];
4993
+ const m = filename.match(/\.((?:\d+\.)*\d+)\.zip$/i);
4994
+ return m?.[1] ?? "";
4995
+ }
4996
+ function collectZips(nodes, out = []) {
4997
+ for (const node of nodes || []) {
4998
+ if (!node.isDirectory && /\.zip$/i.test(node.name || "") && node.url) {
4999
+ out.push(node);
5000
+ }
5001
+ if (node.children?.length) collectZips(node.children, out);
5002
+ }
5003
+ return out;
5004
+ }
5005
+ function flattenOfficialPlugins(items) {
5006
+ const best = /* @__PURE__ */ new Map();
5007
+ for (const zip of collectZips(items)) {
5008
+ const path7 = (zip.path || "").replace(/\\/g, "/");
5009
+ const filename = zip.name || path7.split("/").pop() || "";
5010
+ const slug = path7.split("/").filter(Boolean)[0] || filename.replace(/\.zip$/i, "");
5011
+ if (!slug) continue;
5012
+ const candidate = {
5013
+ slug,
5014
+ version: versionFromPath(path7, filename),
5015
+ filename,
5016
+ path: path7,
5017
+ size: Number(zip.size) || 0,
5018
+ url: zip.url || "",
5019
+ lastModified: zip.lastModified || ""
5020
+ };
5021
+ const prev = best.get(slug);
5022
+ if (!prev || compareVersion(candidate.version, prev.version) > 0) {
5023
+ best.set(slug, candidate);
5024
+ }
5025
+ }
5026
+ return [...best.values()].sort((a, b) => a.slug.localeCompare(b.slug));
5027
+ }
5028
+ async function fetchOfficialPluginList(config, opts = {}) {
5029
+ const params = new URLSearchParams();
5030
+ if (opts.prefix?.trim()) params.set("prefix", opts.prefix.trim());
5031
+ const qs = params.toString();
5032
+ const path7 = `/cso/v1/wp-plugin/list${qs ? `?${qs}` : ""}`;
5033
+ const bases = pluginApiBases(config);
5034
+ let lastErr;
5035
+ for (let i = 0; i < bases.length; i++) {
5036
+ const url = `${bases[i]}${path7}`;
5037
+ try {
5038
+ const raw = await apiFetch2(url, config, {}, opts.verbose);
5039
+ const code = raw.code;
5040
+ if (code !== void 0 && code !== 1) {
5041
+ throw new Error(raw.message || `\u76EE\u5F55\u63A5\u53E3\u8FD4\u56DE code=${code}`);
5042
+ }
5043
+ const data = raw.data || {};
5044
+ return {
5045
+ container: data.container || "wp-plugins",
5046
+ items: flattenOfficialPlugins(data.items)
5047
+ };
5048
+ } catch (e) {
5049
+ lastErr = e;
5050
+ if (i < bases.length - 1 && isNetworkish(lastErr)) {
5051
+ console.log(`\u76EE\u5F55\u63A5\u53E3 ${bases[i]} \u4E0D\u53EF\u8FBE\uFF0C\u6539\u8D70 ${bases[i + 1]} \u2026`);
5052
+ continue;
5053
+ }
5054
+ throw lastErr;
5055
+ }
5056
+ }
5057
+ throw lastErr || new Error("\u76EE\u5F55\u63A5\u53E3\u4E0D\u53EF\u7528");
5058
+ }
5059
+ async function findOfficialPlugin(config, slugOrPlugin, verbose = false) {
5060
+ const needle = slugOrPlugin.replace(/\\/g, "/").replace(/\.php$/i, "").toLowerCase();
5061
+ if (!needle) return null;
5062
+ const { items } = await fetchOfficialPluginList(config, { verbose });
5063
+ return items.find((p) => p.slug.toLowerCase() === needle) || items.find((p) => needle === p.slug.toLowerCase() || needle.startsWith(`${p.slug.toLowerCase()}/`)) || null;
5064
+ }
5065
+ function downloadOfficialZip(url) {
5066
+ return new Promise((resolve4, reject) => {
5067
+ let parsed;
5068
+ try {
5069
+ parsed = new URL(url);
5070
+ } catch {
5071
+ reject(new Error("\u76EE\u5F55\u5305\u5730\u5740\u4E0D\u5408\u6CD5"));
5072
+ return;
5073
+ }
5074
+ if (parsed.protocol !== "https:" && parsed.protocol !== "http:") {
5075
+ reject(new Error("\u76EE\u5F55\u5305\u5730\u5740\u5FC5\u987B\u662F http(s)"));
5076
+ return;
5077
+ }
5078
+ const transport = parsed.protocol === "https:" ? https2 : http2;
5079
+ const req = transport.get(url, { timeout: 12e4 }, (res) => {
5080
+ const status = res.statusCode ?? 0;
5081
+ if (status >= 300 && status < 400 && res.headers.location) {
5082
+ res.resume();
5083
+ downloadOfficialZip(res.headers.location).then(resolve4, reject);
5084
+ return;
5085
+ }
5086
+ if (status < 200 || status >= 300) {
5087
+ res.resume();
5088
+ reject(new Error(`\u4E0B\u8F7D\u76EE\u5F55\u5305\u5931\u8D25\uFF1AHTTP ${status}`));
5089
+ return;
5090
+ }
5091
+ const chunks = [];
5092
+ let size = 0;
5093
+ res.on("data", (chunk) => {
5094
+ size += chunk.length;
5095
+ if (size > 40 * 1024 * 1024) {
5096
+ res.destroy();
5097
+ reject(new Error("\u76EE\u5F55\u5305\u8D85\u8FC7 40MB"));
5098
+ return;
5099
+ }
5100
+ chunks.push(chunk);
5101
+ });
5102
+ res.on("end", () => resolve4(Buffer.concat(chunks)));
5103
+ res.on("error", reject);
5104
+ });
5105
+ req.on("timeout", () => {
5106
+ req.destroy();
5107
+ reject(new Error("\u4E0B\u8F7D\u76EE\u5F55\u5305\u8D85\u65F6"));
5108
+ });
5109
+ req.on("error", reject);
5110
+ });
5111
+ }
5112
+
5113
+ // src/commands/zasp.ts
5114
+ import { readFileSync as readFileSync6 } from "fs";
5115
+ var SECRET_KEY = /api_key|password|token|secret|private_key/i;
5116
+ function zaspUrl(base, path7) {
5117
+ const suffix = path7.startsWith("/") ? path7 : `/${path7}`;
5118
+ return `${base}/wp-json/zasp-b2b/v2${suffix}`;
5119
+ }
5120
+ function explainZaspError(err) {
5121
+ const msg = err instanceof Error ? err.message : String(err);
5122
+ if (/404|rest_no_route|not found/i.test(msg)) {
5123
+ return `${msg}
5124
+ \u7AD9\u70B9\u53EF\u80FD\u6CA1\u88C5 zasp-smart-recommender\uFF0C\u6216\u7248\u672C\u592A\u65E7\u3001\u6CA1\u6709\u7BA1\u7406 REST\u3002
5125
+ \u5148 \`plugins list\`\uFF0C\u518D \`plugins catalog\` / \`install --slug zasp-smart-recommender\`\uFF0C
5126
+ \u6216 \`update --plugin zasp-smart-recommender/zasp-smart-recommender\``;
5127
+ }
5128
+ return msg;
5129
+ }
5130
+ function redactSecrets(value) {
5131
+ if (Array.isArray(value)) return value.map(redactSecrets);
5132
+ if (value && typeof value === "object") {
5133
+ const out = {};
5134
+ for (const [key, nested] of Object.entries(value)) {
5135
+ if (SECRET_KEY.test(key) && typeof nested === "string" && nested) {
5136
+ out[key] = "***";
5137
+ } else {
5138
+ out[key] = redactSecrets(nested);
5139
+ }
5140
+ }
5141
+ return out;
5142
+ }
5143
+ return value;
5144
+ }
5145
+ function printJson(data) {
5146
+ console.log(JSON.stringify(redactSecrets(data), null, 2));
5147
+ }
5148
+ function collectPair(value, acc) {
5149
+ acc.push(value);
5150
+ return acc;
5151
+ }
5152
+ function coerceSetValue(raw) {
5153
+ if (raw === "true") return true;
5154
+ if (raw === "false") return false;
5155
+ if (raw === "null") return null;
5156
+ if (/^-?\d+$/.test(raw)) return Number(raw);
5157
+ if (/^-?\d+\.\d+$/.test(raw)) return Number(raw);
5158
+ return raw;
5159
+ }
5160
+ function parseSetPairs(pairs) {
5161
+ const body = {};
5162
+ for (const raw of pairs ?? []) {
5163
+ const eq = raw.indexOf("=");
5164
+ if (eq <= 0) {
5165
+ throw new Error(`--set \u683C\u5F0F\u5E94\u4E3A key=value\uFF0C\u6536\u5230\uFF1A${raw}`);
5166
+ }
5167
+ const key = raw.slice(0, eq).trim();
5168
+ if (!key) {
5169
+ throw new Error(`--set \u7F3A\u5C11\u5B57\u6BB5\u540D\uFF1A${raw}`);
5170
+ }
5171
+ body[key] = coerceSetValue(raw.slice(eq + 1));
5172
+ }
5173
+ return body;
5174
+ }
5175
+ function parseBodyJson(inline, filePath) {
5176
+ const raw = filePath ? readFileSync6(filePath, "utf8") : inline;
5177
+ if (!raw?.trim()) return {};
5178
+ const parsed = JSON.parse(raw);
5179
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
5180
+ throw new Error("--body / --body-file \u5FC5\u987B\u662F JSON \u5BF9\u8C61");
5181
+ }
5182
+ return parsed;
5183
+ }
5184
+ async function zaspFetch(opts, path7, init = {}) {
5185
+ const target = await resolveTarget(opts);
5186
+ try {
5187
+ const data = await apiFetch2(zaspUrl(target.base, path7), target.config, init, opts.verbose);
5188
+ return { data, siteName: target.site.name, base: target.base };
5189
+ } catch (e) {
5190
+ throw new Error(explainZaspError(e));
5191
+ }
5192
+ }
5193
+ async function runZaspSettings(opts) {
5194
+ let pack;
5195
+ try {
5196
+ pack = await zaspFetch(opts, "/settings");
5197
+ } catch (e) {
5198
+ console.error(`
5199
+ \u274C \u8BFB\u53D6\u914D\u7F6E\u5931\u8D25\uFF1A${e.message}
5200
+ `);
5201
+ process.exit(1);
5202
+ return;
5203
+ }
5204
+ if (opts.json) {
5205
+ printJson({ site: pack.siteName, url: pack.base, ...pack.data });
5206
+ return;
5207
+ }
5208
+ const settings = pack.data.settings ?? {};
5209
+ const runtime = pack.data.runtime ?? {};
5210
+ console.log(`
5211
+ ${pack.siteName} AI \u63A8\u8350\u914D\u7F6E (${pack.base})
5212
+ `);
5213
+ printCliTable(
5214
+ [
5215
+ { k: "ai_provider", v: String(settings.ai_provider ?? "-") },
5216
+ { k: "vector_provider", v: String(settings.vector_provider ?? "-") },
5217
+ { k: "related_enabled", v: String(settings.related_enabled ?? "-") },
5218
+ { k: "related_limit", v: String(settings.related_limit ?? "-") },
5219
+ { k: "auto_sync", v: String(settings.auto_sync ?? "-") },
5220
+ { k: "has_ai_api_key", v: String(settings.has_ai_api_key ?? "-") },
5221
+ { k: "has_vector_api_key", v: String(settings.has_vector_api_key ?? "-") },
5222
+ { k: "has_vector_embed_api_key", v: String(settings.has_vector_embed_api_key ?? "-") },
5223
+ { k: "runtime.ai_configured", v: String(runtime.ai_configured ?? "-") },
5224
+ { k: "runtime.vector_configured", v: String(runtime.vector_configured ?? "-") },
5225
+ { k: "runtime.vector_site_id", v: String(runtime.vector_site_id ?? "-") },
5226
+ { k: "runtime.retrieval_mode", v: String(runtime.retrieval_mode ?? "-") }
5227
+ ],
5228
+ [
5229
+ { key: "k", header: "\u5B57\u6BB5" },
5230
+ { key: "v", header: "\u503C" }
5231
+ ]
5232
+ );
5233
+ const sync = runtime.sync_state;
5234
+ if (sync?.error) {
5235
+ console.log(`
5236
+ \u4E0A\u6B21\u540C\u6B65\u5931\u8D25\uFF1A${String(sync.error)}`);
5237
+ }
5238
+ console.log("\n\u5B8C\u6574\u5B57\u6BB5\u7528 --json\uFF1B\u5B57\u6BB5\u5B57\u5178\u7528 `zasp schema`\u3002\n");
5239
+ }
5240
+ async function runZaspSchema(opts) {
5241
+ let pack;
5242
+ try {
5243
+ pack = await zaspFetch(opts, "/settings/schema");
5244
+ } catch (e) {
5245
+ console.error(`
5246
+ \u274C \u8BFB\u53D6\u5B57\u6BB5\u5B57\u5178\u5931\u8D25\uFF1A${e.message}
5247
+ `);
5248
+ process.exit(1);
5249
+ return;
5250
+ }
5251
+ if (opts.json) {
5252
+ printJson(pack.data);
5253
+ return;
5254
+ }
5255
+ console.log(`
5256
+ ${pack.siteName} \u5B57\u6BB5\u5B57\u5178
5257
+ `);
5258
+ printJson(pack.data);
5259
+ console.log();
5260
+ }
5261
+ async function runZaspSet(opts) {
5262
+ let patch;
5263
+ try {
5264
+ patch = {
5265
+ ...parseBodyJson(opts.body, opts.bodyFile),
5266
+ ...parseSetPairs(opts.set)
5267
+ };
5268
+ } catch (e) {
5269
+ console.error(`
5270
+ \u274C ${e.message}
5271
+ `);
5272
+ process.exit(1);
5273
+ return;
5274
+ }
5275
+ if (opts.clearAiKey) patch.clear_ai_key = true;
5276
+ if (opts.clearVectorKey) patch.clear_vector_key = true;
5277
+ if (opts.clearVectorEmbedKey) patch.clear_vector_embed_key = true;
5278
+ if (Object.keys(patch).length === 0) {
5279
+ console.error(`
5280
+ \u274C \u6CA1\u6709\u8981\u6539\u7684\u5B57\u6BB5\u3002\u7528 --set key=value\uFF0C\u6216 --body '{"related_enabled":1}'
5281
+ `);
5282
+ process.exit(1);
5283
+ }
5284
+ let pack;
5285
+ try {
5286
+ pack = await zaspFetch(opts, "/settings", {
5287
+ method: "PATCH",
5288
+ body: JSON.stringify(patch)
5289
+ });
5290
+ } catch (e) {
5291
+ console.error(`
5292
+ \u274C \u66F4\u65B0\u914D\u7F6E\u5931\u8D25\uFF1A${e.message}
5293
+ `);
5294
+ process.exit(1);
5295
+ return;
5296
+ }
5297
+ const changed = Object.keys(patch).filter((k) => !SECRET_KEY.test(k) && !k.startsWith("clear_"));
5298
+ console.log(`
5299
+ \u2705 \u5DF2\u66F4\u65B0 ${pack.siteName} \u7684 AI \u63A8\u8350\u914D\u7F6E`);
5300
+ if (changed.length) console.log(` \u5B57\u6BB5\uFF1A${changed.join(", ")}`);
5301
+ if (opts.clearAiKey || opts.clearVectorKey || opts.clearVectorEmbedKey) {
5302
+ console.log(" \u5DF2\u6309\u5F00\u5173\u6E05\u7A7A\u5BF9\u5E94\u5BC6\u94A5\uFF08\u660E\u6587\u4E0D\u4F1A\u56DE\u663E\uFF09");
5303
+ }
5304
+ console.log(` \u7AD9\u70B9\uFF1A${pack.base}
5305
+ `);
5306
+ if (opts.json) {
5307
+ printJson(pack.data);
5308
+ return;
5309
+ }
5310
+ const settings = pack.data.settings ?? {};
5311
+ const runtime = pack.data.runtime ?? {};
5312
+ console.log(
5313
+ ` ai_provider=${String(settings.ai_provider ?? "-")} vector_provider=${String(settings.vector_provider ?? "-")} ai_configured=${String(runtime.ai_configured ?? "-")} vector_configured=${String(runtime.vector_configured ?? "-")}`
5314
+ );
5315
+ console.log(" \u6539\u4E86\u5411\u91CF\u540E\u7AEF\u7684\u8BDD\uFF0C\u63A5\u7740\u8DD1 `zasp sync`\uFF1B\u53EA\u6539\u76F8\u5173\u63A8\u8350 / custom AI \u4E00\u822C\u4E0D\u7528\u3002\n");
5316
+ }
5317
+ async function runZaspSync(opts) {
5318
+ let pack;
5319
+ try {
5320
+ pack = await zaspFetch(opts, "/sync", { method: "POST" });
5321
+ } catch (e) {
5322
+ console.error(`
5323
+ \u274C \u540C\u6B65\u5931\u8D25\uFF1A${e.message}
5324
+ `);
5325
+ process.exit(1);
5326
+ return;
5327
+ }
5328
+ if (opts.json) {
5329
+ printJson(pack.data);
5330
+ return;
5331
+ }
5332
+ if (pack.data.ok) {
5333
+ console.log(`
5334
+ \u2705 ${pack.siteName} \u5168\u91CF\u540C\u6B65\u5B8C\u6210\uFF0C\u5199\u5165 ${pack.data.count ?? 0} \u6761
5335
+ `);
5336
+ return;
5337
+ }
5338
+ console.error(`
5339
+ \u274C \u540C\u6B65\u672A\u5B8C\u6210\uFF1A${pack.data.error || "\u672A\u77E5\u9519\u8BEF"}`);
5340
+ console.error(" \u5148\u4FEE Collection / key / \u7EF4\u5EA6\uFF0C\u518D `zasp set`\uFF0C\u518D `zasp sync`\n");
5341
+ process.exit(1);
5342
+ }
5343
+ async function runZaspStatus(opts) {
5344
+ let pack;
5345
+ try {
5346
+ pack = await zaspFetch(opts, "/status");
5347
+ } catch (e) {
5348
+ console.error(`
5349
+ \u274C \u8BFB\u53D6\u72B6\u6001\u5931\u8D25\uFF1A${e.message}
5350
+ `);
5351
+ process.exit(1);
5352
+ return;
5353
+ }
5354
+ if (opts.json) {
5355
+ printJson({ site: pack.siteName, url: pack.base, ...pack.data });
5356
+ return;
5357
+ }
5358
+ const counts = pack.data.source_counts ?? {};
5359
+ console.log(`
5360
+ ${pack.siteName} AI \u63A8\u8350\u72B6\u6001 (${pack.base})
5361
+ `);
5362
+ printCliTable(
5363
+ [
5364
+ { k: "ready", v: String(pack.data.ready ?? pack.data.status ?? "-") },
5365
+ { k: "ai_configured", v: String(pack.data.ai_configured ?? "-") },
5366
+ { k: "vector_configured", v: String(pack.data.vector_configured ?? "-") },
5367
+ { k: "vector_site_id", v: String(pack.data.vector_site_id ?? "-") },
5368
+ { k: "mode", v: String(pack.data.mode ?? "-") },
5369
+ { k: "version", v: String(pack.data.version ?? "-") },
5370
+ { k: "documents", v: String(counts.documents ?? "-") },
5371
+ { k: "products", v: String(counts.products ?? "-") }
5372
+ ],
5373
+ [
5374
+ { key: "k", header: "\u5B57\u6BB5" },
5375
+ { key: "v", header: "\u503C" }
5376
+ ]
5377
+ );
5378
+ console.log();
5379
+ }
5380
+ async function runZaspDiagnostics(opts) {
5381
+ let pack;
5382
+ try {
5383
+ pack = await zaspFetch(opts, "/diagnostics");
5384
+ } catch (e) {
5385
+ console.error(`
5386
+ \u274C \u8BCA\u65AD\u5931\u8D25\uFF1A${e.message}
5387
+ `);
5388
+ process.exit(1);
5389
+ return;
5390
+ }
5391
+ console.log(`
5392
+ ${pack.siteName} \u8BCA\u65AD
5393
+ `);
5394
+ printJson(pack.data);
5395
+ console.log();
5396
+ }
5397
+ async function runZaspRecommend(opts) {
5398
+ const placement = opts.placement?.trim() || "assistant";
5399
+ const limit = Number(opts.limit ?? 5);
5400
+ const pageId = Number(opts.pageId ?? 0);
5401
+ if (!Number.isFinite(limit) || limit < 1) {
5402
+ console.error("\n\u274C --limit \u5FC5\u987B\u662F\u6B63\u6574\u6570\n");
5403
+ process.exit(1);
5404
+ }
5405
+ if (placement === "related_products" && (!Number.isFinite(pageId) || pageId <= 0)) {
5406
+ console.error("\n\u274C \u9875\u9762\u76F8\u5173\u63A8\u8350\u5FC5\u987B\u63D0\u4F9B\u6709\u6548\u5546\u54C1 --page-id\n");
5407
+ process.exit(1);
5408
+ }
5409
+ const body = {
5410
+ query: opts.query?.trim() ?? "",
5411
+ placement,
5412
+ limit,
5413
+ page_id: Number.isFinite(pageId) ? pageId : 0,
5414
+ constraints: {},
5415
+ session: { seen: [], interest: {} }
5416
+ };
5417
+ let pack;
5418
+ try {
5419
+ pack = await zaspFetch(opts, "/recommend", {
5420
+ method: "POST",
5421
+ body: JSON.stringify(body)
5422
+ });
5423
+ } catch (e) {
5424
+ console.error(`
5425
+ \u274C \u8BD5\u63A8\u5931\u8D25\uFF1A${e.message}
5426
+ `);
5427
+ process.exit(1);
5428
+ return;
5429
+ }
5430
+ if (opts.json) {
5431
+ printJson(pack.data);
5432
+ return;
5433
+ }
5434
+ const items = pack.data.items ?? [];
5435
+ console.log(`
5436
+ ${pack.siteName} \u8BD5\u63A8 status=${pack.data.status ?? "-"} mode=${pack.data.mode ?? "-"}`);
5437
+ if (items.length === 0) {
5438
+ console.log("\u6CA1\u6709\u5339\u914D\u7ED3\u679C\u3002\n");
5439
+ return;
5440
+ }
5441
+ printCliTable(
5442
+ items.map((item) => ({
5443
+ id: item.id != null ? String(item.id) : "-",
5444
+ title: item.title || "-",
5445
+ type: item.type || "-",
5446
+ score: item.score != null ? String(item.score) : "-",
5447
+ url: item.url || "-"
5448
+ })),
5449
+ [
5450
+ { key: "id", header: "id" },
5451
+ { key: "title", header: "\u6807\u9898" },
5452
+ { key: "type", header: "\u7C7B\u578B" },
5453
+ { key: "score", header: "\u5206" },
5454
+ { key: "url", header: "\u94FE\u63A5" }
5455
+ ]
5456
+ );
5457
+ console.log();
5458
+ }
5459
+ function hintZaspIfNeeded(pluginOrSlug) {
5460
+ if (!pluginOrSlug.toLowerCase().includes("zasp-smart-recommender")) return;
5461
+ console.log(" \u63A5\u4E0B\u6765\u7528 `siluzan-website zasp settings / set / sync` \u914D\u7F6E AI \u63A8\u8350\uFF08\u89C1 references/zasp-recommender.md\uFF09\n");
5462
+ }
5463
+ function register11(program2) {
5464
+ const zasp = program2.command("zasp").description("zasp-smart-recommender\uFF08AI \u63A8\u8350\uFF09\u914D\u7F6E\u4E0E\u9A8C\u6536\uFF0C\u8D70\u7AD9\u70B9 /wp-json/zasp-b2b/v2");
5465
+ zasp.command("settings").description("\u67E5\u770B\u5F53\u524D AI \u63A8\u8350\u914D\u7F6E\uFF08GET /settings\uFF09").option("-s, --site <guidOrName>", "\u7AD9\u70B9 guid \u6216\u540D\u79F0").option("--url <url>", "\u76F4\u63A5\u6307\u5B9A\u7AD9\u70B9\u5730\u5740").option("--json", "\u8F93\u51FA\u5B8C\u6574 JSON", false).option("--verbose", "\u8F93\u51FA\u8BF7\u6C42\u8BE6\u60C5", false).action(async (opts) => {
5466
+ await runZaspSettings(opts);
5467
+ });
5468
+ zasp.command("schema").description("\u67E5\u770B\u53EF\u5199\u5B57\u6BB5\u5B57\u5178\uFF08GET /settings/schema\uFF09").option("-s, --site <guidOrName>", "\u7AD9\u70B9 guid \u6216\u540D\u79F0").option("--url <url>", "\u76F4\u63A5\u6307\u5B9A\u7AD9\u70B9\u5730\u5740").option("--json", "\u8F93\u51FA JSON", false).option("--verbose", "\u8F93\u51FA\u8BF7\u6C42\u8BE6\u60C5", false).action(async (opts) => {
5469
+ await runZaspSchema(opts);
5470
+ });
5471
+ zasp.command("set").description("\u53EA\u6539\u8981\u6539\u7684\u5B57\u6BB5\uFF08PATCH /settings\uFF09").option("-s, --site <guidOrName>", "\u7AD9\u70B9 guid \u6216\u540D\u79F0").option("--url <url>", "\u76F4\u63A5\u6307\u5B9A\u7AD9\u70B9\u5730\u5740").option("--body <json>", "PATCH JSON \u5BF9\u8C61\uFF0C\u53EA\u542B\u8981\u6539\u7684\u5B57\u6BB5").option("--body-file <file>", "\u4ECE\u6587\u4EF6\u8BFB PATCH JSON").option("--set <key=value>", "\u5355\u4E2A\u5B57\u6BB5\uFF0C\u53EF\u91CD\u590D", collectPair, []).option("--clear-ai-key", "\u6E05\u7A7A\u5DF2\u4FDD\u5B58\u7684 AI Key", false).option("--clear-vector-key", "\u6E05\u7A7A\u5DF2\u4FDD\u5B58\u7684\u5411\u91CF\u5E93 Key", false).option("--clear-vector-embed-key", "\u6E05\u7A7A\u5DF2\u4FDD\u5B58\u7684 Embedding Key", false).option("--json", "\u8F93\u51FA\u66F4\u65B0\u540E\u7684\u5B8C\u6574 JSON", false).option("--verbose", "\u8F93\u51FA\u8BF7\u6C42\u8BE6\u60C5", false).action(async (opts) => {
5472
+ await runZaspSet(opts);
5473
+ });
5474
+ zasp.command("sync").description("\u5168\u91CF\u540C\u6B65\u5546\u54C1\u5230\u5411\u91CF\u5E93\uFF08POST /sync\uFF09").option("-s, --site <guidOrName>", "\u7AD9\u70B9 guid \u6216\u540D\u79F0").option("--url <url>", "\u76F4\u63A5\u6307\u5B9A\u7AD9\u70B9\u5730\u5740").option("--json", "\u8F93\u51FA JSON", false).option("--verbose", "\u8F93\u51FA\u8BF7\u6C42\u8BE6\u60C5", false).action(async (opts) => {
5475
+ await runZaspSync(opts);
5476
+ });
5477
+ zasp.command("status").description("\u516C\u5F00\u9A8C\u6536\uFF1Aready / \u662F\u5426\u914D\u597D\uFF08GET /status\uFF09").option("-s, --site <guidOrName>", "\u7AD9\u70B9 guid \u6216\u540D\u79F0").option("--url <url>", "\u76F4\u63A5\u6307\u5B9A\u7AD9\u70B9\u5730\u5740").option("--json", "\u8F93\u51FA JSON", false).option("--verbose", "\u8F93\u51FA\u8BF7\u6C42\u8BE6\u60C5", false).action(async (opts) => {
5478
+ await runZaspStatus(opts);
5479
+ });
5480
+ zasp.command("diagnostics").description("\u7BA1\u7406\u5458\u6DF1\u67E5\uFF08GET /diagnostics\uFF09").option("-s, --site <guidOrName>", "\u7AD9\u70B9 guid \u6216\u540D\u79F0").option("--url <url>", "\u76F4\u63A5\u6307\u5B9A\u7AD9\u70B9\u5730\u5740").option("--json", "\u8F93\u51FA JSON", false).option("--verbose", "\u8F93\u51FA\u8BF7\u6C42\u8BE6\u60C5", false).action(async (opts) => {
5481
+ await runZaspDiagnostics(opts);
5482
+ });
5483
+ zasp.command("recommend").description("\u524D\u53F0\u8BD5\u63A8\u4E00\u6761\uFF08POST /recommend\uFF09").option("-s, --site <guidOrName>", "\u7AD9\u70B9 guid \u6216\u540D\u79F0").option("--url <url>", "\u76F4\u63A5\u6307\u5B9A\u7AD9\u70B9\u5730\u5740").option("--query <q>", "\u68C0\u7D22\u8BCD\uFF1B\u76F8\u5173\u63A8\u8350\u53EF\u7559\u7A7A").option("--placement <p>", "assistant \u6216 related_products", "assistant").option("--limit <n>", "\u6761\u6570", "5").option("--page-id <id>", "related_products \u65F6\u7684\u5546\u54C1\u9875 ID", "0").option("--json", "\u8F93\u51FA JSON", false).option("--verbose", "\u8F93\u51FA\u8BF7\u6C42\u8BE6\u60C5", false).action(async (opts) => {
5484
+ await runZaspRecommend(opts);
5485
+ });
5486
+ }
5487
+
5488
+ // src/commands/plugins.ts
5489
+ var MAX_ZIP_BYTES = 40 * 1024 * 1024;
5490
+ var PROTECTED_PLUGIN_PREFIXES = ["siluzan-helper-plugin", "wp-oauth2"];
5491
+ function isProtectedPlugin(plugin) {
5492
+ const key = pluginKey(plugin);
5493
+ return PROTECTED_PLUGIN_PREFIXES.some((prefix) => key === prefix || key.startsWith(`${prefix}/`));
5494
+ }
5495
+ function wpPluginRestPath(plugin) {
5496
+ return plugin.replace(/\\/g, "/").split("/").filter(Boolean).map((part) => encodeURIComponent(part)).join("/");
5497
+ }
5498
+ function pluginName(item) {
5499
+ if (typeof item.name === "string") return item.name;
5500
+ return item.name?.raw || item.name?.rendered || item.plugin || "";
5501
+ }
5502
+ function pluginKey(value) {
5503
+ return value.replace(/\\/g, "/").replace(/\.php$/i, "").toLowerCase();
5504
+ }
5505
+ function formatBytes(n) {
5506
+ if (!n) return "-";
5507
+ if (n < 1024) return `${n} B`;
5508
+ if (n < 1024 * 1024) return `${(n / 1024).toFixed(1)} KB`;
5509
+ return `${(n / 1024 / 1024).toFixed(1)} MB`;
5510
+ }
5511
+ async function resolveTarget2(opts) {
5512
+ const config = loadConfig();
5513
+ const site = await resolveSite(config, opts);
5514
+ return { config, site, base: trimTrailingSlash(site.url) };
5515
+ }
5516
+ function isRouteMissing(err) {
5517
+ const msg = err.message || "";
5518
+ return /HTTP 404/.test(msg) && /No route was found|rest_no_route/i.test(msg);
5519
+ }
5520
+ function readZipPayload(zipPath) {
5521
+ const abs = resolve2(zipPath);
5522
+ if (!existsSync3(abs)) {
5523
+ console.error(`
5524
+ \u274C zip \u4E0D\u5B58\u5728\uFF1A${abs}
5525
+ `);
5526
+ process.exit(1);
5527
+ }
5528
+ const buf = readFileSync7(abs);
5529
+ if (buf.length > MAX_ZIP_BYTES) {
5530
+ console.error("\n\u274C zip \u8D85\u8FC7 20MB\uFF0C\u8BF7\u6362\u66F4\u5C0F\u7684\u5305\n");
5531
+ process.exit(1);
5532
+ }
5533
+ return {
5534
+ filename: basename2(abs),
5535
+ zip_base64: buf.toString("base64")
5536
+ };
5537
+ }
5538
+ function printActionResult(result, site, base, okTitle) {
5539
+ if (!result.success) {
5540
+ console.error(`
5541
+ \u274C ${result.message || "\u7AD9\u70B9\u62D2\u7EDD\u4E86\u8FD9\u6B21\u64CD\u4F5C"}`);
5542
+ if (result.code) console.error(` code : ${result.code}`);
5543
+ process.exit(1);
5544
+ }
5545
+ console.log(result.already ? "\n\u2705 \u63D2\u4EF6\u5DF2\u5728\u7AD9\u70B9\u4E0A\uFF08\u5DF2\u542F\u7528\uFF09" : `
5546
+ \u2705 ${okTitle}`);
5547
+ if (result.plugin) console.log(` plugin : ${result.plugin}`);
5548
+ if (result.version) console.log(` \u7248\u672C : ${result.version}`);
5549
+ if (result.zip) console.log(` zip : ${result.zip}`);
5550
+ if (result.message) console.log(` \u8BF4\u660E : ${result.message}`);
5551
+ console.log(` \u7AD9\u70B9 : ${site.name} (${base})
5552
+ `);
5553
+ }
5554
+ async function withHelperBootstrap(opts, target, run) {
5555
+ try {
5556
+ return await run();
5557
+ } catch (e) {
5558
+ const err = e;
5559
+ if (!isRouteMissing(err)) throw err;
5560
+ console.log("\u7AD9\u70B9 helper REST \u4E0D\u53EF\u7528\uFF0C\u5148\u4ECE\u955C\u50CF\u672C\u5730 zip \u5347\u7EA7 helper\u2026");
5561
+ await runUpdateHelper({ ...opts, site: target.site.guid || opts.site, url: target.site.url }, true);
5562
+ return await run();
5563
+ }
5564
+ }
5565
+ async function runPluginsList(opts) {
5566
+ const { config, site, base } = await resolveTarget2(opts);
5567
+ const api = `${base}/wp-json/wp/v2/plugins`;
5568
+ let plugins;
5569
+ try {
5570
+ plugins = await apiFetch2(api, config, {}, opts.verbose);
5571
+ } catch (e) {
5572
+ const msg = e.message || "";
5573
+ console.error(`
5574
+ \u274C \u83B7\u53D6\u5DF2\u88C5\u63D2\u4EF6\u5931\u8D25\uFF1A${msg}`);
5575
+ if (/HTTP 401/.test(msg)) {
5576
+ console.error(" \u7AD9\u70B9 oauth2 \u8FC7\u65E7\u6216\u4E0D\u8BA4 API Key\uFF0C\u9700\u8981\u5148\u505A SiteMan \u955C\u50CF\u5347\u7EA7\u3002\n");
5577
+ }
5578
+ if (opts.exitOnError === false) return;
5579
+ process.exit(1);
5580
+ return;
5581
+ }
5582
+ if (!Array.isArray(plugins)) {
5583
+ console.error("\n\u274C \u7AD9\u70B9\u8FD4\u56DE\u7684\u63D2\u4EF6\u5217\u8868\u683C\u5F0F\u5F02\u5E38\n");
5584
+ if (opts.exitOnError === false) return;
5585
+ process.exit(1);
5586
+ }
5587
+ let official = [];
5588
+ try {
5589
+ official = (await fetchOfficialPluginList(config, { verbose: opts.verbose })).items;
5590
+ } catch {
5591
+ }
5592
+ const officialBySlug = new Map(official.map((item) => [item.slug.toLowerCase(), item]));
5593
+ const rows = plugins.map((p) => {
5594
+ const plugin = p.plugin ?? "";
5595
+ const slug = pluginKey(plugin).split("/")[0];
5596
+ const hit = officialBySlug.get(slug);
5597
+ return {
5598
+ plugin,
5599
+ name: pluginName(p),
5600
+ status: p.status ?? "",
5601
+ version: p.version ?? "",
5602
+ updateSource: hit ? "catalog" : "none",
5603
+ catalogVersion: hit?.version ?? ""
5604
+ };
5605
+ });
5606
+ if (opts.json) {
5607
+ console.log(
5608
+ JSON.stringify(
5609
+ {
5610
+ site: { guid: site.guid, name: site.name, url: site.url },
5611
+ total: rows.length,
5612
+ plugins: rows
5613
+ },
5614
+ null,
5615
+ 2
5616
+ )
5617
+ );
5618
+ return;
5619
+ }
5620
+ if (rows.length === 0) {
5621
+ console.log(`
5622
+ \u7AD9\u70B9 ${site.name} \u672A\u8FD4\u56DE\u63D2\u4EF6\u3002
5623
+ `);
5624
+ return;
5625
+ }
5626
+ const columns = [
5627
+ { key: "plugin", header: "plugin" },
5628
+ { key: "name", header: "\u540D\u79F0" },
5629
+ { key: "status", header: "\u72B6\u6001" },
5630
+ { key: "version", header: "\u7248\u672C" },
5631
+ { key: "updateSource", header: "\u66F4\u65B0\u6E90" },
5632
+ { key: "catalogVersion", header: "\u76EE\u5F55\u7248\u672C" }
5633
+ ];
5634
+ console.log(`
5635
+ ${site.name} \u5DF2\u88C5\u63D2\u4EF6\uFF08${rows.length}\uFF09
5636
+ `);
5637
+ printCliTable(
5638
+ rows.map((r) => ({
5639
+ plugin: r.plugin || "-",
5640
+ name: r.name || "-",
5641
+ status: r.status || "-",
5642
+ version: r.version || "-",
5643
+ updateSource: r.updateSource,
5644
+ catalogVersion: r.catalogVersion || "-"
5645
+ })),
4065
5646
  columns
4066
5647
  );
4067
5648
  console.log();
4068
5649
  }
4069
5650
  async function runPluginsCatalog(opts) {
4070
- const { config, site, base } = await resolveTarget(opts);
4071
- const api = `${base}/wp-json/siluzan-helper/v1/plugins/catalog`;
4072
- let res;
5651
+ const config = loadConfig();
5652
+ let pack;
5653
+ try {
5654
+ pack = await fetchOfficialPluginList(config, { prefix: opts.prefix, verbose: opts.verbose });
5655
+ } catch (e) {
5656
+ console.error(`
5657
+ \u274C \u83B7\u53D6\u63D2\u4EF6\u76EE\u5F55\u5931\u8D25\uFF1A${e.message}
5658
+ `);
5659
+ process.exit(1);
5660
+ return;
5661
+ }
5662
+ const installedBySlug = /* @__PURE__ */ new Map();
5663
+ if (opts.site || opts.url) {
5664
+ try {
5665
+ const target = await resolveTarget2(opts);
5666
+ const plugins = await apiFetch2(
5667
+ `${target.base}/wp-json/wp/v2/plugins`,
5668
+ target.config,
5669
+ {},
5670
+ opts.verbose
5671
+ );
5672
+ if (Array.isArray(plugins)) {
5673
+ for (const p of plugins) {
5674
+ const slug = pluginKey(p.plugin || "").split("/")[0];
5675
+ if (slug) installedBySlug.set(slug, { version: p.version || "", status: p.status || "" });
5676
+ }
5677
+ }
5678
+ } catch {
5679
+ }
5680
+ }
5681
+ const rows = pack.items.map((p) => {
5682
+ const onSite = installedBySlug.get(p.slug.toLowerCase());
5683
+ return {
5684
+ slug: p.slug,
5685
+ version: p.version,
5686
+ size: formatBytes(p.size),
5687
+ installed: onSite ? "yes" : opts.site || opts.url ? "no" : "-",
5688
+ filename: p.filename
5689
+ };
5690
+ });
5691
+ if (opts.json) {
5692
+ console.log(
5693
+ JSON.stringify({ container: pack.container, total: pack.items.length, items: pack.items }, null, 2)
5694
+ );
5695
+ return;
5696
+ }
5697
+ if (rows.length === 0) {
5698
+ console.log("\n\u5B98\u65B9\u63D2\u4EF6\u76EE\u5F55\u4E3A\u7A7A\u3002\n");
5699
+ return;
5700
+ }
5701
+ console.log(`
5702
+ \u5B98\u65B9\u63D2\u4EF6\u76EE\u5F55 ${pack.container}\uFF08${rows.length}\uFF09
5703
+ `);
5704
+ printCliTable(rows, [
5705
+ { key: "slug", header: "slug" },
5706
+ { key: "version", header: "\u76EE\u5F55\u7248\u672C" },
5707
+ { key: "size", header: "\u5927\u5C0F" },
5708
+ { key: "installed", header: "\u672C\u7AD9\u5DF2\u88C5" },
5709
+ { key: "filename", header: "zip" }
5710
+ ]);
5711
+ console.log("\n\u5B89\u88C5\uFF1Asiluzan-website plugins install --site <guid> --slug <slug>\n");
5712
+ }
5713
+ async function installOfficialZip(target, official, verbose = false) {
5714
+ if (official.size > MAX_ZIP_BYTES) {
5715
+ throw new Error(`\u76EE\u5F55\u5305 ${official.filename} \u8D85\u8FC7 40MB`);
5716
+ }
5717
+ console.log(`\u4ECE\u5B98\u65B9\u76EE\u5F55\u4E0B\u8F7D ${official.slug} ${official.version} \u2026`);
5718
+ const buf = await downloadOfficialZip(official.url);
5719
+ if (buf.length > MAX_ZIP_BYTES) {
5720
+ throw new Error(`\u76EE\u5F55\u5305 ${official.filename} \u8D85\u8FC7 40MB`);
5721
+ }
5722
+ return apiFetch2(
5723
+ `${target.base}/wp-json/siluzan-helper/v1/plugins/install-zip`,
5724
+ target.config,
5725
+ {
5726
+ method: "POST",
5727
+ body: JSON.stringify({
5728
+ filename: official.filename,
5729
+ zip_base64: buf.toString("base64")
5730
+ })
5731
+ },
5732
+ verbose
5733
+ );
5734
+ }
5735
+ async function runPluginsInstall(opts) {
5736
+ const slug = opts.slug?.trim() ?? "";
5737
+ const zipPath = opts.zip?.trim() ?? "";
5738
+ if (slug && zipPath || !slug && !zipPath) {
5739
+ console.error("\n\u274C \u76EE\u5F55\u63D2\u4EF6\u7528 --slug\uFF0C\u5916\u90E8\u63D2\u4EF6\u7528 --zip\uFF0C\u4E24\u8005\u53EA\u4F20\u4E00\u4E2A\n");
5740
+ process.exit(1);
5741
+ }
5742
+ const target = await resolveTarget2(opts);
5743
+ const { site, base } = target;
5744
+ let result;
5745
+ try {
5746
+ result = await withHelperBootstrap(opts, target, async () => {
5747
+ if (slug) {
5748
+ const official = await findOfficialPlugin(target.config, slug, opts.verbose);
5749
+ if (official) {
5750
+ return installOfficialZip(target, official, opts.verbose);
5751
+ }
5752
+ return apiFetch2(
5753
+ `${base}/wp-json/siluzan-helper/v1/plugins/install`,
5754
+ target.config,
5755
+ { method: "POST", body: JSON.stringify({ slug }) },
5756
+ opts.verbose
5757
+ );
5758
+ }
5759
+ const zip = readZipPayload(zipPath);
5760
+ return apiFetch2(
5761
+ `${base}/wp-json/siluzan-helper/v1/plugins/install-zip`,
5762
+ target.config,
5763
+ { method: "POST", body: JSON.stringify(zip) },
5764
+ opts.verbose
5765
+ );
5766
+ });
5767
+ } catch (e) {
5768
+ console.error(`
5769
+ \u274C \u5B89\u88C5\u5931\u8D25\uFF1A${e.message}
5770
+ `);
5771
+ process.exit(1);
5772
+ return;
5773
+ }
5774
+ printActionResult(result, site, base, "\u63D2\u4EF6\u5DF2\u5B89\u88C5\u5E76\u542F\u7528");
5775
+ hintZaspIfNeeded(`${result.plugin || ""} ${slug} ${zipPath}`);
5776
+ await runPluginsList({
5777
+ site: site.guid || opts.site,
5778
+ url: site.url,
5779
+ verbose: opts.verbose,
5780
+ exitOnError: false
5781
+ });
5782
+ }
5783
+ async function runPluginsUpdate(opts) {
5784
+ const plugin = opts.plugin?.trim() ?? "";
5785
+ if (!plugin) {
5786
+ console.error("\n\u274C \u8BF7\u63D0\u4F9B --plugin\uFF08\u5148 plugins list \u770B plugin \u5217\uFF09\n");
5787
+ process.exit(1);
5788
+ }
5789
+ const target = await resolveTarget2(opts);
5790
+ const { site, base } = target;
5791
+ const zipPath = opts.zip?.trim() ?? "";
5792
+ const body = { plugin };
5793
+ if (zipPath) {
5794
+ const zip = readZipPayload(zipPath);
5795
+ body.zip_base64 = zip.zip_base64;
5796
+ body.filename = zip.filename;
5797
+ }
5798
+ let result;
5799
+ try {
5800
+ result = await withHelperBootstrap(opts, target, async () => {
5801
+ if (!zipPath) {
5802
+ const official = await findOfficialPlugin(target.config, plugin, opts.verbose);
5803
+ if (official) {
5804
+ return installOfficialZip(target, official, opts.verbose);
5805
+ }
5806
+ }
5807
+ return apiFetch2(
5808
+ `${base}/wp-json/siluzan-helper/v1/plugins/update`,
5809
+ target.config,
5810
+ { method: "POST", body: JSON.stringify(body) },
5811
+ opts.verbose
5812
+ );
5813
+ });
5814
+ } catch (e) {
5815
+ const msg = e.message || "";
5816
+ if (/HTTP 409/.test(msg) && /no_package/i.test(msg)) {
5817
+ console.error(`
5818
+ \u274C ${msg}`);
5819
+ console.error(" \u76EE\u5F55\u548C WordPress.org \u90FD\u6CA1\u6709\u5B89\u88C5\u5305\u3002\u5916\u90E8\u63D2\u4EF6\u8BF7\u5E26 --zip \u518D\u5347\u7EA7\u3002\n");
5820
+ process.exit(1);
5821
+ }
5822
+ console.error(`
5823
+ \u274C \u5347\u7EA7\u5931\u8D25\uFF1A${msg}
5824
+ `);
5825
+ process.exit(1);
5826
+ return;
5827
+ }
5828
+ printActionResult(result, site, base, "\u63D2\u4EF6\u5DF2\u5347\u7EA7");
5829
+ hintZaspIfNeeded(`${result.plugin || ""} ${plugin}`);
5830
+ await runPluginsList({
5831
+ site: site.guid || opts.site,
5832
+ url: site.url,
5833
+ verbose: opts.verbose,
5834
+ exitOnError: false
5835
+ });
5836
+ }
5837
+ async function runHelperStatus(opts) {
5838
+ const { config, site, base } = await resolveTarget2(opts);
5839
+ let status;
5840
+ try {
5841
+ status = await apiFetch2(
5842
+ `${base}/wp-json/wposso/v1/helper/status`,
5843
+ config,
5844
+ {},
5845
+ opts.verbose
5846
+ );
5847
+ } catch (e) {
5848
+ const msg = e.message || "";
5849
+ console.error(`
5850
+ \u274C \u65E0\u6CD5\u8BFB\u53D6 helper \u72B6\u6001\uFF1A${msg}`);
5851
+ if (isRouteMissing(e) || /HTTP 404/.test(msg)) {
5852
+ console.error(" \u7AD9\u70B9 oauth2 \u8FD8\u6CA1\u6709\u5F15\u5BFC\u5347\u7EA7\u63A5\u53E3\uFF0C\u9700\u8981\u5148\u505A SiteMan \u955C\u50CF\u5347\u7EA7\u3002\n");
5853
+ }
5854
+ process.exit(1);
5855
+ return;
5856
+ }
5857
+ if (opts.json) {
5858
+ console.log(JSON.stringify({ site: { guid: site.guid, name: site.name, url: site.url }, ...status }, null, 2));
5859
+ return;
5860
+ }
5861
+ console.log(`
5862
+ ${site.name} helper \u72B6\u6001`);
5863
+ console.log(` \u5DF2\u5B89\u88C5 : ${status.helper_installed ? "yes" : "no"}`);
5864
+ console.log(` \u5DF2\u542F\u7528 : ${status.helper_active ? "yes" : "no"}`);
5865
+ console.log(` \u7248\u672C : ${status.helper_version || "-"}`);
5866
+ console.log(` helper REST: ${status.helper_rest_available ? "yes" : "no"}`);
5867
+ console.log(` \u955C\u50CF zip : ${status.bootstrap_zip || "-"}`);
5868
+ console.log(` \u53EF\u5F15\u5BFC\u5347\u7EA7 : ${status.can_upgrade ? "yes" : "no"}
5869
+ `);
5870
+ }
5871
+ async function runUpdateHelper(opts, fromBootstrap = false) {
5872
+ const { config, site, base } = await resolveTarget2(opts);
5873
+ let result;
5874
+ try {
5875
+ result = await apiFetch2(
5876
+ `${base}/wp-json/wposso/v1/helper/upgrade`,
5877
+ config,
5878
+ { method: "POST", body: JSON.stringify({}) },
5879
+ opts.verbose
5880
+ );
5881
+ } catch (e) {
5882
+ const msg = e.message || "";
5883
+ console.error(`
5884
+ \u274C helper \u5347\u7EA7\u5931\u8D25\uFF1A${msg}`);
5885
+ if (isRouteMissing(e)) {
5886
+ console.error(" \u7AD9\u70B9 oauth2 \u8FD8\u6CA1\u6709\u5F15\u5BFC\u5347\u7EA7\u63A5\u53E3\uFF0C\u9700\u8981\u5148\u505A SiteMan \u955C\u50CF\u5347\u7EA7\u3002");
5887
+ } else if (/HTTP 409/.test(msg)) {
5888
+ console.error(" \u5F53\u524D\u955C\u50CF\u91CC\u6CA1\u6709 siluzan-helper-plugin.1.0.*.zip\u3002");
5889
+ }
5890
+ console.error();
5891
+ process.exit(1);
5892
+ return;
5893
+ }
5894
+ printActionResult(result, site, base, "helper \u5DF2\u4ECE\u955C\u50CF\u672C\u5730 zip \u5347\u7EA7");
5895
+ if (!fromBootstrap) {
5896
+ await runHelperStatus({ site: site.guid || opts.site, url: site.url, verbose: opts.verbose });
5897
+ }
5898
+ }
5899
+ async function findInstalledPlugin(base, config, pluginArg, verbose = false) {
5900
+ const plugins = await apiFetch2(`${base}/wp-json/wp/v2/plugins`, config, {}, verbose);
5901
+ if (!Array.isArray(plugins)) {
5902
+ throw new Error("\u7AD9\u70B9\u8FD4\u56DE\u7684\u63D2\u4EF6\u5217\u8868\u683C\u5F0F\u5F02\u5E38");
5903
+ }
5904
+ const needle = pluginKey(pluginArg);
5905
+ const exact = plugins.find((p) => pluginKey(p.plugin || "") === needle);
5906
+ if (exact?.plugin) return exact;
5907
+ const hits = plugins.filter((p) => {
5908
+ const key = pluginKey(p.plugin || "");
5909
+ return key === needle || key.startsWith(`${needle}/`) || key.endsWith(`/${needle}`);
5910
+ });
5911
+ if (hits.length === 1 && hits[0].plugin) return hits[0];
5912
+ if (hits.length > 1) {
5913
+ const names = hits.map((p) => p.plugin).join("\u3001");
5914
+ throw new Error(`\u300C${pluginArg}\u300D\u5339\u914D\u5230\u591A\u4E2A\u63D2\u4EF6\uFF0C\u8BF7\u6539\u7528\u5B8C\u6574 --plugin\uFF1A${names}`);
5915
+ }
5916
+ throw new Error(`\u7AD9\u70B9\u4E0A\u6CA1\u6709\u63D2\u4EF6\u300C${pluginArg}\u300D\uFF0C\u5148 plugins list \u770B plugin \u5217`);
5917
+ }
5918
+ async function runPluginsUninstall(opts) {
5919
+ const pluginArg = opts.plugin?.trim() ?? "";
5920
+ if (!pluginArg) {
5921
+ console.error("\n\u274C \u8BF7\u63D0\u4F9B --plugin\uFF08\u5148 plugins list \u770B plugin \u5217\uFF09\n");
5922
+ process.exit(1);
5923
+ }
5924
+ if (isProtectedPlugin(pluginArg)) {
5925
+ console.error("\n\u274C \u4E0D\u80FD\u5378\u8F7D siluzan-helper-plugin \u6216 wp-oauth2\uFF0C\u5378\u6389\u540E\u7AD9\u70B9\u65E0\u6CD5\u518D\u7528 Skill \u7BA1\u7406\u3002\n");
5926
+ process.exit(1);
5927
+ }
5928
+ const target = await resolveTarget2(opts);
5929
+ const { site, base } = target;
5930
+ let current;
5931
+ try {
5932
+ current = await findInstalledPlugin(base, target.config, pluginArg, opts.verbose);
5933
+ } catch (e) {
5934
+ console.error(`
5935
+ \u274C ${e.message}
5936
+ `);
5937
+ process.exit(1);
5938
+ return;
5939
+ }
5940
+ const plugin = current.plugin || pluginArg;
5941
+ if (isProtectedPlugin(plugin)) {
5942
+ console.error("\n\u274C \u4E0D\u80FD\u5378\u8F7D siluzan-helper-plugin \u6216 wp-oauth2\uFF0C\u5378\u6389\u540E\u7AD9\u70B9\u65E0\u6CD5\u518D\u7528 Skill \u7BA1\u7406\u3002\n");
5943
+ process.exit(1);
5944
+ }
5945
+ const restPath = `${base}/wp-json/wp/v2/plugins/${wpPluginRestPath(plugin)}`;
5946
+ try {
5947
+ if (current.status === "active") {
5948
+ console.log(`\u5148\u505C\u7528 ${plugin} \u2026`);
5949
+ await apiFetch2(
5950
+ restPath,
5951
+ target.config,
5952
+ { method: "POST", body: JSON.stringify({ status: "inactive" }) },
5953
+ opts.verbose
5954
+ );
5955
+ }
5956
+ await apiFetch2(restPath, target.config, { method: "DELETE" }, opts.verbose);
5957
+ } catch (e) {
5958
+ console.error(`
5959
+ \u274C \u5378\u8F7D\u5931\u8D25\uFF1A${e.message}
5960
+ `);
5961
+ process.exit(1);
5962
+ return;
5963
+ }
5964
+ console.log(`
5965
+ \u2705 \u5DF2\u5378\u8F7D ${plugin}`);
5966
+ console.log(` \u7AD9\u70B9 : ${site.name} (${base})
5967
+ `);
5968
+ await runPluginsList({
5969
+ site: site.guid || opts.site,
5970
+ url: site.url,
5971
+ verbose: opts.verbose,
5972
+ exitOnError: false
5973
+ });
5974
+ }
5975
+ function register12(program2) {
5976
+ const plugins = program2.command("plugins").description("WordPress \u63D2\u4EF6\uFF1A\u5217\u51FA\u3001\u76EE\u5F55\u3001\u5B89\u88C5\u3001\u5347\u7EA7\u3001\u5378\u8F7D");
5977
+ plugins.command("list").description("\u5217\u51FA\u7AD9\u70B9\u5DF2\u5B89\u88C5\u7684\u5168\u90E8\u63D2\u4EF6").option("-s, --site <guidOrName>", "\u7AD9\u70B9 guid \u6216\u540D\u79F0").option("--url <url>", "\u76F4\u63A5\u6307\u5B9A\u7AD9\u70B9\u5730\u5740").option("--json", "\u8F93\u51FA JSON", false).option("--verbose", "\u8F93\u51FA\u8BF7\u6C42\u8BE6\u60C5", false).action(async (opts) => {
5978
+ await runPluginsList(opts);
5979
+ });
5980
+ plugins.command("catalog").description("\u5217\u51FA\u5B98\u65B9\u63D2\u4EF6\u76EE\u5F55\uFF08sammk8s / wp-plugins\uFF0C\u4E0D\u4F9D\u8D56\u7AD9\u70B9\uFF09").option("-s, --site <guidOrName>", "\u53EF\u9009\uFF0C\u5BF9\u7167\u8BE5\u7AD9\u662F\u5426\u5DF2\u88C5").option("--url <url>", "\u76F4\u63A5\u6307\u5B9A\u7AD9\u70B9\u5730\u5740").option("--prefix <prefix>", "\u53EA\u5217\u67D0\u4E2A\u76EE\u5F55\uFF0C\u5982 zasp-smart-recommender/").option("--json", "\u8F93\u51FA JSON", false).option("--verbose", "\u8F93\u51FA\u8BF7\u6C42\u8BE6\u60C5", false).action(async (opts) => {
5981
+ await runPluginsCatalog(opts);
5982
+ });
5983
+ plugins.command("install").description("\u5B89\u88C5\u5E76\u542F\u7528\u63D2\u4EF6\uFF1A\u5B98\u65B9\u76EE\u5F55\u7528 --slug\uFF0C\u5916\u90E8\u7528 --zip").option("-s, --site <guidOrName>", "\u7AD9\u70B9 guid \u6216\u540D\u79F0").option("--url <url>", "\u76F4\u63A5\u6307\u5B9A\u7AD9\u70B9\u5730\u5740").option("--slug <slug>", "\u4E1D\u8DEF\u8D5E\u76EE\u5F55\u4E2D\u7684 slug \u6216 plugin \u8DEF\u5F84").option("--zip <file>", "\u5916\u90E8\u63D2\u4EF6 zip\uFF08\u6839\u76EE\u5F55\u5FC5\u987B\u662F\u63D2\u4EF6\u76EE\u5F55\uFF09").option("--verbose", "\u8F93\u51FA\u8BF7\u6C42\u8BE6\u60C5", false).action(async (opts) => {
5984
+ await runPluginsInstall(opts);
5985
+ });
5986
+ plugins.command("update").description("\u5347\u7EA7\u5DF2\u88C5\u63D2\u4EF6\uFF1A\u6709\u76EE\u5F55/\u5B98\u65B9\u5305\u5219\u4E0D\u7528 zip\uFF0C\u5916\u90E8\u63D2\u4EF6\u5E26 --zip").option("-s, --site <guidOrName>", "\u7AD9\u70B9 guid \u6216\u540D\u79F0").option("--url <url>", "\u76F4\u63A5\u6307\u5B9A\u7AD9\u70B9\u5730\u5740").requiredOption("--plugin <plugin>", "\u5DF2\u88C5\u63D2\u4EF6\u8DEF\u5F84\uFF0C\u5982 theme-manage/theme-manage").option("--zip <file>", "\u5916\u90E8\u63D2\u4EF6\u5347\u7EA7\u5305").option("--verbose", "\u8F93\u51FA\u8BF7\u6C42\u8BE6\u60C5", false).action(async (opts) => {
5987
+ await runPluginsUpdate(opts);
5988
+ });
5989
+ plugins.command("uninstall").description("\u5378\u8F7D\u5DF2\u88C5\u63D2\u4EF6\uFF08\u5148\u505C\u7528\u518D\u5220\u9664\uFF1Bhelper / oauth2 \u4E0D\u5141\u8BB8\uFF09").option("-s, --site <guidOrName>", "\u7AD9\u70B9 guid \u6216\u540D\u79F0").option("--url <url>", "\u76F4\u63A5\u6307\u5B9A\u7AD9\u70B9\u5730\u5740").requiredOption("--plugin <plugin>", "\u5DF2\u88C5\u63D2\u4EF6\u8DEF\u5F84\uFF0C\u5982 dummy-e2e-plugin/dummy-e2e-plugin").option("--verbose", "\u8F93\u51FA\u8BF7\u6C42\u8BE6\u60C5", false).action(async (opts) => {
5990
+ await runPluginsUninstall(opts);
5991
+ });
5992
+ plugins.command("helper-status").description("\u67E5\u770B\u7AD9\u70B9 helper \u4E0E\u955C\u50CF\u672C\u5730 zip").option("-s, --site <guidOrName>", "\u7AD9\u70B9 guid \u6216\u540D\u79F0").option("--url <url>", "\u76F4\u63A5\u6307\u5B9A\u7AD9\u70B9\u5730\u5740").option("--json", "\u8F93\u51FA JSON", false).option("--verbose", "\u8F93\u51FA\u8BF7\u6C42\u8BE6\u60C5", false).action(async (opts) => {
5993
+ await runHelperStatus(opts);
5994
+ });
5995
+ plugins.command("update-helper").description("\u7528\u955C\u50CF\u91CC\u7684 siluzan-helper-plugin.1.0.*.zip \u5347\u7EA7 helper\uFF08\u5199\u64CD\u4F5C\uFF09").option("-s, --site <guidOrName>", "\u7AD9\u70B9 guid \u6216\u540D\u79F0").option("--url <url>", "\u76F4\u63A5\u6307\u5B9A\u7AD9\u70B9\u5730\u5740").option("--verbose", "\u8F93\u51FA\u8BF7\u6C42\u8BE6\u60C5", false).action(async (opts) => {
5996
+ await runUpdateHelper(opts);
5997
+ });
5998
+ }
5999
+
6000
+ // src/commands/content.ts
6001
+ import * as fs8 from "fs";
6002
+
6003
+ // src/types/wp-rest.ts
6004
+ function wpRenderedText(value) {
6005
+ if (!value) return "";
6006
+ if (typeof value === "string") return value;
6007
+ return value.raw || value.rendered || "";
6008
+ }
6009
+
6010
+ // src/commands/content.ts
6011
+ function parseIdList(raw) {
6012
+ if (!raw?.trim()) return void 0;
6013
+ return raw.split(",").map((s) => Number(s.trim())).filter((n) => Number.isFinite(n) && n > 0);
6014
+ }
6015
+ function printPost(item, restBase) {
6016
+ console.log(`
6017
+ \u2705 ${restBase} #${item.id}`);
6018
+ console.log(` \u6807\u9898 : ${wpRenderedText(item.title) || "-"}`);
6019
+ console.log(` \u72B6\u6001 : ${item.status || "-"}`);
6020
+ console.log(` slug : ${item.slug || "-"}`);
6021
+ if (item.link) console.log(` \u94FE\u63A5 : ${item.link}`);
6022
+ console.log();
6023
+ }
6024
+ async function runContentTypes(opts) {
6025
+ const target = await resolveTarget(opts);
6026
+ let types;
6027
+ try {
6028
+ types = await apiFetch2(
6029
+ wpV2(target.base, "/types?context=edit"),
6030
+ target.config,
6031
+ {},
6032
+ opts.verbose
6033
+ );
6034
+ } catch (e) {
6035
+ console.error(`
6036
+ \u274C \u83B7\u53D6\u5185\u5BB9\u7C7B\u578B\u5931\u8D25\uFF1A${e.message}
6037
+ `);
6038
+ process.exit(1);
6039
+ return;
6040
+ }
6041
+ const rows = Object.entries(types || {}).map(([slug, info]) => ({
6042
+ slug,
6043
+ rest_base: info.rest_base || slug,
6044
+ name: info.name || slug
6045
+ }));
6046
+ if (opts.json) {
6047
+ console.log(JSON.stringify({ site: target.site, types: rows }, null, 2));
6048
+ return;
6049
+ }
6050
+ console.log(`
6051
+ ${target.site.name} \u53EF REST \u7BA1\u7406\u7684\u5185\u5BB9\u7C7B\u578B\uFF08${rows.length}\uFF09
6052
+ `);
6053
+ printCliTable(rows, [
6054
+ { key: "slug", header: "slug" },
6055
+ { key: "rest_base", header: "rest_base\uFF08--type\uFF09" },
6056
+ { key: "name", header: "\u540D\u79F0" }
6057
+ ]);
6058
+ console.log("\n\u9875\u9762\u6B63\u6587\u8BF7\u7528 pages add/update\uFF1B\u5176\u5B83\u7C7B\u578B\u7528 content add --type <rest_base>\n");
6059
+ }
6060
+ async function runContentList(opts) {
6061
+ const typeArg = opts.type?.trim() || "posts";
6062
+ const target = await resolveTarget(opts);
6063
+ let restBase;
6064
+ try {
6065
+ restBase = await resolveTypeRestBase(target, typeArg, opts.verbose);
6066
+ } catch (e) {
6067
+ console.error(`
6068
+ \u274C ${e.message}
6069
+ `);
6070
+ process.exit(1);
6071
+ return;
6072
+ }
6073
+ const status = opts.status?.trim() || "publish,draft,private,pending";
6074
+ const api = wpV2(target.base, `/${restBase}?per_page=100&status=${encodeURIComponent(status)}`);
6075
+ let items;
4073
6076
  try {
4074
- res = await apiFetch2(api, config, {}, opts.verbose);
6077
+ items = await apiFetch2(api, target.config, {}, opts.verbose);
4075
6078
  } catch (e) {
4076
6079
  console.error(`
4077
- \u274C \u83B7\u53D6\u63D2\u4EF6\u76EE\u5F55\u5931\u8D25\uFF1A${e.message}`);
4078
- console.error(" \u9700\u8981\u7AD9\u70B9\u5DF2\u90E8\u7F72\u5E26 REST \u7684 siluzan-helper-plugin\u3002\n");
6080
+ \u274C \u83B7\u53D6 ${restBase} \u5931\u8D25\uFF1A${e.message}
6081
+ `);
4079
6082
  process.exit(1);
4080
6083
  return;
4081
6084
  }
4082
- const items = Array.isArray(res.items) ? res.items : [];
6085
+ if (!Array.isArray(items)) {
6086
+ console.error("\n\u274C \u7AD9\u70B9\u8FD4\u56DE\u7684\u5217\u8868\u683C\u5F0F\u5F02\u5E38\n");
6087
+ process.exit(1);
6088
+ }
4083
6089
  if (opts.json) {
4084
6090
  console.log(
4085
6091
  JSON.stringify(
4086
- { site: { guid: site.guid, name: site.name, url: site.url }, total: items.length, items },
6092
+ {
6093
+ site: { guid: target.site.guid, name: target.site.name, url: target.site.url },
6094
+ type: restBase,
6095
+ total: items.length,
6096
+ items: items.map((p) => ({
6097
+ id: p.id,
6098
+ title: wpRenderedText(p.title),
6099
+ status: p.status ?? "",
6100
+ slug: p.slug ?? "",
6101
+ link: p.link ?? "",
6102
+ modified: p.modified ?? ""
6103
+ }))
6104
+ },
4087
6105
  null,
4088
6106
  2
4089
6107
  )
@@ -4092,96 +6110,633 @@ async function runPluginsCatalog(opts) {
4092
6110
  }
4093
6111
  if (items.length === 0) {
4094
6112
  console.log(`
4095
- \u7AD9\u70B9 ${site.name} \u7684\u4E1D\u8DEF\u8D5E\u63D2\u4EF6\u76EE\u5F55\u4E3A\u7A7A\u3002
6113
+ ${target.site.name} \u6CA1\u6709 ${restBase}\u3002
4096
6114
  `);
4097
6115
  return;
4098
6116
  }
4099
6117
  const columns = [
6118
+ { key: "id", header: "id" },
6119
+ { key: "title", header: "\u6807\u9898" },
6120
+ { key: "status", header: "\u72B6\u6001" },
4100
6121
  { key: "slug", header: "slug" },
4101
- { key: "name", header: "\u540D\u79F0" },
4102
- { key: "new_version", header: "\u76EE\u5F55\u7248\u672C" },
4103
- { key: "installed", header: "\u5DF2\u88C5" },
4104
- { key: "active", header: "\u542F\u7528" }
6122
+ { key: "link", header: "\u94FE\u63A5" }
4105
6123
  ];
4106
6124
  console.log(`
4107
- ${site.name} \u53EF\u5B89\u88C5\u76EE\u5F55\uFF08${items.length}\uFF09
6125
+ ${target.site.name} ${restBase}\uFF08${items.length}\uFF09
4108
6126
  `);
4109
6127
  printCliTable(
4110
6128
  items.map((p) => ({
4111
- slug: p.slug || p.plugin || "-",
4112
- name: p.name || "-",
4113
- new_version: p.new_version || "-",
4114
- installed: p.installed ? "yes" : "no",
4115
- active: p.active ? "yes" : "no"
6129
+ id: String(p.id),
6130
+ title: wpRenderedText(p.title) || "(\u65E0\u6807\u9898)",
6131
+ status: p.status ?? "-",
6132
+ slug: p.slug ?? "-",
6133
+ link: p.link ?? "-"
4116
6134
  })),
4117
6135
  columns
4118
6136
  );
4119
- console.log("\n\u5B89\u88C5\uFF1Asiluzan-website plugins install --site <guid> --slug <slug>\n");
6137
+ console.log();
4120
6138
  }
4121
- async function runPluginsInstall(opts) {
4122
- const slug = opts.slug?.trim() ?? "";
4123
- if (!slug) {
4124
- console.error("\n\u274C \u8BF7\u63D0\u4F9B --slug\uFF08\u5148 plugins catalog \u67E5\u770B\u53EF\u88C5\u5217\u8868\uFF09\n");
6139
+ async function runContentGet(opts) {
6140
+ const id = Number(opts.id);
6141
+ if (!Number.isFinite(id) || id <= 0) {
6142
+ console.error("\n\u274C \u8BF7\u63D0\u4F9B\u6709\u6548 --id\n");
4125
6143
  process.exit(1);
4126
6144
  }
4127
- const { config, site, base } = await resolveTarget(opts);
4128
- const api = `${base}/wp-json/siluzan-helper/v1/plugins/install`;
4129
- let result;
6145
+ const target = await resolveTarget(opts);
6146
+ const restBase = await resolveTypeRestBase(target, opts.type?.trim() || "posts", opts.verbose);
6147
+ const item = await apiFetch2(
6148
+ wpV2(target.base, `/${restBase}/${id}?context=edit`),
6149
+ target.config,
6150
+ {},
6151
+ opts.verbose
6152
+ ).catch((e) => {
6153
+ console.error(`
6154
+ \u274C \u83B7\u53D6\u5931\u8D25\uFF1A${e.message}
6155
+ `);
6156
+ process.exit(1);
6157
+ });
6158
+ if (opts.json) {
6159
+ console.log(JSON.stringify(item, null, 2));
6160
+ return;
6161
+ }
6162
+ console.log(`
6163
+ ${restBase} #${item.id}`);
6164
+ console.log(` \u6807\u9898 : ${wpRenderedText(item.title) || "-"}`);
6165
+ console.log(` \u72B6\u6001 : ${item.status || "-"}`);
6166
+ console.log(` slug : ${item.slug || "-"}`);
6167
+ console.log(` \u94FE\u63A5 : ${item.link || "-"}`);
6168
+ if (item.featured_media) console.log(` \u7279\u8272\u56FE : ${item.featured_media}`);
6169
+ const excerpt = wpRenderedText(item.excerpt);
6170
+ if (excerpt) console.log(` \u6458\u8981 : ${excerpt.slice(0, 120)}`);
6171
+ console.log();
6172
+ }
6173
+ async function runContentWrite(mode, opts) {
6174
+ const typeArg = opts.type?.trim() || "posts";
6175
+ if (typeArg === "page" || typeArg === "pages") {
6176
+ console.error("\n\u274C \u9875\u9762\u6B63\u6587\u8BF7\u7528 pages add / pages update\uFF08Zion visual-edit\uFF09\u3002");
6177
+ console.error(" \u53EA\u6539 slug/\u72B6\u6001/\u56DE\u6536\u7AD9\u7528 pages meta / pages trash\u3002\n");
6178
+ process.exit(1);
6179
+ }
6180
+ const target = await resolveTarget(opts);
6181
+ const restBase = await resolveTypeRestBase(target, typeArg, opts.verbose);
6182
+ const content = opts.contentFile ? fs8.readFileSync(opts.contentFile, "utf8") : opts.content ?? "";
6183
+ if (mode === "add" && !opts.title?.trim() && !content.trim()) {
6184
+ console.error("\n\u274C \u65B0\u589E\u81F3\u5C11\u8981 --title \u6216 --content / --content-file\n");
6185
+ process.exit(1);
6186
+ }
6187
+ const body = {};
6188
+ if (opts.title?.trim()) body.title = opts.title.trim();
6189
+ if (content.trim()) body.content = content;
6190
+ if (opts.status?.trim()) body.status = opts.status.trim();
6191
+ if (opts.slug?.trim()) body.slug = opts.slug.trim();
6192
+ if (opts.excerpt?.trim()) body.excerpt = opts.excerpt.trim();
6193
+ const featured = Number(opts.featuredMedia);
6194
+ if (Number.isFinite(featured) && featured > 0) body.featured_media = featured;
6195
+ const cats = parseIdList(opts.categories);
6196
+ if (cats) body.categories = cats;
6197
+ const tags = parseIdList(opts.tags);
6198
+ if (tags) body.tags = tags;
6199
+ if (mode === "update") {
6200
+ const id = Number(opts.id);
6201
+ if (!Number.isFinite(id) || id <= 0) {
6202
+ console.error("\n\u274C \u66F4\u65B0\u5FC5\u987B\u63D0\u4F9B --id\uFF08\u5148 content list\uFF09\n");
6203
+ process.exit(1);
6204
+ }
6205
+ if (Object.keys(body).length === 0) {
6206
+ console.error("\n\u274C \u6CA1\u6709\u8981\u6539\u7684\u5B57\u6BB5\n");
6207
+ process.exit(1);
6208
+ }
6209
+ const item2 = await apiFetch2(
6210
+ wpV2(target.base, `/${restBase}/${id}`),
6211
+ target.config,
6212
+ { method: "POST", body: JSON.stringify(body) },
6213
+ opts.verbose
6214
+ ).catch((e) => {
6215
+ console.error(`
6216
+ \u274C \u66F4\u65B0\u5931\u8D25\uFF1A${e.message}
6217
+ `);
6218
+ process.exit(1);
6219
+ });
6220
+ printPost(item2, restBase);
6221
+ return;
6222
+ }
6223
+ const item = await apiFetch2(
6224
+ wpV2(target.base, `/${restBase}`),
6225
+ target.config,
6226
+ { method: "POST", body: JSON.stringify(body) },
6227
+ opts.verbose
6228
+ ).catch((e) => {
6229
+ console.error(`
6230
+ \u274C \u65B0\u589E\u5931\u8D25\uFF1A${e.message}
6231
+ `);
6232
+ process.exit(1);
6233
+ });
6234
+ printPost(item, restBase);
6235
+ }
6236
+ async function runContentTrash(opts) {
6237
+ const id = Number(opts.id);
6238
+ if (!Number.isFinite(id) || id <= 0) {
6239
+ console.error("\n\u274C \u8BF7\u63D0\u4F9B --id\n");
6240
+ process.exit(1);
6241
+ }
6242
+ const target = await resolveTarget(opts);
6243
+ const restBase = await resolveTypeRestBase(target, opts.type?.trim() || "posts", opts.verbose);
6244
+ const qs = opts.force ? "?force=true" : "";
6245
+ const item = await apiFetch2(
6246
+ wpV2(target.base, `/${restBase}/${id}${qs}`),
6247
+ target.config,
6248
+ { method: "DELETE" },
6249
+ opts.verbose
6250
+ ).catch((e) => {
6251
+ console.error(`
6252
+ \u274C \u5220\u9664\u5931\u8D25\uFF1A${e.message}
6253
+ `);
6254
+ process.exit(1);
6255
+ });
6256
+ console.log(opts.force ? `
6257
+ \u2705 \u5DF2\u6C38\u4E45\u5220\u9664 ${restBase} #${id}
6258
+ ` : `
6259
+ \u2705 \u5DF2\u79FB\u5165\u56DE\u6536\u7AD9 ${restBase} #${id}\uFF08status=${item.status || "trash"}\uFF09
6260
+ `);
6261
+ }
6262
+ function register13(program2) {
6263
+ const content = program2.command("content").description("\u901A\u7528\u5185\u5BB9\uFF1A\u6587\u7AE0/\u4EA7\u54C1\u7B49 REST \u7C7B\u578B\uFF08\u9875\u9762\u6B63\u6587\u8BF7\u7528 pages\uFF09");
6264
+ content.command("types").description("\u5217\u51FA\u7AD9\u70B9\u53EF REST \u7BA1\u7406\u7684\u5185\u5BB9\u7C7B\u578B").option("-s, --site <guidOrName>", "\u7AD9\u70B9 guid \u6216\u540D\u79F0").option("--url <url>", "\u76F4\u63A5\u6307\u5B9A\u7AD9\u70B9\u5730\u5740").option("--json", "\u8F93\u51FA JSON", false).option("--verbose", "\u8F93\u51FA\u8BF7\u6C42\u8BE6\u60C5", false).action(async (opts) => {
6265
+ await runContentTypes(opts);
6266
+ });
6267
+ content.command("list").description("\u5217\u51FA\u67D0\u4E00\u7C7B\u578B\u7684\u5185\u5BB9").option("-s, --site <guidOrName>", "\u7AD9\u70B9 guid \u6216\u540D\u79F0").option("--url <url>", "\u76F4\u63A5\u6307\u5B9A\u7AD9\u70B9\u5730\u5740").option("--type <restBase>", "\u7C7B\u578B rest_base\uFF0C\u9ED8\u8BA4 posts", "posts").option("--status <status>", "\u72B6\u6001\uFF0C\u9017\u53F7\u5206\u9694", "publish,draft,private,pending").option("--json", "\u8F93\u51FA JSON", false).option("--verbose", "\u8F93\u51FA\u8BF7\u6C42\u8BE6\u60C5", false).action(async (opts) => {
6268
+ await runContentList(opts);
6269
+ });
6270
+ content.command("get").description("\u67E5\u770B\u5355\u6761\u5185\u5BB9").option("-s, --site <guidOrName>", "\u7AD9\u70B9 guid \u6216\u540D\u79F0").option("--url <url>", "\u76F4\u63A5\u6307\u5B9A\u7AD9\u70B9\u5730\u5740").option("--type <restBase>", "\u7C7B\u578B rest_base\uFF0C\u9ED8\u8BA4 posts", "posts").requiredOption("--id <id>", "\u5185\u5BB9 ID").option("--json", "\u8F93\u51FA JSON", false).option("--verbose", "\u8F93\u51FA\u8BF7\u6C42\u8BE6\u60C5", false).action(async (opts) => {
6271
+ await runContentGet(opts);
6272
+ });
6273
+ content.command("add").description("\u65B0\u589E\u6587\u7AE0\u6216\u5176\u5B83 CPT\uFF08\u4E0D\u8981\u7528\u6765\u52A0 Zion \u9875\u9762\uFF09").option("-s, --site <guidOrName>", "\u7AD9\u70B9 guid \u6216\u540D\u79F0").option("--url <url>", "\u76F4\u63A5\u6307\u5B9A\u7AD9\u70B9\u5730\u5740").option("--type <restBase>", "\u7C7B\u578B rest_base\uFF0C\u9ED8\u8BA4 posts", "posts").option("-t, --title <title>", "\u6807\u9898").option("-c, --content <html>", "\u6B63\u6587 HTML").option("--content-file <path>", "\u4ECE\u6587\u4EF6\u8BFB\u6B63\u6587").option("--status <status>", "publish / draft / private", "draft").option("--slug <slug>", "\u522B\u540D").option("--excerpt <text>", "\u6458\u8981").option("--featured-media <id>", "\u7279\u8272\u56FE\u5A92\u4F53 ID").option("--categories <ids>", "\u5206\u7C7B ID\uFF0C\u9017\u53F7\u5206\u9694").option("--tags <ids>", "\u6807\u7B7E ID\uFF0C\u9017\u53F7\u5206\u9694").option("--verbose", "\u8F93\u51FA\u8BF7\u6C42\u8BE6\u60C5", false).action(async (opts) => {
6274
+ await runContentWrite("add", opts);
6275
+ });
6276
+ content.command("update").description("\u66F4\u65B0\u5DF2\u6709\u5185\u5BB9\u5B57\u6BB5").option("-s, --site <guidOrName>", "\u7AD9\u70B9 guid \u6216\u540D\u79F0").option("--url <url>", "\u76F4\u63A5\u6307\u5B9A\u7AD9\u70B9\u5730\u5740").option("--type <restBase>", "\u7C7B\u578B rest_base\uFF0C\u9ED8\u8BA4 posts", "posts").requiredOption("--id <id>", "\u5185\u5BB9 ID").option("-t, --title <title>", "\u6807\u9898").option("-c, --content <html>", "\u6B63\u6587 HTML").option("--content-file <path>", "\u4ECE\u6587\u4EF6\u8BFB\u6B63\u6587").option("--status <status>", "publish / draft / private / pending").option("--slug <slug>", "\u522B\u540D").option("--excerpt <text>", "\u6458\u8981").option("--featured-media <id>", "\u7279\u8272\u56FE\u5A92\u4F53 ID").option("--categories <ids>", "\u5206\u7C7B ID\uFF0C\u9017\u53F7\u5206\u9694").option("--tags <ids>", "\u6807\u7B7E ID\uFF0C\u9017\u53F7\u5206\u9694").option("--verbose", "\u8F93\u51FA\u8BF7\u6C42\u8BE6\u60C5", false).action(async (opts) => {
6277
+ await runContentWrite("update", opts);
6278
+ });
6279
+ content.command("trash").description("\u79FB\u5165\u56DE\u6536\u7AD9\uFF1B\u52A0 --force \u6C38\u4E45\u5220\u9664").option("-s, --site <guidOrName>", "\u7AD9\u70B9 guid \u6216\u540D\u79F0").option("--url <url>", "\u76F4\u63A5\u6307\u5B9A\u7AD9\u70B9\u5730\u5740").option("--type <restBase>", "\u7C7B\u578B rest_base\uFF0C\u9ED8\u8BA4 posts", "posts").requiredOption("--id <id>", "\u5185\u5BB9 ID").option("--force", "\u6C38\u4E45\u5220\u9664", false).option("--verbose", "\u8F93\u51FA\u8BF7\u6C42\u8BE6\u60C5", false).action(async (opts) => {
6280
+ await runContentTrash(opts);
6281
+ });
6282
+ }
6283
+
6284
+ // src/commands/media.ts
6285
+ import { existsSync as existsSync4, readFileSync as readFileSync9 } from "fs";
6286
+ import { basename as basename3, extname, resolve as resolve3 } from "path";
6287
+ var MIME_BY_EXT = {
6288
+ ".jpg": "image/jpeg",
6289
+ ".jpeg": "image/jpeg",
6290
+ ".png": "image/png",
6291
+ ".gif": "image/gif",
6292
+ ".webp": "image/webp",
6293
+ ".svg": "image/svg+xml",
6294
+ ".pdf": "application/pdf",
6295
+ ".mp4": "video/mp4",
6296
+ ".zip": "application/zip"
6297
+ };
6298
+ var MAX_MEDIA_BYTES = 20 * 1024 * 1024;
6299
+ function guessMime(filename) {
6300
+ return MIME_BY_EXT[extname(filename).toLowerCase()] || "application/octet-stream";
6301
+ }
6302
+ async function runMediaList(opts) {
6303
+ const target = await resolveTarget(opts);
6304
+ let items;
4130
6305
  try {
4131
- result = await apiFetch2(
4132
- api,
4133
- config,
4134
- { method: "POST", body: JSON.stringify({ slug }) },
6306
+ items = await apiFetch2(
6307
+ wpV2(target.base, "/media?per_page=50"),
6308
+ target.config,
6309
+ {},
4135
6310
  opts.verbose
4136
6311
  );
4137
6312
  } catch (e) {
4138
6313
  console.error(`
4139
- \u274C \u5B89\u88C5\u5931\u8D25\uFF1A${e.message}
6314
+ \u274C \u83B7\u53D6\u5A92\u4F53\u5E93\u5931\u8D25\uFF1A${e.message}
4140
6315
  `);
4141
6316
  process.exit(1);
4142
6317
  return;
4143
6318
  }
4144
- if (!result.success) {
6319
+ if (!Array.isArray(items)) {
6320
+ console.error("\n\u274C \u7AD9\u70B9\u8FD4\u56DE\u7684\u5A92\u4F53\u5217\u8868\u683C\u5F0F\u5F02\u5E38\n");
6321
+ process.exit(1);
6322
+ }
6323
+ if (opts.json) {
6324
+ console.log(
6325
+ JSON.stringify(
6326
+ {
6327
+ site: { guid: target.site.guid, name: target.site.name, url: target.site.url },
6328
+ total: items.length,
6329
+ items: items.map((m) => ({
6330
+ id: m.id,
6331
+ title: wpRenderedText(m.title),
6332
+ mime: m.mime_type ?? "",
6333
+ url: m.source_url ?? ""
6334
+ }))
6335
+ },
6336
+ null,
6337
+ 2
6338
+ )
6339
+ );
6340
+ return;
6341
+ }
6342
+ if (items.length === 0) {
6343
+ console.log(`
6344
+ ${target.site.name} \u5A92\u4F53\u5E93\u4E3A\u7A7A\u3002
6345
+ `);
6346
+ return;
6347
+ }
6348
+ console.log(`
6349
+ ${target.site.name} \u5A92\u4F53\uFF08\u6700\u8FD1 ${items.length}\uFF09
6350
+ `);
6351
+ printCliTable(
6352
+ items.map((m) => ({
6353
+ id: String(m.id),
6354
+ title: wpRenderedText(m.title) || "-",
6355
+ mime: m.mime_type || "-",
6356
+ url: m.source_url || "-"
6357
+ })),
6358
+ [
6359
+ { key: "id", header: "id" },
6360
+ { key: "title", header: "\u6807\u9898" },
6361
+ { key: "mime", header: "\u7C7B\u578B" },
6362
+ { key: "url", header: "\u5730\u5740" }
6363
+ ]
6364
+ );
6365
+ console.log();
6366
+ }
6367
+ async function runMediaGet(opts) {
6368
+ const id = Number(opts.id);
6369
+ if (!Number.isFinite(id) || id <= 0) {
6370
+ console.error("\n\u274C \u8BF7\u63D0\u4F9B --id\n");
6371
+ process.exit(1);
6372
+ }
6373
+ const target = await resolveTarget(opts);
6374
+ const item = await apiFetch2(
6375
+ wpV2(target.base, `/media/${id}`),
6376
+ target.config,
6377
+ {},
6378
+ opts.verbose
6379
+ ).catch((e) => {
4145
6380
  console.error(`
4146
- \u274C ${result.message || "\u5B89\u88C5\u88AB\u7AD9\u70B9\u62D2\u7EDD"}
6381
+ \u274C \u83B7\u53D6\u5A92\u4F53\u5931\u8D25\uFF1A${e.message}
4147
6382
  `);
4148
6383
  process.exit(1);
6384
+ });
6385
+ if (opts.json) {
6386
+ console.log(JSON.stringify(item, null, 2));
6387
+ return;
6388
+ }
6389
+ console.log(`
6390
+ \u5A92\u4F53 #${item.id}`);
6391
+ console.log(` \u6807\u9898 : ${wpRenderedText(item.title) || "-"}`);
6392
+ console.log(` \u7C7B\u578B : ${item.mime_type || "-"}`);
6393
+ console.log(` \u5730\u5740 : ${item.source_url || "-"}`);
6394
+ if (item.alt_text) console.log(` alt : ${item.alt_text}`);
6395
+ console.log();
6396
+ }
6397
+ async function runMediaUpload(opts) {
6398
+ const filePath = opts.file?.trim() ?? "";
6399
+ if (!filePath) {
6400
+ console.error("\n\u274C \u8BF7\u63D0\u4F9B --file\n");
6401
+ process.exit(1);
4149
6402
  }
4150
- console.log(result.already ? "\n\u2705 \u63D2\u4EF6\u5DF2\u5728\u7AD9\u70B9\u4E0A\uFF08\u5DF2\u542F\u7528\uFF09" : "\n\u2705 \u63D2\u4EF6\u5DF2\u5B89\u88C5\u5E76\u542F\u7528");
4151
- if (result.plugin) console.log(` plugin : ${result.plugin}`);
4152
- if (result.message) console.log(` \u8BF4\u660E : ${result.message}`);
4153
- console.log(` \u7AD9\u70B9 : ${site.name} (${base})
6403
+ const abs = resolve3(filePath);
6404
+ if (!existsSync4(abs)) {
6405
+ console.error(`
6406
+ \u274C \u6587\u4EF6\u4E0D\u5B58\u5728\uFF1A${abs}
4154
6407
  `);
6408
+ process.exit(1);
6409
+ }
6410
+ const data = readFileSync9(abs);
6411
+ if (data.length > MAX_MEDIA_BYTES) {
6412
+ console.error("\n\u274C \u6587\u4EF6\u8D85\u8FC7 20MB\n");
6413
+ process.exit(1);
6414
+ }
6415
+ const filename = basename3(abs);
6416
+ const target = await resolveTarget(opts);
6417
+ const fields = {};
6418
+ if (opts.title?.trim()) fields.title = opts.title.trim();
6419
+ if (opts.alt?.trim()) fields.alt_text = opts.alt.trim();
6420
+ if (opts.caption?.trim()) fields.caption = opts.caption.trim();
6421
+ let item;
4155
6422
  try {
4156
- await runPluginsList({ site: site.guid || opts.site, url: site.url, verbose: opts.verbose });
4157
- } catch {
6423
+ item = await apiFetchMultipart2(
6424
+ wpV2(target.base, "/media"),
6425
+ target.config,
6426
+ {
6427
+ fields,
6428
+ files: [
6429
+ {
6430
+ field: "file",
6431
+ filename,
6432
+ contentType: guessMime(filename),
6433
+ data
6434
+ }
6435
+ ]
6436
+ },
6437
+ opts.verbose
6438
+ );
6439
+ } catch (e) {
6440
+ console.error(`
6441
+ \u274C \u4E0A\u4F20\u5931\u8D25\uFF1A${e.message}
6442
+ `);
6443
+ process.exit(1);
6444
+ return;
4158
6445
  }
6446
+ console.log(`
6447
+ \u2705 \u5DF2\u4E0A\u4F20\u5A92\u4F53 #${item.id}`);
6448
+ console.log(` \u5730\u5740 : ${item.source_url || "-"}`);
6449
+ console.log(` \u6807\u9898 : ${wpRenderedText(item.title) || filename}`);
6450
+ console.log();
4159
6451
  }
4160
- function register7(program2) {
4161
- const plugins = program2.command("plugins").description("WordPress \u63D2\u4EF6\uFF1A\u5217\u51FA\u3001\u76EE\u5F55\u3001\u5B89\u88C5");
4162
- plugins.command("list").description("\u5217\u51FA\u7AD9\u70B9\u5DF2\u5B89\u88C5\u63D2\u4EF6").option("-s, --site <guidOrName>", "\u7AD9\u70B9 guid \u6216\u540D\u79F0").option("--url <url>", "\u76F4\u63A5\u6307\u5B9A\u7AD9\u70B9\u5730\u5740").option("--json", "\u8F93\u51FA JSON", false).option("--verbose", "\u8F93\u51FA\u8BF7\u6C42\u8BE6\u60C5", false).action(async (opts) => {
4163
- await runPluginsList(opts);
6452
+ function register14(program2) {
6453
+ const media = program2.command("media").description("\u5A92\u4F53\u5E93\uFF1A\u5217\u51FA\u3001\u67E5\u770B\u3001\u4E0A\u4F20");
6454
+ media.command("list").description("\u5217\u51FA\u5A92\u4F53\u5E93\uFF08\u6700\u8FD1 50 \u6761\uFF09").option("-s, --site <guidOrName>", "\u7AD9\u70B9 guid \u6216\u540D\u79F0").option("--url <url>", "\u76F4\u63A5\u6307\u5B9A\u7AD9\u70B9\u5730\u5740").option("--json", "\u8F93\u51FA JSON", false).option("--verbose", "\u8F93\u51FA\u8BF7\u6C42\u8BE6\u60C5", false).action(async (opts) => {
6455
+ await runMediaList(opts);
4164
6456
  });
4165
- plugins.command("catalog").description("\u5217\u51FA\u4E1D\u8DEF\u8D5E\u63D2\u4EF6\u76EE\u5F55\uFF08\u53EF\u5B89\u88C5\u5217\u8868\uFF09").option("-s, --site <guidOrName>", "\u7AD9\u70B9 guid \u6216\u540D\u79F0").option("--url <url>", "\u76F4\u63A5\u6307\u5B9A\u7AD9\u70B9\u5730\u5740").option("--json", "\u8F93\u51FA JSON", false).option("--verbose", "\u8F93\u51FA\u8BF7\u6C42\u8BE6\u60C5", false).action(async (opts) => {
4166
- await runPluginsCatalog(opts);
6457
+ media.command("get").description("\u67E5\u770B\u5355\u4E2A\u5A92\u4F53").option("-s, --site <guidOrName>", "\u7AD9\u70B9 guid \u6216\u540D\u79F0").option("--url <url>", "\u76F4\u63A5\u6307\u5B9A\u7AD9\u70B9\u5730\u5740").requiredOption("--id <id>", "\u5A92\u4F53 ID").option("--json", "\u8F93\u51FA JSON", false).option("--verbose", "\u8F93\u51FA\u8BF7\u6C42\u8BE6\u60C5", false).action(async (opts) => {
6458
+ await runMediaGet(opts);
4167
6459
  });
4168
- plugins.command("install").description("\u4ECE\u4E1D\u8DEF\u8D5E\u76EE\u5F55\u5B89\u88C5\u5E76\u542F\u7528\u63D2\u4EF6\uFF08\u5199\u64CD\u4F5C\uFF0C\u4F1A\u7ACB\u523B\u751F\u6548\uFF09").option("-s, --site <guidOrName>", "\u7AD9\u70B9 guid \u6216\u540D\u79F0").option("--url <url>", "\u76F4\u63A5\u6307\u5B9A\u7AD9\u70B9\u5730\u5740").requiredOption("--slug <slug>", "\u76EE\u5F55\u4E2D\u7684 slug \u6216 plugin \u8DEF\u5F84").option("--verbose", "\u8F93\u51FA\u8BF7\u6C42\u8BE6\u60C5", false).action(async (opts) => {
4169
- await runPluginsInstall(opts);
6460
+ media.command("upload").description("\u4E0A\u4F20\u672C\u5730\u6587\u4EF6\u5230\u5A92\u4F53\u5E93\uFF08\u5199\u64CD\u4F5C\uFF09").option("-s, --site <guidOrName>", "\u7AD9\u70B9 guid \u6216\u540D\u79F0").option("--url <url>", "\u76F4\u63A5\u6307\u5B9A\u7AD9\u70B9\u5730\u5740").requiredOption("--file <path>", "\u672C\u5730\u6587\u4EF6\u8DEF\u5F84").option("-t, --title <title>", "\u5A92\u4F53\u6807\u9898").option("--alt <text>", "\u56FE\u7247 alt").option("--caption <text>", "\u8BF4\u660E").option("--verbose", "\u8F93\u51FA\u8BF7\u6C42\u8BE6\u60C5", false).action(async (opts) => {
6461
+ await runMediaUpload(opts);
6462
+ });
6463
+ }
6464
+
6465
+ // src/commands/terms.ts
6466
+ async function runTermsTaxonomies(opts) {
6467
+ const target = await resolveTarget(opts);
6468
+ let taxes;
6469
+ try {
6470
+ taxes = await apiFetch2(
6471
+ wpV2(target.base, "/taxonomies?context=edit"),
6472
+ target.config,
6473
+ {},
6474
+ opts.verbose
6475
+ );
6476
+ } catch (e) {
6477
+ console.error(`
6478
+ \u274C \u83B7\u53D6\u5206\u7C7B\u6CD5\u5931\u8D25\uFF1A${e.message}
6479
+ `);
6480
+ process.exit(1);
6481
+ return;
6482
+ }
6483
+ const rows = Object.entries(taxes || {}).map(([slug, info]) => ({
6484
+ slug,
6485
+ rest_base: info.rest_base || slug,
6486
+ name: info.name || slug
6487
+ }));
6488
+ if (opts.json) {
6489
+ console.log(JSON.stringify({ site: target.site, taxonomies: rows }, null, 2));
6490
+ return;
6491
+ }
6492
+ console.log(`
6493
+ ${target.site.name} \u5206\u7C7B\u6CD5\uFF08${rows.length}\uFF09
6494
+ `);
6495
+ printCliTable(rows, [
6496
+ { key: "slug", header: "slug" },
6497
+ { key: "rest_base", header: "--taxonomy" },
6498
+ { key: "name", header: "\u540D\u79F0" }
6499
+ ]);
6500
+ console.log();
6501
+ }
6502
+ async function runTermsList(opts) {
6503
+ const target = await resolveTarget(opts);
6504
+ const restBase = await resolveTaxonomyRestBase(target, opts.taxonomy || "category", opts.verbose);
6505
+ let items;
6506
+ try {
6507
+ items = await apiFetch2(
6508
+ wpV2(target.base, `/${restBase}?per_page=100`),
6509
+ target.config,
6510
+ {},
6511
+ opts.verbose
6512
+ );
6513
+ } catch (e) {
6514
+ console.error(`
6515
+ \u274C \u83B7\u53D6 ${restBase} \u5931\u8D25\uFF1A${e.message}
6516
+ `);
6517
+ process.exit(1);
6518
+ return;
6519
+ }
6520
+ if (!Array.isArray(items)) {
6521
+ console.error("\n\u274C \u7AD9\u70B9\u8FD4\u56DE\u7684\u672F\u8BED\u5217\u8868\u683C\u5F0F\u5F02\u5E38\n");
6522
+ process.exit(1);
6523
+ }
6524
+ if (opts.json) {
6525
+ console.log(JSON.stringify({ taxonomy: restBase, total: items.length, items }, null, 2));
6526
+ return;
6527
+ }
6528
+ if (items.length === 0) {
6529
+ console.log(`
6530
+ \u6CA1\u6709 ${restBase}\u3002
6531
+ `);
6532
+ return;
6533
+ }
6534
+ console.log(`
6535
+ ${target.site.name} ${restBase}\uFF08${items.length}\uFF09
6536
+ `);
6537
+ printCliTable(
6538
+ items.map((t) => ({
6539
+ id: String(t.id),
6540
+ name: t.name || "-",
6541
+ slug: t.slug || "-",
6542
+ count: String(t.count ?? 0)
6543
+ })),
6544
+ [
6545
+ { key: "id", header: "id" },
6546
+ { key: "name", header: "\u540D\u79F0" },
6547
+ { key: "slug", header: "slug" },
6548
+ { key: "count", header: "\u6570\u91CF" }
6549
+ ]
6550
+ );
6551
+ console.log();
6552
+ }
6553
+ async function runTermsAdd(opts) {
6554
+ const name = opts.name?.trim() ?? "";
6555
+ if (!name) {
6556
+ console.error("\n\u274C \u8BF7\u63D0\u4F9B --name\n");
6557
+ process.exit(1);
6558
+ }
6559
+ const target = await resolveTarget(opts);
6560
+ const restBase = await resolveTaxonomyRestBase(target, opts.taxonomy || "category", opts.verbose);
6561
+ const body = { name };
6562
+ if (opts.slug?.trim()) body.slug = opts.slug.trim();
6563
+ const parent = Number(opts.parent);
6564
+ if (Number.isFinite(parent) && parent > 0) body.parent = parent;
6565
+ const item = await apiFetch2(
6566
+ wpV2(target.base, `/${restBase}`),
6567
+ target.config,
6568
+ { method: "POST", body: JSON.stringify(body) },
6569
+ opts.verbose
6570
+ ).catch((e) => {
6571
+ console.error(`
6572
+ \u274C \u65B0\u589E\u5931\u8D25\uFF1A${e.message}
6573
+ `);
6574
+ process.exit(1);
6575
+ });
6576
+ console.log(`
6577
+ \u2705 \u5DF2\u65B0\u589E ${restBase} #${item.id} ${item.name || name}
6578
+ `);
6579
+ }
6580
+ async function runTermsUpdate(opts) {
6581
+ const id = Number(opts.id);
6582
+ if (!Number.isFinite(id) || id <= 0) {
6583
+ console.error("\n\u274C \u8BF7\u63D0\u4F9B --id\n");
6584
+ process.exit(1);
6585
+ }
6586
+ const body = {};
6587
+ if (opts.name?.trim()) body.name = opts.name.trim();
6588
+ if (opts.slug?.trim()) body.slug = opts.slug.trim();
6589
+ if (Object.keys(body).length === 0) {
6590
+ console.error("\n\u274C \u6CA1\u6709\u8981\u6539\u7684\u5B57\u6BB5\n");
6591
+ process.exit(1);
6592
+ }
6593
+ const target = await resolveTarget(opts);
6594
+ const restBase = await resolveTaxonomyRestBase(target, opts.taxonomy || "category", opts.verbose);
6595
+ const item = await apiFetch2(
6596
+ wpV2(target.base, `/${restBase}/${id}`),
6597
+ target.config,
6598
+ { method: "POST", body: JSON.stringify(body) },
6599
+ opts.verbose
6600
+ ).catch((e) => {
6601
+ console.error(`
6602
+ \u274C \u66F4\u65B0\u5931\u8D25\uFF1A${e.message}
6603
+ `);
6604
+ process.exit(1);
6605
+ });
6606
+ console.log(`
6607
+ \u2705 \u5DF2\u66F4\u65B0 ${restBase} #${item.id} ${item.name || ""}
6608
+ `);
6609
+ }
6610
+ async function runTermsDelete(opts) {
6611
+ const id = Number(opts.id);
6612
+ if (!Number.isFinite(id) || id <= 0) {
6613
+ console.error("\n\u274C \u8BF7\u63D0\u4F9B --id\n");
6614
+ process.exit(1);
6615
+ }
6616
+ const target = await resolveTarget(opts);
6617
+ const restBase = await resolveTaxonomyRestBase(target, opts.taxonomy || "category", opts.verbose);
6618
+ await apiFetch2(
6619
+ wpV2(target.base, `/${restBase}/${id}?force=true`),
6620
+ target.config,
6621
+ { method: "DELETE" },
6622
+ opts.verbose
6623
+ ).catch((e) => {
6624
+ console.error(`
6625
+ \u274C \u5220\u9664\u5931\u8D25\uFF1A${e.message}
6626
+ `);
6627
+ process.exit(1);
6628
+ });
6629
+ console.log(`
6630
+ \u2705 \u5DF2\u5220\u9664 ${restBase} #${id}
6631
+ `);
6632
+ }
6633
+ function register15(program2) {
6634
+ const terms = program2.command("terms").description("\u5206\u7C7B / \u6807\u7B7E / \u81EA\u5B9A\u4E49\u5206\u7C7B\u6CD5");
6635
+ terms.command("taxonomies").description("\u5217\u51FA\u5206\u7C7B\u6CD5").option("-s, --site <guidOrName>", "\u7AD9\u70B9 guid \u6216\u540D\u79F0").option("--url <url>", "\u76F4\u63A5\u6307\u5B9A\u7AD9\u70B9\u5730\u5740").option("--json", "\u8F93\u51FA JSON", false).option("--verbose", "\u8F93\u51FA\u8BF7\u6C42\u8BE6\u60C5", false).action(async (opts) => {
6636
+ await runTermsTaxonomies(opts);
6637
+ });
6638
+ terms.command("list").description("\u5217\u51FA\u67D0\u5206\u7C7B\u6CD5\u4E0B\u7684\u672F\u8BED").option("-s, --site <guidOrName>", "\u7AD9\u70B9 guid \u6216\u540D\u79F0").option("--url <url>", "\u76F4\u63A5\u6307\u5B9A\u7AD9\u70B9\u5730\u5740").option("--taxonomy <slug>", "category / post_tag / \u5176\u5B83 rest_base", "category").option("--json", "\u8F93\u51FA JSON", false).option("--verbose", "\u8F93\u51FA\u8BF7\u6C42\u8BE6\u60C5", false).action(async (opts) => {
6639
+ await runTermsList(opts);
6640
+ });
6641
+ terms.command("add").description("\u65B0\u589E\u672F\u8BED\uFF08\u5199\u64CD\u4F5C\uFF09").option("-s, --site <guidOrName>", "\u7AD9\u70B9 guid \u6216\u540D\u79F0").option("--url <url>", "\u76F4\u63A5\u6307\u5B9A\u7AD9\u70B9\u5730\u5740").option("--taxonomy <slug>", "\u9ED8\u8BA4 category", "category").requiredOption("-n, --name <name>", "\u540D\u79F0").option("--slug <slug>", "\u522B\u540D").option("--parent <id>", "\u7236\u7EA7 ID").option("--verbose", "\u8F93\u51FA\u8BF7\u6C42\u8BE6\u60C5", false).action(async (opts) => {
6642
+ await runTermsAdd(opts);
6643
+ });
6644
+ terms.command("update").description("\u66F4\u65B0\u672F\u8BED\uFF08\u5199\u64CD\u4F5C\uFF09").option("-s, --site <guidOrName>", "\u7AD9\u70B9 guid \u6216\u540D\u79F0").option("--url <url>", "\u76F4\u63A5\u6307\u5B9A\u7AD9\u70B9\u5730\u5740").option("--taxonomy <slug>", "\u9ED8\u8BA4 category", "category").requiredOption("--id <id>", "\u672F\u8BED ID").option("-n, --name <name>", "\u540D\u79F0").option("--slug <slug>", "\u522B\u540D").option("--verbose", "\u8F93\u51FA\u8BF7\u6C42\u8BE6\u60C5", false).action(async (opts) => {
6645
+ await runTermsUpdate(opts);
6646
+ });
6647
+ terms.command("delete").description("\u5220\u9664\u672F\u8BED\uFF08\u5199\u64CD\u4F5C\uFF0C\u4E0D\u53EF\u8FDB\u56DE\u6536\u7AD9\uFF09").option("-s, --site <guidOrName>", "\u7AD9\u70B9 guid \u6216\u540D\u79F0").option("--url <url>", "\u76F4\u63A5\u6307\u5B9A\u7AD9\u70B9\u5730\u5740").option("--taxonomy <slug>", "\u9ED8\u8BA4 category", "category").requiredOption("--id <id>", "\u672F\u8BED ID").option("--verbose", "\u8F93\u51FA\u8BF7\u6C42\u8BE6\u60C5", false).action(async (opts) => {
6648
+ await runTermsDelete(opts);
6649
+ });
6650
+ }
6651
+
6652
+ // src/commands/search.ts
6653
+ async function runSearch(opts) {
6654
+ const q = opts.q?.trim() ?? "";
6655
+ if (!q) {
6656
+ console.error("\n\u274C \u8BF7\u63D0\u4F9B --q\n");
6657
+ process.exit(1);
6658
+ }
6659
+ const target = await resolveTarget(opts);
6660
+ const params = new URLSearchParams({
6661
+ search: q,
6662
+ per_page: "20"
6663
+ });
6664
+ if (opts.type?.trim()) params.set("subtype", opts.type.trim());
6665
+ let hits;
6666
+ try {
6667
+ hits = await apiFetch2(
6668
+ wpV2(target.base, `/search?${params.toString()}`),
6669
+ target.config,
6670
+ {},
6671
+ opts.verbose
6672
+ );
6673
+ } catch (e) {
6674
+ console.error(`
6675
+ \u274C \u641C\u7D22\u5931\u8D25\uFF1A${e.message}
6676
+ `);
6677
+ process.exit(1);
6678
+ return;
6679
+ }
6680
+ if (!Array.isArray(hits)) {
6681
+ console.error("\n\u274C \u7AD9\u70B9\u8FD4\u56DE\u7684\u641C\u7D22\u7ED3\u679C\u683C\u5F0F\u5F02\u5E38\n");
6682
+ process.exit(1);
6683
+ }
6684
+ if (opts.json) {
6685
+ console.log(JSON.stringify({ q, total: hits.length, hits }, null, 2));
6686
+ return;
6687
+ }
6688
+ if (hits.length === 0) {
6689
+ console.log(`
6690
+ \u6CA1\u6709\u5339\u914D\u300C${q}\u300D\u7684\u7ED3\u679C\u3002
6691
+ `);
6692
+ return;
6693
+ }
6694
+ console.log(`
6695
+ ${target.site.name} \u641C\u7D22\u300C${q}\u300D\uFF08${hits.length}\uFF09
6696
+ `);
6697
+ printCliTable(
6698
+ hits.map((h) => ({
6699
+ id: h.id != null ? String(h.id) : "-",
6700
+ title: h.title || "-",
6701
+ type: [h.type, h.subtype].filter(Boolean).join("/") || "-",
6702
+ url: h.url || "-"
6703
+ })),
6704
+ [
6705
+ { key: "id", header: "id" },
6706
+ { key: "title", header: "\u6807\u9898" },
6707
+ { key: "type", header: "\u7C7B\u578B" },
6708
+ { key: "url", header: "\u94FE\u63A5" }
6709
+ ]
6710
+ );
6711
+ console.log();
6712
+ }
6713
+ function register16(program2) {
6714
+ program2.command("search").description("\u5168\u7AD9\u641C\u7D22\uFF08\u9875\u9762/\u6587\u7AE0/\u5A92\u4F53\u7B49\uFF09").option("-s, --site <guidOrName>", "\u7AD9\u70B9 guid \u6216\u540D\u79F0").option("--url <url>", "\u76F4\u63A5\u6307\u5B9A\u7AD9\u70B9\u5730\u5740").requiredOption("-q, --q <keyword>", "\u5173\u952E\u8BCD").option("--type <subtype>", "\u9650\u5B9A rest \u5B50\u7C7B\u578B\uFF0C\u5982 page / post").option("--json", "\u8F93\u51FA JSON", false).option("--verbose", "\u8F93\u51FA\u8BF7\u6C42\u8BE6\u60C5", false).action(async (opts) => {
6715
+ await runSearch(opts);
4170
6716
  });
4171
6717
  }
4172
6718
 
4173
6719
  // src/index.ts
4174
6720
  installProcessHandlers();
4175
6721
  var program = new Command();
4176
- program.name("siluzan-website").description("Siluzan WordPress \u7AD9\u70B9\u7BA1\u7406\uFF1A\u5217\u51FA\u7AD9\u70B9\u3001\u65B0\u589E/\u7F16\u8F91\u9875\u9762\u3001\u67E5\u770B\u63D2\u4EF6").version(getCurrentVersion2());
6722
+ program.name("siluzan-website").description("Siluzan WordPress\uFF1A\u5F00\u901A\u5EFA\u7AD9\u3001\u7AD9\u70B9\u3001\u9875\u9762\u3001\u6587\u7AE0\u3001\u5A92\u4F53\u3001\u5206\u7C7B\u3001\u63D2\u4EF6\u3001AI \u63A8\u8350").version(getCurrentVersion2());
4177
6723
  var REGISTRARS = [
4178
6724
  register,
4179
6725
  register2,
4180
6726
  register3,
4181
6727
  register4,
4182
- register5,
4183
6728
  register6,
4184
- register7
6729
+ register7,
6730
+ register8,
6731
+ register9,
6732
+ register5,
6733
+ register10,
6734
+ register13,
6735
+ register14,
6736
+ register15,
6737
+ register16,
6738
+ register12,
6739
+ register11
4185
6740
  ];
4186
6741
  for (const reg of REGISTRARS) reg(program);
4187
6742
  program.parse();