siluzan-cso-cli 1.1.8-beta.6 → 1.1.9-beta.2
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 +31 -1
- package/dist/index.js +60 -200
- package/dist/skill/SKILL.md +57 -6
- package/dist/skill/_meta.json +18 -2
- package/dist/skill/references/setup.md +1 -1
- package/package.json +11 -3
package/README.md
CHANGED
|
@@ -2,6 +2,36 @@
|
|
|
2
2
|
|
|
3
3
|
当用户发来本页面的 **URL** 时,请按顺序协助用户完成安装。
|
|
4
4
|
|
|
5
|
+
## 0. 安全与透明性说明
|
|
6
|
+
|
|
7
|
+
本 Skill 是 **instruction-only**(纯指令型),不包含可执行代码文件。它通过指导 AI 助手调用 `siluzan-cso` CLI 来操作丝路赞内容发布平台。
|
|
8
|
+
|
|
9
|
+
### 运行时依赖
|
|
10
|
+
| 项目 | 说明 |
|
|
11
|
+
|------|------|
|
|
12
|
+
| **Node.js 18+** | CLI 运行时 |
|
|
13
|
+
| **npm 8+** 或 **pnpm** | 安装 CLI 全局包 |
|
|
14
|
+
| **siluzan-cso** CLI | 由 `npm install -g siluzan-cso-cli` 安装 |
|
|
15
|
+
| **ffmpeg**(可选) | `extract-cover` 命令截取视频封面帧 |
|
|
16
|
+
|
|
17
|
+
### 凭据与网络
|
|
18
|
+
| 项目 | 说明 |
|
|
19
|
+
|------|------|
|
|
20
|
+
| API Key / Token | 存储在 `~/.siluzan/config.json`,用于所有 API 调用鉴权 |
|
|
21
|
+
| CSO API | `api.siluzan.com`(生产)/ `api-ci.siluzan.com`(测试) |
|
|
22
|
+
| 前端页面 | `cso.siluzan.com`(授权回调等浏览器操作) |
|
|
23
|
+
| 版本检查 | `registry.npmjs.org` |
|
|
24
|
+
|
|
25
|
+
### 可选环境变量
|
|
26
|
+
| 变量 | 说明 |
|
|
27
|
+
|------|------|
|
|
28
|
+
| `SILUZAN_AUTH_TOKEN` | 从环境变量读取 Token(优先级高于 config.json,CI/CD 推荐) |
|
|
29
|
+
|
|
30
|
+
### 可执行的操作范围
|
|
31
|
+
- **只读**:查询媒体账号、运营报表、发布任务状态、人设列表、RAG 知识库检索等
|
|
32
|
+
- **写入**(需用户确认):上传素材、提交发布任务、创建/更新账号分组、生成 AI 内容规划
|
|
33
|
+
- **本地文件操作**:`extract-cover` 截取视频帧输出图片;`init` 将 Skill 文件写入 AI 助手目录
|
|
34
|
+
|
|
5
35
|
## 1. 环境
|
|
6
36
|
|
|
7
37
|
- Node.js **18+**
|
|
@@ -20,7 +50,7 @@ siluzan-cso init -d /path/to/skills # 写入自定义目录
|
|
|
20
50
|
siluzan-cso init --force # 强制覆盖已存在文件
|
|
21
51
|
```
|
|
22
52
|
|
|
23
|
-
> **注意**:当前为测试版(1.1.
|
|
53
|
+
> **注意**:当前为测试版(1.1.9-beta.2),供内部测试使用。正式发布后安装命令将改为 `npm install -g siluzan-cso-cli`。
|
|
24
54
|
|
|
25
55
|
| 助手 | 建议 `--ai` |
|
|
26
56
|
|------|-------------|
|
package/dist/index.js
CHANGED
|
@@ -342,8 +342,8 @@ var require_semver = __commonJS({
|
|
|
342
342
|
}
|
|
343
343
|
// preminor will bump the version up to the next minor release, and immediately
|
|
344
344
|
// down to pre-release. premajor and prepatch work the same way.
|
|
345
|
-
inc(
|
|
346
|
-
if (
|
|
345
|
+
inc(release, identifier, identifierBase) {
|
|
346
|
+
if (release.startsWith("pre")) {
|
|
347
347
|
if (!identifier && identifierBase === false) {
|
|
348
348
|
throw new Error("invalid increment argument: identifier is empty");
|
|
349
349
|
}
|
|
@@ -354,7 +354,7 @@ var require_semver = __commonJS({
|
|
|
354
354
|
}
|
|
355
355
|
}
|
|
356
356
|
}
|
|
357
|
-
switch (
|
|
357
|
+
switch (release) {
|
|
358
358
|
case "premajor":
|
|
359
359
|
this.prerelease.length = 0;
|
|
360
360
|
this.patch = 0;
|
|
@@ -445,7 +445,7 @@ var require_semver = __commonJS({
|
|
|
445
445
|
break;
|
|
446
446
|
}
|
|
447
447
|
default:
|
|
448
|
-
throw new Error(`invalid increment argument: ${
|
|
448
|
+
throw new Error(`invalid increment argument: ${release}`);
|
|
449
449
|
}
|
|
450
450
|
this.raw = this.format();
|
|
451
451
|
if (this.build.length) {
|
|
@@ -511,7 +511,7 @@ var require_inc = __commonJS({
|
|
|
511
511
|
"../node_modules/.pnpm/semver@7.7.4/node_modules/semver/functions/inc.js"(exports, module) {
|
|
512
512
|
"use strict";
|
|
513
513
|
var SemVer = require_semver();
|
|
514
|
-
var inc = (version,
|
|
514
|
+
var inc = (version, release, options, identifier, identifierBase) => {
|
|
515
515
|
if (typeof options === "string") {
|
|
516
516
|
identifierBase = identifier;
|
|
517
517
|
identifier = options;
|
|
@@ -521,7 +521,7 @@ var require_inc = __commonJS({
|
|
|
521
521
|
return new SemVer(
|
|
522
522
|
version instanceof SemVer ? version.version : version,
|
|
523
523
|
options
|
|
524
|
-
).inc(
|
|
524
|
+
).inc(release, identifier, identifierBase).version;
|
|
525
525
|
} catch (er) {
|
|
526
526
|
return null;
|
|
527
527
|
}
|
|
@@ -2129,7 +2129,6 @@ import { randomUUID as _randomUUID } from "crypto";
|
|
|
2129
2129
|
import * as fs22 from "fs";
|
|
2130
2130
|
import * as path22 from "path";
|
|
2131
2131
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
2132
|
-
import * as os22 from "os";
|
|
2133
2132
|
var SILUZAN_DIR = path3.join(os2.homedir(), ".siluzan");
|
|
2134
2133
|
var CONFIG_FILE = path3.join(SILUZAN_DIR, "config.json");
|
|
2135
2134
|
function readStr(raw, key) {
|
|
@@ -2210,21 +2209,33 @@ function validateBaseUrl(raw) {
|
|
|
2210
2209
|
}
|
|
2211
2210
|
return null;
|
|
2212
2211
|
}
|
|
2212
|
+
var DEFAULT_TIMEOUT_MS = 10 * 60 * 1e3;
|
|
2213
|
+
var MAX_RESPONSE_BYTES = 50 * 1024 * 1024;
|
|
2213
2214
|
function rawRequest(url, options) {
|
|
2214
2215
|
return new Promise((resolve6, reject) => {
|
|
2215
2216
|
const parsed = new URL(url);
|
|
2216
2217
|
const transport = parsed.protocol === "https:" ? https : http;
|
|
2218
|
+
const timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;
|
|
2219
|
+
const maxBytes = options.maxResponseBytes ?? MAX_RESPONSE_BYTES;
|
|
2217
2220
|
const reqOpts = {
|
|
2218
2221
|
hostname: parsed.hostname,
|
|
2219
2222
|
port: parsed.port || (parsed.protocol === "https:" ? 443 : 80),
|
|
2220
2223
|
path: parsed.pathname + parsed.search,
|
|
2221
2224
|
method: options.method ?? "GET",
|
|
2222
|
-
headers: options.headers
|
|
2225
|
+
headers: options.headers,
|
|
2226
|
+
timeout: timeoutMs || void 0
|
|
2223
2227
|
};
|
|
2224
2228
|
const req = transport.request(reqOpts, (res) => {
|
|
2225
2229
|
let data = "";
|
|
2230
|
+
let byteLen = 0;
|
|
2226
2231
|
res.setEncoding("utf8");
|
|
2227
2232
|
res.on("data", (chunk) => {
|
|
2233
|
+
byteLen += Buffer.byteLength(chunk, "utf8");
|
|
2234
|
+
if (maxBytes && byteLen > maxBytes) {
|
|
2235
|
+
res.destroy();
|
|
2236
|
+
reject(new Error(`\u54CD\u5E94\u4F53\u8D85\u8FC7\u4E0A\u9650\uFF08${(maxBytes / 1024 / 1024).toFixed(0)} MB\uFF09\uFF0C\u5DF2\u4E2D\u65AD\u8FDE\u63A5`));
|
|
2237
|
+
return;
|
|
2238
|
+
}
|
|
2228
2239
|
data += chunk;
|
|
2229
2240
|
});
|
|
2230
2241
|
res.on("end", () => {
|
|
@@ -2237,6 +2248,10 @@ function rawRequest(url, options) {
|
|
|
2237
2248
|
resolve6({ status: res.statusCode ?? 0, text: data, headers });
|
|
2238
2249
|
});
|
|
2239
2250
|
});
|
|
2251
|
+
req.on("timeout", () => {
|
|
2252
|
+
req.destroy();
|
|
2253
|
+
reject(new Error(`\u8BF7\u6C42\u8D85\u65F6\uFF08${(timeoutMs / 1e3).toFixed(0)} \u79D2\uFF09\uFF1A${options.method ?? "GET"} ${url}`));
|
|
2254
|
+
});
|
|
2240
2255
|
req.on("error", reject);
|
|
2241
2256
|
if (options.body) req.write(options.body);
|
|
2242
2257
|
req.end();
|
|
@@ -2332,140 +2347,29 @@ async function fetchNpmVersion(pkgName, tag, timeoutMs = 4e3) {
|
|
|
2332
2347
|
return null;
|
|
2333
2348
|
}
|
|
2334
2349
|
}
|
|
2335
|
-
|
|
2336
|
-
function isSentryDisabled() {
|
|
2337
|
-
return process.env.SILUZAN_SENTRY_DISABLED === "1" || process.env.SILUZAN_SENTRY_DISABLED === "true";
|
|
2338
|
-
}
|
|
2339
|
-
function getDsn() {
|
|
2340
|
-
return process.env.SILUZAN_SENTRY_DSN?.trim() || DEFAULT_SENTRY_DSN;
|
|
2341
|
-
}
|
|
2342
|
-
var cliMeta = { name: "siluzan-cli", version: "unknown" };
|
|
2343
|
-
var cliInvocation = "";
|
|
2344
|
-
function setSiluzanCliInvocation(redactedCommandLine) {
|
|
2345
|
-
cliInvocation = redactedCommandLine;
|
|
2346
|
-
}
|
|
2347
|
-
function redactCliArgvForSentry(argv) {
|
|
2348
|
-
const args = argv.slice(2);
|
|
2349
|
-
const redactNext = /* @__PURE__ */ new Set(["-t", "--token", "--api-key", "--password"]);
|
|
2350
|
-
const out = [];
|
|
2351
|
-
for (let i = 0; i < args.length; i++) {
|
|
2352
|
-
const a = args[i];
|
|
2353
|
-
if (redactNext.has(a)) {
|
|
2354
|
-
out.push(a, "***");
|
|
2355
|
-
i++;
|
|
2356
|
-
continue;
|
|
2357
|
-
}
|
|
2358
|
-
const eq = a.indexOf("=");
|
|
2359
|
-
if (eq > 0) {
|
|
2360
|
-
const key = a.slice(0, eq).toLowerCase();
|
|
2361
|
-
if (key === "--token" || key === "--api-key" || key === "--password") {
|
|
2362
|
-
out.push(`${a.slice(0, eq)}=***`);
|
|
2363
|
-
continue;
|
|
2364
|
-
}
|
|
2365
|
-
}
|
|
2366
|
-
if (/^-t[^-]/.test(a) && a.length > 3) {
|
|
2367
|
-
out.push("-t***");
|
|
2368
|
-
continue;
|
|
2369
|
-
}
|
|
2370
|
-
out.push(a);
|
|
2371
|
-
}
|
|
2372
|
-
return out.join(" ");
|
|
2373
|
-
}
|
|
2374
|
-
function setSiluzanCliMeta(name, version) {
|
|
2375
|
-
cliMeta = { name, version };
|
|
2376
|
-
if (sentryReady) {
|
|
2377
|
-
void import("@sentry/node").then((Sentry) => {
|
|
2378
|
-
Sentry.setTag("cli", name);
|
|
2379
|
-
Sentry.setTag("cli_version", version);
|
|
2380
|
-
}).catch(() => {
|
|
2381
|
-
});
|
|
2382
|
-
}
|
|
2383
|
-
}
|
|
2384
|
-
var sentryReady = false;
|
|
2385
|
-
var sentryInitPromise = null;
|
|
2386
|
-
var flushHookRegistered = false;
|
|
2387
|
-
function buildRuntimeContext() {
|
|
2388
|
-
const platform = process.platform;
|
|
2389
|
-
const osName = platform === "win32" ? "Windows" : platform === "darwin" ? "macOS" : "Linux";
|
|
2390
|
-
return {
|
|
2391
|
-
os: {
|
|
2392
|
-
name: osName,
|
|
2393
|
-
version: os22.release(),
|
|
2394
|
-
// 内核版本,如 10.0.26100(Win11)、24.3.0(macOS)
|
|
2395
|
-
arch: process.arch
|
|
2396
|
-
// x64 / arm64
|
|
2397
|
-
},
|
|
2398
|
-
runtime: {
|
|
2399
|
-
node_version: process.version,
|
|
2400
|
-
// v18.x.x / v20.x.x
|
|
2401
|
-
timezone: Intl.DateTimeFormat().resolvedOptions().timeZone
|
|
2402
|
-
}
|
|
2403
|
-
};
|
|
2404
|
-
}
|
|
2405
|
-
async function ensureSentryInitialized(requestUrl) {
|
|
2406
|
-
const dsn = getDsn();
|
|
2407
|
-
if (!dsn || isSentryDisabled()) return false;
|
|
2408
|
-
if (sentryReady) return true;
|
|
2409
|
-
if (!sentryInitPromise) {
|
|
2410
|
-
sentryInitPromise = (async () => {
|
|
2411
|
-
const Sentry = await import("@sentry/node");
|
|
2412
|
-
const envOverride = process.env.SILUZAN_SENTRY_ENV?.trim();
|
|
2413
|
-
const environment = envOverride || (inferSiluzanRuntimeEnvironment(requestUrl) === "test" ? "test" : "production");
|
|
2414
|
-
Sentry.init({
|
|
2415
|
-
dsn,
|
|
2416
|
-
environment,
|
|
2417
|
-
sendDefaultPii: true,
|
|
2418
|
-
tracesSampleRate: 0
|
|
2419
|
-
});
|
|
2420
|
-
const ctx = buildRuntimeContext();
|
|
2421
|
-
Sentry.setContext("os", ctx.os);
|
|
2422
|
-
Sentry.setContext("runtime", ctx.runtime);
|
|
2423
|
-
Sentry.setTag("cli", cliMeta.name);
|
|
2424
|
-
Sentry.setTag("cli_version", cliMeta.version);
|
|
2425
|
-
if (!flushHookRegistered) {
|
|
2426
|
-
flushHookRegistered = true;
|
|
2427
|
-
process.once("beforeExit", () => {
|
|
2428
|
-
void Sentry.flush(2e3).catch(() => {
|
|
2429
|
-
});
|
|
2430
|
-
});
|
|
2431
|
-
}
|
|
2432
|
-
sentryReady = true;
|
|
2433
|
-
})();
|
|
2434
|
-
}
|
|
2435
|
-
await sentryInitPromise;
|
|
2436
|
-
return sentryReady;
|
|
2437
|
-
}
|
|
2438
|
-
function deriveMainApiOriginFromRequestUrl(requestUrl) {
|
|
2350
|
+
function deriveMainApiOrigin(apiBase) {
|
|
2439
2351
|
try {
|
|
2440
|
-
const u = new URL(
|
|
2352
|
+
const u = new URL(apiBase);
|
|
2441
2353
|
const host = u.hostname.toLowerCase();
|
|
2442
|
-
if (!host.endsWith("siluzan.com"))
|
|
2354
|
+
if (!host.endsWith("siluzan.com")) {
|
|
2355
|
+
return apiBase.includes("-ci") ? "https://api-ci.siluzan.com" : "https://api.siluzan.com";
|
|
2356
|
+
}
|
|
2443
2357
|
if (host.startsWith("tso-api")) {
|
|
2444
2358
|
return `${u.protocol}//${host.replace(/^tso-api/, "api")}`;
|
|
2445
2359
|
}
|
|
2446
2360
|
if (host === "api.siluzan.com" || host === "api-ci.siluzan.com") {
|
|
2447
2361
|
return `${u.protocol}//${host}`;
|
|
2448
2362
|
}
|
|
2449
|
-
return
|
|
2450
|
-
} catch {
|
|
2451
|
-
return null;
|
|
2452
|
-
}
|
|
2453
|
-
}
|
|
2454
|
-
function inferSiluzanRuntimeEnvironment(requestUrl) {
|
|
2455
|
-
try {
|
|
2456
|
-
const host = new URL(requestUrl).hostname.toLowerCase();
|
|
2457
|
-
return host.includes("-ci") ? "test" : "production";
|
|
2363
|
+
return apiBase.includes("-ci") ? "https://api-ci.siluzan.com" : "https://api.siluzan.com";
|
|
2458
2364
|
} catch {
|
|
2459
|
-
return "
|
|
2365
|
+
return apiBase.includes("-ci") ? "https://api-ci.siluzan.com" : "https://api.siluzan.com";
|
|
2460
2366
|
}
|
|
2461
2367
|
}
|
|
2462
|
-
function
|
|
2463
|
-
const
|
|
2464
|
-
return
|
|
2368
|
+
function pickStr(obj, key) {
|
|
2369
|
+
const v = obj[key];
|
|
2370
|
+
return typeof v === "string" && v.trim() ? v.trim() : void 0;
|
|
2465
2371
|
}
|
|
2466
|
-
|
|
2467
|
-
var userContextInflight = /* @__PURE__ */ new Map();
|
|
2468
|
-
function pickCompanyIdFromMe(data) {
|
|
2372
|
+
function pickCompanyId(data) {
|
|
2469
2373
|
const direct = pickStr(data, "companyId") ?? pickStr(data, "companyID") ?? pickStr(data, "CompanyId");
|
|
2470
2374
|
if (direct) return direct;
|
|
2471
2375
|
const ci = data["companyInfo"];
|
|
@@ -2482,40 +2386,15 @@ function parseMeResponse(text) {
|
|
|
2482
2386
|
const id = pickStr(data, "entityId") ?? pickStr(data, "id") ?? pickStr(data, "userId") ?? pickStr(data, "accountId");
|
|
2483
2387
|
const email = pickStr(data, "email");
|
|
2484
2388
|
const username = pickStr(data, "userName") ?? pickStr(data, "username") ?? pickStr(data, "name") ?? pickStr(data, "phone");
|
|
2485
|
-
const companyId =
|
|
2389
|
+
const companyId = pickCompanyId(data);
|
|
2486
2390
|
if (!id && !email && !username && !companyId) return null;
|
|
2487
2391
|
return { id, email, username, companyId };
|
|
2488
2392
|
} catch {
|
|
2489
2393
|
return null;
|
|
2490
2394
|
}
|
|
2491
2395
|
}
|
|
2492
|
-
function pickStr(obj, key) {
|
|
2493
|
-
const v = obj[key];
|
|
2494
|
-
return typeof v === "string" && v.trim() ? v.trim() : void 0;
|
|
2495
|
-
}
|
|
2496
|
-
async function fetchAndSetUser(mainOrigin, config) {
|
|
2497
|
-
const meUrl = `${mainOrigin.replace(/\/$/, "")}/query/account/me`;
|
|
2498
|
-
const authHeaders = config.apiKey ? { "x-api-key": config.apiKey } : { Authorization: `Bearer ${config.authToken}` };
|
|
2499
|
-
const res = await rawRequest(meUrl, {
|
|
2500
|
-
method: "GET",
|
|
2501
|
-
headers: {
|
|
2502
|
-
"Content-Type": "application/json",
|
|
2503
|
-
"Accept-Language": "zh-CN",
|
|
2504
|
-
...authHeaders
|
|
2505
|
-
}
|
|
2506
|
-
});
|
|
2507
|
-
if (res.status < 200 || res.status >= 300) return;
|
|
2508
|
-
const parsed = parseMeResponse(res.text);
|
|
2509
|
-
if (!parsed) return;
|
|
2510
|
-
const Sentry = await import("@sentry/node");
|
|
2511
|
-
const user = {};
|
|
2512
|
-
if (parsed.id) user.id = parsed.id;
|
|
2513
|
-
if (parsed.email) user.email = parsed.email;
|
|
2514
|
-
if (parsed.username) user.username = parsed.username;
|
|
2515
|
-
Sentry.setUser(user);
|
|
2516
|
-
}
|
|
2517
2396
|
async function fetchSiluzanCurrentUser(apiBase, config) {
|
|
2518
|
-
const mainOrigin =
|
|
2397
|
+
const mainOrigin = deriveMainApiOrigin(apiBase);
|
|
2519
2398
|
const meUrl = `${mainOrigin.replace(/\/$/, "")}/query/account/me`;
|
|
2520
2399
|
const authHeaders = config.apiKey ? { "x-api-key": config.apiKey } : { Authorization: `Bearer ${config.authToken}` };
|
|
2521
2400
|
try {
|
|
@@ -2540,38 +2419,6 @@ async function fetchSiluzanCurrentUser(apiBase, config) {
|
|
|
2540
2419
|
return null;
|
|
2541
2420
|
}
|
|
2542
2421
|
}
|
|
2543
|
-
function scheduleUserContext(mainOrigin, config) {
|
|
2544
|
-
const key = cacheKeyForUser(mainOrigin, config);
|
|
2545
|
-
if (userContextDone.has(key)) return;
|
|
2546
|
-
let p = userContextInflight.get(key);
|
|
2547
|
-
if (!p) {
|
|
2548
|
-
p = (async () => {
|
|
2549
|
-
try {
|
|
2550
|
-
await fetchAndSetUser(mainOrigin, config);
|
|
2551
|
-
} catch {
|
|
2552
|
-
} finally {
|
|
2553
|
-
userContextInflight.delete(key);
|
|
2554
|
-
userContextDone.add(key);
|
|
2555
|
-
}
|
|
2556
|
-
})();
|
|
2557
|
-
userContextInflight.set(key, p);
|
|
2558
|
-
}
|
|
2559
|
-
}
|
|
2560
|
-
function refreshSiluzanUser(apiBase, config) {
|
|
2561
|
-
if (isSentryDisabled()) return;
|
|
2562
|
-
void (async () => {
|
|
2563
|
-
try {
|
|
2564
|
-
const ok = await ensureSentryInitialized(apiBase);
|
|
2565
|
-
if (!ok) return;
|
|
2566
|
-
const mainOrigin = deriveMainApiOriginFromRequestUrl(apiBase) ?? (apiBase.includes("-ci") ? "https://api-ci.siluzan.com" : "https://api.siluzan.com");
|
|
2567
|
-
const key = cacheKeyForUser(mainOrigin, config);
|
|
2568
|
-
userContextDone.delete(key);
|
|
2569
|
-
userContextInflight.delete(key);
|
|
2570
|
-
scheduleUserContext(mainOrigin, config);
|
|
2571
|
-
} catch {
|
|
2572
|
-
}
|
|
2573
|
-
})();
|
|
2574
|
-
}
|
|
2575
2422
|
|
|
2576
2423
|
// src/commands/login.ts
|
|
2577
2424
|
async function runLogin(opts = {}) {
|
|
@@ -2582,7 +2429,6 @@ async function runLogin(opts = {}) {
|
|
|
2582
2429
|
process.exit(1);
|
|
2583
2430
|
}
|
|
2584
2431
|
writeSharedConfig({ authToken: token });
|
|
2585
|
-
refreshSiluzanUser(DEFAULT_API_BASE, { authToken: token });
|
|
2586
2432
|
console.log(`
|
|
2587
2433
|
\u2705 Token \u5DF2\u4FDD\u5B58\uFF08${maskSecret(token)}\uFF09`);
|
|
2588
2434
|
console.log(` \u914D\u7F6E\u6587\u4EF6\uFF1A${CONFIG_FILE}`);
|
|
@@ -2597,7 +2443,6 @@ async function runLogin(opts = {}) {
|
|
|
2597
2443
|
process.exit(1);
|
|
2598
2444
|
}
|
|
2599
2445
|
writeSharedConfig({ apiKey: key });
|
|
2600
|
-
refreshSiluzanUser(DEFAULT_API_BASE, { authToken: "", apiKey: key });
|
|
2601
2446
|
console.log(`
|
|
2602
2447
|
\u2705 API Key \u5DF2\u4FDD\u5B58\uFF08${maskSecret(key)}\uFF09`);
|
|
2603
2448
|
console.log(` \u914D\u7F6E\u6587\u4EF6\uFF1A${CONFIG_FILE}`);
|
|
@@ -2638,7 +2483,6 @@ async function runLogin(opts = {}) {
|
|
|
2638
2483
|
process.exit(1);
|
|
2639
2484
|
}
|
|
2640
2485
|
writeSharedConfig({ apiKey });
|
|
2641
|
-
refreshSiluzanUser(DEFAULT_API_BASE, { authToken: "", apiKey });
|
|
2642
2486
|
console.log(`
|
|
2643
2487
|
\u2705 API Key \u5DF2\u4FDD\u5B58\uFF08${maskSecret(apiKey)}\uFF09`);
|
|
2644
2488
|
console.log(` \u914D\u7F6E\u6587\u4EF6\uFF1A${CONFIG_FILE}`);
|
|
@@ -2823,6 +2667,7 @@ async function runUpdate(options) {
|
|
|
2823
2667
|
}
|
|
2824
2668
|
console.log(`
|
|
2825
2669
|
\u{1F504} \u6B63\u5728\u66F4\u65B0 ${targets.length} \u5904 skill \u5B89\u88C5\u4F4D\u7F6E \u2026`);
|
|
2670
|
+
let failCount = 0;
|
|
2826
2671
|
for (const entry of targets) {
|
|
2827
2672
|
const label = entry.target === "custom" ? entry.dir ?? "unknown" : entry.target;
|
|
2828
2673
|
const cwd = entry.cwd || os4.homedir();
|
|
@@ -2846,9 +2691,16 @@ async function runUpdate(options) {
|
|
|
2846
2691
|
});
|
|
2847
2692
|
}
|
|
2848
2693
|
} catch (e) {
|
|
2694
|
+
failCount++;
|
|
2849
2695
|
console.error(` \u274C \u66F4\u65B0\u5931\u8D25\uFF1A${e.message}`);
|
|
2850
2696
|
}
|
|
2851
2697
|
}
|
|
2698
|
+
if (failCount > 0) {
|
|
2699
|
+
console.error(`
|
|
2700
|
+
\u26A0\uFE0F ${targets.length} \u5904\u5B89\u88C5\u4F4D\u7F6E\u4E2D\u6709 ${failCount} \u5904\u66F4\u65B0\u5931\u8D25\uFF0C\u8BF7\u68C0\u67E5\u4E0A\u65B9\u9519\u8BEF\u4FE1\u606F\u3002`);
|
|
2701
|
+
console.log(" \u5982\u679C AI \u52A9\u624B\u6B63\u5728\u8FD0\u884C\uFF0C\u5EFA\u8BAE\u91CD\u542F\u4EE5\u4F7F\u5DF2\u6210\u529F\u7684 skill \u6587\u4EF6\u751F\u6548\u3002\n");
|
|
2702
|
+
process.exit(1);
|
|
2703
|
+
}
|
|
2852
2704
|
console.log("\n\u2705 \u5168\u90E8 skill \u6587\u4EF6\u5DF2\u5237\u65B0\u3002");
|
|
2853
2705
|
console.log(" \u5982\u679C AI \u52A9\u624B\u6B63\u5728\u8FD0\u884C\uFF0C\u5EFA\u8BAE\u91CD\u542F\u4EE5\u4F7F\u65B0 skill \u6587\u4EF6\u751F\u6548\u3002\n");
|
|
2854
2706
|
}
|
|
@@ -2885,7 +2737,6 @@ function loadConfig(tokenArg) {
|
|
|
2885
2737
|
\u274C agentBaseUrl \u4E0D\u5408\u6CD5\uFF1A${agentErr}`);
|
|
2886
2738
|
process.exit(1);
|
|
2887
2739
|
}
|
|
2888
|
-
setSiluzanCliMeta("siluzan-cso", getCurrentVersion2());
|
|
2889
2740
|
return { apiBaseUrl, csoBaseUrl, agentBaseUrl, authToken, apiKey, dataPermission: shared.dataPermission };
|
|
2890
2741
|
}
|
|
2891
2742
|
function apiFetch2(url, config, options = {}, verbose = false) {
|
|
@@ -3045,8 +2896,7 @@ async function runListAccounts(options) {
|
|
|
3045
2896
|
mediaCustomerName: a.mediaCustomerName,
|
|
3046
2897
|
mediaAccountState: a.mediaAccountState ?? "",
|
|
3047
2898
|
invalidOAuthToken: a.invalidOAuthToken ?? false,
|
|
3048
|
-
|
|
3049
|
-
expiresOn: a.expiresOn ?? a.tokenTime ?? null,
|
|
2899
|
+
expiresOn: a.expiresOn ?? null,
|
|
3050
2900
|
lastAuthorizationTime: a.lastAuthorizationTime ?? null,
|
|
3051
2901
|
totalActiveTaskCount: a.totalActiveTaskCount ?? 0,
|
|
3052
2902
|
ownerInfo: a.ownerInfo ?? [],
|
|
@@ -3091,7 +2941,7 @@ async function runListAccounts(options) {
|
|
|
3091
2941
|
{ key: "commentCount", header: "\u8BC4\u8BBA\u6570" },
|
|
3092
2942
|
{ key: "diggCount", header: "\u83B7\u8D5E\u6570" },
|
|
3093
2943
|
{ key: "lastAuthTime", header: "\u4E0A\u6B21\u6388\u6743" },
|
|
3094
|
-
{ key: "
|
|
2944
|
+
{ key: "expiresOn", header: "Token\u5230\u671F" },
|
|
3095
2945
|
{ key: "owners", header: "\u8D1F\u8D23\u4EBA" }
|
|
3096
2946
|
];
|
|
3097
2947
|
for (const [platform, accounts] of groups) {
|
|
@@ -3110,7 +2960,7 @@ async function runListAccounts(options) {
|
|
|
3110
2960
|
commentCount: formatCount(ov?.commentCount),
|
|
3111
2961
|
diggCount: formatCount(ov?.diggCount),
|
|
3112
2962
|
lastAuthTime: formatDate(a.lastAuthorizationTime),
|
|
3113
|
-
|
|
2963
|
+
expiresOn: formatDate(a.expiresOn),
|
|
3114
2964
|
owners: formatOwners(a.ownerInfo)
|
|
3115
2965
|
};
|
|
3116
2966
|
});
|
|
@@ -6421,11 +6271,21 @@ function cmdConfigClear() {
|
|
|
6421
6271
|
}
|
|
6422
6272
|
|
|
6423
6273
|
// src/index.ts
|
|
6274
|
+
process.on("uncaughtException", (err) => {
|
|
6275
|
+
console.error(`
|
|
6276
|
+
\u274C \u672A\u6355\u83B7\u7684\u5F02\u5E38\uFF1A${err.message}`);
|
|
6277
|
+
if (process.argv.includes("--verbose")) console.error(err.stack);
|
|
6278
|
+
process.exit(1);
|
|
6279
|
+
});
|
|
6280
|
+
process.on("unhandledRejection", (reason) => {
|
|
6281
|
+
const msg = reason instanceof Error ? reason.message : String(reason);
|
|
6282
|
+
console.error(`
|
|
6283
|
+
\u274C \u672A\u5904\u7406\u7684\u5F02\u6B65\u9519\u8BEF\uFF1A${msg}`);
|
|
6284
|
+
if (process.argv.includes("--verbose") && reason instanceof Error) console.error(reason.stack);
|
|
6285
|
+
process.exit(1);
|
|
6286
|
+
});
|
|
6424
6287
|
var program = new Command();
|
|
6425
6288
|
program.name("siluzan-cso").description("Siluzan \u5E73\u53F0 Skill \u5DE5\u5177\uFF1A\u521D\u59CB\u5316\u3001\u8D26\u53F7\u67E5\u8BE2\u3001\u4E0A\u4F20\u3001\u56FE\u6587/\u89C6\u9891\u53D1\u5E03").version(getCurrentVersion2());
|
|
6426
|
-
program.hook("preAction", () => {
|
|
6427
|
-
setSiluzanCliInvocation(redactCliArgvForSentry(process.argv));
|
|
6428
|
-
});
|
|
6429
6289
|
var configCmd = program.command("config").description("\u67E5\u770B\u6216\u8BBE\u7F6E Siluzan \u8BA4\u8BC1\u914D\u7F6E\uFF08~/.siluzan/config.json\uFF09");
|
|
6430
6290
|
configCmd.command("show").description("\u5C55\u793A\u5F53\u524D\u5DF2\u4FDD\u5B58\u7684\u914D\u7F6E\uFF08Token \u8131\u654F\u663E\u793A\uFF09").action(() => cmdConfigShow());
|
|
6431
6291
|
configCmd.command("set").description("\u4FDD\u5B58\u914D\u7F6E\u5230 ~/.siluzan/config.json\uFF0C\u540E\u7EED\u547D\u4EE4\u81EA\u52A8\u8BFB\u53D6").option("--api-key <key>", "API Key\uFF08\u63A8\u8350\uFF0C\u4E0E siluzan-tso \u5171\u7528\uFF0C\u4F18\u5148\u7EA7\u9AD8\u4E8E token\uFF09").option("-t, --token <token>", "\u7528\u6237 Auth Token\uFF08JWT\uFF09").action((opts) => {
|
package/dist/skill/SKILL.md
CHANGED
|
@@ -9,6 +9,54 @@ compatibility: Requires siluzan-cso-cli installed and authenticated via `siluzan
|
|
|
9
9
|
|
|
10
10
|
# siluzan-cso
|
|
11
11
|
|
|
12
|
+
## 前置条件与运行时依赖
|
|
13
|
+
|
|
14
|
+
使用本 Skill 前,以下组件必须已安装并就绪:
|
|
15
|
+
|
|
16
|
+
### 必需二进制 / 运行时
|
|
17
|
+
| 依赖 | 最低版本 | 用途 |
|
|
18
|
+
|------|---------|------|
|
|
19
|
+
| **Node.js** | 18+ | CLI 执行运行时以及 `node -e` 数据过滤 |
|
|
20
|
+
| **npm** 或 **pnpm** | npm 8+ / pnpm 8+ | 安装 `siluzan-cso-cli` 全局包 |
|
|
21
|
+
| **siluzan-cso** CLI | 与 Skill 同版本 | 所有业务操作的执行入口(由 `npm install -g siluzan-cso-cli` 安装) |
|
|
22
|
+
|
|
23
|
+
### 可选二进制
|
|
24
|
+
| 依赖 | 用途 |
|
|
25
|
+
|------|------|
|
|
26
|
+
| **ffmpeg** | `extract-cover` 命令截取视频封面帧(未安装时该命令会报错提示) |
|
|
27
|
+
|
|
28
|
+
### 凭据与配置文件
|
|
29
|
+
| 项目 | 位置 | 说明 |
|
|
30
|
+
|------|------|------|
|
|
31
|
+
| API Key 或 Token | `~/.siluzan/config.json` 中的 `apiKey` 或 `authToken` 字段 | 用于所有 CSO API 调用的鉴权。API Key 在丝路赞控制台「个人设置 → API Key 管理」创建。**请勿将此文件提交到 Git。** |
|
|
32
|
+
| csoBaseUrl | `~/.siluzan/config.json` 中的 `apiBaseUrl` | CSO 后端 API 地址,默认值由 CLI 构建时写入 |
|
|
33
|
+
|
|
34
|
+
### 网络端点
|
|
35
|
+
本 Skill 通过 CLI 访问以下远程服务:
|
|
36
|
+
| 端点 | 用途 |
|
|
37
|
+
|------|------|
|
|
38
|
+
| `api.siluzan.com` / `api-ci.siluzan.com` | CSO 核心 API(账号管理、发布、素材、报表等) |
|
|
39
|
+
| `cso.siluzan.com` / `cso-ci.siluzan.com` | CSO 前端页面(授权回调等浏览器操作) |
|
|
40
|
+
| `www.siluzan.com` / `www-ci.siluzan.com` | 丝路赞主站(注册、API Key 管理) |
|
|
41
|
+
| `registry.npmjs.org` | 版本更新检查 |
|
|
42
|
+
|
|
43
|
+
### 可选环境变量
|
|
44
|
+
| 变量 | 说明 |
|
|
45
|
+
|------|------|
|
|
46
|
+
| `SILUZAN_AUTH_TOKEN` | 从环境变量读取 Token(优先级高于 config.json,CI/CD 推荐) |
|
|
47
|
+
|
|
48
|
+
如果上述依赖缺失,请先参照 `references/setup.md` 完成安装与配置。
|
|
49
|
+
|
|
50
|
+
---
|
|
51
|
+
|
|
52
|
+
## 可执行的操作范围
|
|
53
|
+
|
|
54
|
+
- **只读**:查询媒体账号列表、账号分组、运营报表、发布任务状态、人设列表、RAG 知识库检索、AI 内容规划详情
|
|
55
|
+
- **写入**(需用户确认):上传素材、提交发布任务、创建/更新账号分组、生成 AI 内容规划、站内信回复
|
|
56
|
+
- **本地文件操作**:`extract-cover` 在本地截取视频帧并输出图片文件;`init` 将 Skill 文件写入 AI 助手目录
|
|
57
|
+
|
|
58
|
+
---
|
|
59
|
+
|
|
12
60
|
## 能力范围
|
|
13
61
|
|
|
14
62
|
| 业务流程 | 手段 | 说明 |
|
|
@@ -37,10 +85,12 @@ compatibility: Requires siluzan-cso-cli installed and authenticated via `siluzan
|
|
|
37
85
|
| `siluzan-cso task list/detail/item` | 查看任务状态 / 处理失败 / 重试 | `references/task.md` |
|
|
38
86
|
| `siluzan-cso report fetch --media <平台>` | 运营报表(核心指标 / 视频排行 / 趋势) | `references/report.md` |
|
|
39
87
|
| `siluzan-cso planning ...` | AI 内容规划:生成、监控、详情、导出 | `references/planning.md` |
|
|
40
|
-
| —(网页端) | CSO
|
|
88
|
+
| —(网页端) | CSO web端全部页面 URL | `references/web-pages.md` |
|
|
41
89
|
|
|
42
90
|
---
|
|
43
91
|
|
|
92
|
+
|
|
93
|
+
|
|
44
94
|
## 常见业务场景 → 阅读哪个文件
|
|
45
95
|
|
|
46
96
|
| 用户在做什么 | 先阅读 |
|
|
@@ -95,14 +145,15 @@ account-group ──需要 mediaCustomerId──► list-accounts
|
|
|
95
145
|
- **先查账号再操作**:对具体账号做操作前,先用 `list-accounts --name <名称> --media-type <平台>` 确认账号存在且 Token 有效。
|
|
96
146
|
- **使用 `--json` 处理数据**:需要对返回结果做计算或筛选时,加 `--json` 再用 `node -e` 提取(`node -e "const d=require('fs').readFileSync('/dev/stdin','utf8'); ..."`)。
|
|
97
147
|
- **不猜账号 ID**:`entityId` ≠ `mediaCustomerId`,两者均须从 `list-accounts --json` 获取,不可假设。
|
|
98
|
-
-
|
|
148
|
+
- **命令透明性**:以简洁的方式向用户说明即将执行的操作意图(如「正在上传视频到素材库」「正在为您查询 YouTube 账号列表」),让用户了解操作进度。用户主动要求查看执行细节时,应如实提供完整命令。安装/登录/更新等一次性命令(见 `references/setup.md`)可直接展示给用户自行执行。
|
|
99
149
|
- **操作后必须验证**:完成发布、上传、分组等写操作后,需通过对应的查询命令确认结果。
|
|
100
150
|
|
|
101
|
-
###
|
|
102
|
-
|
|
103
|
-
- 输出的任何内容(计划、总结、报告)中,**严禁出现 CLI 命令**(setup.md 相关命令除外)。
|
|
104
|
-
- 每次执行前主动检查 CLI 版本,若需更新请先执行更新流程(详见 `references/setup.md`)。
|
|
151
|
+
### 必须遵守
|
|
105
152
|
|
|
153
|
+
- 主动更新(详情请读取 `references/setup.md`)。
|
|
154
|
+
- **破坏性操作必须用户确认**:涉及写入/修改/删除的操作(发布、上传、分组变更等),执行前必须明确告知用户操作内容并获得确认。
|
|
155
|
+
- **只读操作可自主执行**:查询类命令(`list-accounts`、`report fetch`、`task list`、`config show` 等)可直接执行,无需额外确认。
|
|
156
|
+
- 禁止提供虚假信息,比如web端连接就必须确认 `references/web-pages.md` 中存在才能提供给用户
|
|
106
157
|
---
|
|
107
158
|
|
|
108
159
|
## 常见 HTTP 错误处理
|
package/dist/skill/_meta.json
CHANGED
|
@@ -1,5 +1,21 @@
|
|
|
1
1
|
{
|
|
2
2
|
"slug": "siluzan-cso",
|
|
3
|
-
"version": "1.1.
|
|
4
|
-
"publishedAt":
|
|
3
|
+
"version": "1.1.9-beta.2",
|
|
4
|
+
"publishedAt": 1776070442759,
|
|
5
|
+
"homepage": "https://www.siluzan.com",
|
|
6
|
+
"source": "https://dev.azure.com/jack4it/Sammamish/_git/siluzan-skill",
|
|
7
|
+
"requiredBinaries": [
|
|
8
|
+
"node",
|
|
9
|
+
"npm"
|
|
10
|
+
],
|
|
11
|
+
"optionalBinaries": [
|
|
12
|
+
"ffmpeg"
|
|
13
|
+
],
|
|
14
|
+
"requiredEnv": [],
|
|
15
|
+
"optionalEnv": [
|
|
16
|
+
"SILUZAN_AUTH_TOKEN"
|
|
17
|
+
],
|
|
18
|
+
"configPaths": [
|
|
19
|
+
"~/.siluzan/config.json"
|
|
20
|
+
]
|
|
5
21
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "siluzan-cso-cli",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.9-beta.2",
|
|
4
4
|
"description": "Siluzan platform AI Skill CLI — multi-platform content publishing (video/image-text) for Cursor, Claude Code, and OpenClaw.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -24,13 +24,21 @@
|
|
|
24
24
|
"content-publishing",
|
|
25
25
|
"cli"
|
|
26
26
|
],
|
|
27
|
+
"homepage": "https://www.siluzan.com",
|
|
28
|
+
"repository": {
|
|
29
|
+
"type": "git",
|
|
30
|
+
"url": "https://dev.azure.com/jack4it/Sammamish/_git/siluzan-skill",
|
|
31
|
+
"directory": "cso-cli"
|
|
32
|
+
},
|
|
33
|
+
"bugs": {
|
|
34
|
+
"url": "https://dev.azure.com/jack4it/Sammamish/_git/siluzan-skill/issues"
|
|
35
|
+
},
|
|
27
36
|
"license": "UNLICENSED",
|
|
28
37
|
"publishConfig": {
|
|
29
38
|
"access": "public"
|
|
30
39
|
},
|
|
31
40
|
"dependencies": {
|
|
32
41
|
"@azure/storage-blob": "^12.31.0",
|
|
33
|
-
"@sentry/node": "9",
|
|
34
42
|
"cli-table3": "^0.6.5",
|
|
35
43
|
"commander": "^12.1.0",
|
|
36
44
|
"image-size": "^2.0.2"
|
|
@@ -42,7 +50,7 @@
|
|
|
42
50
|
"siluzan-cli-common": "1.0.0"
|
|
43
51
|
},
|
|
44
52
|
"engines": {
|
|
45
|
-
"node": ">=
|
|
53
|
+
"node": ">=18"
|
|
46
54
|
},
|
|
47
55
|
"scripts": {
|
|
48
56
|
"postinstall": "node scripts/postinstall.mjs",
|