@helixlife-ai/xiantao 0.1.19 → 0.1.21
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 +11 -1
- package/dist/base-command.js +1 -103
- package/dist/commands/auth/login.js +2 -76
- package/dist/commands/auth/logout.js +1 -20
- package/dist/commands/auth/status.js +2 -60
- package/dist/commands/history/delete.js +1 -38
- package/dist/commands/history/download.js +5 -149
- package/dist/commands/history/list.js +3 -72
- package/dist/commands/history/rename.js +1 -45
- package/dist/commands/login.js +1 -3
- package/dist/commands/logout.js +1 -3
- package/dist/commands/plot/download.js +1 -31
- package/dist/commands/plot/fetch-all.js +1 -47
- package/dist/commands/plot/login.js +2 -76
- package/dist/commands/plot/menu.js +1 -37
- package/dist/commands/plot/menus-raw.js +1 -31
- package/dist/commands/plot/menus.js +2 -47
- package/dist/commands/plot/resolve.js +1 -48
- package/dist/commands/plot/run.js +5 -803
- package/dist/commands/status.js +1 -3
- package/dist/commands/tool/cloud.js +1 -0
- package/dist/commands/tool/download.js +1 -3
- package/dist/commands/tool/exec.js +1 -96
- package/dist/commands/tool/fetch-all.js +1 -3
- package/dist/commands/tool/inspect.js +3 -180
- package/dist/commands/tool/login.js +1 -3
- package/dist/commands/tool/menu.js +1 -3
- package/dist/commands/tool/menus-raw.js +1 -3
- package/dist/commands/tool/menus.js +1 -3
- package/dist/commands/tool/prepare.js +1 -110
- package/dist/commands/tool/resolve.js +1 -3
- package/dist/commands/tool/run.js +1 -3
- package/dist/commands/tool/search.js +2 -53
- package/dist/index.js +0 -1
- package/dist/lib/auth.js +1 -90
- package/dist/lib/constants.js +1 -12
- package/dist/lib/download.js +1 -32
- package/dist/lib/envelope.js +1 -70
- package/dist/lib/errors.js +1 -42
- package/dist/lib/flags.js +1 -11
- package/dist/lib/history.js +1 -200
- package/dist/lib/http.js +1 -41
- package/dist/lib/json.js +1 -20
- package/dist/lib/login-flow.js +1 -10
- package/dist/lib/open-url.js +1 -25
- package/dist/lib/plot-interactive.js +39 -631
- package/dist/lib/plot-options.js +1 -84
- package/dist/lib/plot-schema.js +1 -17
- package/dist/lib/plot.js +1 -144
- package/dist/lib/storage.js +2 -150
- package/dist/lib/tool-inputs.js +1 -51
- package/dist/lib/update.js +2 -151
- package/dist/lib/xiantao-auth.js +7 -117
- package/dist/lib/xiantao-cloud.js +1 -0
- package/dist/lib/xiantao-plot.js +1 -184
- package/dist/lib/xiantao.js +1 -184
- package/dist/xtz-help.js +6 -101
- package/package.json +7 -3
- package/bin/dev.js +0 -7
package/README.md
CHANGED
|
@@ -42,6 +42,11 @@ xt tool exec gsea_analysis --demo --profile opencode --json
|
|
|
42
42
|
xt tool prepare gsea_plot --profile opencode --json
|
|
43
43
|
xt tool exec gsea_plot --profile opencode --json --download ./gsea_plot.pdf
|
|
44
44
|
xt tool exec gsea_customize --file gene_set=./gene_set.gmt --file data=./rank.xlsx --profile opencode --json
|
|
45
|
+
|
|
46
|
+
xt tool cloud km_plot_gene --profile opencode --json --filter '胆管癌'
|
|
47
|
+
xt tool exec km_plot_gene --profile opencode --json --cloudFilter '胆管癌'
|
|
48
|
+
xt tool exec km_plot_gene --profile opencode --json --cloudFilter '胆管癌' --cloudIndex 1
|
|
49
|
+
xt tool exec km_plot_gene --profile opencode --json --cloudDataId tcga-chol-2
|
|
45
50
|
```
|
|
46
51
|
|
|
47
52
|
For machine callers, use `xt tool prepare` to fetch the final schema, then `xt tool exec` to submit. Keep `--json`, pass an explicit profile with `--profile`, and avoid interactive-only flows.
|
|
@@ -52,11 +57,15 @@ The examples below illustrate command shapes, not a fixed allowlist of tools. Ap
|
|
|
52
57
|
- multi-upload modules: repeat `--file key=path`, for example `--file gene_set=./gene_set.gmt --file data=./rank.xlsx`
|
|
53
58
|
- demo-capable upload modules: pass `--demo`
|
|
54
59
|
- history-record modules such as `gsea_plot`: pass neither `--file` nor `--demo`; the CLI reuses the default `XTRecord` returned by `tool inspect` / `tool prepare`
|
|
60
|
+
- cloud-capable modules: use `--cloudFilter <keyword>` to narrow cloud records, then retry with `--cloudIndex <n>` or `--cloudDataId <id>` when multiple matches exist
|
|
55
61
|
|
|
56
62
|
Current operational notes for agent-style callers:
|
|
57
63
|
- serialize `xt tool exec` submits per profile; Xiantao may reject overlapping or too-frequent submits with `NETWORK_ERROR`
|
|
58
64
|
- `tool inspect` now includes the full `args_data` payload in JSON output and summarizes every detected `XTUpload` field
|
|
65
|
+
- `tool inspect` also reports `inputs.cloud_available` and `inputs.cloud_default` for `XTCloud` modules
|
|
59
66
|
- for multi-upload modules, pass keyed uploads in the same field names returned by `tool inspect`
|
|
67
|
+
- `tool cloud --json --filter <keyword>` returns structured cloud candidates via `data.choices`
|
|
68
|
+
- if `tool prepare` or `tool exec` returns `code=TOOL_AMBIGUOUS` with `data.selection_type=cloud_record`, do not auto-pick; ask the user which item to use, then retry with `--cloudIndex` or `--cloudDataId`
|
|
60
69
|
- `gsea_customize` has been validated through `tool prepare` and `tool exec` with repeated `--file gene_set=... --file data=...`
|
|
61
70
|
|
|
62
71
|
For agent workflows, do not use `xt tool run`. Treat `xt tool run` as the human-first path and `xt tool exec` as the machine path.
|
|
@@ -83,6 +92,7 @@ For agent workflows, do not use `xt tool run`. Treat `xt tool run` as the human-
|
|
|
83
92
|
|
|
84
93
|
- `xt tool search`
|
|
85
94
|
- `xt tool inspect`
|
|
95
|
+
- `xt tool cloud`
|
|
86
96
|
- `xt tool prepare`
|
|
87
97
|
- `xt tool run`
|
|
88
98
|
- `xt tool exec`
|
|
@@ -102,7 +112,7 @@ For the common Xiantao tool product, `tool search`, `tool inspect`, `tool run`,
|
|
|
102
112
|
|
|
103
113
|
The CLI also loads a project-root `.env` file on startup. You can set `XIANTAO_BASE_URL=https://agent.helixlife.cn` there to switch the API base URL without prefixing each command manually.
|
|
104
114
|
|
|
105
|
-
`xt tool search <keyword>` searches remote tool menus by tool id, title, path, and route. `xt tool inspect <tool_id>` prints resolved metadata together with the dynamic `args_main` schema, the full `args_data` payload in JSON mode, and the detected input source summary, including per-field `XTUpload` defaults and `
|
|
115
|
+
`xt tool search <keyword>` searches remote tool menus by tool id, title, path, and route. `xt tool inspect <tool_id>` prints resolved metadata together with the dynamic `args_main` schema, the full `args_data` payload in JSON mode, and the detected input source summary, including `XTCloud`, per-field `XTUpload`, and `XTRecord` defaults. `xt tool cloud <tool_id>` fetches paginated cloud candidates and returns a machine-friendly `data.choices` list when `--json` is used. `xt tool run <tool_id>` runs a Xiantao bioinformatics tool in the human-first path. `xt tool exec <tool_id>` is the agent-safe submit command and also supports `--download <path>` when a local artifact is needed. `xt tool resolve <tool_id>` remains available as the low-level UUID and route lookup. `xt tool menus` returns a concise catalog with each tool title, `module_id`, `path`, and `route`, which is useful when `tool search` finds nothing helpful or when you want to shortlist tools for recommendation. `--demo` reuses the demo file metadata returned by `tool fetch-all`; `--file` uploads a local file first; multi-upload modules accept repeated `--file key=path`; for `XTRecord` modules the CLI can submit directly from the default history record returned by `fetch-all`; for `XTCloud` modules use `--cloudFilter`, then `--cloudIndex` or `--cloudDataId` to pin one cloud record before submit. Run `xt login` first to authorize the stored token. When cloud filtering matches multiple records, `tool prepare` and `tool exec` return `code=TOOL_AMBIGUOUS` plus `data.selection_type=cloud_record` and `data.choices`; callers should ask the user which record to use before retrying. When a tool exposes multiple downloadable results, `--download <path>` uses the output file extension to select the matching artifact.
|
|
106
116
|
|
|
107
117
|
For the current GSEA tool family, `gsea_plot`, `gsea_plot2`, `gsea_bar`, `gsea_point`, `gsea_ridge`, `gsea_emapplot`, `gsea_tree`, and `gsea_path_cluster` are record-backed visual modules that reuse the default `gsea_analysis` history record. `gsea_analysis` itself is an upload/demo analysis module. `gsea_customize` is a custom gene-set upload module whose frontend expects two uploads, `gene_set` and `data`; submit it with `--file gene_set=... --file data=...`. A real CLI submit path has been verified with the sample files in [`docs/GSEA-基因集.csv`](/Users/chenyunjie/Desktop/xtz-cli/xiantao/docs/GSEA-基因集.csv) and [`docs/GSEA-分子.xlsx`](/Users/chenyunjie/Desktop/xtz-cli/xiantao/docs/GSEA-分子.xlsx).
|
|
108
118
|
|
package/dist/base-command.js
CHANGED
|
@@ -1,103 +1 @@
|
|
|
1
|
-
import
|
|
2
|
-
import { createErrorEnvelope, createSuccessEnvelope } from './lib/envelope.js';
|
|
3
|
-
import { XtzError } from './lib/errors.js';
|
|
4
|
-
import { resolveAgent } from './lib/storage.js';
|
|
5
|
-
import { getUpdateReminder } from './lib/update.js';
|
|
6
|
-
export class XtzCommand extends Command {
|
|
7
|
-
async init() {
|
|
8
|
-
await super.init();
|
|
9
|
-
await this.warnIfUpdateAvailable();
|
|
10
|
-
}
|
|
11
|
-
async getProfile(profileFlag) {
|
|
12
|
-
return resolveAgent(profileFlag);
|
|
13
|
-
}
|
|
14
|
-
async getAgent(agentFlag) {
|
|
15
|
-
return this.getProfile(agentFlag);
|
|
16
|
-
}
|
|
17
|
-
print(flags, data, text, context) {
|
|
18
|
-
if (flags.json) {
|
|
19
|
-
if (context) {
|
|
20
|
-
this.log(JSON.stringify(createSuccessEnvelope(context.profile, context.command ?? this.getCommandName(), data), null, 2));
|
|
21
|
-
return;
|
|
22
|
-
}
|
|
23
|
-
this.log(JSON.stringify(data, null, 2));
|
|
24
|
-
return;
|
|
25
|
-
}
|
|
26
|
-
this.log(text);
|
|
27
|
-
}
|
|
28
|
-
async catch(error) {
|
|
29
|
-
if (this.isJsonOutputRequested()) {
|
|
30
|
-
const profile = await this.getProfile(this.readProfileFlagFromArgv());
|
|
31
|
-
this.log(JSON.stringify(createErrorEnvelope(profile, this.getCommandName(), error), null, 2));
|
|
32
|
-
this.exit(1);
|
|
33
|
-
}
|
|
34
|
-
if (error instanceof XtzError) {
|
|
35
|
-
this.error(error.message, { exit: 1 });
|
|
36
|
-
}
|
|
37
|
-
throw error;
|
|
38
|
-
}
|
|
39
|
-
warnIfLegacyPlotCommand() {
|
|
40
|
-
if (!this.id?.startsWith('plot:') || this.argv.includes('--json')) {
|
|
41
|
-
return;
|
|
42
|
-
}
|
|
43
|
-
const command = this.id.replaceAll(':', ' ');
|
|
44
|
-
const replacement = command.replace(/^plot\b/, 'tool');
|
|
45
|
-
this.warn(`\`xt ${command}\` 已兼容保留,建议改用 \`xt ${replacement}\``);
|
|
46
|
-
}
|
|
47
|
-
warnIfLegacyAuthCommand() {
|
|
48
|
-
if (!this.id?.startsWith('auth:') || this.argv.includes('--json')) {
|
|
49
|
-
return;
|
|
50
|
-
}
|
|
51
|
-
const command = this.id.replaceAll(':', ' ');
|
|
52
|
-
const replacement = command.replace(/^auth /, '');
|
|
53
|
-
this.warn(`\`xt ${command}\` 已兼容保留,建议改用 \`xt ${replacement}\``);
|
|
54
|
-
}
|
|
55
|
-
async warnIfUpdateAvailable() {
|
|
56
|
-
if (this.argv.includes('--json') || !process.stdout.isTTY || this.shouldSkipUpdateReminder()) {
|
|
57
|
-
return;
|
|
58
|
-
}
|
|
59
|
-
const reminder = await getUpdateReminder(this.config.version);
|
|
60
|
-
if (!reminder) {
|
|
61
|
-
return;
|
|
62
|
-
}
|
|
63
|
-
this.warn(reminder);
|
|
64
|
-
}
|
|
65
|
-
getCommandName() {
|
|
66
|
-
return this.id?.replaceAll(':', ' ') ?? 'unknown';
|
|
67
|
-
}
|
|
68
|
-
isJsonOutputRequested() {
|
|
69
|
-
return this.argv.includes('--json');
|
|
70
|
-
}
|
|
71
|
-
readProfileFlagFromArgv() {
|
|
72
|
-
for (let index = 0; index < this.argv.length; index += 1) {
|
|
73
|
-
const token = this.argv[index];
|
|
74
|
-
if ((token === '--profile' || token === '--agent') && this.argv[index + 1]) {
|
|
75
|
-
return this.argv[index + 1];
|
|
76
|
-
}
|
|
77
|
-
if (token.startsWith('--profile=')) {
|
|
78
|
-
return token.slice('--profile='.length);
|
|
79
|
-
}
|
|
80
|
-
if (token.startsWith('--agent=')) {
|
|
81
|
-
return token.slice('--agent='.length);
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
return undefined;
|
|
85
|
-
}
|
|
86
|
-
shouldSkipUpdateReminder() {
|
|
87
|
-
const commandId = this.id ?? '';
|
|
88
|
-
return [
|
|
89
|
-
'login',
|
|
90
|
-
'logout',
|
|
91
|
-
'status',
|
|
92
|
-
'auth:login',
|
|
93
|
-
'auth:logout',
|
|
94
|
-
'auth:status',
|
|
95
|
-
'plot:login',
|
|
96
|
-
'plot:run',
|
|
97
|
-
'tool:exec',
|
|
98
|
-
'tool:login',
|
|
99
|
-
'tool:prepare',
|
|
100
|
-
'tool:run',
|
|
101
|
-
].includes(commandId);
|
|
102
|
-
}
|
|
103
|
-
}
|
|
1
|
+
import{Command as n}from"@oclif/core";import{createErrorEnvelope as s,createSuccessEnvelope as o}from"./lib/envelope.js";import{XtzError as a}from"./lib/errors.js";import{resolveAgent as l}from"./lib/storage.js";import{getUpdateReminder as h}from"./lib/update.js";class f extends n{async init(){await super.init(),await this.warnIfUpdateAvailable()}async getProfile(t){return l(t)}async getAgent(t){return this.getProfile(t)}print(t,e,r,i){if(t.json){if(i){this.log(JSON.stringify(o(i.profile,i.command??this.getCommandName(),e),null,2));return}this.log(JSON.stringify(e,null,2));return}this.log(r)}async catch(t){if(this.isJsonOutputRequested()){const e=await this.getProfile(this.readProfileFlagFromArgv());this.log(JSON.stringify(s(e,this.getCommandName(),t),null,2)),this.exit(1)}throw t instanceof a&&this.error(t.message,{exit:1}),t}warnIfLegacyPlotCommand(){if(!this.id?.startsWith("plot:")||this.argv.includes("--json"))return;const t=this.id.replaceAll(":"," "),e=t.replace(/^plot\b/,"tool");this.warn(`\`xt ${t}\` \u5DF2\u517C\u5BB9\u4FDD\u7559\uFF0C\u5EFA\u8BAE\u6539\u7528 \`xt ${e}\``)}warnIfLegacyAuthCommand(){if(!this.id?.startsWith("auth:")||this.argv.includes("--json"))return;const t=this.id.replaceAll(":"," "),e=t.replace(/^auth /,"");this.warn(`\`xt ${t}\` \u5DF2\u517C\u5BB9\u4FDD\u7559\uFF0C\u5EFA\u8BAE\u6539\u7528 \`xt ${e}\``)}async warnIfUpdateAvailable(){if(this.argv.includes("--json")||!process.stdout.isTTY||this.shouldSkipUpdateReminder())return;const t=await h(this.config.version);t&&this.warn(t)}getCommandName(){return this.id?.replaceAll(":"," ")??"unknown"}isJsonOutputRequested(){return this.argv.includes("--json")}readProfileFlagFromArgv(){for(let t=0;t<this.argv.length;t+=1){const e=this.argv[t];if((e==="--profile"||e==="--agent")&&this.argv[t+1])return this.argv[t+1];if(e.startsWith("--profile="))return e.slice(10);if(e.startsWith("--agent="))return e.slice(8)}}shouldSkipUpdateReminder(){const t=this.id??"";return["login","logout","status","auth:login","auth:logout","auth:status","plot:login","plot:run","tool:exec","tool:login","tool:prepare","tool:run"].includes(t)}}export{f as XtzCommand};
|
|
@@ -1,76 +1,2 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
3
|
-
import { globalFlags } from '../../lib/flags.js';
|
|
4
|
-
import { loginAuth } from '../../lib/auth.js';
|
|
5
|
-
import { loginAll } from '../../lib/login-flow.js';
|
|
6
|
-
import { getTokenPath } from '../../lib/storage.js';
|
|
7
|
-
export default class AuthLogin extends XtzCommand {
|
|
8
|
-
static description = 'Authorize the current profile token';
|
|
9
|
-
static flags = {
|
|
10
|
-
...globalFlags,
|
|
11
|
-
open: Flags.boolean({
|
|
12
|
-
allowNo: true,
|
|
13
|
-
default: true,
|
|
14
|
-
description: 'Open the authorization link in the browser',
|
|
15
|
-
}),
|
|
16
|
-
wait: Flags.boolean({
|
|
17
|
-
allowNo: true,
|
|
18
|
-
default: true,
|
|
19
|
-
description: 'Wait until the browser authorization is confirmed before exiting',
|
|
20
|
-
}),
|
|
21
|
-
};
|
|
22
|
-
async run() {
|
|
23
|
-
this.warnIfLegacyAuthCommand();
|
|
24
|
-
const { flags } = await this.parse(AuthLogin);
|
|
25
|
-
const agent = await this.getProfile(flags.profile);
|
|
26
|
-
const waitForAuthorization = this.shouldWait(flags);
|
|
27
|
-
const result = waitForAuthorization
|
|
28
|
-
? await loginAll(agent, flags.open, ({ auth, phase }) => {
|
|
29
|
-
if (flags.json) {
|
|
30
|
-
return;
|
|
31
|
-
}
|
|
32
|
-
if (phase === 'auth_started') {
|
|
33
|
-
this.log(auth.browserOpened ? '浏览器已打开授权链接,等待授权完成...' : `请先在浏览器中打开授权链接: ${auth.linkUrl}`);
|
|
34
|
-
return;
|
|
35
|
-
}
|
|
36
|
-
this.log('授权已确认。');
|
|
37
|
-
})
|
|
38
|
-
: { auth: await loginAuth(agent, flags.open) };
|
|
39
|
-
const authorized = waitForAuthorization;
|
|
40
|
-
this.print(flags, {
|
|
41
|
-
agent,
|
|
42
|
-
authorization_pending: !authorized,
|
|
43
|
-
authorized,
|
|
44
|
-
browser_opened: result.auth.browserOpened,
|
|
45
|
-
link_url: result.auth.linkUrl,
|
|
46
|
-
token_path: result.auth.tokenPath,
|
|
47
|
-
wait: waitForAuthorization,
|
|
48
|
-
}, this.formatLoginText({
|
|
49
|
-
agent,
|
|
50
|
-
authorized,
|
|
51
|
-
browserOpened: result.auth.browserOpened,
|
|
52
|
-
linkUrl: result.auth.linkUrl,
|
|
53
|
-
}), { profile: agent });
|
|
54
|
-
}
|
|
55
|
-
shouldWait(flags) {
|
|
56
|
-
if (!this.hasExplicitWaitFlag()) {
|
|
57
|
-
return !flags.json;
|
|
58
|
-
}
|
|
59
|
-
return flags.wait;
|
|
60
|
-
}
|
|
61
|
-
hasExplicitWaitFlag() {
|
|
62
|
-
return this.argv.includes('--wait') || this.argv.includes('--no-wait');
|
|
63
|
-
}
|
|
64
|
-
formatLoginText(input) {
|
|
65
|
-
const lines = [
|
|
66
|
-
`profile: ${input.agent}`,
|
|
67
|
-
`token: ${getTokenPath(input.agent)}`,
|
|
68
|
-
`authorized: ${input.authorized}`,
|
|
69
|
-
];
|
|
70
|
-
if (input.authorized) {
|
|
71
|
-
return lines.join('\n');
|
|
72
|
-
}
|
|
73
|
-
lines.push(input.browserOpened ? '浏览器已打开授权链接,请完成授权后运行 `xt status`。' : `请在浏览器中打开: ${input.linkUrl}`);
|
|
74
|
-
return lines.join('\n');
|
|
75
|
-
}
|
|
76
|
-
}
|
|
1
|
+
import{Flags as s}from"@oclif/core";import{XtzCommand as h}from"../../base-command.js";import{globalFlags as u}from"../../lib/flags.js";import{loginAuth as d}from"../../lib/auth.js";import{loginAll as p}from"../../lib/login-flow.js";import{getTokenPath as f}from"../../lib/storage.js";class a extends h{static description="Authorize the current profile token";static flags={...u,open:s.boolean({allowNo:!0,default:!0,description:"Open the authorization link in the browser"}),wait:s.boolean({allowNo:!0,default:!0,description:"Wait until the browser authorization is confirmed before exiting"})};async run(){this.warnIfLegacyAuthCommand();const{flags:t}=await this.parse(a),o=await this.getProfile(t.profile),i=this.shouldWait(t),e=i?await p(o,t.open,({auth:n,phase:l})=>{if(!t.json){if(l==="auth_started"){this.log(n.browserOpened?"\u6D4F\u89C8\u5668\u5DF2\u6253\u5F00\u6388\u6743\u94FE\u63A5\uFF0C\u7B49\u5F85\u6388\u6743\u5B8C\u6210...":`\u8BF7\u5148\u5728\u6D4F\u89C8\u5668\u4E2D\u6253\u5F00\u6388\u6743\u94FE\u63A5: ${n.linkUrl}`);return}this.log("\u6388\u6743\u5DF2\u786E\u8BA4\u3002")}}):{auth:await d(o,t.open)},r=i;this.print(t,{agent:o,authorization_pending:!r,authorized:r,browser_opened:e.auth.browserOpened,link_url:e.auth.linkUrl,token_path:e.auth.tokenPath,wait:i},this.formatLoginText({agent:o,authorized:r,browserOpened:e.auth.browserOpened,linkUrl:e.auth.linkUrl}),{profile:o})}shouldWait(t){return this.hasExplicitWaitFlag()?t.wait:!t.json}hasExplicitWaitFlag(){return this.argv.includes("--wait")||this.argv.includes("--no-wait")}formatLoginText(t){const o=[`profile: ${t.agent}`,`token: ${f(t.agent)}`,`authorized: ${t.authorized}`];return t.authorized||o.push(t.browserOpened?"\u6D4F\u89C8\u5668\u5DF2\u6253\u5F00\u6388\u6743\u94FE\u63A5\uFF0C\u8BF7\u5B8C\u6210\u6388\u6743\u540E\u8FD0\u884C `xt status`\u3002":`\u8BF7\u5728\u6D4F\u89C8\u5668\u4E2D\u6253\u5F00: ${t.linkUrl}`),o.join(`
|
|
2
|
+
`)}}export{a as default};
|
|
@@ -1,20 +1 @@
|
|
|
1
|
-
import
|
|
2
|
-
import { globalFlags } from '../../lib/flags.js';
|
|
3
|
-
import { deleteToken, getTokenPath } from '../../lib/storage.js';
|
|
4
|
-
export default class AuthLogout extends XtzCommand {
|
|
5
|
-
static description = 'Delete the stored token for the current profile';
|
|
6
|
-
static flags = {
|
|
7
|
-
...globalFlags,
|
|
8
|
-
};
|
|
9
|
-
async run() {
|
|
10
|
-
this.warnIfLegacyAuthCommand();
|
|
11
|
-
const { flags } = await this.parse(AuthLogout);
|
|
12
|
-
const agent = await this.getProfile(flags.profile);
|
|
13
|
-
const removed = await deleteToken(agent);
|
|
14
|
-
this.print(flags, {
|
|
15
|
-
agent,
|
|
16
|
-
removed,
|
|
17
|
-
token_path: getTokenPath(agent),
|
|
18
|
-
}, removed ? `已删除 token: ${getTokenPath(agent)}` : `未找到 token: ${getTokenPath(agent)}`, { profile: agent });
|
|
19
|
-
}
|
|
20
|
-
}
|
|
1
|
+
import{XtzCommand as i}from"../../base-command.js";import{globalFlags as n}from"../../lib/flags.js";import{deleteToken as s,getTokenPath as e}from"../../lib/storage.js";class o extends i{static description="Delete the stored token for the current profile";static flags={...n};async run(){this.warnIfLegacyAuthCommand();const{flags:a}=await this.parse(o),t=await this.getProfile(a.profile),r=await s(t);this.print(a,{agent:t,removed:r,token_path:e(t)},r?`\u5DF2\u5220\u9664 token: ${e(t)}`:`\u672A\u627E\u5230 token: ${e(t)}`,{profile:t})}}export{o as default};
|
|
@@ -1,60 +1,2 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
3
|
-
import { checkToken } from '../../lib/auth.js';
|
|
4
|
-
import { globalFlags } from '../../lib/flags.js';
|
|
5
|
-
import { getTokenPath, loadToken } from '../../lib/storage.js';
|
|
6
|
-
export default class AuthStatus extends XtzCommand {
|
|
7
|
-
static description = 'Show token auth status for the current profile';
|
|
8
|
-
static flags = {
|
|
9
|
-
...globalFlags,
|
|
10
|
-
};
|
|
11
|
-
async run() {
|
|
12
|
-
this.warnIfLegacyAuthCommand();
|
|
13
|
-
const { flags } = await this.parse(AuthStatus);
|
|
14
|
-
const agent = await this.getProfile(flags.profile);
|
|
15
|
-
const tokenPath = getTokenPath(agent);
|
|
16
|
-
const token = await loadToken(agent);
|
|
17
|
-
const status = !token
|
|
18
|
-
? {
|
|
19
|
-
authorized: false,
|
|
20
|
-
reason: 'missing_token',
|
|
21
|
-
}
|
|
22
|
-
: await this.resolveAuthorization(agent, token);
|
|
23
|
-
this.print(flags, {
|
|
24
|
-
agent,
|
|
25
|
-
authorized: status.authorized,
|
|
26
|
-
reason: status.reason,
|
|
27
|
-
token_path: tokenPath,
|
|
28
|
-
}, this.formatStatusText(agent, tokenPath, status), { profile: agent });
|
|
29
|
-
}
|
|
30
|
-
async resolveAuthorization(agent, token) {
|
|
31
|
-
try {
|
|
32
|
-
await checkToken(agent, token);
|
|
33
|
-
return {
|
|
34
|
-
authorized: true,
|
|
35
|
-
reason: null,
|
|
36
|
-
};
|
|
37
|
-
}
|
|
38
|
-
catch (error) {
|
|
39
|
-
if (!(error instanceof XtzError) || !error.message.includes('授权已过期')) {
|
|
40
|
-
throw error;
|
|
41
|
-
}
|
|
42
|
-
return {
|
|
43
|
-
authorized: false,
|
|
44
|
-
reason: 'expired_token',
|
|
45
|
-
};
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
formatStatusText(agent, tokenPath, status) {
|
|
49
|
-
const lines = [
|
|
50
|
-
`profile: ${agent}`,
|
|
51
|
-
`authorized: ${status.authorized}`,
|
|
52
|
-
`token: ${tokenPath}`,
|
|
53
|
-
];
|
|
54
|
-
if (!status.authorized && status.reason) {
|
|
55
|
-
lines.push(`reason: ${status.reason}`);
|
|
56
|
-
lines.push(`run: xt login --profile ${agent}`);
|
|
57
|
-
}
|
|
58
|
-
return lines.join('\n');
|
|
59
|
-
}
|
|
60
|
-
}
|
|
1
|
+
import{XtzCommand as n}from"../../base-command.js";import{XtzError as s}from"../../lib/errors.js";import{checkToken as h}from"../../lib/auth.js";import{globalFlags as u}from"../../lib/flags.js";import{getTokenPath as f,loadToken as l}from"../../lib/storage.js";class i extends n{static description="Show token auth status for the current profile";static flags={...u};async run(){this.warnIfLegacyAuthCommand();const{flags:e}=await this.parse(i),o=await this.getProfile(e.profile),t=f(o),r=await l(o),a=r?await this.resolveAuthorization(o,r):{authorized:!1,reason:"missing_token"};this.print(e,{agent:o,authorized:a.authorized,reason:a.reason,token_path:t},this.formatStatusText(o,t,a),{profile:o})}async resolveAuthorization(e,o){try{return await h(e,o),{authorized:!0,reason:null}}catch(t){if(!(t instanceof s)||!t.message.includes("\u6388\u6743\u5DF2\u8FC7\u671F"))throw t;return{authorized:!1,reason:"expired_token"}}}formatStatusText(e,o,t){const r=[`profile: ${e}`,`authorized: ${t.authorized}`,`token: ${o}`];return!t.authorized&&t.reason&&(r.push(`reason: ${t.reason}`),r.push(`run: xt login --profile ${e}`)),r.join(`
|
|
2
|
+
`)}}export{i as default};
|
|
@@ -1,38 +1 @@
|
|
|
1
|
-
import
|
|
2
|
-
import { XtzCommand } from '../../base-command.js';
|
|
3
|
-
import { getAuthContext } from '../../lib/auth.js';
|
|
4
|
-
import { deleteXiantaoHistoryRecord, findXiantaoHistoryRecordByFuid } from '../../lib/history.js';
|
|
5
|
-
import { globalFlags } from '../../lib/flags.js';
|
|
6
|
-
export default class HistoryDelete extends XtzCommand {
|
|
7
|
-
static description = 'Delete a Xiantao history record';
|
|
8
|
-
static args = {
|
|
9
|
-
fuid: Args.string({
|
|
10
|
-
description: 'History record fuid',
|
|
11
|
-
required: true,
|
|
12
|
-
}),
|
|
13
|
-
};
|
|
14
|
-
static flags = {
|
|
15
|
-
...globalFlags,
|
|
16
|
-
token: Flags.string({
|
|
17
|
-
description: 'Bearer token for agent.helixlife.cn xiantao APIs; falls back to the stored agent token',
|
|
18
|
-
}),
|
|
19
|
-
};
|
|
20
|
-
async run() {
|
|
21
|
-
const { args, flags } = await this.parse(HistoryDelete);
|
|
22
|
-
const agent = await this.getProfile(flags.profile);
|
|
23
|
-
const auth = await getAuthContext(agent, flags.token);
|
|
24
|
-
const before = await findXiantaoHistoryRecordByFuid(auth, args.fuid);
|
|
25
|
-
await deleteXiantaoHistoryRecord(auth, { fuid: args.fuid });
|
|
26
|
-
const output = {
|
|
27
|
-
agent,
|
|
28
|
-
fuid: args.fuid,
|
|
29
|
-
module_id: before?.module_id?.trim() ?? '',
|
|
30
|
-
module_name: before?.module_name?.trim() ?? '',
|
|
31
|
-
name: before?.name?.trim() ?? '',
|
|
32
|
-
};
|
|
33
|
-
this.print(flags, output, args.fuid, {
|
|
34
|
-
command: 'history delete',
|
|
35
|
-
profile: agent,
|
|
36
|
-
});
|
|
37
|
-
}
|
|
38
|
-
}
|
|
1
|
+
import{Args as n,Flags as d}from"@oclif/core";import{XtzCommand as m}from"../../base-command.js";import{getAuthContext as f}from"../../lib/auth.js";import{deleteXiantaoHistoryRecord as l,findXiantaoHistoryRecordByFuid as u}from"../../lib/history.js";import{globalFlags as c}from"../../lib/flags.js";class r extends m{static description="Delete a Xiantao history record";static args={fuid:n.string({description:"History record fuid",required:!0})};static flags={...c,token:d.string({description:"Bearer token for agent.helixlife.cn xiantao APIs; falls back to the stored agent token"})};async run(){const{args:t,flags:i}=await this.parse(r),e=await this.getProfile(i.profile),a=await f(e,i.token),o=await u(a,t.fuid);await l(a,{fuid:t.fuid});const s={agent:e,fuid:t.fuid,module_id:o?.module_id?.trim()??"",module_name:o?.module_name?.trim()??"",name:o?.name?.trim()??""};this.print(i,s,t.fuid,{command:"history delete",profile:e})}}export{r as default};
|
|
@@ -1,149 +1,5 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
import { XtzError } from '../../lib/errors.js';
|
|
7
|
-
import { fetchXiantaoHistoryDownloadButtons, findXiantaoHistoryRecordByFuid } from '../../lib/history.js';
|
|
8
|
-
import { globalFlags } from '../../lib/flags.js';
|
|
9
|
-
import { resolveXiantaoDownload } from '../../lib/xiantao-plot.js';
|
|
10
|
-
export default class HistoryDownload extends XtzCommand {
|
|
11
|
-
static description = 'Download a file from a Xiantao history record';
|
|
12
|
-
static args = {
|
|
13
|
-
fuid: Args.string({
|
|
14
|
-
description: 'History record fuid',
|
|
15
|
-
required: true,
|
|
16
|
-
}),
|
|
17
|
-
};
|
|
18
|
-
static flags = {
|
|
19
|
-
...globalFlags,
|
|
20
|
-
device: Flags.string({
|
|
21
|
-
description: 'Preferred device/format, e.g. pdf, xlsx, zip',
|
|
22
|
-
}),
|
|
23
|
-
item: Flags.integer({
|
|
24
|
-
description: 'Select a download item by its 1-based index from the listed results',
|
|
25
|
-
}),
|
|
26
|
-
label: Flags.string({
|
|
27
|
-
description: 'Select a download item by its label',
|
|
28
|
-
}),
|
|
29
|
-
output: Flags.string({
|
|
30
|
-
char: 'o',
|
|
31
|
-
description: 'Destination path; defaults to ~/Downloads/<file name>',
|
|
32
|
-
}),
|
|
33
|
-
token: Flags.string({
|
|
34
|
-
description: 'Bearer token for agent.helixlife.cn xiantao APIs; falls back to the stored agent token',
|
|
35
|
-
}),
|
|
36
|
-
};
|
|
37
|
-
async run() {
|
|
38
|
-
const { args, flags } = await this.parse(HistoryDownload);
|
|
39
|
-
const agent = await this.getProfile(flags.profile);
|
|
40
|
-
const auth = await getAuthContext(agent, flags.token);
|
|
41
|
-
const record = await findXiantaoHistoryRecordByFuid(auth, args.fuid);
|
|
42
|
-
if (flags.item !== undefined && flags.label) {
|
|
43
|
-
throw new XtzError('`--item` 与 `--label` 不能同时使用。');
|
|
44
|
-
}
|
|
45
|
-
if (!record?.module_id?.trim()) {
|
|
46
|
-
throw new XtzError(`未找到 fuid 为 ${args.fuid} 的历史记录。`);
|
|
47
|
-
}
|
|
48
|
-
const result = await fetchXiantaoHistoryDownloadButtons(auth, { fuid: args.fuid });
|
|
49
|
-
const item = this.pickDownloadItem(result.downloads, {
|
|
50
|
-
device: flags.device,
|
|
51
|
-
item: flags.item,
|
|
52
|
-
label: flags.label,
|
|
53
|
-
outputPath: flags.output,
|
|
54
|
-
});
|
|
55
|
-
if (!item) {
|
|
56
|
-
throw new XtzError(this.buildMultipleDownloadsMessage(result.downloads));
|
|
57
|
-
}
|
|
58
|
-
const resolved = await resolveXiantaoDownload(auth, {
|
|
59
|
-
item,
|
|
60
|
-
moduleId: record.module_id.trim(),
|
|
61
|
-
uuid: XIANTAO_HISTORY_UUID,
|
|
62
|
-
});
|
|
63
|
-
const filePath = await downloadToPath(resolved.url, flags.output);
|
|
64
|
-
const output = {
|
|
65
|
-
agent,
|
|
66
|
-
device: item.device,
|
|
67
|
-
endpoint: item.endpoint,
|
|
68
|
-
file_name: resolved.fileName ?? item.label,
|
|
69
|
-
fuid: args.fuid,
|
|
70
|
-
module_id: record.module_id.trim(),
|
|
71
|
-
output: filePath,
|
|
72
|
-
url: resolved.url,
|
|
73
|
-
};
|
|
74
|
-
this.print(flags, output, filePath, {
|
|
75
|
-
command: 'history download',
|
|
76
|
-
profile: agent,
|
|
77
|
-
});
|
|
78
|
-
}
|
|
79
|
-
pickDownloadItem(downloads, input) {
|
|
80
|
-
if (input.item !== undefined) {
|
|
81
|
-
return this.pickDownloadItemByIndex(downloads, input.item);
|
|
82
|
-
}
|
|
83
|
-
if (input.label) {
|
|
84
|
-
return this.pickDownloadItemByLabel(downloads, input.label);
|
|
85
|
-
}
|
|
86
|
-
const normalizedExpectedDevice = this.normalizeDevice(input.device ?? this.inferDeviceFromOutputPath(input.outputPath));
|
|
87
|
-
if (normalizedExpectedDevice) {
|
|
88
|
-
const matched = downloads.filter((item) => this.normalizeDevice(item.device) === normalizedExpectedDevice);
|
|
89
|
-
if (matched.length === 1) {
|
|
90
|
-
return matched[0];
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
const results = downloads.filter((item) => item.endpoint === 'public.output.download-result');
|
|
94
|
-
if (results.length === 1) {
|
|
95
|
-
return results[0];
|
|
96
|
-
}
|
|
97
|
-
if (downloads.length === 1) {
|
|
98
|
-
return downloads[0];
|
|
99
|
-
}
|
|
100
|
-
return undefined;
|
|
101
|
-
}
|
|
102
|
-
pickDownloadItemByIndex(downloads, itemIndex) {
|
|
103
|
-
if (!Number.isInteger(itemIndex) || itemIndex < 1 || itemIndex > downloads.length) {
|
|
104
|
-
throw new XtzError(`下载项序号 ${itemIndex} 无效,可选范围为 1-${downloads.length}。\n${this.buildMultipleDownloadsMessage(downloads)}`);
|
|
105
|
-
}
|
|
106
|
-
return downloads[itemIndex - 1];
|
|
107
|
-
}
|
|
108
|
-
pickDownloadItemByLabel(downloads, expectedLabel) {
|
|
109
|
-
const normalizedExpectedLabel = expectedLabel.trim().toLowerCase();
|
|
110
|
-
if (!normalizedExpectedLabel) {
|
|
111
|
-
return undefined;
|
|
112
|
-
}
|
|
113
|
-
const matched = downloads.filter((item) => item.label.trim().toLowerCase() === normalizedExpectedLabel);
|
|
114
|
-
if (matched.length === 1) {
|
|
115
|
-
return matched[0];
|
|
116
|
-
}
|
|
117
|
-
if (matched.length > 1) {
|
|
118
|
-
throw new XtzError(`下载项名称 ${expectedLabel} 匹配到多个结果,请改用 \`--item\` 精确选择。\n${this.buildMultipleDownloadsMessage(downloads)}`);
|
|
119
|
-
}
|
|
120
|
-
return undefined;
|
|
121
|
-
}
|
|
122
|
-
inferDeviceFromOutputPath(outputPath) {
|
|
123
|
-
const extension = outputPath?.trim().split('.').pop()?.toLowerCase();
|
|
124
|
-
return extension ? this.normalizeDevice(extension) : undefined;
|
|
125
|
-
}
|
|
126
|
-
normalizeDevice(device) {
|
|
127
|
-
const normalized = device?.trim().toLowerCase();
|
|
128
|
-
if (!normalized) {
|
|
129
|
-
return undefined;
|
|
130
|
-
}
|
|
131
|
-
if (normalized === 'tif') {
|
|
132
|
-
return 'tiff';
|
|
133
|
-
}
|
|
134
|
-
if (normalized === 'jpg') {
|
|
135
|
-
return 'jpeg';
|
|
136
|
-
}
|
|
137
|
-
return normalized;
|
|
138
|
-
}
|
|
139
|
-
buildMultipleDownloadsMessage(downloads) {
|
|
140
|
-
const lines = [
|
|
141
|
-
'当前历史记录返回多个可下载结果,请传入 `--item`、`--label`、`--device`,或将 `--output` 改为带目标扩展名的文件名。',
|
|
142
|
-
'可选下载项:',
|
|
143
|
-
];
|
|
144
|
-
downloads.forEach((item, index) => {
|
|
145
|
-
lines.push(`${index + 1}. ${item.label} (device=${item.device}, endpoint=${item.endpoint})`);
|
|
146
|
-
});
|
|
147
|
-
return lines.join('\n');
|
|
148
|
-
}
|
|
149
|
-
}
|
|
1
|
+
import{Args as m,Flags as l}from"@oclif/core";import{XtzCommand as p}from"../../base-command.js";import{getAuthContext as h}from"../../lib/auth.js";import{XIANTAO_HISTORY_UUID as g}from"../../lib/constants.js";import{downloadToPath as w}from"../../lib/download.js";import{XtzError as n}from"../../lib/errors.js";import{fetchXiantaoHistoryDownloadButtons as b,findXiantaoHistoryRecordByFuid as D}from"../../lib/history.js";import{globalFlags as v}from"../../lib/flags.js";import{resolveXiantaoDownload as y}from"../../lib/xiantao-plot.js";class d extends p{static description="Download a file from a Xiantao history record";static args={fuid:m.string({description:"History record fuid",required:!0})};static flags={...v,device:l.string({description:"Preferred device/format, e.g. pdf, xlsx, zip"}),item:l.integer({description:"Select a download item by its 1-based index from the listed results"}),label:l.string({description:"Select a download item by its label"}),output:l.string({char:"o",description:"Destination path; defaults to ~/Downloads/<file name>"}),token:l.string({description:"Bearer token for agent.helixlife.cn xiantao APIs; falls back to the stored agent token"})};async run(){const{args:t,flags:e}=await this.parse(d),i=await this.getProfile(e.profile),o=await h(i,e.token),r=await D(o,t.fuid);if(e.item!==void 0&&e.label)throw new n("`--item` \u4E0E `--label` \u4E0D\u80FD\u540C\u65F6\u4F7F\u7528\u3002");if(!r?.module_id?.trim())throw new n(`\u672A\u627E\u5230 fuid \u4E3A ${t.fuid} \u7684\u5386\u53F2\u8BB0\u5F55\u3002`);const u=await b(o,{fuid:t.fuid}),a=this.pickDownloadItem(u.downloads,{device:e.device,item:e.item,label:e.label,outputPath:e.output});if(!a)throw new n(this.buildMultipleDownloadsMessage(u.downloads));const s=await y(o,{item:a,moduleId:r.module_id.trim(),uuid:g}),f=await w(s.url,e.output),c={agent:i,device:a.device,endpoint:a.endpoint,file_name:s.fileName??a.label,fuid:t.fuid,module_id:r.module_id.trim(),output:f,url:s.url};this.print(e,c,f,{command:"history download",profile:i})}pickDownloadItem(t,e){if(e.item!==void 0)return this.pickDownloadItemByIndex(t,e.item);if(e.label)return this.pickDownloadItemByLabel(t,e.label);const i=this.normalizeDevice(e.device??this.inferDeviceFromOutputPath(e.outputPath));if(i){const o=t.filter(r=>this.normalizeDevice(r.device)===i);if(o.length===1)return o[0];if(o.length>1)throw new n(`\u4E0B\u8F7D\u683C\u5F0F ${i} \u5339\u914D\u5230\u591A\u4E2A\u7ED3\u679C\uFF0C\u8BF7\u6539\u7528 \`--item\` \u6216 \`--label\` \u7CBE\u786E\u9009\u62E9\u3002
|
|
2
|
+
${this.buildMultipleDownloadsMessage(t)}`)}if(t.length===1)return t[0]}pickDownloadItemByIndex(t,e){if(!Number.isInteger(e)||e<1||e>t.length)throw new n(`\u4E0B\u8F7D\u9879\u5E8F\u53F7 ${e} \u65E0\u6548\uFF0C\u53EF\u9009\u8303\u56F4\u4E3A 1-${t.length}\u3002
|
|
3
|
+
${this.buildMultipleDownloadsMessage(t)}`);return t[e-1]}pickDownloadItemByLabel(t,e){const i=e.trim().toLowerCase();if(!i)return;const o=t.filter(r=>r.label.trim().toLowerCase()===i);if(o.length===1)return o[0];if(o.length>1)throw new n(`\u4E0B\u8F7D\u9879\u540D\u79F0 ${e} \u5339\u914D\u5230\u591A\u4E2A\u7ED3\u679C\uFF0C\u8BF7\u6539\u7528 \`--item\` \u7CBE\u786E\u9009\u62E9\u3002
|
|
4
|
+
${this.buildMultipleDownloadsMessage(t)}`)}inferDeviceFromOutputPath(t){const e=t?.trim().split(".").pop()?.toLowerCase();return e?this.normalizeDevice(e):void 0}normalizeDevice(t){const e=t?.trim().toLowerCase();if(e)return e==="tif"?"tiff":e==="jpg"?"jpeg":e}buildMultipleDownloadsMessage(t){const e=["\u5F53\u524D\u5386\u53F2\u8BB0\u5F55\u5305\u542B\u591A\u4E2A\u53EF\u4E0B\u8F7D\u6587\u4EF6\uFF0C\u8BF7\u4F7F\u7528 `--item`\u3001`--label` \u6216 `--device` \u660E\u786E\u9009\u62E9\u3002","\u53EF\u9009\u4E0B\u8F7D\u9879\uFF1A"];return t.forEach((i,o)=>{e.push(`${o+1}. ${i.label} (device=${i.device}, endpoint=${i.endpoint})`)}),e.join(`
|
|
5
|
+
`)}}export{d as default};
|
|
@@ -1,72 +1,3 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
import { fetchXiantaoHistoryRecords, getXiantaoHistoryRecordStatus } from '../../lib/history.js';
|
|
5
|
-
import { globalFlags } from '../../lib/flags.js';
|
|
6
|
-
export default class HistoryList extends XtzCommand {
|
|
7
|
-
static description = 'List Xiantao history records';
|
|
8
|
-
static flags = {
|
|
9
|
-
...globalFlags,
|
|
10
|
-
page: Flags.integer({
|
|
11
|
-
default: 1,
|
|
12
|
-
description: 'History page number',
|
|
13
|
-
min: 1,
|
|
14
|
-
}),
|
|
15
|
-
token: Flags.string({
|
|
16
|
-
description: 'Bearer token for agent.helixlife.cn xiantao APIs; falls back to the stored agent token',
|
|
17
|
-
}),
|
|
18
|
-
};
|
|
19
|
-
async run() {
|
|
20
|
-
const { flags } = await this.parse(HistoryList);
|
|
21
|
-
const agent = await this.getProfile(flags.profile);
|
|
22
|
-
const auth = await getAuthContext(agent, flags.token);
|
|
23
|
-
const page = await fetchXiantaoHistoryRecords(auth, { currentPage: flags.page });
|
|
24
|
-
const records = page.records.map((record) => ({
|
|
25
|
-
fuid: record.fuid?.trim() ?? '',
|
|
26
|
-
id: typeof record.id === 'number' ? record.id : null,
|
|
27
|
-
module_id: record.module_id?.trim() ?? '',
|
|
28
|
-
module_name: record.module_name?.trim() ?? '',
|
|
29
|
-
name: record.name?.trim() ?? '',
|
|
30
|
-
status: getXiantaoHistoryRecordStatus(record),
|
|
31
|
-
time: record.time?.trim() ?? '',
|
|
32
|
-
type: record.type?.trim() ?? '',
|
|
33
|
-
}));
|
|
34
|
-
const output = {
|
|
35
|
-
agent,
|
|
36
|
-
current_page: page.currentPage,
|
|
37
|
-
info: page.info,
|
|
38
|
-
last_page: page.lastPage,
|
|
39
|
-
per_page: page.perPage,
|
|
40
|
-
records,
|
|
41
|
-
total: page.total,
|
|
42
|
-
};
|
|
43
|
-
this.print(flags, output, this.formatHistoryText(page.currentPage, page.lastPage, page.total, records, page.info), {
|
|
44
|
-
command: 'history list',
|
|
45
|
-
profile: agent,
|
|
46
|
-
});
|
|
47
|
-
}
|
|
48
|
-
formatHistoryText(currentPage, lastPage, total, records, info) {
|
|
49
|
-
const lines = [`历史记录 ${total} 条,第 ${currentPage}/${lastPage} 页`];
|
|
50
|
-
if (records.length === 0) {
|
|
51
|
-
lines.push('');
|
|
52
|
-
lines.push('暂无历史记录');
|
|
53
|
-
return lines.join('\n');
|
|
54
|
-
}
|
|
55
|
-
for (const record of records) {
|
|
56
|
-
lines.push('');
|
|
57
|
-
lines.push(`${record.module_id || '-'} ${record.module_name || '-'}`);
|
|
58
|
-
lines.push(` status: ${record.status}`);
|
|
59
|
-
lines.push(` time: ${record.time || '-'}`);
|
|
60
|
-
lines.push(` type: ${record.type || '-'}`);
|
|
61
|
-
lines.push(` fuid: ${record.fuid || '-'}`);
|
|
62
|
-
if (record.name) {
|
|
63
|
-
lines.push(` name: ${record.name}`);
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
if (info) {
|
|
67
|
-
lines.push('');
|
|
68
|
-
lines.push(info);
|
|
69
|
-
}
|
|
70
|
-
return lines.join('\n');
|
|
71
|
-
}
|
|
72
|
-
}
|
|
1
|
+
import{Flags as m}from"@oclif/core";import{XtzCommand as u}from"../../base-command.js";import{getAuthContext as p}from"../../lib/auth.js";import{fetchXiantaoHistoryRecords as l,getXiantaoHistoryRecordStatus as f}from"../../lib/history.js";import{globalFlags as g}from"../../lib/flags.js";class r extends u{static description="List Xiantao history records";static flags={...g,page:m.integer({default:1,description:"History page number",min:1}),token:m.string({description:"Bearer token for agent.helixlife.cn xiantao APIs; falls back to the stored agent token"})};async run(){const{flags:i}=await this.parse(r),s=await this.getProfile(i.profile),n=await p(s,i.token),a=await l(n,{currentPage:i.page}),o=a.records.map(t=>({fuid:t.fuid?.trim()??"",id:typeof t.id=="number"?t.id:null,module_id:t.module_id?.trim()??"",module_name:t.module_name?.trim()??"",name:t.name?.trim()??"",status:f(t),time:t.time?.trim()??"",type:t.type?.trim()??""})),e={agent:s,current_page:a.currentPage,info:a.info,last_page:a.lastPage,per_page:a.perPage,records:o,total:a.total};this.print(i,e,this.formatHistoryText(a.currentPage,a.lastPage,a.total,o,a.info),{command:"history list",profile:s})}formatHistoryText(i,s,n,a,o){const e=[`\u5386\u53F2\u8BB0\u5F55 ${n} \u6761\uFF0C\u7B2C ${i}/${s} \u9875`];if(a.length===0)return e.push(""),e.push("\u6682\u65E0\u5386\u53F2\u8BB0\u5F55"),e.join(`
|
|
2
|
+
`);for(const t of a)e.push(""),e.push(`${t.module_id||"-"} ${t.module_name||"-"}`),e.push(` status: ${t.status}`),e.push(` time: ${t.time||"-"}`),e.push(` type: ${t.type||"-"}`),e.push(` fuid: ${t.fuid||"-"}`),t.name&&e.push(` name: ${t.name}`);return o&&(e.push(""),e.push(o)),e.join(`
|
|
3
|
+
`)}}export{r as default};
|