siluzan-website-cli 1.0.1-beta.3 → 1.0.1-beta.4
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/README.md +1 -1
- package/dist/index.js +263 -70
- package/dist/skill/SKILL.md +1 -1
- package/dist/skill/_meta.json +2 -2
- package/dist/skill/references/plugins.md +7 -4
- package/dist/skill/scripts/install.ps1 +1 -1
- package/dist/skill/scripts/install.sh +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -22,7 +22,7 @@ siluzan-website content list --site <guid> --type posts
|
|
|
22
22
|
siluzan-website media upload --site <guid> --file ./hero.png
|
|
23
23
|
siluzan-website search --site <guid> --q "关于我们"
|
|
24
24
|
siluzan-website plugins list --site <guid>
|
|
25
|
-
siluzan-website plugins catalog
|
|
25
|
+
siluzan-website plugins catalog
|
|
26
26
|
siluzan-website plugins install --site <guid> --slug <slug>
|
|
27
27
|
siluzan-website plugins install --site <guid> --zip ./plugin.zip
|
|
28
28
|
siluzan-website plugins update --site <guid> --plugin <plugin>
|
package/dist/index.js
CHANGED
|
@@ -3317,6 +3317,7 @@ import { spawnSync } from "child_process";
|
|
|
3317
3317
|
var BUILD_ENV = "test";
|
|
3318
3318
|
var DEFAULT_API_BASE = "https://api-ci.siluzan.com";
|
|
3319
3319
|
var DEFAULT_CSO_BASE = "https://cso-ci.siluzan.com";
|
|
3320
|
+
var DEFAULT_CSO_PLUGIN_API = "https://cso-api-ci.siluzan.com";
|
|
3320
3321
|
var DEFAULT_WEB_BASE = "https://www-ci.siluzan.com";
|
|
3321
3322
|
var DEFAULT_SITE_STAGE = "ci";
|
|
3322
3323
|
|
|
@@ -3727,6 +3728,7 @@ function loadConfig() {
|
|
|
3727
3728
|
}
|
|
3728
3729
|
const apiBaseUrl = process.env.SILUZAN_WEBSITE_API_BASE ?? DEFAULT_API_BASE;
|
|
3729
3730
|
const csoBaseUrl = process.env.SILUZAN_CSO_BASE ?? DEFAULT_CSO_BASE;
|
|
3731
|
+
const csoPluginApiBaseUrl = process.env.SILUZAN_CSO_PLUGIN_API ?? DEFAULT_CSO_PLUGIN_API;
|
|
3730
3732
|
const apiErr = validateBaseUrl(apiBaseUrl);
|
|
3731
3733
|
if (apiErr) {
|
|
3732
3734
|
console.error(`
|
|
@@ -3739,9 +3741,16 @@ function loadConfig() {
|
|
|
3739
3741
|
\u274C csoBaseUrl \u4E0D\u5408\u6CD5\uFF1A${csoErr}`);
|
|
3740
3742
|
process.exit(1);
|
|
3741
3743
|
}
|
|
3744
|
+
const pluginApiErr = validateBaseUrl(csoPluginApiBaseUrl);
|
|
3745
|
+
if (pluginApiErr) {
|
|
3746
|
+
console.error(`
|
|
3747
|
+
\u274C csoPluginApiBaseUrl \u4E0D\u5408\u6CD5\uFF1A${pluginApiErr}`);
|
|
3748
|
+
process.exit(1);
|
|
3749
|
+
}
|
|
3742
3750
|
return {
|
|
3743
3751
|
apiBaseUrl,
|
|
3744
3752
|
csoBaseUrl,
|
|
3753
|
+
csoPluginApiBaseUrl,
|
|
3745
3754
|
authToken: "",
|
|
3746
3755
|
apiKey,
|
|
3747
3756
|
dataPermission: process.env.SILUZAN_DATA_PERMISSION ?? shared.dataPermission
|
|
@@ -4218,7 +4227,166 @@ function register6(program2) {
|
|
|
4218
4227
|
// src/commands/plugins.ts
|
|
4219
4228
|
import { readFileSync as readFileSync6, existsSync as existsSync3 } from "fs";
|
|
4220
4229
|
import { basename as basename2, resolve as resolve2 } from "path";
|
|
4221
|
-
|
|
4230
|
+
|
|
4231
|
+
// src/utils/wp-plugin-catalog.ts
|
|
4232
|
+
import * as http2 from "http";
|
|
4233
|
+
import * as https2 from "https";
|
|
4234
|
+
function trimSlash(url) {
|
|
4235
|
+
return url.replace(/\/+$/, "");
|
|
4236
|
+
}
|
|
4237
|
+
function pluginApiBases(config) {
|
|
4238
|
+
const seen = /* @__PURE__ */ new Set();
|
|
4239
|
+
const out = [];
|
|
4240
|
+
for (const raw of [config.csoPluginApiBaseUrl, config.csoBaseUrl]) {
|
|
4241
|
+
const base = trimSlash(raw || "");
|
|
4242
|
+
if (!base || seen.has(base)) continue;
|
|
4243
|
+
seen.add(base);
|
|
4244
|
+
out.push(base);
|
|
4245
|
+
}
|
|
4246
|
+
return out;
|
|
4247
|
+
}
|
|
4248
|
+
function isNetworkish(err) {
|
|
4249
|
+
const msg = err.message || "";
|
|
4250
|
+
return /fetch failed|ENOTFOUND|ECONNREFUSED|ETIMEDOUT|ECONNRESET|EPROTO|TLS|socket disconnected|certificate|HTTP 5\d\d/i.test(
|
|
4251
|
+
msg
|
|
4252
|
+
);
|
|
4253
|
+
}
|
|
4254
|
+
function compareVersion(a, b) {
|
|
4255
|
+
const pa = a.split(".").map((p) => Number(p) || 0);
|
|
4256
|
+
const pb = b.split(".").map((p) => Number(p) || 0);
|
|
4257
|
+
const n = Math.max(pa.length, pb.length);
|
|
4258
|
+
for (let i = 0; i < n; i++) {
|
|
4259
|
+
const da = pa[i] ?? 0;
|
|
4260
|
+
const db = pb[i] ?? 0;
|
|
4261
|
+
if (da !== db) return da - db;
|
|
4262
|
+
}
|
|
4263
|
+
return 0;
|
|
4264
|
+
}
|
|
4265
|
+
function versionFromPath(path6, filename) {
|
|
4266
|
+
const parts = path6.replace(/\\/g, "/").split("/").filter(Boolean);
|
|
4267
|
+
if (parts.length >= 2) return parts[1];
|
|
4268
|
+
const m = filename.match(/\.((?:\d+\.)*\d+)\.zip$/i);
|
|
4269
|
+
return m?.[1] ?? "";
|
|
4270
|
+
}
|
|
4271
|
+
function collectZips(nodes, out = []) {
|
|
4272
|
+
for (const node of nodes || []) {
|
|
4273
|
+
if (!node.isDirectory && /\.zip$/i.test(node.name || "") && node.url) {
|
|
4274
|
+
out.push(node);
|
|
4275
|
+
}
|
|
4276
|
+
if (node.children?.length) collectZips(node.children, out);
|
|
4277
|
+
}
|
|
4278
|
+
return out;
|
|
4279
|
+
}
|
|
4280
|
+
function flattenOfficialPlugins(items) {
|
|
4281
|
+
const best = /* @__PURE__ */ new Map();
|
|
4282
|
+
for (const zip of collectZips(items)) {
|
|
4283
|
+
const path6 = (zip.path || "").replace(/\\/g, "/");
|
|
4284
|
+
const filename = zip.name || path6.split("/").pop() || "";
|
|
4285
|
+
const slug = path6.split("/").filter(Boolean)[0] || filename.replace(/\.zip$/i, "");
|
|
4286
|
+
if (!slug) continue;
|
|
4287
|
+
const candidate = {
|
|
4288
|
+
slug,
|
|
4289
|
+
version: versionFromPath(path6, filename),
|
|
4290
|
+
filename,
|
|
4291
|
+
path: path6,
|
|
4292
|
+
size: Number(zip.size) || 0,
|
|
4293
|
+
url: zip.url || "",
|
|
4294
|
+
lastModified: zip.lastModified || ""
|
|
4295
|
+
};
|
|
4296
|
+
const prev = best.get(slug);
|
|
4297
|
+
if (!prev || compareVersion(candidate.version, prev.version) > 0) {
|
|
4298
|
+
best.set(slug, candidate);
|
|
4299
|
+
}
|
|
4300
|
+
}
|
|
4301
|
+
return [...best.values()].sort((a, b) => a.slug.localeCompare(b.slug));
|
|
4302
|
+
}
|
|
4303
|
+
async function fetchOfficialPluginList(config, opts = {}) {
|
|
4304
|
+
const params = new URLSearchParams();
|
|
4305
|
+
if (opts.prefix?.trim()) params.set("prefix", opts.prefix.trim());
|
|
4306
|
+
const qs = params.toString();
|
|
4307
|
+
const path6 = `/cso/v1/wp-plugin/list${qs ? `?${qs}` : ""}`;
|
|
4308
|
+
const bases = pluginApiBases(config);
|
|
4309
|
+
let lastErr;
|
|
4310
|
+
for (let i = 0; i < bases.length; i++) {
|
|
4311
|
+
const url = `${bases[i]}${path6}`;
|
|
4312
|
+
try {
|
|
4313
|
+
const raw = await apiFetch2(url, config, {}, opts.verbose);
|
|
4314
|
+
const code = raw.code;
|
|
4315
|
+
if (code !== void 0 && code !== 1) {
|
|
4316
|
+
throw new Error(raw.message || `\u76EE\u5F55\u63A5\u53E3\u8FD4\u56DE code=${code}`);
|
|
4317
|
+
}
|
|
4318
|
+
const data = raw.data || {};
|
|
4319
|
+
return {
|
|
4320
|
+
container: data.container || "wp-plugins",
|
|
4321
|
+
items: flattenOfficialPlugins(data.items)
|
|
4322
|
+
};
|
|
4323
|
+
} catch (e) {
|
|
4324
|
+
lastErr = e;
|
|
4325
|
+
if (i < bases.length - 1 && isNetworkish(lastErr)) {
|
|
4326
|
+
console.log(`\u76EE\u5F55\u63A5\u53E3 ${bases[i]} \u4E0D\u53EF\u8FBE\uFF0C\u6539\u8D70 ${bases[i + 1]} \u2026`);
|
|
4327
|
+
continue;
|
|
4328
|
+
}
|
|
4329
|
+
throw lastErr;
|
|
4330
|
+
}
|
|
4331
|
+
}
|
|
4332
|
+
throw lastErr || new Error("\u76EE\u5F55\u63A5\u53E3\u4E0D\u53EF\u7528");
|
|
4333
|
+
}
|
|
4334
|
+
async function findOfficialPlugin(config, slugOrPlugin, verbose = false) {
|
|
4335
|
+
const needle = slugOrPlugin.replace(/\\/g, "/").replace(/\.php$/i, "").toLowerCase();
|
|
4336
|
+
if (!needle) return null;
|
|
4337
|
+
const { items } = await fetchOfficialPluginList(config, { verbose });
|
|
4338
|
+
return items.find((p) => p.slug.toLowerCase() === needle) || items.find((p) => needle === p.slug.toLowerCase() || needle.startsWith(`${p.slug.toLowerCase()}/`)) || null;
|
|
4339
|
+
}
|
|
4340
|
+
function downloadOfficialZip(url) {
|
|
4341
|
+
return new Promise((resolve4, reject) => {
|
|
4342
|
+
let parsed;
|
|
4343
|
+
try {
|
|
4344
|
+
parsed = new URL(url);
|
|
4345
|
+
} catch {
|
|
4346
|
+
reject(new Error("\u76EE\u5F55\u5305\u5730\u5740\u4E0D\u5408\u6CD5"));
|
|
4347
|
+
return;
|
|
4348
|
+
}
|
|
4349
|
+
if (parsed.protocol !== "https:" && parsed.protocol !== "http:") {
|
|
4350
|
+
reject(new Error("\u76EE\u5F55\u5305\u5730\u5740\u5FC5\u987B\u662F http(s)"));
|
|
4351
|
+
return;
|
|
4352
|
+
}
|
|
4353
|
+
const transport = parsed.protocol === "https:" ? https2 : http2;
|
|
4354
|
+
const req = transport.get(url, { timeout: 12e4 }, (res) => {
|
|
4355
|
+
const status = res.statusCode ?? 0;
|
|
4356
|
+
if (status >= 300 && status < 400 && res.headers.location) {
|
|
4357
|
+
res.resume();
|
|
4358
|
+
downloadOfficialZip(res.headers.location).then(resolve4, reject);
|
|
4359
|
+
return;
|
|
4360
|
+
}
|
|
4361
|
+
if (status < 200 || status >= 300) {
|
|
4362
|
+
res.resume();
|
|
4363
|
+
reject(new Error(`\u4E0B\u8F7D\u76EE\u5F55\u5305\u5931\u8D25\uFF1AHTTP ${status}`));
|
|
4364
|
+
return;
|
|
4365
|
+
}
|
|
4366
|
+
const chunks = [];
|
|
4367
|
+
let size = 0;
|
|
4368
|
+
res.on("data", (chunk) => {
|
|
4369
|
+
size += chunk.length;
|
|
4370
|
+
if (size > 40 * 1024 * 1024) {
|
|
4371
|
+
res.destroy();
|
|
4372
|
+
reject(new Error("\u76EE\u5F55\u5305\u8D85\u8FC7 40MB"));
|
|
4373
|
+
return;
|
|
4374
|
+
}
|
|
4375
|
+
chunks.push(chunk);
|
|
4376
|
+
});
|
|
4377
|
+
res.on("end", () => resolve4(Buffer.concat(chunks)));
|
|
4378
|
+
res.on("error", reject);
|
|
4379
|
+
});
|
|
4380
|
+
req.on("timeout", () => {
|
|
4381
|
+
req.destroy();
|
|
4382
|
+
reject(new Error("\u4E0B\u8F7D\u76EE\u5F55\u5305\u8D85\u65F6"));
|
|
4383
|
+
});
|
|
4384
|
+
req.on("error", reject);
|
|
4385
|
+
});
|
|
4386
|
+
}
|
|
4387
|
+
|
|
4388
|
+
// src/commands/plugins.ts
|
|
4389
|
+
var MAX_ZIP_BYTES = 40 * 1024 * 1024;
|
|
4222
4390
|
var PROTECTED_PLUGIN_PREFIXES = ["siluzan-helper-plugin", "wp-oauth2"];
|
|
4223
4391
|
function isProtectedPlugin(plugin) {
|
|
4224
4392
|
const key = pluginKey(plugin);
|
|
@@ -4234,6 +4402,12 @@ function pluginName(item) {
|
|
|
4234
4402
|
function pluginKey(value) {
|
|
4235
4403
|
return value.replace(/\\/g, "/").replace(/\.php$/i, "").toLowerCase();
|
|
4236
4404
|
}
|
|
4405
|
+
function formatBytes(n) {
|
|
4406
|
+
if (!n) return "-";
|
|
4407
|
+
if (n < 1024) return `${n} B`;
|
|
4408
|
+
if (n < 1024 * 1024) return `${(n / 1024).toFixed(1)} KB`;
|
|
4409
|
+
return `${(n / 1024 / 1024).toFixed(1)} MB`;
|
|
4410
|
+
}
|
|
4237
4411
|
async function resolveTarget2(opts) {
|
|
4238
4412
|
const config = loadConfig();
|
|
4239
4413
|
const site = await resolveSite(config, opts);
|
|
@@ -4310,34 +4484,23 @@ async function runPluginsList(opts) {
|
|
|
4310
4484
|
if (opts.exitOnError === false) return;
|
|
4311
4485
|
process.exit(1);
|
|
4312
4486
|
}
|
|
4313
|
-
let
|
|
4487
|
+
let official = [];
|
|
4314
4488
|
try {
|
|
4315
|
-
|
|
4316
|
-
`${base}/wp-json/siluzan-helper/v1/plugins/catalog`,
|
|
4317
|
-
config,
|
|
4318
|
-
{},
|
|
4319
|
-
opts.verbose
|
|
4320
|
-
);
|
|
4321
|
-
catalog = Array.isArray(res.items) ? res.items : [];
|
|
4489
|
+
official = (await fetchOfficialPluginList(config, { verbose: opts.verbose })).items;
|
|
4322
4490
|
} catch {
|
|
4323
4491
|
}
|
|
4324
|
-
const
|
|
4325
|
-
for (const item of catalog) {
|
|
4326
|
-
if (item.plugin) catalogByKey.set(pluginKey(item.plugin), item);
|
|
4327
|
-
if (item.slug) catalogByKey.set(pluginKey(item.slug), item);
|
|
4328
|
-
}
|
|
4492
|
+
const officialBySlug = new Map(official.map((item) => [item.slug.toLowerCase(), item]));
|
|
4329
4493
|
const rows = plugins.map((p) => {
|
|
4330
4494
|
const plugin = p.plugin ?? "";
|
|
4331
|
-
const
|
|
4332
|
-
|
|
4333
|
-
if (hit?.update_available) updateSource = "catalog";
|
|
4495
|
+
const slug = pluginKey(plugin).split("/")[0];
|
|
4496
|
+
const hit = officialBySlug.get(slug);
|
|
4334
4497
|
return {
|
|
4335
4498
|
plugin,
|
|
4336
4499
|
name: pluginName(p),
|
|
4337
4500
|
status: p.status ?? "",
|
|
4338
4501
|
version: p.version ?? "",
|
|
4339
|
-
updateSource,
|
|
4340
|
-
catalogVersion: hit?.
|
|
4502
|
+
updateSource: hit ? "catalog" : "none",
|
|
4503
|
+
catalogVersion: hit?.version ?? ""
|
|
4341
4504
|
};
|
|
4342
4505
|
});
|
|
4343
4506
|
if (opts.json) {
|
|
@@ -4385,20 +4548,10 @@ ${site.name} \u5DF2\u88C5\u63D2\u4EF6\uFF08${rows.length}\uFF09
|
|
|
4385
4548
|
console.log();
|
|
4386
4549
|
}
|
|
4387
4550
|
async function runPluginsCatalog(opts) {
|
|
4388
|
-
const
|
|
4389
|
-
|
|
4390
|
-
let res;
|
|
4551
|
+
const config = loadConfig();
|
|
4552
|
+
let pack;
|
|
4391
4553
|
try {
|
|
4392
|
-
|
|
4393
|
-
opts,
|
|
4394
|
-
target,
|
|
4395
|
-
() => apiFetch2(
|
|
4396
|
-
`${base}/wp-json/siluzan-helper/v1/plugins/catalog`,
|
|
4397
|
-
target.config,
|
|
4398
|
-
{},
|
|
4399
|
-
opts.verbose
|
|
4400
|
-
)
|
|
4401
|
-
);
|
|
4554
|
+
pack = await fetchOfficialPluginList(config, { prefix: opts.prefix, verbose: opts.verbose });
|
|
4402
4555
|
} catch (e) {
|
|
4403
4556
|
console.error(`
|
|
4404
4557
|
\u274C \u83B7\u53D6\u63D2\u4EF6\u76EE\u5F55\u5931\u8D25\uFF1A${e.message}
|
|
@@ -4406,46 +4559,78 @@ async function runPluginsCatalog(opts) {
|
|
|
4406
4559
|
process.exit(1);
|
|
4407
4560
|
return;
|
|
4408
4561
|
}
|
|
4409
|
-
const
|
|
4562
|
+
const installedBySlug = /* @__PURE__ */ new Map();
|
|
4563
|
+
if (opts.site || opts.url) {
|
|
4564
|
+
try {
|
|
4565
|
+
const target = await resolveTarget2(opts);
|
|
4566
|
+
const plugins = await apiFetch2(
|
|
4567
|
+
`${target.base}/wp-json/wp/v2/plugins`,
|
|
4568
|
+
target.config,
|
|
4569
|
+
{},
|
|
4570
|
+
opts.verbose
|
|
4571
|
+
);
|
|
4572
|
+
if (Array.isArray(plugins)) {
|
|
4573
|
+
for (const p of plugins) {
|
|
4574
|
+
const slug = pluginKey(p.plugin || "").split("/")[0];
|
|
4575
|
+
if (slug) installedBySlug.set(slug, { version: p.version || "", status: p.status || "" });
|
|
4576
|
+
}
|
|
4577
|
+
}
|
|
4578
|
+
} catch {
|
|
4579
|
+
}
|
|
4580
|
+
}
|
|
4581
|
+
const rows = pack.items.map((p) => {
|
|
4582
|
+
const onSite = installedBySlug.get(p.slug.toLowerCase());
|
|
4583
|
+
return {
|
|
4584
|
+
slug: p.slug,
|
|
4585
|
+
version: p.version,
|
|
4586
|
+
size: formatBytes(p.size),
|
|
4587
|
+
installed: onSite ? "yes" : opts.site || opts.url ? "no" : "-",
|
|
4588
|
+
filename: p.filename
|
|
4589
|
+
};
|
|
4590
|
+
});
|
|
4410
4591
|
if (opts.json) {
|
|
4411
4592
|
console.log(
|
|
4412
|
-
JSON.stringify(
|
|
4413
|
-
{ site: { guid: site.guid, name: site.name, url: site.url }, total: items.length, items },
|
|
4414
|
-
null,
|
|
4415
|
-
2
|
|
4416
|
-
)
|
|
4593
|
+
JSON.stringify({ container: pack.container, total: pack.items.length, items: pack.items }, null, 2)
|
|
4417
4594
|
);
|
|
4418
4595
|
return;
|
|
4419
4596
|
}
|
|
4420
|
-
if (
|
|
4421
|
-
console.log(
|
|
4422
|
-
\u7AD9\u70B9 ${site.name} \u7684\u4E1D\u8DEF\u8D5E\u63D2\u4EF6\u76EE\u5F55\u4E3A\u7A7A\u3002
|
|
4423
|
-
`);
|
|
4597
|
+
if (rows.length === 0) {
|
|
4598
|
+
console.log("\n\u5B98\u65B9\u63D2\u4EF6\u76EE\u5F55\u4E3A\u7A7A\u3002\n");
|
|
4424
4599
|
return;
|
|
4425
4600
|
}
|
|
4426
|
-
const columns = [
|
|
4427
|
-
{ key: "slug", header: "slug" },
|
|
4428
|
-
{ key: "name", header: "\u540D\u79F0" },
|
|
4429
|
-
{ key: "new_version", header: "\u76EE\u5F55\u7248\u672C" },
|
|
4430
|
-
{ key: "installed", header: "\u5DF2\u88C5" },
|
|
4431
|
-
{ key: "active", header: "\u542F\u7528" },
|
|
4432
|
-
{ key: "update_available", header: "\u53EF\u66F4\u65B0" }
|
|
4433
|
-
];
|
|
4434
4601
|
console.log(`
|
|
4435
|
-
|
|
4602
|
+
\u5B98\u65B9\u63D2\u4EF6\u76EE\u5F55 ${pack.container}\uFF08${rows.length}\uFF09
|
|
4436
4603
|
`);
|
|
4437
|
-
printCliTable(
|
|
4438
|
-
|
|
4439
|
-
|
|
4440
|
-
|
|
4441
|
-
|
|
4442
|
-
|
|
4443
|
-
|
|
4444
|
-
|
|
4445
|
-
|
|
4446
|
-
|
|
4604
|
+
printCliTable(rows, [
|
|
4605
|
+
{ key: "slug", header: "slug" },
|
|
4606
|
+
{ key: "version", header: "\u76EE\u5F55\u7248\u672C" },
|
|
4607
|
+
{ key: "size", header: "\u5927\u5C0F" },
|
|
4608
|
+
{ key: "installed", header: "\u672C\u7AD9\u5DF2\u88C5" },
|
|
4609
|
+
{ key: "filename", header: "zip" }
|
|
4610
|
+
]);
|
|
4611
|
+
console.log("\n\u5B89\u88C5\uFF1Asiluzan-website plugins install --site <guid> --slug <slug>\n");
|
|
4612
|
+
}
|
|
4613
|
+
async function installOfficialZip(target, official, verbose = false) {
|
|
4614
|
+
if (official.size > MAX_ZIP_BYTES) {
|
|
4615
|
+
throw new Error(`\u76EE\u5F55\u5305 ${official.filename} \u8D85\u8FC7 40MB`);
|
|
4616
|
+
}
|
|
4617
|
+
console.log(`\u4ECE\u5B98\u65B9\u76EE\u5F55\u4E0B\u8F7D ${official.slug} ${official.version} \u2026`);
|
|
4618
|
+
const buf = await downloadOfficialZip(official.url);
|
|
4619
|
+
if (buf.length > MAX_ZIP_BYTES) {
|
|
4620
|
+
throw new Error(`\u76EE\u5F55\u5305 ${official.filename} \u8D85\u8FC7 40MB`);
|
|
4621
|
+
}
|
|
4622
|
+
return apiFetch2(
|
|
4623
|
+
`${target.base}/wp-json/siluzan-helper/v1/plugins/install-zip`,
|
|
4624
|
+
target.config,
|
|
4625
|
+
{
|
|
4626
|
+
method: "POST",
|
|
4627
|
+
body: JSON.stringify({
|
|
4628
|
+
filename: official.filename,
|
|
4629
|
+
zip_base64: buf.toString("base64")
|
|
4630
|
+
})
|
|
4631
|
+
},
|
|
4632
|
+
verbose
|
|
4447
4633
|
);
|
|
4448
|
-
console.log("\n\u5B89\u88C5 / \u5347\u7EA7\uFF1Asiluzan-website plugins install --site <guid> --slug <slug>\n");
|
|
4449
4634
|
}
|
|
4450
4635
|
async function runPluginsInstall(opts) {
|
|
4451
4636
|
const slug = opts.slug?.trim() ?? "";
|
|
@@ -4460,6 +4645,10 @@ async function runPluginsInstall(opts) {
|
|
|
4460
4645
|
try {
|
|
4461
4646
|
result = await withHelperBootstrap(opts, target, async () => {
|
|
4462
4647
|
if (slug) {
|
|
4648
|
+
const official = await findOfficialPlugin(target.config, slug, opts.verbose);
|
|
4649
|
+
if (official) {
|
|
4650
|
+
return installOfficialZip(target, official, opts.verbose);
|
|
4651
|
+
}
|
|
4463
4652
|
return apiFetch2(
|
|
4464
4653
|
`${base}/wp-json/siluzan-helper/v1/plugins/install`,
|
|
4465
4654
|
target.config,
|
|
@@ -4507,16 +4696,20 @@ async function runPluginsUpdate(opts) {
|
|
|
4507
4696
|
}
|
|
4508
4697
|
let result;
|
|
4509
4698
|
try {
|
|
4510
|
-
result = await withHelperBootstrap(
|
|
4511
|
-
|
|
4512
|
-
|
|
4513
|
-
|
|
4699
|
+
result = await withHelperBootstrap(opts, target, async () => {
|
|
4700
|
+
if (!zipPath) {
|
|
4701
|
+
const official = await findOfficialPlugin(target.config, plugin, opts.verbose);
|
|
4702
|
+
if (official) {
|
|
4703
|
+
return installOfficialZip(target, official, opts.verbose);
|
|
4704
|
+
}
|
|
4705
|
+
}
|
|
4706
|
+
return apiFetch2(
|
|
4514
4707
|
`${base}/wp-json/siluzan-helper/v1/plugins/update`,
|
|
4515
4708
|
target.config,
|
|
4516
4709
|
{ method: "POST", body: JSON.stringify(body) },
|
|
4517
4710
|
opts.verbose
|
|
4518
|
-
)
|
|
4519
|
-
);
|
|
4711
|
+
);
|
|
4712
|
+
});
|
|
4520
4713
|
} catch (e) {
|
|
4521
4714
|
const msg = e.message || "";
|
|
4522
4715
|
if (/HTTP 409/.test(msg) && /no_package/i.test(msg)) {
|
|
@@ -4682,10 +4875,10 @@ function register7(program2) {
|
|
|
4682
4875
|
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) => {
|
|
4683
4876
|
await runPluginsList(opts);
|
|
4684
4877
|
});
|
|
4685
|
-
plugins.command("catalog").description("\u5217\u51FA\
|
|
4878
|
+
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) => {
|
|
4686
4879
|
await runPluginsCatalog(opts);
|
|
4687
4880
|
});
|
|
4688
|
-
plugins.command("install").description("\u5B89\u88C5\u5E76\u542F\u7528\u63D2\u4EF6\uFF1A\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) => {
|
|
4881
|
+
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) => {
|
|
4689
4882
|
await runPluginsInstall(opts);
|
|
4690
4883
|
});
|
|
4691
4884
|
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) => {
|
package/dist/skill/SKILL.md
CHANGED
|
@@ -62,7 +62,7 @@ Windows 注意:部分 Agent 通过 PowerShell / cmd 代执行时可能失败
|
|
|
62
62
|
| 分类标签 | `references/terms.md` | `terms list` 再 add/update |
|
|
63
63
|
| 按关键词找内容 | `references/search.md` | `search --q` |
|
|
64
64
|
| 这个站装了哪些插件 | `references/plugins.md` | `plugins list`(全部已装,不只是目录) |
|
|
65
|
-
| 安装 / 启用目录插件 | `references/plugins.md` | `catalog
|
|
65
|
+
| 安装 / 启用目录插件 | `references/plugins.md` | `plugins catalog`(官方存储目录,含 AI 推荐)→ 确认 → `install --slug` |
|
|
66
66
|
| 安装外部插件 | `references/plugins.md` | 确认 → `install --zip` |
|
|
67
67
|
| 升级已装插件 | `references/plugins.md` | `list` 拿 plugin → 确认 → `update --plugin`;外部再加 `--zip` |
|
|
68
68
|
| 卸载插件 | `references/plugins.md` | `list` 拿 plugin → 确认 → `uninstall --plugin` |
|
package/dist/skill/_meta.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"slug": "siluzan-website",
|
|
3
|
-
"version": "1.0.1-beta.
|
|
4
|
-
"publishedAt":
|
|
3
|
+
"version": "1.0.1-beta.4",
|
|
4
|
+
"publishedAt": 1789699291560,
|
|
5
5
|
"homepage": "https://www.siluzan.com",
|
|
6
6
|
"source": "https://dev.azure.com/jack4it/Sammamish/_git/siluzan-skill",
|
|
7
7
|
"requiredBinaries": [
|
|
@@ -3,9 +3,10 @@
|
|
|
3
3
|
鉴权一律 **API Key(x-api-key)**。
|
|
4
4
|
|
|
5
5
|
- **已装列表**走 WordPress 核心 `GET /wp-json/wp/v2/plugins`,能看到站点上的全部插件。
|
|
6
|
-
-
|
|
6
|
+
- **可安装目录**走 CSO `GET /cso/v1/wp-plugin/list`(CI:`cso-api-ci.siluzan.com`,连不上回落 `cso-ci.siluzan.com`)。这是 sammk8s 存储账号 `wp-plugins` 容器,每个插件取最高版本 zip。
|
|
7
|
+
- **目录安装 / 无 zip 升级**:CLI 从官方目录下载 zip,再交给站点 helper 的 `install-zip`。不把任意 URL 交给 WordPress。
|
|
7
8
|
- **外部插件**首次安装和升级都带本地 `--zip`。zip 根目录必须是插件目录本身(`插件名/xxx.php`),不能再套一层版本号目录。
|
|
8
|
-
- helper 太旧、没有 REST 时,命令会先打 oauth2 `POST /wp-json/wposso/v1/helper/upgrade`,用镜像里的 `siluzan-helper-plugin.1.0.*.zip` 升 helper,再继续原来的操作。
|
|
9
|
+
- helper 太旧、没有 REST 时,命令会先打 oauth2 `POST /wp-json/wposso/v1/helper/upgrade`,用镜像里的 `siluzan-helper-plugin.1.0.*.zip` 升 helper,再继续原来的操作。
|
|
9
10
|
|
|
10
11
|
## 已装列表
|
|
11
12
|
|
|
@@ -21,10 +22,12 @@ siluzan-website plugins list --site <guid> --json
|
|
|
21
22
|
## 可安装目录
|
|
22
23
|
|
|
23
24
|
```bash
|
|
25
|
+
siluzan-website plugins catalog
|
|
26
|
+
siluzan-website plugins catalog --prefix zasp-smart-recommender/
|
|
24
27
|
siluzan-website plugins catalog --site <guid>
|
|
25
28
|
```
|
|
26
29
|
|
|
27
|
-
|
|
30
|
+
不传 `--site` 也能列。记下 `slug`。目录里有 `zasp-smart-recommender`(AI 推荐)等官方包。
|
|
28
31
|
|
|
29
32
|
## 安装
|
|
30
33
|
|
|
@@ -76,7 +79,7 @@ siluzan-website plugins update-helper --site <guid>
|
|
|
76
79
|
|
|
77
80
|
1. `sites list` 确定 guid
|
|
78
81
|
2. 用户要「装了哪些插件」→ `plugins list`
|
|
79
|
-
3. 用户要装目录插件 → `catalog
|
|
82
|
+
3. 用户要装目录插件 → `plugins catalog`(不用站点)对上 slug → 确认 → `install --slug`
|
|
80
83
|
4. 用户要升级已装插件 → `list` 拿到 `plugin` → 确认 → `update --plugin`;外部插件再加 `--zip`
|
|
81
84
|
5. 用户要卸载 → `list` 拿到 `plugin` → 确认不是 helper / oauth2 → `uninstall --plugin`
|
|
82
85
|
6. catalog / install / update 报路由 404 → 命令会自动 `update-helper` 再重试;oauth2 本身 404 / 401 → 告诉用户要先 SiteMan 镜像升级
|
|
@@ -9,7 +9,7 @@ $ErrorActionPreference = 'Stop'
|
|
|
9
9
|
# -- Package info (injected at build time) ------------------------------------
|
|
10
10
|
$PKG_NAME = 'siluzan-website-cli'
|
|
11
11
|
# PKG_VERSION 锁定到与本脚本同批构建产物一致的版本,避免与 dist/skill 错位
|
|
12
|
-
$PKG_VERSION = '1.0.1-beta.
|
|
12
|
+
$PKG_VERSION = '1.0.1-beta.4'
|
|
13
13
|
$CLI_BIN = 'siluzan-website'
|
|
14
14
|
$SKILL_LABEL = 'Siluzan Website'
|
|
15
15
|
$INSTALL_CMD = 'npm install -g siluzan-website-cli@beta'
|
|
@@ -9,7 +9,7 @@ set -euo pipefail
|
|
|
9
9
|
# -- Package info (injected at build time) ------------------------------------
|
|
10
10
|
readonly PKG_NAME="siluzan-website-cli"
|
|
11
11
|
# PKG_VERSION 锁定到与本脚本同批构建产物一致的版本,避免与 dist/skill 错位
|
|
12
|
-
readonly PKG_VERSION="1.0.1-beta.
|
|
12
|
+
readonly PKG_VERSION="1.0.1-beta.4"
|
|
13
13
|
readonly CLI_BIN="siluzan-website"
|
|
14
14
|
readonly SKILL_LABEL="Siluzan Website"
|
|
15
15
|
readonly INSTALL_CMD="npm install -g siluzan-website-cli@beta"
|