@helixlife-ai/xiantao 0.1.11 → 0.1.13

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 CHANGED
@@ -34,10 +34,16 @@ This starts a menu-driven path for choosing a tool, selecting demo data or a loc
34
34
  ### Agent Automation
35
35
 
36
36
  ```bash
37
+ xt tool prepare violin_flat --file ./data.xlsx --profile opencode --json
37
38
  xt tool exec violin_flat --file ./data.xlsx --profile opencode --json
39
+ xt tool exec violin_flat --file ./data.xlsx --profile opencode --json --download ./violin.pdf
38
40
  ```
39
41
 
40
- For machine callers, use `xt tool exec`, keep `--json`, pass an explicit profile with `--profile`, and avoid interactive-only flows.
42
+ For machine callers, use `xt tool prepare` to fetch the upload-dependent final schema, then `xt tool exec` to submit. Keep `--json`, pass an explicit profile with `--profile`, and avoid interactive-only flows.
43
+
44
+ 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.
45
+
46
+ `xt login --json` now returns the authorization link immediately and defaults to `authorized: false` until the browser step completes. Use `xt login --json --wait` when you explicitly want the command to block until authorization is confirmed. `xt status` is a probe-style check and returns `authorized: true` or `authorized: false` together with a reason such as `missing_token` or `expired_token`.
41
47
 
42
48
  ## Command Groups
43
49
 
@@ -52,6 +58,7 @@ For machine callers, use `xt tool exec`, keep `--json`, pass an explicit profile
52
58
 
53
59
  - `xt tool search`
54
60
  - `xt tool inspect`
61
+ - `xt tool prepare`
55
62
  - `xt tool run`
56
63
  - `xt tool exec`
57
64
  - `xt tool download`
@@ -67,7 +74,7 @@ For machine callers, use `xt tool exec`, keep `--json`, pass an explicit profile
67
74
 
68
75
  For the common Xiantao tool product, `tool search`, `tool inspect`, `tool run`, `tool resolve`, and `tool menu` default `toolProductUuid` to `c0b6febb-52dd-4525-970a-61bbe9e263ff`. You can override it with `--toolProductUuid`, `XIANTAO_TOOL_PRODUCT_UUID`, or `~/.config/xtz/config.json` under `xiantao.toolProductUuid`.
69
76
 
70
- `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 used by the tool. `xt tool run <tool_id>` runs a Xiantao bioinformatics tool. `xt tool resolve <tool_id>` remains available as the low-level UUID and route lookup. `--demo` reuses the demo file metadata returned by `tool fetch-all`; otherwise `tool run` uploads the local file first and therefore also needs token auth. Run `xt login` first to authorize the stored token. When a tool exposes multiple downloadable results, `--download <path>` uses the output file extension to select the matching artifact.
77
+ `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 used by the tool. `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. `--demo` reuses the demo file metadata returned by `tool fetch-all`; otherwise `tool run` uploads the local file first and therefore also needs token auth. Run `xt login` first to authorize the stored token. When a tool exposes multiple downloadable results, `--download <path>` uses the output file extension to select the matching artifact.
71
78
 
72
79
  `xt tool run <tool_id> ... --interactive` prompts for dynamic `args_main` values before the final submit, prints reusable `--set` flags, and supports `<` for the previous item plus `/skip` for the current section.
73
80
 
@@ -1,4 +1,5 @@
1
1
  import { Command } from '@oclif/core';
2
+ import { createErrorEnvelope, createSuccessEnvelope } from './lib/envelope.js';
2
3
  import { XtzError } from './lib/errors.js';
3
4
  import { resolveAgent } from './lib/storage.js';
4
5
  import { getUpdateReminder } from './lib/update.js';
@@ -13,14 +14,23 @@ export class XtzCommand extends Command {
13
14
  async getAgent(agentFlag) {
14
15
  return this.getProfile(agentFlag);
15
16
  }
16
- print(flags, data, text) {
17
+ print(flags, data, text, context) {
17
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
+ }
18
23
  this.log(JSON.stringify(data, null, 2));
19
24
  return;
20
25
  }
21
26
  this.log(text);
22
27
  }
23
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
+ }
24
34
  if (error instanceof XtzError) {
25
35
  this.error(error.message, { exit: 1 });
26
36
  }
@@ -43,7 +53,7 @@ export class XtzCommand extends Command {
43
53
  this.warn(`\`xt ${command}\` 已兼容保留,建议改用 \`xt ${replacement}\``);
44
54
  }
45
55
  async warnIfUpdateAvailable() {
46
- if (this.argv.includes('--json') || !process.stdout.isTTY) {
56
+ if (this.argv.includes('--json') || !process.stdout.isTTY || this.shouldSkipUpdateReminder()) {
47
57
  return;
48
58
  }
49
59
  const reminder = await getUpdateReminder(this.config.version);
@@ -52,4 +62,42 @@ export class XtzCommand extends Command {
52
62
  }
53
63
  this.warn(reminder);
54
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
+ }
55
103
  }
@@ -1,6 +1,7 @@
1
1
  import { Flags } from '@oclif/core';
2
2
  import { XtzCommand } from '../../base-command.js';
3
3
  import { globalFlags } from '../../lib/flags.js';
4
+ import { loginAuth } from '../../lib/auth.js';
4
5
  import { loginAll } from '../../lib/login-flow.js';
5
6
  import { getTokenPath } from '../../lib/storage.js';
6
7
  export default class AuthLogin extends XtzCommand {
@@ -12,32 +13,64 @@ export default class AuthLogin extends XtzCommand {
12
13
  default: true,
13
14
  description: 'Open the authorization link in the browser',
14
15
  }),
16
+ wait: Flags.boolean({
17
+ allowNo: true,
18
+ default: true,
19
+ description: 'Wait until the browser authorization is confirmed before exiting',
20
+ }),
15
21
  };
16
22
  async run() {
17
23
  this.warnIfLegacyAuthCommand();
18
24
  const { flags } = await this.parse(AuthLogin);
19
25
  const agent = await this.getProfile(flags.profile);
20
- const result = await loginAll(agent, flags.open, ({ auth, phase }) => {
21
- if (flags.json) {
22
- return;
23
- }
24
- if (phase === 'auth_started') {
25
- this.log(auth.browserOpened ? '浏览器已打开授权链接,等待授权完成...' : `请先在浏览器中打开授权链接: ${auth.linkUrl}`);
26
- return;
27
- }
28
- this.log('授权已确认。');
29
- });
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;
30
40
  this.print(flags, {
31
41
  agent,
42
+ authorization_pending: !authorized,
43
+ authorized,
32
44
  browser_opened: result.auth.browserOpened,
33
45
  link_url: result.auth.linkUrl,
34
46
  token_path: result.auth.tokenPath,
35
- }, [
36
- `profile: ${agent}`,
37
- `token: ${getTokenPath(agent)}`,
38
- result.auth.browserOpened
39
- ? '浏览器已打开授权链接,请完成授权后运行 `xt status`。'
40
- : `请在浏览器中打开: ${result.auth.linkUrl}`,
41
- ].join('\n'));
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');
42
75
  }
43
76
  }
@@ -15,6 +15,6 @@ export default class AuthLogout extends XtzCommand {
15
15
  agent,
16
16
  removed,
17
17
  token_path: getTokenPath(agent),
18
- }, removed ? `已删除 token: ${getTokenPath(agent)}` : `未找到 token: ${getTokenPath(agent)}`);
18
+ }, removed ? `已删除 token: ${getTokenPath(agent)}` : `未找到 token: ${getTokenPath(agent)}`, { profile: agent });
19
19
  }
20
20
  }
@@ -1,9 +1,10 @@
1
1
  import { XtzCommand } from '../../base-command.js';
2
+ import { XtzError } from '../../lib/errors.js';
2
3
  import { checkToken } from '../../lib/auth.js';
3
4
  import { globalFlags } from '../../lib/flags.js';
4
- import { getTokenPath, requireToken } from '../../lib/storage.js';
5
+ import { getTokenPath, loadToken } from '../../lib/storage.js';
5
6
  export default class AuthStatus extends XtzCommand {
6
- static description = 'Check whether the current profile token is authorized';
7
+ static description = 'Show token auth status for the current profile';
7
8
  static flags = {
8
9
  ...globalFlags,
9
10
  };
@@ -11,12 +12,49 @@ export default class AuthStatus extends XtzCommand {
11
12
  this.warnIfLegacyAuthCommand();
12
13
  const { flags } = await this.parse(AuthStatus);
13
14
  const agent = await this.getProfile(flags.profile);
14
- const token = await requireToken(agent);
15
- await checkToken(agent, token);
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);
16
23
  this.print(flags, {
17
24
  agent,
18
- authorized: true,
19
- token_path: getTokenPath(agent),
20
- }, `profile: ${agent}\nauthorized: true\ntoken: ${getTokenPath(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');
21
59
  }
22
60
  }
@@ -42,6 +42,6 @@ export default class PlotFetchAll extends XtzCommand {
42
42
  notice: result.notice ?? '',
43
43
  uuid: flags.uuid,
44
44
  };
45
- this.print(flags, output, JSON.stringify(output, null, 2));
45
+ this.print(flags, output, JSON.stringify(output, null, 2), { profile: agent });
46
46
  }
47
47
  }
@@ -1,5 +1,6 @@
1
1
  import { Flags } from '@oclif/core';
2
2
  import { XtzCommand } from '../../base-command.js';
3
+ import { loginAuth } from '../../lib/auth.js';
3
4
  import { globalFlags } from '../../lib/flags.js';
4
5
  import { loginAll } from '../../lib/login-flow.js';
5
6
  import { getTokenPath } from '../../lib/storage.js';
@@ -12,32 +13,64 @@ export default class PlotLogin extends XtzCommand {
12
13
  default: true,
13
14
  description: 'Open the authorization link in the browser',
14
15
  }),
16
+ wait: Flags.boolean({
17
+ allowNo: true,
18
+ default: true,
19
+ description: 'Wait until the browser authorization is confirmed before exiting',
20
+ }),
15
21
  };
16
22
  async run() {
17
23
  this.warnIfLegacyPlotCommand();
18
24
  const { flags } = await this.parse(PlotLogin);
19
25
  const agent = await this.getProfile(flags.profile);
20
- const result = await loginAll(agent, flags.open, ({ auth, phase }) => {
21
- if (flags.json) {
22
- return;
23
- }
24
- if (phase === 'auth_started') {
25
- this.log(auth.browserOpened ? '浏览器已打开授权链接,等待授权完成...' : `请先在浏览器中打开授权链接: ${auth.linkUrl}`);
26
- return;
27
- }
28
- this.log('授权已确认。');
29
- });
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;
30
40
  this.print(flags, {
31
41
  agent,
42
+ authorization_pending: !authorized,
43
+ authorized,
32
44
  browser_opened: result.auth.browserOpened,
33
45
  link_url: result.auth.linkUrl,
34
46
  token_path: result.auth.tokenPath,
35
- }, [
36
- `profile: ${agent}`,
37
- `token: ${getTokenPath(agent)}`,
38
- result.auth.browserOpened
39
- ? '浏览器已打开授权链接,请完成授权后运行 `xt status`。'
40
- : `请在浏览器中打开: ${result.auth.linkUrl}`,
41
- ].join('\n'));
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');
42
75
  }
43
76
  }
@@ -32,6 +32,6 @@ export default class PlotMenu extends XtzCommand {
32
32
  agent,
33
33
  menu,
34
34
  tool_product_uuid: toolProductUuid,
35
- }, JSON.stringify(menu, null, 2));
35
+ }, JSON.stringify(menu, null, 2), { profile: agent });
36
36
  }
37
37
  }
@@ -26,6 +26,6 @@ export default class PlotMenus extends XtzCommand {
26
26
  agent,
27
27
  menus,
28
28
  tool_product_uuid: toolProductUuid,
29
- }, JSON.stringify(menus, null, 2));
29
+ }, JSON.stringify(menus, null, 2), { profile: agent });
30
30
  }
31
31
  }
@@ -43,6 +43,6 @@ export default class PlotResolve extends XtzCommand {
43
43
  title: resolved.title,
44
44
  tool_product_uuid: toolProductUuid,
45
45
  uuid: resolved.uuid,
46
- }, null, 2));
46
+ }, null, 2), { profile: agent });
47
47
  }
48
48
  }
@@ -427,6 +427,6 @@ export default class PlotRun extends ToolRunCommandBase {
427
427
  throw new XtzError('FILE 与 `--file` 不能同时使用。');
428
428
  }
429
429
  const result = await this.executeToolRun(args.tool, args.file ?? flags.file, flags);
430
- this.print(flags, result.data, result.text);
430
+ this.print(flags, result.data, result.text, { profile: result.data.agent });
431
431
  }
432
432
  }
@@ -6,7 +6,7 @@ import { plotOverrideFlags } from '../../lib/plot-options.js';
6
6
  import { ToolRunCommandBase } from '../plot/run.js';
7
7
  export default class ToolExec extends ToolRunCommandBase {
8
8
  static description = 'Execute a Xiantao bioinformatics tool in agent mode';
9
- static usage = 'tool exec <tool> (--file <value> | --demo) --json';
9
+ static usage = 'tool exec <tool> (--file <value> | --demo) --json [--download <path>]';
10
10
  static args = {
11
11
  tool: Args.string({
12
12
  description: 'Tool id, e.g. violin_flat',
@@ -24,7 +24,7 @@ export default class ToolExec extends ToolRunCommandBase {
24
24
  description: 'Use the module demo data returned by fetch-all instead of uploading a local file',
25
25
  }),
26
26
  download: Flags.string({
27
- hidden: true,
27
+ description: 'Download the generated file or preferred analysis result to this local path after submission',
28
28
  }),
29
29
  file: Flags.string({
30
30
  description: 'Path to the local xlsx file',
@@ -71,7 +71,6 @@ export default class ToolExec extends ToolRunCommandBase {
71
71
  }
72
72
  const result = await this.executeToolRun(args.tool, filePath, {
73
73
  ...flags,
74
- download: undefined,
75
74
  interactive: false,
76
75
  });
77
76
  const profile = await this.getProfile(flags.profile);
@@ -51,7 +51,7 @@ export default class ToolInspect extends XtzCommand {
51
51
  tool_product_uuid: toolProductUuid,
52
52
  uuid: resolved.uuid,
53
53
  };
54
- this.print(flags, output, this.formatInspectText(output.module_id, output.title, output.path, output.route, output.uuid, output.notice, inputs, summary, schema));
54
+ this.print(flags, output, this.formatInspectText(output.module_id, output.title, output.path, output.route, output.uuid, output.notice, inputs, summary, schema), { profile: agent });
55
55
  }
56
56
  formatInspectText(moduleId, title, path, route, uuid, notice, inputs, summary, schema) {
57
57
  const lines = [
@@ -7,7 +7,7 @@ import { buildArgsMainFromSchema } from '../../lib/plot-schema.js';
7
7
  import { ToolRunCommandBase } from '../plot/run.js';
8
8
  export default class ToolPrepare extends ToolRunCommandBase {
9
9
  static description = 'Prepare a Xiantao bioinformatics tool in agent mode and return the final dynamic schema';
10
- static usage = 'tool:prepare <tool> (--file <value> | --demo) --json';
10
+ static usage = 'tool prepare <tool> (--file <value> | --demo) --json';
11
11
  static args = {
12
12
  tool: Args.string({
13
13
  description: 'Tool id, e.g. violin_flat',
@@ -34,7 +34,7 @@ export default class ToolSearch extends XtzCommand {
34
34
  tools,
35
35
  total: tools.length,
36
36
  };
37
- this.print(flags, output, this.formatSearchText(args.keyword, tools));
37
+ this.print(flags, output, this.formatSearchText(args.keyword, tools), { profile: agent });
38
38
  }
39
39
  formatSearchText(keyword, tools) {
40
40
  if (tools.length === 0) {
package/dist/xtz-help.js CHANGED
@@ -6,7 +6,7 @@ export default class XtzHelp extends Help {
6
6
  this.log(this.section('MAIN FLOWS', [
7
7
  ['First use', '$ xt login\n$ xt tool search violin\n$ xt tool inspect violin_flat\n$ xt tool run violin_flat ./data.xlsx'],
8
8
  ['Interactive tool run', '$ xt tool run --interactive'],
9
- ['Agent automation', '$ xt tool:prepare violin_flat --file ./data.xlsx --profile opencode --json\n$ xt tool exec violin_flat --file ./data.xlsx --profile opencode --json'],
9
+ ['Agent automation', '$ xt tool prepare violin_flat --file ./data.xlsx --profile opencode --json\n$ xt tool exec violin_flat --file ./data.xlsx --profile opencode --json'],
10
10
  ]));
11
11
  this.log('');
12
12
  this.log(this.section('COMMON COMMANDS', this.renderCommandItems([
@@ -35,11 +35,11 @@ export default class XtzHelp extends Help {
35
35
  id: 'tool:inspect',
36
36
  },
37
37
  {
38
- description: 'Run a tool in human-first mode',
38
+ description: 'Run a tool in human-first mode; avoid this in agent workflows',
39
39
  id: 'tool:run',
40
40
  },
41
41
  {
42
- description: 'Execute a tool in agent mode with JSON envelope output',
42
+ description: 'Execute a tool in agent mode with JSON envelope output; supports --download',
43
43
  id: 'tool:exec',
44
44
  },
45
45
  {
@@ -58,7 +58,7 @@ export default class XtzHelp extends Help {
58
58
  ['xt tool menu', 'Fetch one raw tool menu by UUID'],
59
59
  ['xt tool menus', 'Fetch all raw tool menus for a product'],
60
60
  ['xt tool fetch-all', 'Fetch raw dynamic args for a tool'],
61
- ['xt tool:prepare', 'Resolve upload-dependent dynamic schema for agent workflows'],
61
+ ['xt tool prepare', 'Resolve upload-dependent dynamic schema for agent workflows'],
62
62
  ['xt auth ...', 'Legacy auth topic kept for compatibility'],
63
63
  ['xt plot ...', 'Legacy plot topic kept for compatibility'],
64
64
  ]));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@helixlife-ai/xiantao",
3
- "version": "0.1.11",
3
+ "version": "0.1.13",
4
4
  "description": "CLI for Xiantao bioinformatics tools",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",