siluzan-tso-cli 1.1.18-beta.7 → 1.1.18
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 -2
- package/dist/index.js +266 -64
- package/dist/skill/_meta.json +2 -2
- package/dist/skill/references/finance.md +5 -5
- package/dist/skill/references/reporting.md +2 -2
- package/dist/skill/references/setup.md +8 -7
- package/dist/skill/references/tso-home.md +1 -1
- package/dist/skill/scripts/install.ps1 +2 -2
- package/dist/skill/scripts/install.sh +2 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -43,7 +43,7 @@ HTML 报告模板引用以下 CDN:`cdn.tailwindcss.com`、`cdnjs.cloudflare.co
|
|
|
43
43
|
在**用户的目标项目根目录**执行(根据用户使用的助手选择 `--ai`):
|
|
44
44
|
|
|
45
45
|
```bash
|
|
46
|
-
npm install -g siluzan-tso-cli
|
|
46
|
+
npm install -g siluzan-tso-cli
|
|
47
47
|
siluzan-tso init --ai cursor # 写入 Cursor(默认)
|
|
48
48
|
siluzan-tso init --ai cursor,claude # 同时写入多个平台
|
|
49
49
|
siluzan-tso init --ai all # 写入所有支持的平台
|
|
@@ -51,7 +51,6 @@ siluzan-tso init -d /path/to/skills # 写入自定义目录
|
|
|
51
51
|
siluzan-tso init --force # 强制覆盖已存在文件
|
|
52
52
|
```
|
|
53
53
|
|
|
54
|
-
> **注意**:当前为测试版(1.1.18-beta.7),供内部测试使用。正式发布后安装命令将改为 `npm install -g siluzan-tso-cli`。
|
|
55
54
|
|
|
56
55
|
| 助手 | 建议 `--ai` |
|
|
57
56
|
| ----------------------- | ------------------------------------ |
|
package/dist/index.js
CHANGED
|
@@ -2559,16 +2559,11 @@ function printAuthMissingHelp(binName) {
|
|
|
2559
2559
|
`
|
|
2560
2560
|
\u274C \u672A\u627E\u5230\u8BA4\u8BC1\u51ED\u636E\u3002\u8BF7\u9009\u62E9\u4EE5\u4E0B\u4EFB\u610F\u4E00\u79CD\u65B9\u5F0F\uFF1A
|
|
2561
2561
|
|
|
2562
|
-
|
|
2563
|
-
|
|
2564
|
-
|
|
2565
|
-
|
|
2566
|
-
|
|
2567
|
-
export SILUZAN_API_KEY=<YOUR_API_KEY>
|
|
2568
|
-
# \u6216 export SILUZAN_AUTH_TOKEN=<YOUR_TOKEN>
|
|
2569
|
-
|
|
2570
|
-
\u65B9\u5F0F\u4E09\uFF1AJWT Token
|
|
2571
|
-
${binName} login
|
|
2562
|
+
\u8BF7\u4F7F\u7528\u624B\u673A\u53F7\u91CD\u65B0\u767B\u5F55
|
|
2563
|
+
${binName} send-login-code --phone <YOUR_PHONE>
|
|
2564
|
+
`,
|
|
2565
|
+
`\u7136\u540E\u4F7F\u7528\u6536\u5230\u7684\u9A8C\u8BC1\u7801\u5B8C\u6210\u767B\u5F55
|
|
2566
|
+
${binName} login --phone <YOUR_PHONE> --code <YOUR_CODE>
|
|
2572
2567
|
`
|
|
2573
2568
|
);
|
|
2574
2569
|
process.exit(1);
|
|
@@ -3060,6 +3055,35 @@ function normalizeChinaPhone(input) {
|
|
|
3060
3055
|
function isValidChinaPhone(input) {
|
|
3061
3056
|
return /^\+861\d{10}$/.test(normalizeChinaPhone(input));
|
|
3062
3057
|
}
|
|
3058
|
+
async function sendPhoneLoginCode(opts) {
|
|
3059
|
+
const phone = normalizeChinaPhone(opts.phone);
|
|
3060
|
+
const url = `${opts.ssoBaseUrl}/Account/SendVaildCode?Phone=${encodeURIComponent(
|
|
3061
|
+
phone
|
|
3062
|
+
)}&RandStr=&Iicket=`;
|
|
3063
|
+
if (opts.verbose) {
|
|
3064
|
+
process.stderr.write(`[phone-login] GET ${url}
|
|
3065
|
+
`);
|
|
3066
|
+
}
|
|
3067
|
+
const res = await rawRequest(url, {
|
|
3068
|
+
method: "GET",
|
|
3069
|
+
headers: {
|
|
3070
|
+
Accept: "application/json",
|
|
3071
|
+
"Accept-Language": "zh-CN"
|
|
3072
|
+
}
|
|
3073
|
+
});
|
|
3074
|
+
if (res.status < 200 || res.status >= 300) {
|
|
3075
|
+
return { ok: false, message: `HTTP ${res.status}` };
|
|
3076
|
+
}
|
|
3077
|
+
let body;
|
|
3078
|
+
try {
|
|
3079
|
+
body = JSON.parse(res.text);
|
|
3080
|
+
} catch {
|
|
3081
|
+
return { ok: false, message: `\u54CD\u5E94\u975E JSON\uFF1A${res.text.slice(0, 120)}` };
|
|
3082
|
+
}
|
|
3083
|
+
const state = (body.State ?? body.state ?? "").toLowerCase();
|
|
3084
|
+
const message = body.Message ?? body.message ?? "";
|
|
3085
|
+
return { ok: state === "ok", message };
|
|
3086
|
+
}
|
|
3063
3087
|
async function loginByPhoneCode(opts) {
|
|
3064
3088
|
const phone = normalizeChinaPhone(opts.phone);
|
|
3065
3089
|
const url = `${opts.ssoBaseUrl}/Account/LoginByMiniCode?phone=${encodeURIComponent(
|
|
@@ -3272,7 +3296,7 @@ var DEFAULT_API_BASE;
|
|
|
3272
3296
|
var init_defaults = __esm({
|
|
3273
3297
|
"src/config/defaults.ts"() {
|
|
3274
3298
|
"use strict";
|
|
3275
|
-
DEFAULT_API_BASE = "https://tso-api
|
|
3299
|
+
DEFAULT_API_BASE = "https://tso-api.siluzan.com";
|
|
3276
3300
|
}
|
|
3277
3301
|
});
|
|
3278
3302
|
|
|
@@ -6620,17 +6644,38 @@ function validateAndNormalizePhone(rawInput) {
|
|
|
6620
6644
|
}
|
|
6621
6645
|
return normalizeChinaPhone(rawPhone);
|
|
6622
6646
|
}
|
|
6623
|
-
async function
|
|
6647
|
+
async function runSendLoginCode(opts) {
|
|
6624
6648
|
const phone = validateAndNormalizePhone(opts.phone);
|
|
6625
|
-
const
|
|
6626
|
-
|
|
6627
|
-
|
|
6628
|
-
|
|
6629
|
-
|
|
6649
|
+
const tsoApiBase = process.env.SILUZAN_TSO_API_BASE ?? DEFAULT_API_BASE;
|
|
6650
|
+
const ssoBaseUrl = deriveSsoBaseUrl(tsoApiBase);
|
|
6651
|
+
console.log("\n\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550");
|
|
6652
|
+
console.log(" Siluzan \u53D1\u9001\u767B\u5F55\u77ED\u4FE1\u9A8C\u8BC1\u7801");
|
|
6653
|
+
console.log("\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n");
|
|
6654
|
+
console.log(` \u624B\u673A\u53F7 : ${phone}`);
|
|
6655
|
+
console.log("\u2192 \u6B63\u5728\u5411\u624B\u673A\u53D1\u9001\u9A8C\u8BC1\u7801...");
|
|
6656
|
+
const r = await sendPhoneLoginCode({ ssoBaseUrl, phone, verbose: opts.verbose });
|
|
6657
|
+
if (!r.ok) {
|
|
6658
|
+
console.error(`
|
|
6659
|
+
\u274C \u77ED\u4FE1\u9A8C\u8BC1\u7801\u53D1\u9001\u5931\u8D25\uFF1A${r.message || "(\u540E\u7AEF\u672A\u8FD4\u56DE\u539F\u56E0)"}
|
|
6630
6660
|
`);
|
|
6631
|
-
console.error("\uFF08\u62C6\u6210\u4E24\u6B65\u662F\u4E3A\u4E86\u907F\u514D AI Agent \u5361\u5728\u4EA4\u4E92\u8F93\u5165\u65F6\u53CD\u590D\u91CD\u8BD5\u5BFC\u81F4\u77ED\u4FE1\u8F70\u70B8\uFF09\n");
|
|
6632
6661
|
process.exit(1);
|
|
6633
6662
|
}
|
|
6663
|
+
console.log(`\u2713 \u9A8C\u8BC1\u7801\u5DF2\u53D1\u9001\uFF0810 \u5206\u949F\u5185\u6709\u6548\uFF09\u3002
|
|
6664
|
+
`);
|
|
6665
|
+
console.log("\u4E0B\u4E00\u6B65\uFF1A\u62FF\u5230 6 \u4F4D\u9A8C\u8BC1\u7801\u540E\uFF0C\u8FD0\u884C\u4E0B\u9762\u7684\u547D\u4EE4\u5B8C\u6210\u767B\u5F55\uFF1A\n");
|
|
6666
|
+
console.log(` siluzan-tso login --phone ${phone} --code <6\u4F4D\u9A8C\u8BC1\u7801>
|
|
6667
|
+
`);
|
|
6668
|
+
console.log("\u53EF\u9009\u53C2\u6570\uFF1A--name / --valid-days / --expires-at / --services");
|
|
6669
|
+
console.log("\uFF08\u9ED8\u8BA4\u521B\u5EFA 90 \u5929\u6709\u6548\u3001\u52FE\u9009 TSO + CUT \u670D\u52A1\u7684 API Key\uFF09\n");
|
|
6670
|
+
}
|
|
6671
|
+
function normalizeBearerTokenInput(raw) {
|
|
6672
|
+
const t = raw.trim();
|
|
6673
|
+
if (/^bearer\s+/i.test(t)) {
|
|
6674
|
+
return t.replace(/^bearer\s+/i, "").trim();
|
|
6675
|
+
}
|
|
6676
|
+
return t;
|
|
6677
|
+
}
|
|
6678
|
+
async function executePhoneLoginWithVerifiedCode(phone, code, opts) {
|
|
6634
6679
|
let allowedServices;
|
|
6635
6680
|
try {
|
|
6636
6681
|
allowedServices = parseAllowedServices(opts.services);
|
|
@@ -6702,9 +6747,10 @@ async function runPhoneLogin(opts) {
|
|
|
6702
6747
|
`
|
|
6703
6748
|
\u8BE5\u624B\u673A\u53F7\u5C1A\u672A\u6CE8\u518C\u4E1D\u8DEF\u8D5E\u8D26\u53F7\u3002\u8BF7\u5148\u5728\u7F51\u9875\u7AEF\u6CE8\u518C\uFF1A
|
|
6704
6749
|
${WEB_BASE_URL}
|
|
6705
|
-
\u6CE8\u518C\u6210\u529F\u540E\u518D\u56DE\u5230 CLI \u91CD\u8BD5\
|
|
6750
|
+
\u6CE8\u518C\u6210\u529F\u540E\u518D\u56DE\u5230 CLI \u91CD\u8BD5\uFF1A
|
|
6706
6751
|
siluzan-tso send-login-code --phone ${phone}
|
|
6707
6752
|
siluzan-tso login --phone ${phone} --code <6\u4F4D\u9A8C\u8BC1\u7801>
|
|
6753
|
+
\u6216\u5728\u7EC8\u7AEF\u6267\u884C\u65E0\u53C2 siluzan-tso login \u540E\u9009\u62E9\u300C\u624B\u673A\u53F7\u767B\u5F55\u300D\u3002
|
|
6708
6754
|
`
|
|
6709
6755
|
);
|
|
6710
6756
|
} else if (/验证码错误|验证码/.test(msg)) {
|
|
@@ -6718,34 +6764,72 @@ async function runPhoneLogin(opts) {
|
|
|
6718
6764
|
process.exit(1);
|
|
6719
6765
|
}
|
|
6720
6766
|
}
|
|
6721
|
-
async function
|
|
6722
|
-
|
|
6723
|
-
|
|
6724
|
-
|
|
6725
|
-
|
|
6767
|
+
async function runPhoneLogin(opts) {
|
|
6768
|
+
const phone = validateAndNormalizePhone(opts.phone);
|
|
6769
|
+
const code = opts.code?.trim() ?? "";
|
|
6770
|
+
if (!code) {
|
|
6771
|
+
console.error("\n\u274C \u7F3A\u5C11 --code \u53C2\u6570\u3002\u624B\u673A\u53F7\u767B\u5F55\u662F\u4E24\u6BB5\u5F0F\u8C03\u7528\uFF0C\u8BF7\u6309\u987A\u5E8F\u6267\u884C\uFF1A\n");
|
|
6772
|
+
console.error(` 1) siluzan-tso send-login-code --phone ${phone}`);
|
|
6773
|
+
console.error(` 2) siluzan-tso login --phone ${phone} --code <\u6536\u5230\u76846\u4F4D\u9A8C\u8BC1\u7801>
|
|
6774
|
+
`);
|
|
6775
|
+
console.error("\uFF08\u62C6\u6210\u4E24\u6B65\u662F\u4E3A\u4E86\u907F\u514D AI Agent \u5361\u5728\u4EA4\u4E92\u8F93\u5165\u65F6\u53CD\u590D\u91CD\u8BD5\u5BFC\u81F4\u77ED\u4FE1\u8F70\u70B8\uFF09\n");
|
|
6776
|
+
console.error("\u6216\u5728\u7EC8\u7AEF\u6267\u884C\uFF1Asiluzan-tso login\uFF08\u65E0\u53C2\u6570\uFF09\uFF0C\u9009\u62E9\u300C\u624B\u673A\u53F7 + \u77ED\u4FE1\u9A8C\u8BC1\u7801\u300D\u7531\u672C CLI \u53D1\u7801\u3002\n");
|
|
6777
|
+
process.exit(1);
|
|
6778
|
+
}
|
|
6779
|
+
await executePhoneLoginWithVerifiedCode(phone, code, opts);
|
|
6780
|
+
}
|
|
6781
|
+
async function runInteractiveJwtLogin() {
|
|
6782
|
+
const shared = readSharedConfig();
|
|
6783
|
+
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
6784
|
+
const prompt = (q) => new Promise((res) => rl.question(q, (a) => res(a.trim())));
|
|
6785
|
+
try {
|
|
6786
|
+
if (shared.apiKey) {
|
|
6787
|
+
console.log(`
|
|
6788
|
+
\u5DF2\u4FDD\u5B58 API Key\uFF08${maskSecret(shared.apiKey)}\uFF09\u3002\u6539\u7528 JWT \u5C06\u6E05\u9664 API Key \u5E76\u4F18\u5148\u4F7F\u7528 Bearer Token\u3002`);
|
|
6789
|
+
const ans = await prompt("\u662F\u5426\u7EE7\u7EED\uFF1F(y/N) ");
|
|
6790
|
+
if (ans.toLowerCase() !== "y") {
|
|
6791
|
+
console.log("\n\u5DF2\u53D6\u6D88\u3002\n");
|
|
6792
|
+
return;
|
|
6793
|
+
}
|
|
6794
|
+
}
|
|
6795
|
+
console.log("\n\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550");
|
|
6796
|
+
console.log(" Siluzan \u767B\u5F55\uFF08JWT Token\uFF09");
|
|
6797
|
+
console.log("\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550");
|
|
6798
|
+
console.log("\n\u8BF7\u7C98\u8D34 access token\uFF08\u53EF\u5E26\u6216\u4E0D\u5E26 `Bearer ` \u524D\u7F00\uFF09\uFF1A\n");
|
|
6799
|
+
let token = "";
|
|
6800
|
+
for (let i = 0; i < 3; i++) {
|
|
6801
|
+
const input = await prompt("Token\uFF1A");
|
|
6802
|
+
const normalized = normalizeBearerTokenInput(input);
|
|
6803
|
+
if (normalized) {
|
|
6804
|
+
token = normalized;
|
|
6805
|
+
break;
|
|
6806
|
+
}
|
|
6807
|
+
console.log("\u274C Token \u4E0D\u80FD\u4E3A\u7A7A\uFF0C\u8BF7\u91CD\u8BD5");
|
|
6808
|
+
}
|
|
6809
|
+
if (!token) {
|
|
6810
|
+
console.error("\n\u274C \u591A\u6B21\u8F93\u5165\u65E0\u6548\u3002\n");
|
|
6726
6811
|
process.exit(1);
|
|
6727
6812
|
}
|
|
6728
|
-
writeSharedConfig({ apiKey:
|
|
6813
|
+
writeSharedConfig({ authToken: token, apiKey: "" });
|
|
6729
6814
|
console.log(`
|
|
6730
|
-
\u2705
|
|
6815
|
+
\u2705 JWT \u5DF2\u4FDD\u5B58\uFF08${maskSecret(token)}\uFF09`);
|
|
6731
6816
|
console.log(` \u914D\u7F6E\u6587\u4EF6\uFF1A${CONFIG_FILE}`);
|
|
6732
6817
|
printPostLoginReminderBanner();
|
|
6733
6818
|
console.log("\u73B0\u5728\u53EF\u4EE5\u8FD0\u884C siluzan-tso -h \u547D\u4EE4\u67E5\u770B\u5E2E\u52A9\u4E86\n");
|
|
6734
|
-
|
|
6735
|
-
|
|
6736
|
-
if (opts.phone !== void 0) {
|
|
6737
|
-
await runPhoneLogin(opts);
|
|
6738
|
-
return;
|
|
6819
|
+
} finally {
|
|
6820
|
+
rl.close();
|
|
6739
6821
|
}
|
|
6822
|
+
}
|
|
6823
|
+
async function runInteractiveApiKeyLogin() {
|
|
6740
6824
|
const shared = readSharedConfig();
|
|
6741
6825
|
const currentKey = shared.apiKey ?? "";
|
|
6742
6826
|
if (currentKey) {
|
|
6743
6827
|
console.log(`
|
|
6744
6828
|
\u5DF2\u68C0\u6D4B\u5230\u5DF2\u4FDD\u5B58\u7684 API Key\uFF08${maskSecret(currentKey)}\uFF09\u3002`);
|
|
6745
|
-
const
|
|
6829
|
+
const rl0 = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
6746
6830
|
const answer = await new Promise(
|
|
6747
|
-
(res) =>
|
|
6748
|
-
|
|
6831
|
+
(res) => rl0.question("\u662F\u5426\u8986\u76D6\uFF1F(y/N) ", (a) => {
|
|
6832
|
+
rl0.close();
|
|
6749
6833
|
res(a.trim());
|
|
6750
6834
|
})
|
|
6751
6835
|
);
|
|
@@ -6756,46 +6840,164 @@ async function runLogin(opts = {}) {
|
|
|
6756
6840
|
}
|
|
6757
6841
|
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
6758
6842
|
const prompt = (q) => new Promise((res) => rl.question(q, (a) => res(a.trim())));
|
|
6759
|
-
|
|
6760
|
-
|
|
6761
|
-
|
|
6762
|
-
|
|
6763
|
-
|
|
6764
|
-
|
|
6843
|
+
try {
|
|
6844
|
+
console.log("\n\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550");
|
|
6845
|
+
console.log(" Siluzan \u767B\u5F55\uFF08API Key\uFF09");
|
|
6846
|
+
console.log("\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550");
|
|
6847
|
+
console.log("\n\u8BF7\u6309\u4EE5\u4E0B\u6B65\u9AA4\u83B7\u53D6 API Key\uFF1A");
|
|
6848
|
+
console.log("\n 1. \u5728\u6D4F\u89C8\u5668\u4E2D\u6253\u5F00\u4EE5\u4E0B\u5730\u5740\uFF08\u9700\u5DF2\u767B\u5F55\u4E1D\u8DEF\u8D5E\u8D26\u53F7\uFF09\uFF1A");
|
|
6849
|
+
console.log(`
|
|
6765
6850
|
${API_KEY_MANAGEMENT_URL}
|
|
6766
6851
|
`);
|
|
6767
|
-
|
|
6768
|
-
|
|
6769
|
-
|
|
6770
|
-
|
|
6771
|
-
|
|
6772
|
-
|
|
6773
|
-
|
|
6774
|
-
|
|
6775
|
-
|
|
6776
|
-
|
|
6852
|
+
console.log(
|
|
6853
|
+
" 2. \u70B9\u51FB\u300C\u521B\u5EFA API Key\u300D\u6309\u94AE\u751F\u6210\u4E00\u4E2A\u65B0\u7684 Key, \u52FE\u9009TSO (\u5E7F\u544A\u6295\u653E\u670D\u52A1)\u4E0ESUCAI (\u7D20\u6750\u4E2D\u5FC3\u670D\u52A1)"
|
|
6854
|
+
);
|
|
6855
|
+
console.log(" 3. \u590D\u5236\u751F\u6210\u7684 API Key");
|
|
6856
|
+
console.log(" 4. \u7C98\u8D34\u5230\u4E0B\u65B9\u5E76\u6309\u56DE\u8F66\n");
|
|
6857
|
+
let apiKey = "";
|
|
6858
|
+
for (let i = 0; i < 3; i++) {
|
|
6859
|
+
const input = await prompt("\u7C98\u8D34 API Key\uFF1A");
|
|
6860
|
+
if (input) {
|
|
6861
|
+
apiKey = input;
|
|
6862
|
+
break;
|
|
6863
|
+
}
|
|
6864
|
+
console.log("\u274C API Key \u4E0D\u80FD\u4E3A\u7A7A\uFF0C\u8BF7\u91CD\u8BD5");
|
|
6865
|
+
}
|
|
6866
|
+
if (!apiKey) {
|
|
6867
|
+
console.error("\n\u274C \u591A\u6B21\u8F93\u5165\u65E0\u6548\uFF0C\u8BF7\u91CD\u8BD5\u3002\n");
|
|
6868
|
+
process.exit(1);
|
|
6869
|
+
}
|
|
6870
|
+
writeSharedConfig({ apiKey });
|
|
6871
|
+
console.log(`
|
|
6872
|
+
\u2705 API Key \u5DF2\u4FDD\u5B58\uFF08${maskSecret(apiKey)}\uFF09`);
|
|
6873
|
+
printPostLoginReminderBanner();
|
|
6874
|
+
console.log("\u73B0\u5728\u53EF\u4EE5\u8FD0\u884C\uFF1A");
|
|
6875
|
+
console.log(" siluzan-tso list-accounts \u67E5\u770B\u5E7F\u544A\u8D26\u6237\u5217\u8868");
|
|
6876
|
+
console.log(" siluzan-tso balance -m Google \u67E5\u770B\u8D26\u6237\u4F59\u989D\n");
|
|
6877
|
+
} finally {
|
|
6878
|
+
rl.close();
|
|
6879
|
+
}
|
|
6880
|
+
}
|
|
6881
|
+
async function runInteractivePhoneLogin(menuOpts) {
|
|
6882
|
+
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
6883
|
+
const prompt = (q) => new Promise((res) => rl.question(q, (a) => res(a.trim())));
|
|
6884
|
+
try {
|
|
6885
|
+
const phoneRaw = await prompt("\n\u8BF7\u8F93\u5165\u624B\u673A\u53F7\uFF08\u5927\u9646\u53F7\u7801\uFF0C\u53EF\u5E26 +86\uFF09\uFF1A");
|
|
6886
|
+
const phone = validateAndNormalizePhone(phoneRaw);
|
|
6887
|
+
const tsoApiBase = process.env.SILUZAN_TSO_API_BASE ?? DEFAULT_API_BASE;
|
|
6888
|
+
const ssoBaseUrl = deriveSsoBaseUrl(tsoApiBase);
|
|
6889
|
+
console.log("\n\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550");
|
|
6890
|
+
console.log(" \u53D1\u9001\u767B\u5F55\u77ED\u4FE1\u9A8C\u8BC1\u7801");
|
|
6891
|
+
console.log("\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550");
|
|
6892
|
+
console.log(` \u624B\u673A\u53F7 : ${phone}`);
|
|
6893
|
+
console.log("\u2192 \u6B63\u5728\u5411\u624B\u673A\u53D1\u9001\u9A8C\u8BC1\u7801...");
|
|
6894
|
+
const sendRes = await sendPhoneLoginCode({ ssoBaseUrl, phone, verbose: menuOpts.verbose });
|
|
6895
|
+
if (!sendRes.ok) {
|
|
6896
|
+
console.error(`
|
|
6897
|
+
\u274C \u77ED\u4FE1\u9A8C\u8BC1\u7801\u53D1\u9001\u5931\u8D25\uFF1A${sendRes.message || "(\u540E\u7AEF\u672A\u8FD4\u56DE\u539F\u56E0)"}
|
|
6898
|
+
`);
|
|
6899
|
+
process.exit(1);
|
|
6900
|
+
}
|
|
6901
|
+
console.log("\u2713 \u9A8C\u8BC1\u7801\u5DF2\u53D1\u9001\uFF0810 \u5206\u949F\u5185\u6709\u6548\uFF09\u3002\n");
|
|
6902
|
+
const code = await prompt("\u8BF7\u8F93\u5165 6 \u4F4D\u9A8C\u8BC1\u7801\uFF1A");
|
|
6903
|
+
if (!code.trim()) {
|
|
6904
|
+
console.error("\n\u274C \u9A8C\u8BC1\u7801\u4E0D\u80FD\u4E3A\u7A7A\u3002\n");
|
|
6905
|
+
process.exit(1);
|
|
6906
|
+
}
|
|
6907
|
+
await executePhoneLoginWithVerifiedCode(phone, code.trim(), menuOpts);
|
|
6908
|
+
} finally {
|
|
6909
|
+
rl.close();
|
|
6910
|
+
}
|
|
6911
|
+
}
|
|
6912
|
+
async function runLoginMethodMenu(menuOpts) {
|
|
6913
|
+
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
6914
|
+
const prompt = (q) => new Promise((res) => rl.question(q, (a) => res(a.trim())));
|
|
6915
|
+
console.log("\n\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550");
|
|
6916
|
+
console.log(" Siluzan \u767B\u5F55");
|
|
6917
|
+
console.log("\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550");
|
|
6918
|
+
console.log("\n\u8BF7\u9009\u62E9\u767B\u5F55\u65B9\u5F0F\uFF1A");
|
|
6919
|
+
console.log(" 1) JWT Token\uFF08Bearer\uFF0C\u7C98\u8D34 access token\uFF09");
|
|
6920
|
+
console.log(" 2) API Key\uFF08\u7F51\u9875\u300C\u8BBE\u7F6E \u2192 API Key \u7BA1\u7406\u300D\u521B\u5EFA\u540E\u7C98\u8D34\uFF09");
|
|
6921
|
+
console.log(" 3) \u624B\u673A\u53F7 + \u77ED\u4FE1\u9A8C\u8BC1\u7801\uFF08\u5C06\u5411\u624B\u673A\u53D1\u9001\u9A8C\u8BC1\u7801\uFF0C\u9A8C\u8BC1\u540E\u81EA\u52A8\u521B\u5EFA API Key\uFF09");
|
|
6922
|
+
console.log(" 0) \u9000\u51FA\n");
|
|
6923
|
+
let choice = "";
|
|
6924
|
+
for (let attempt = 0; attempt < 5; attempt++) {
|
|
6925
|
+
choice = await prompt("\u8BF7\u8F93\u5165\u9009\u9879 [0-3]\uFF1A");
|
|
6926
|
+
if (choice === "0" || choice === "1" || choice === "2" || choice === "3") {
|
|
6777
6927
|
break;
|
|
6778
6928
|
}
|
|
6779
|
-
console.log("\
|
|
6929
|
+
console.log("\u65E0\u6548\u9009\u62E9\uFF0C\u8BF7\u8F93\u5165 0\u30011\u30012 \u6216 3\u3002");
|
|
6780
6930
|
}
|
|
6781
6931
|
rl.close();
|
|
6782
|
-
if (
|
|
6783
|
-
console.
|
|
6784
|
-
|
|
6932
|
+
if (choice === "0" || choice === "") {
|
|
6933
|
+
console.log("\n\u5DF2\u53D6\u6D88\u3002\n");
|
|
6934
|
+
return;
|
|
6785
6935
|
}
|
|
6786
|
-
|
|
6787
|
-
|
|
6788
|
-
|
|
6789
|
-
|
|
6790
|
-
|
|
6791
|
-
|
|
6792
|
-
|
|
6793
|
-
|
|
6936
|
+
if (choice === "1") {
|
|
6937
|
+
await runInteractiveJwtLogin();
|
|
6938
|
+
return;
|
|
6939
|
+
}
|
|
6940
|
+
if (choice === "2") {
|
|
6941
|
+
await runInteractiveApiKeyLogin();
|
|
6942
|
+
return;
|
|
6943
|
+
}
|
|
6944
|
+
await runInteractivePhoneLogin(menuOpts);
|
|
6945
|
+
}
|
|
6946
|
+
async function runLogin(opts = {}) {
|
|
6947
|
+
if (opts.apiKey !== void 0) {
|
|
6948
|
+
const key = opts.apiKey.trim();
|
|
6949
|
+
if (!key) {
|
|
6950
|
+
console.error("\n\u274C API Key \u4E0D\u80FD\u4E3A\u7A7A\u3002\n");
|
|
6951
|
+
process.exit(1);
|
|
6952
|
+
}
|
|
6953
|
+
writeSharedConfig({ apiKey: key });
|
|
6954
|
+
console.log(`
|
|
6955
|
+
\u2705 API Key \u5DF2\u4FDD\u5B58\uFF08${maskSecret(key)}\uFF09`);
|
|
6956
|
+
console.log(` \u914D\u7F6E\u6587\u4EF6\uFF1A${CONFIG_FILE}`);
|
|
6957
|
+
printPostLoginReminderBanner();
|
|
6958
|
+
console.log("\u73B0\u5728\u53EF\u4EE5\u8FD0\u884C siluzan-tso -h \u547D\u4EE4\u67E5\u770B\u5E2E\u52A9\u4E86\n");
|
|
6959
|
+
return;
|
|
6960
|
+
}
|
|
6961
|
+
if (opts.phone !== void 0) {
|
|
6962
|
+
await runPhoneLogin(opts);
|
|
6963
|
+
return;
|
|
6964
|
+
}
|
|
6965
|
+
if (opts.manual) {
|
|
6966
|
+
await runInteractiveJwtLogin();
|
|
6967
|
+
return;
|
|
6968
|
+
}
|
|
6969
|
+
await runLoginMethodMenu(opts);
|
|
6794
6970
|
}
|
|
6795
6971
|
function register(program2) {
|
|
6796
|
-
program2.command("login").description("\
|
|
6797
|
-
await
|
|
6972
|
+
program2.command("send-login-code").description("\u5411\u624B\u673A\u53F7\u53D1\u9001\u4E1D\u8DEF\u8D5E\u767B\u5F55\u77ED\u4FE1\u9A8C\u8BC1\u7801\uFF08\u65E0\u4EA4\u4E92\uFF0C\u9002\u5408 Agent\uFF1A\u5148\u53D1\u7801\u518D login --phone --code\uFF09").requiredOption("--phone <phone>", "\u4E2D\u56FD\u5927\u9646\u624B\u673A\u53F7\uFF08\u53EF\u5E26 +86\uFF09").option("--verbose", "\u8BE6\u7EC6\u9519\u8BEF\u4FE1\u606F", false).action(async (opts) => {
|
|
6973
|
+
await runSendLoginCode({ phone: opts.phone, verbose: opts.verbose });
|
|
6798
6974
|
});
|
|
6975
|
+
program2.command("login").description(
|
|
6976
|
+
"\u4FDD\u5B58\u8BA4\u8BC1\u51ED\u636E\u5230 ~/.siluzan/config.json\uFF1B\u65E0\u53C2\u6570\u65F6\u5C55\u5F00 JWT / API Key / \u624B\u673A\u53F7\u4E09\u79CD\u4EA4\u4E92\u767B\u5F55"
|
|
6977
|
+
).option("--api-key <key>", "\u76F4\u63A5\u4FDD\u5B58 API Key\uFF08\u7F51\u9875\u300C\u8BBE\u7F6E \u2192 API Key \u7BA1\u7406\u300D\u521B\u5EFA\uFF09").option("--phone <phone>", "\u624B\u673A\u53F7\uFF08\u987B\u4E0E --code \u540C\u4F20\uFF1B\u6216\u7EC8\u7AEF\u65E0\u53C2 login \u9009 3 \u7531 CLI \u53D1\u7801\uFF09").option("--code <code>", "\u77ED\u4FE1\u9A8C\u8BC1\u7801\uFF08\u987B\u4E0E --phone \u540C\u4F20\uFF09").option("--name <text>", "\u624B\u673A\u53F7\u767B\u5F55\u65F6\u81EA\u52A8\u521B\u5EFA\u7684 API Key \u540D\u79F0").option("--valid-days <n>", "API Key \u6709\u6548\u5929\u6570\uFF0C\u9ED8\u8BA4 90").option("--expires-at <iso>", "API Key \u7EDD\u5BF9\u8FC7\u671F\u65F6\u95F4 ISO8601\uFF08\u4E0E --valid-days \u4E8C\u9009\u4E00\uFF09").option("--services <csv>", "API Key \u670D\u52A1\uFF1ACSO,TSO,CUT \u9017\u53F7\u5206\u9694\uFF0C\u9ED8\u8BA4 TSO,CUT").option("--manual", "\u8DF3\u8FC7\u83DC\u5355\uFF0C\u76F4\u63A5\u7C98\u8D34 JWT\uFF08\u4E0E\u65E0\u53C2\u83DC\u5355\u9009\u9879 1 \u7B49\u4EF7\uFF09").option("--verbose", "\u8BE6\u7EC6 HTTP", false).action(
|
|
6978
|
+
async (opts) => {
|
|
6979
|
+
let validDays;
|
|
6980
|
+
if (opts.validDays !== void 0 && String(opts.validDays).trim() !== "") {
|
|
6981
|
+
const n = parseInt(String(opts.validDays), 10);
|
|
6982
|
+
if (Number.isNaN(n)) {
|
|
6983
|
+
console.error("\n\u274C --valid-days \u987B\u4E3A\u6574\u6570\n");
|
|
6984
|
+
process.exit(1);
|
|
6985
|
+
}
|
|
6986
|
+
validDays = n;
|
|
6987
|
+
}
|
|
6988
|
+
await runLogin({
|
|
6989
|
+
apiKey: opts.apiKey,
|
|
6990
|
+
phone: opts.phone,
|
|
6991
|
+
code: opts.code,
|
|
6992
|
+
name: opts.name,
|
|
6993
|
+
validDays,
|
|
6994
|
+
expiresAt: opts.expiresAt,
|
|
6995
|
+
services: opts.services,
|
|
6996
|
+
verbose: opts.verbose,
|
|
6997
|
+
manual: opts.manual
|
|
6998
|
+
});
|
|
6999
|
+
}
|
|
7000
|
+
);
|
|
6799
7001
|
}
|
|
6800
7002
|
|
|
6801
7003
|
// src/commands/config.ts
|
package/dist/skill/_meta.json
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
|
|
8
8
|
## invoice-info — 发票抬头管理
|
|
9
9
|
|
|
10
|
-
对应页面:`https://www
|
|
10
|
+
对应页面:`https://www.siluzan.com/v3/foreign_trade/settings/invoiceInformation`
|
|
11
11
|
|
|
12
12
|
发票抬头是开票申请时使用的公司/企业信息模板,支持三种类型:
|
|
13
13
|
|
|
@@ -133,10 +133,10 @@ siluzan-tso config show
|
|
|
133
133
|
**示例:**
|
|
134
134
|
|
|
135
135
|
```
|
|
136
|
-
- 现金充值(单笔):https://www
|
|
137
|
-
- 现金充值(批量):https://www
|
|
138
|
-
- 月结充值: https://www
|
|
139
|
-
- 丝路赞钱包: https://www
|
|
136
|
+
- 现金充值(单笔):https://www.siluzan.com/recharge/pay
|
|
137
|
+
- 现金充值(批量):https://www.siluzan.com/recharge/pay_batch
|
|
138
|
+
- 月结充值: https://www.siluzan.com/recharge/accountBillingQuota
|
|
139
|
+
- 丝路赞钱包: https://www.siluzan.com/recharge/siluzanWallet
|
|
140
140
|
```
|
|
141
141
|
|
|
142
142
|
---
|
|
@@ -214,8 +214,8 @@ siluzan-tso report list -m Google --json
|
|
|
214
214
|
|
|
215
215
|
# 第二步:查看 webUrl
|
|
216
216
|
siluzan-tso config show
|
|
217
|
-
# webUrl: https://www
|
|
217
|
+
# webUrl: https://www.siluzan.com
|
|
218
218
|
|
|
219
219
|
# 第三步:拼接链接(Google 日报)
|
|
220
|
-
# https://www
|
|
220
|
+
# https://www.siluzan.com/media-report/publish/rpt_abc123?culture=zh-CN
|
|
221
221
|
```
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
## 安装 CLI
|
|
11
11
|
|
|
12
12
|
```bash
|
|
13
|
-
npm install -g siluzan-tso-cli
|
|
13
|
+
npm install -g siluzan-tso-cli
|
|
14
14
|
```
|
|
15
15
|
|
|
16
16
|
---
|
|
@@ -57,13 +57,14 @@ siluzan-tso init -d /path/to-your/skills # 写入自定义目录
|
|
|
57
57
|
## 其它登录方式(TTY 交互 / 已有 API Key / JWT)
|
|
58
58
|
|
|
59
59
|
```bash
|
|
60
|
-
siluzan-tso login #
|
|
60
|
+
siluzan-tso login # 无参:TTY 下展开菜单 → 1 JWT / 2 API Key / 3 手机号(发码+输码)
|
|
61
|
+
siluzan-tso login --manual # 跳过菜单,直接粘贴 JWT(会清除已存 API Key 以启用 Bearer)
|
|
61
62
|
siluzan-tso login --api-key <YOUR_API_KEY> # 直接设置 API Key(跳过交互)
|
|
62
63
|
siluzan-tso config set --api-key <Key> # 或 config 直接写入
|
|
63
64
|
siluzan-tso config set --token <Token> # 备用:设置 JWT Token
|
|
64
65
|
```
|
|
65
66
|
|
|
66
|
-
API Key 获取入口:`https://www
|
|
67
|
+
API Key 获取入口:`https://www.siluzan.com/v3/foreign_trade/settings/apiKeyManagement`
|
|
67
68
|
|
|
68
69
|
|
|
69
70
|
```bash
|
|
@@ -94,7 +95,7 @@ siluzan-tso login --phone 13800138000 --code 123456 \
|
|
|
94
95
|
>
|
|
95
96
|
> **验证码错误/过期**:返回明确提示,让用户重新跑 `send-login-code` 拿新验证码。
|
|
96
97
|
>
|
|
97
|
-
> **AI 助手用法**:先调 `send-login-code` 发码、立即返回继续对话;等用户报出收到的验证码后,再调 `login --phone xxx --code xxx` 完成登录。**永远不要在没拿到 `--code` 的情况下调用 `login --phone xxx
|
|
98
|
+
> **AI 助手用法**:先调 `send-login-code` 发码、立即返回继续对话;等用户报出收到的验证码后,再调 `login --phone xxx --code xxx` 完成登录。**永远不要在没拿到 `--code` 的情况下调用 `login --phone xxx`,那会直接报错。**(人类在本地终端可直接运行无参 `siluzan-tso login` 选 3,由 CLI 发码并读验证码,无需先记 `send-login-code`。)
|
|
98
99
|
|
|
99
100
|
### 通过环境变量传入凭据(CI/CD 推荐)
|
|
100
101
|
|
|
@@ -129,9 +130,9 @@ siluzan-tso config show
|
|
|
129
130
|
|
|
130
131
|
```
|
|
131
132
|
构建环境 : production
|
|
132
|
-
apiBaseUrl : https://tso-api
|
|
133
|
-
googleApiUrl : https://googleapi
|
|
134
|
-
webUrl : https://www
|
|
133
|
+
apiBaseUrl : https://tso-api.siluzan.com
|
|
134
|
+
googleApiUrl : https://googleapi.mysiluzan.com
|
|
135
|
+
webUrl : https://www.siluzan.com
|
|
135
136
|
apiKey : abcd****1234
|
|
136
137
|
```
|
|
137
138
|
|
|
@@ -10,8 +10,8 @@ $ErrorActionPreference = 'Stop'
|
|
|
10
10
|
$PKG_NAME = 'siluzan-tso-cli'
|
|
11
11
|
$CLI_BIN = 'siluzan-tso'
|
|
12
12
|
$SKILL_LABEL = 'Siluzan TSO'
|
|
13
|
-
$INSTALL_CMD = 'npm install -g siluzan-tso-cli
|
|
14
|
-
$WEB_BASE = 'https://www
|
|
13
|
+
$INSTALL_CMD = 'npm install -g siluzan-tso-cli'
|
|
14
|
+
$WEB_BASE = 'https://www.siluzan.com'
|
|
15
15
|
|
|
16
16
|
# -- Constants ----------------------------------------------------------------
|
|
17
17
|
$NODE_MAJOR_MIN = 18
|
|
@@ -10,8 +10,8 @@ set -euo pipefail
|
|
|
10
10
|
readonly PKG_NAME="siluzan-tso-cli"
|
|
11
11
|
readonly CLI_BIN="siluzan-tso"
|
|
12
12
|
readonly SKILL_LABEL="Siluzan TSO"
|
|
13
|
-
readonly INSTALL_CMD="npm install -g siluzan-tso-cli
|
|
14
|
-
readonly WEB_BASE="https://www
|
|
13
|
+
readonly INSTALL_CMD="npm install -g siluzan-tso-cli"
|
|
14
|
+
readonly WEB_BASE="https://www.siluzan.com"
|
|
15
15
|
|
|
16
16
|
# -- Constants ----------------------------------------------------------------
|
|
17
17
|
readonly NODE_MAJOR_MIN=18
|