siluzan-cso-cli 1.1.8-beta.3 → 1.1.8-beta.5
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 +2 -215
- package/dist/skill/_meta.json +2 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -20,7 +20,7 @@ siluzan-cso init -d /path/to/skills # 写入自定义目录
|
|
|
20
20
|
siluzan-cso init --force # 强制覆盖已存在文件
|
|
21
21
|
```
|
|
22
22
|
|
|
23
|
-
> **注意**:当前为测试版(1.1.8-beta.
|
|
23
|
+
> **注意**:当前为测试版(1.1.8-beta.5),供内部测试使用。正式发布后安装命令将改为 `npm install -g siluzan-cso-cli`。
|
|
24
24
|
|
|
25
25
|
| 助手 | 建议 `--ai` |
|
|
26
26
|
|------|-------------|
|
package/dist/index.js
CHANGED
|
@@ -2281,11 +2281,6 @@ function redactCliArgvForSentry(argv) {
|
|
|
2281
2281
|
}
|
|
2282
2282
|
return out.join(" ");
|
|
2283
2283
|
}
|
|
2284
|
-
function isApiTrackingEnabled() {
|
|
2285
|
-
const v = process.env.SILUZAN_SENTRY_TRACKING?.trim().toLowerCase();
|
|
2286
|
-
if (v === "0" || v === "false" || v === "off" || v === "no") return false;
|
|
2287
|
-
return true;
|
|
2288
|
-
}
|
|
2289
2284
|
function setSiluzanCliMeta(name, version) {
|
|
2290
2285
|
cliMeta = { name, version };
|
|
2291
2286
|
if (sentryReady) {
|
|
@@ -2340,7 +2335,8 @@ async function ensureSentryInitialized(requestUrl) {
|
|
|
2340
2335
|
if (!flushHookRegistered) {
|
|
2341
2336
|
flushHookRegistered = true;
|
|
2342
2337
|
process.once("beforeExit", () => {
|
|
2343
|
-
void Sentry.flush(2e3)
|
|
2338
|
+
void Sentry.flush(2e3).catch(() => {
|
|
2339
|
+
});
|
|
2344
2340
|
});
|
|
2345
2341
|
}
|
|
2346
2342
|
sentryReady = true;
|
|
@@ -2373,178 +2369,6 @@ function inferSiluzanRuntimeEnvironment(requestUrl) {
|
|
|
2373
2369
|
return "production";
|
|
2374
2370
|
}
|
|
2375
2371
|
}
|
|
2376
|
-
function breadcrumbUrl(requestUrl) {
|
|
2377
|
-
try {
|
|
2378
|
-
const u = new URL(requestUrl);
|
|
2379
|
-
return `${u.origin}${u.pathname}`;
|
|
2380
|
-
} catch {
|
|
2381
|
-
return requestUrl.slice(0, 120);
|
|
2382
|
-
}
|
|
2383
|
-
}
|
|
2384
|
-
function trackingPathParts(requestUrl) {
|
|
2385
|
-
try {
|
|
2386
|
-
const u = new URL(requestUrl);
|
|
2387
|
-
return { host: u.hostname.toLowerCase(), pathname: u.pathname || "/" };
|
|
2388
|
-
} catch {
|
|
2389
|
-
return { host: "unknown", pathname: "/" };
|
|
2390
|
-
}
|
|
2391
|
-
}
|
|
2392
|
-
var SENSITIVE_QUERY_KEYS = /* @__PURE__ */ new Set([
|
|
2393
|
-
"token",
|
|
2394
|
-
"password",
|
|
2395
|
-
"api_key",
|
|
2396
|
-
"apikey",
|
|
2397
|
-
"key",
|
|
2398
|
-
"secret",
|
|
2399
|
-
"authorization",
|
|
2400
|
-
"auth"
|
|
2401
|
-
]);
|
|
2402
|
-
function redactUrlForTracking(url) {
|
|
2403
|
-
try {
|
|
2404
|
-
const u = new URL(url);
|
|
2405
|
-
const q = new URLSearchParams(u.search);
|
|
2406
|
-
const out = new URLSearchParams();
|
|
2407
|
-
for (const [k, v] of q.entries()) {
|
|
2408
|
-
out.set(k, SENSITIVE_QUERY_KEYS.has(k.toLowerCase()) ? "[REDACTED]" : v);
|
|
2409
|
-
}
|
|
2410
|
-
const qs = out.toString();
|
|
2411
|
-
return `${u.origin}${u.pathname}${qs ? `?${qs}` : ""}`;
|
|
2412
|
-
} catch {
|
|
2413
|
-
return url.slice(0, 800);
|
|
2414
|
-
}
|
|
2415
|
-
}
|
|
2416
|
-
function redactTrackingHeaders(h) {
|
|
2417
|
-
const out = {};
|
|
2418
|
-
for (const [k, v] of Object.entries(h)) {
|
|
2419
|
-
const low = k.toLowerCase();
|
|
2420
|
-
if (low === "authorization" || low === "x-api-key") {
|
|
2421
|
-
out[k] = "[REDACTED]";
|
|
2422
|
-
} else if (v.length > 2e3) {
|
|
2423
|
-
out[k] = `${v.slice(0, 500)}\u2026[truncated ${v.length} chars]`;
|
|
2424
|
-
} else {
|
|
2425
|
-
out[k] = v;
|
|
2426
|
-
}
|
|
2427
|
-
}
|
|
2428
|
-
return out;
|
|
2429
|
-
}
|
|
2430
|
-
var SENSITIVE_JSON_KEY = /* @__PURE__ */ new Set([
|
|
2431
|
-
"password",
|
|
2432
|
-
"token",
|
|
2433
|
-
"apikey",
|
|
2434
|
-
"api_key",
|
|
2435
|
-
"authorization",
|
|
2436
|
-
"authtoken",
|
|
2437
|
-
"accesstoken",
|
|
2438
|
-
"refreshtoken",
|
|
2439
|
-
"secret",
|
|
2440
|
-
"client_secret",
|
|
2441
|
-
"privatekey",
|
|
2442
|
-
"private_key"
|
|
2443
|
-
]);
|
|
2444
|
-
function deepRedactJson(value, depth) {
|
|
2445
|
-
if (depth > 14) return "[MAX_DEPTH]";
|
|
2446
|
-
if (value === null || typeof value !== "object") return value;
|
|
2447
|
-
if (Array.isArray(value)) {
|
|
2448
|
-
return value.map((v) => deepRedactJson(v, depth + 1));
|
|
2449
|
-
}
|
|
2450
|
-
const o = value;
|
|
2451
|
-
const out = {};
|
|
2452
|
-
for (const [k, v] of Object.entries(o)) {
|
|
2453
|
-
const low = k.toLowerCase().replace(/_/g, "");
|
|
2454
|
-
if (SENSITIVE_JSON_KEY.has(low) || low.includes("password") || low.includes("secret")) {
|
|
2455
|
-
out[k] = "[REDACTED]";
|
|
2456
|
-
} else {
|
|
2457
|
-
out[k] = deepRedactJson(v, depth + 1);
|
|
2458
|
-
}
|
|
2459
|
-
}
|
|
2460
|
-
return out;
|
|
2461
|
-
}
|
|
2462
|
-
function redactPlainTextSnippet(input) {
|
|
2463
|
-
let s = input;
|
|
2464
|
-
s = s.replace(/(Bearer\s+)[^\s'",}]+/gi, "$1***");
|
|
2465
|
-
s = s.replace(
|
|
2466
|
-
/("?(?:apiKey|authToken|accessToken|refreshToken|token|password)"?\s*[:=]\s*"?)([^"\s,}]{4,})/gi,
|
|
2467
|
-
"$1***"
|
|
2468
|
-
);
|
|
2469
|
-
return s;
|
|
2470
|
-
}
|
|
2471
|
-
function trackingBodyMaxChars() {
|
|
2472
|
-
const n = Number(process.env.SILUZAN_SENTRY_BODY_MAX);
|
|
2473
|
-
if (Number.isFinite(n) && n > 256) return Math.min(n, 5e5);
|
|
2474
|
-
return 12e3;
|
|
2475
|
-
}
|
|
2476
|
-
function trackingOmitBodies() {
|
|
2477
|
-
const v = process.env.SILUZAN_SENTRY_NO_API_BODY?.trim().toLowerCase();
|
|
2478
|
-
return v === "1" || v === "true" || v === "yes";
|
|
2479
|
-
}
|
|
2480
|
-
function formatTrackingBody(raw) {
|
|
2481
|
-
if (trackingOmitBodies()) return "[omitted: SILUZAN_SENTRY_NO_API_BODY]";
|
|
2482
|
-
if (raw === void 0 || raw === "") return "";
|
|
2483
|
-
const max = trackingBodyMaxChars();
|
|
2484
|
-
let text;
|
|
2485
|
-
try {
|
|
2486
|
-
const parsed = JSON.parse(raw);
|
|
2487
|
-
text = JSON.stringify(deepRedactJson(parsed, 0));
|
|
2488
|
-
} catch {
|
|
2489
|
-
text = redactPlainTextSnippet(raw);
|
|
2490
|
-
}
|
|
2491
|
-
if (text.length > max) {
|
|
2492
|
-
return `${text.slice(0, max)}\u2026[truncated ${text.length} chars]`;
|
|
2493
|
-
}
|
|
2494
|
-
return text;
|
|
2495
|
-
}
|
|
2496
|
-
async function reportSiluzanApiCall(payload) {
|
|
2497
|
-
if (isSentryDisabled() || !getDsn() || !isApiTrackingEnabled()) return;
|
|
2498
|
-
try {
|
|
2499
|
-
const okInit = await ensureSentryInitialized(payload.url);
|
|
2500
|
-
if (!okInit) return;
|
|
2501
|
-
const Sentry = await import("@sentry/node");
|
|
2502
|
-
const { host, pathname } = trackingPathParts(payload.url);
|
|
2503
|
-
const siluzanEnv = inferSiluzanRuntimeEnvironment(payload.url);
|
|
2504
|
-
const authType = payload.config.apiKey ? "apiKey" : "token";
|
|
2505
|
-
const statusOk = payload.status >= 200 && payload.status < 300;
|
|
2506
|
-
Sentry.captureMessage(
|
|
2507
|
-
`siluzan.cli.api ${payload.method} ${host}${pathname} \u2192 ${payload.status}`,
|
|
2508
|
-
{
|
|
2509
|
-
level: statusOk ? "info" : "warning",
|
|
2510
|
-
tags: {
|
|
2511
|
-
siluzan_tracking: "api",
|
|
2512
|
-
cli: cliMeta.name,
|
|
2513
|
-
cli_version: cliMeta.version,
|
|
2514
|
-
http_method: payload.method,
|
|
2515
|
-
http_host: host,
|
|
2516
|
-
http_status: String(payload.status),
|
|
2517
|
-
siluzan_env: siluzanEnv,
|
|
2518
|
-
auth_type: authType
|
|
2519
|
-
},
|
|
2520
|
-
fingerprint: [
|
|
2521
|
-
"siluzan-cli-api",
|
|
2522
|
-
cliMeta.name,
|
|
2523
|
-
payload.method,
|
|
2524
|
-
host,
|
|
2525
|
-
pathname,
|
|
2526
|
-
statusOk ? "2xx" : payload.status >= 500 ? "5xx" : "4xx"
|
|
2527
|
-
],
|
|
2528
|
-
contexts: {
|
|
2529
|
-
siluzan_cli: {
|
|
2530
|
-
command: cliInvocation || "(pre-action \u672A\u6CE8\u518C\u6216\u5148\u4E8E parse \u53D1\u8D77\u8BF7\u6C42)"
|
|
2531
|
-
},
|
|
2532
|
-
siluzan_request: {
|
|
2533
|
-
url: redactUrlForTracking(payload.url),
|
|
2534
|
-
method: payload.method,
|
|
2535
|
-
headers: redactTrackingHeaders(payload.reqHeaders),
|
|
2536
|
-
body: formatTrackingBody(payload.requestBody)
|
|
2537
|
-
},
|
|
2538
|
-
siluzan_response: {
|
|
2539
|
-
status: payload.status,
|
|
2540
|
-
body: formatTrackingBody(payload.responseText)
|
|
2541
|
-
}
|
|
2542
|
-
}
|
|
2543
|
-
}
|
|
2544
|
-
);
|
|
2545
|
-
} catch {
|
|
2546
|
-
}
|
|
2547
|
-
}
|
|
2548
2372
|
function cacheKeyForUser(mainOrigin, config) {
|
|
2549
2373
|
const cred = config.apiKey ? `k:${config.apiKey}` : `t:${config.authToken}`;
|
|
2550
2374
|
return `${mainOrigin}\0${cred}`;
|
|
@@ -2658,33 +2482,6 @@ function refreshSiluzanUser(apiBase, config) {
|
|
|
2658
2482
|
}
|
|
2659
2483
|
})();
|
|
2660
2484
|
}
|
|
2661
|
-
async function prepareSiluzanSentryForApiFetch(url, config, options) {
|
|
2662
|
-
if (isSentryDisabled()) return;
|
|
2663
|
-
if (!getDsn()) return;
|
|
2664
|
-
try {
|
|
2665
|
-
const ok = await ensureSentryInitialized(url);
|
|
2666
|
-
if (!ok) return;
|
|
2667
|
-
const Sentry = await import("@sentry/node");
|
|
2668
|
-
const method = options.method ?? "GET";
|
|
2669
|
-
const siluzanEnv = inferSiluzanRuntimeEnvironment(url);
|
|
2670
|
-
const authType = config.apiKey ? "apiKey" : "token";
|
|
2671
|
-
Sentry.addBreadcrumb({
|
|
2672
|
-
category: "siluzan.api",
|
|
2673
|
-
type: "http",
|
|
2674
|
-
level: "info",
|
|
2675
|
-
message: `${method} ${breadcrumbUrl(url)}`,
|
|
2676
|
-
data: {
|
|
2677
|
-
siluzan_env: siluzanEnv,
|
|
2678
|
-
auth_type: authType
|
|
2679
|
-
}
|
|
2680
|
-
});
|
|
2681
|
-
const mainOrigin = deriveMainApiOriginFromRequestUrl(url);
|
|
2682
|
-
if (mainOrigin) {
|
|
2683
|
-
scheduleUserContext(mainOrigin, config);
|
|
2684
|
-
}
|
|
2685
|
-
} catch {
|
|
2686
|
-
}
|
|
2687
|
-
}
|
|
2688
2485
|
function redactSensitive(input) {
|
|
2689
2486
|
let output = input;
|
|
2690
2487
|
output = output.replace(/(Bearer\s+)[^\s",]+/gi, "$1***");
|
|
@@ -2695,7 +2492,6 @@ function redactSensitive(input) {
|
|
|
2695
2492
|
return output;
|
|
2696
2493
|
}
|
|
2697
2494
|
async function apiFetch(url, config, options = {}, verbose = false) {
|
|
2698
|
-
await prepareSiluzanSentryForApiFetch(url, config, options);
|
|
2699
2495
|
const method = options.method ?? "GET";
|
|
2700
2496
|
const authHeaders = config.apiKey ? { "x-api-key": config.apiKey } : { Authorization: `Bearer ${config.authToken}` };
|
|
2701
2497
|
const reqHeaders = {
|
|
@@ -2713,15 +2509,6 @@ async function apiFetch(url, config, options = {}, verbose = false) {
|
|
|
2713
2509
|
body
|
|
2714
2510
|
});
|
|
2715
2511
|
const text = res.text;
|
|
2716
|
-
await reportSiluzanApiCall({
|
|
2717
|
-
url,
|
|
2718
|
-
config,
|
|
2719
|
-
method,
|
|
2720
|
-
reqHeaders,
|
|
2721
|
-
requestBody: body,
|
|
2722
|
-
status: res.status,
|
|
2723
|
-
responseText: text
|
|
2724
|
-
});
|
|
2725
2512
|
if (res.status < 200 || res.status >= 300) {
|
|
2726
2513
|
const detail = verbose ? `\uFF1A${redactSensitive(text).slice(0, 300)}` : "";
|
|
2727
2514
|
throw new Error(`HTTP ${res.status}${detail}`);
|
package/dist/skill/_meta.json
CHANGED
package/package.json
CHANGED