@helixlife-ai/xiantao 0.1.36 → 0.1.38
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 +28 -3
- package/dist/commands/auth/exchange.js +1 -0
- package/dist/commands/exchange.js +1 -0
- package/dist/lib/auth.js +1 -1
- package/dist/lib/config.js +2 -2
- package/dist/lib/constants.js +1 -1
- package/dist/lib/errors.js +2 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -8,7 +8,7 @@ Install with `npm i -g @helixlife-ai/xiantao` and run it as `xt`.
|
|
|
8
8
|
|
|
9
9
|
`--profile` is the primary profile selector for token lookup and config isolation. If it is omitted, the CLI resolves the profile from `AGENT_NAME`, then the host runtime (`cursor`, `opencode`, `openclaw`), then `~/.config/helixlife/config.json`, and finally defaults to `opencode`. `--agent` is kept as a compatibility alias.
|
|
10
10
|
|
|
11
|
-
`login`, `status`, and `logout` are the primary auth entrypoints. `auth ...` is kept as a compatibility topic and prints a migration warning when executed.
|
|
11
|
+
`login`, `status`, and `logout` are the primary auth entrypoints. `exchange` redeems membership codes for the current profile. `auth ...` is kept as a compatibility topic and prints a migration warning when executed.
|
|
12
12
|
|
|
13
13
|
## Main Flows
|
|
14
14
|
|
|
@@ -23,6 +23,28 @@ xt tool run violin_flat ./data.xlsx
|
|
|
23
23
|
|
|
24
24
|
`xt login` is the recommended first-use entrypoint. It authorizes and stores the profile token in one step. `xt tool login` is kept as an equivalent entrypoint under the `tool` topic.
|
|
25
25
|
|
|
26
|
+
### Membership Exchange
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
xt exchange YOUR_CODE
|
|
30
|
+
xt exchange YOUR_CODE --profile opencode --json
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
`xt exchange <code>` calls `/agent/ticket/exchange` with the current profile token and sends the exchange code as `code`. If an upstream API returns a membership-required 403 such as:
|
|
34
|
+
|
|
35
|
+
```json
|
|
36
|
+
{
|
|
37
|
+
"success": false,
|
|
38
|
+
"code": 403000101,
|
|
39
|
+
"message": "您的账号暂无使用权限,需要购买会员,购买链接: https://www.helixlife.cn/main/vip",
|
|
40
|
+
"data": {
|
|
41
|
+
"vip_buy_link": "https://www.helixlife.cn/main/vip"
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
the CLI reports both paths: open the returned purchase link to buy membership, or run `xt exchange <兑换码>` to redeem membership in the CLI.
|
|
47
|
+
|
|
26
48
|
### Interactive Tool Run
|
|
27
49
|
|
|
28
50
|
```bash
|
|
@@ -102,7 +124,8 @@ Current operational notes for agent-style callers:
|
|
|
102
124
|
- `tool cloud` only supports `--json` and returns structured cloud candidates via `data.choices`
|
|
103
125
|
- `tool specific-search` only supports `--json` and returns normalized dynamic `args_specific` choices via `data.choices`
|
|
104
126
|
- 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`
|
|
105
|
-
- if a command returns `code=PERMISSION_REQUIRED
|
|
127
|
+
- if a command returns `code=PERMISSION_REQUIRED`, use the returned purchase link or redeem a membership code with `xt exchange <code> --profile <profile> --json`; do not treat it as a local input-file problem
|
|
128
|
+
- if a command returns `code=RATE_LIMITED`, treat it as an upstream submit-capacity problem rather than changing local input files
|
|
106
129
|
- `gsea_customize` has been validated through `tool prepare` and `tool exec` with repeated `--file gene_set=... --file data=...`
|
|
107
130
|
|
|
108
131
|
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.
|
|
@@ -116,6 +139,8 @@ For agent workflows, do not use `xt tool run`. Treat `xt tool run` as the human-
|
|
|
116
139
|
- `xt login`
|
|
117
140
|
- `xt status`
|
|
118
141
|
- `xt logout`
|
|
142
|
+
- `xt exchange`
|
|
143
|
+
- `xt auth exchange`
|
|
119
144
|
- `xt tool login`
|
|
120
145
|
|
|
121
146
|
### Config
|
|
@@ -159,7 +184,7 @@ For agent workflows, do not use `xt tool run`. Treat `xt tool run` as the human-
|
|
|
159
184
|
|
|
160
185
|
For Xiantao tool commands that accept `--toolProductUuid`, the default value is `c0b6febb-52dd-4525-970a-61bbe9e263ff`. You can override it with `--toolProductUuid`, `XIANTAO_TOOL_PRODUCT_UUID`, or `~/.config/helixlife/config.json` under `xiantao.toolProductUuid`.
|
|
161
186
|
|
|
162
|
-
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, and `XIANTAO_LOGIN_URL=https://agent.helixlife.cn/` to override the resolved login page value. The same values can be stored with `xt config set agent_api ...` and `xt config set login-url ...`; `base-url` is kept as a compatibility alias for `agent_api`. Environment variables take precedence over `~/.config/helixlife/config.json`. Login stores the access token at `~/.config/helixlife/user-access-token.txt`. Set `DEBUG_MODE=1` to print HTTP request and response debug payloads to stderr.
|
|
187
|
+
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, and `XIANTAO_LOGIN_URL=https://agent.helixlife.cn/` to override the resolved login page value. The same values can be stored with `xt config set agent_api ...` and `xt config set login-url ...`; `base-url` is kept as a compatibility alias for `agent_api`. Environment variables take precedence over `~/.config/helixlife/config.json`. Login stores the access token at `~/.config/helixlife/user-access-token.txt`. `xt exchange <code>` uses that token to redeem membership through `/agent/ticket/exchange`. Set `DEBUG_MODE=1` to print HTTP request and response debug payloads to stderr.
|
|
163
188
|
|
|
164
189
|
`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 specific-search <tool_id> <argsKey> <query> --json` searches dynamic Search-style `args_specific` options and strips frontend highlight markup from returned choices. `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.
|
|
165
190
|
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{Args as n,Flags as c}from"@oclif/core";import{XtzCommand as g}from"../../base-command.js";import{exchangeTicket as f,getAuthContext as l}from"../../lib/auth.js";import{globalFlags as p}from"../../lib/flags.js";class a extends g{static description="Exchange a membership code for the current profile";static args={code:n.string({description:"Membership exchange code",required:!0})};static flags={...p,token:c.string({description:"Bearer token for agent.helixlife.cn xiantao APIs; falls back to the stored agent token"})};async run(){this.warnIfLegacyAuthCommand();const{args:o,flags:t}=await this.parse(a),e=await this.getProfile(t.profile),r=await l(e,t.token),i=await f(r,o.code),s={agent:e,data:i};this.print(t,s,"\u4F1A\u5458\u5151\u6362\u6210\u529F",{profile:e})}}export{a as default};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import e from"./auth/exchange.js";class t extends e{}export{t as default};
|
package/dist/lib/auth.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{debugHttpError as
|
|
1
|
+
import{debugHttpError as d,debugHttpRequest as k,debugHttpResponse as m}from"./debug.js";import{resolveAuthUrlEndpoint as h,resolveCheckTokenEndpoint as l,resolveTicketExchangeEndpoint as f}from"./config.js";import{XtzError as i,raiseApiError as g}from"./errors.js";import{openUrl as y}from"./open-url.js";import{requestJson as c}from"./http.js";import{loadToken as T,requireToken as p,saveToken as x}from"./storage.js";async function A(t){const o=await T(t),e=await c(await h(),{headers:a(o)},{agent:t}),n=new URL(e.data.link_url);return n.searchParams.set("source",t),{linkUrl:n.toString(),tokenKey:e.data.token_key}}async function O(t,o=!0){const{linkUrl:e,tokenKey:n}=await A(t),s=await x(t,n);return{browserOpened:o?await y(e):!1,linkUrl:e,token:n,tokenPath:s}}async function R(t,o){const e=o?.trim()||await p(t);return{agent:t,token:e}}async function q(t,o){const e=o??await p(t),n=new URL(await l());return n.searchParams.set("token_key",e),(await c(n.toString(),{headers:a(e)},{agent:t})).data}async function z(t,o){const e=await c(await f(),{body:JSON.stringify({code:o.trim()}),headers:a(t.token,!0),method:"POST"},{agent:t.agent});return e.success===!1&&await g(e,{agent:t.agent}),e.data}async function C(t,o={}){const e=o.timeoutMs??12e4,n=o.intervalMs??1500,s=Date.now()+e;let r="";for(;Date.now()<s;){const u=await S(t);if(u.success)return;r=u.message?.trim()||r,await new Promise(w=>setTimeout(w,n))}throw new i(r?`\u7B49\u5F85\u6388\u6743\u5B8C\u6210\u8D85\u65F6: ${r}`:"\u7B49\u5F85\u6388\u6743\u5B8C\u6210\u8D85\u65F6\uFF0C\u8BF7\u91CD\u65B0\u8FD0\u884C `xt login`\u3002")}async function S(t){const o=new URL(await l());o.searchParams.set("token_key",t);const e={headers:a(t)};let n;k(o.toString(),e);try{n=await fetch(o.toString(),e)}catch(r){throw d(o.toString(),r),new i("\u7F51\u7EDC\u8BF7\u6C42\u5931\u8D25\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002")}const s=await n.text();m(o.toString(),n,s);try{const r=JSON.parse(s);return{message:r.message,success:n.ok&&r.success!==!1}}catch{throw new i("\u670D\u52A1\u8FD4\u56DE\u4E86\u65E0\u6CD5\u89E3\u6790\u7684\u54CD\u5E94\u3002")}}function a(t,o=!1){const e={platform:"pc",source:"PC"};return t?.trim()&&(e.Authorization=`Bearer ${t.trim()}`),o&&(e["Content-Type"]="application/json"),e}export{q as checkToken,z as exchangeTicket,A as fetchAuthLink,R as getAuthContext,O as loginAuth,C as waitForAuthorizedToken};
|
package/dist/lib/config.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{mkdir as
|
|
2
|
-
`,"utf8"),{key:e,path:o,value:a}}async function g(n){const t=
|
|
1
|
+
import{mkdir as y,readFile as A,writeFile as U}from"node:fs/promises";import _ from"node:os";import c from"node:path";import{DEFAULT_XIANTAO_BASE_URL as E,DEFAULT_XIANTAO_LOGIN_URL as x,XIANTAO_CONFIG_PATH as C}from"./constants.js";import{XtzError as r}from"./errors.js";import{isJsonObject as L}from"./json.js";const f=["agent_api","base-url","login-url"];function p(){return c.join(_.homedir(),C)}async function S(n,t){const e=w(n),a=d(e,t),o=p(),i=await h(o),l=O(e);return i[l]=a,l==="agent_api"&&delete i["base-url"],await y(c.dirname(o),{recursive:!0}),await U(o,`${JSON.stringify(i,null,2)}
|
|
2
|
+
`,"utf8"),{key:e,path:o,value:a}}async function g(n){const t=w(n),e=p(),a=N(t);if(a)return{key:t,path:e,source:"environment",value:a};const o=await h(e),i=T(o,t);return i?{key:t,path:e,source:"config",value:d(t,i)}:{key:t,path:e,source:"default",value:X(t)}}async function b(){return(await g("base-url")).value}async function F(){return(await g("login-url")).value}async function k(){return u("agent/skills/auth-url")}async function G(){return u("agent/skills/check-token")}async function j(){return u("agent/ticket/exchange")}async function D(){return u("agent/bio-api")}async function J(){return u("agent/tool/menus")}async function P(){const n=new URL(await u("agent/upload/config"));return n.searchParams.set("type","bio"),n.searchParams.set("oss_type","bio"),n.toString()}async function u(n){const t=await b();return`${t.endsWith("/api/v1")?t:`${t}/api/v1`}/${n}`}async function h(n){try{const t=await A(n,"utf8"),e=JSON.parse(t);if(!L(e))throw new r(`\u914D\u7F6E\u6587\u4EF6\u683C\u5F0F\u4E0D\u6B63\u786E: ${n}`);const a=e.agent_api;if(a!==void 0&&typeof a!="string")throw new r(`\u914D\u7F6E\u9879 agent_api \u5FC5\u987B\u662F\u5B57\u7B26\u4E32: ${n}`);const o=e["base-url"];if(o!==void 0&&typeof o!="string")throw new r(`\u914D\u7F6E\u9879 base-url \u5FC5\u987B\u662F\u5B57\u7B26\u4E32: ${n}`);const i=e["login-url"];if(i!==void 0&&typeof i!="string")throw new r(`\u914D\u7F6E\u9879 login-url \u5FC5\u987B\u662F\u5B57\u7B26\u4E32: ${n}`);return e}catch(t){if($(t)&&t.code==="ENOENT")return{};throw t}}function w(n){const t=n.trim().toLowerCase();if(f.includes(t))return t;throw new r(`\u4E0D\u652F\u6301\u7684\u914D\u7F6E\u9879 ${n}\uFF0C\u5F53\u524D\u652F\u6301: ${f.join(", ")}`)}function d(n,t){const e=t.trim();if(!e)throw new r(`\u914D\u7F6E\u9879 ${n} \u4E0D\u80FD\u4E3A\u7A7A`);return s(n)?m(e):n==="login-url"?v(e):e}function N(n){if(s(n)){const t=process.env.XIANTAO_BASE_URL?.trim();return t?m(t):void 0}if(n==="login-url"){const t=process.env.XIANTAO_LOGIN_URL?.trim();return t?v(t):void 0}}function X(n){if(s(n))return E;if(n==="login-url")return x;throw new r(`\u4E0D\u652F\u6301\u7684\u914D\u7F6E\u9879 ${n}`)}function O(n){return s(n)?"agent_api":n}function T(n,t){return s(t)?n.agent_api?.trim()||n["base-url"]?.trim():n[t]?.trim()}function s(n){return n==="agent_api"||n==="base-url"}function m(n){let t;try{t=new URL(n)}catch{throw new r("base-url \u5FC5\u987B\u662F\u6709\u6548\u7684\u7EDD\u5BF9 URL\uFF0C\u4F8B\u5982 https://agent.helixlife.cn")}if(t.protocol!=="http:"&&t.protocol!=="https:")throw new r("base-url \u53EA\u652F\u6301 http \u6216 https");return n.replace(/\/+$/,"")}function v(n){let t;try{t=new URL(n)}catch{throw new r("login-url \u5FC5\u987B\u662F\u6709\u6548\u7684\u7EDD\u5BF9 URL\uFF0C\u4F8B\u5982 https://www.helixlife.net/")}if(t.protocol!=="http:"&&t.protocol!=="https:")throw new r("login-url \u53EA\u652F\u6301 http \u6216 https");return n}function $(n){return n instanceof Error&&"code"in n}export{f as XIANTAO_CONFIG_KEYS,p as getXiantaoConfigPath,k as resolveAuthUrlEndpoint,G as resolveCheckTokenEndpoint,j as resolveTicketExchangeEndpoint,P as resolveUploadConfigEndpoint,b as resolveXiantaoBaseUrl,D as resolveXiantaoBioApiEndpoint,g as resolveXiantaoConfigValue,F as resolveXiantaoLoginUrl,J as resolveXiantaoToolMenusEndpoint,S as setXiantaoConfigValue};
|
package/dist/lib/constants.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
const o="opencode",A=".config/helixlife/config.json",t=".config/helixlife/update-check.json",c=".config/helixlife/config.json",e="https://agent.helixlife.
|
|
1
|
+
const o="opencode",A=".config/helixlife/config.json",t=".config/helixlife/update-check.json",c=".config/helixlife/config.json",e="https://agent.helixlife.cn"?.trim(),_=process.env.XTZ_BUILD_XIANTAO_LOGIN_URL?.trim(),n=(e||"https://agent.helixlife.cn").replace(/\/+$/,""),T=_||"https://agent.helixlife.cn/",I="c0b6febb-52dd-4525-970a-61bbe9e263ff",U="2d491694-8c8d-11ee-9409-00163e118c99";export{o as DEFAULT_AGENT,n as DEFAULT_XIANTAO_BASE_URL,T as DEFAULT_XIANTAO_LOGIN_URL,I as DEFAULT_XIANTAO_TOOL_PRODUCT_UUID,c as XIANTAO_CONFIG_PATH,U as XIANTAO_HISTORY_UUID,A as XTZ_CONFIG_PATH,t as XTZ_UPDATE_CHECK_PATH};
|
package/dist/lib/errors.js
CHANGED
|
@@ -1 +1,2 @@
|
|
|
1
|
-
import{deleteToken as
|
|
1
|
+
import{isJsonObject as s}from"./json.js";import{deleteToken as c}from"./storage.js";class r extends Error{constructor(e){super(e),this.name="XtzError"}}class f extends r{data;constructor(e,n){super(e),this.data=n,this.name="XtzChoiceRequiredError"}}function o(t){return t.includes("\u672A\u6388\u6743")||t.includes("\u8BF7\u767B\u5F55")||t.includes("\u91CD\u65B0\u767B\u5F55")||t.includes("\u8EAB\u4EFD\u9A8C\u8BC1\u5DF2\u8FC7\u671F")}async function d(t,e={}){const n=t.message??"\u8BF7\u6C42\u5931\u8D25",i=String(t.code??"");throw o(n)?(e.agent&&await c(e.agent),new r("\u60A8\u7684\u6388\u6743\u5DF2\u8FC7\u671F\u6216\u65E0\u6548\uFF0C\u8BF7\u91CD\u65B0\u5B8C\u6210\u6388\u6743\u3002")):i.startsWith("403")||n.includes("\u65E0\u6743\u9650")||n.includes("\u6743\u9650")?new r(u(t,e.agent)):i==="5000000101"?new r("\u5F53\u524D\u7F51\u7EDC\u72B6\u6001\u5F02\u5E38\uFF0C\u8BF7\u524D\u5F80 https://www.helixlife.cn \u8054\u7CFB\u5BA2\u670D"):i==="4000020101"||i==="400008"?new r("\u60A8\u7684\u8D26\u53F7\u72B6\u6001\u5F02\u5E38\uFF0C\u8BF7\u8054\u7CFB https://www.helixlife.cn"):i==="400004"?new r("\u8BE5\u83DC\u5355\u6216\u5546\u54C1\u5DF2\u4E0B\u67B6\uFF0C\u8BF7\u66F4\u6362 tool_product_uuid \u6216 menu uuid\u3002"):i==="50000"||i==="40000"||i==="40004"?new r("\u8BF7\u524D\u5F80 https://www.helixlife.cn \u8054\u7CFB\u5BA2\u670D"):n.includes("\u901F\u7387\u9650\u5236")?new r("\u5EFA\u8BAE\u6B21\u65E5\u518D\u8BD5"):new r(n||"\u64CD\u4F5C\u5931\u8D25\uFF0C\u8BF7\u8054\u7CFB\u5BA2\u670D https://www.helixlife.cn")}function u(t,e){const n=h(t)??"https://www.helixlife.cn/main/vip",i=e?`xt exchange <\u5151\u6362\u7801> --profile ${e}`:"xt exchange <\u5151\u6362\u7801>";return["\u60A8\u7684\u8D26\u53F7\u6682\u65E0\u4F7F\u7528\u6743\u9650\uFF0C\u53EF\u4EE5\u6253\u5F00\u8D2D\u4E70\u94FE\u63A5\u8D2D\u4E70\u4F1A\u5458\uFF0C\u4E5F\u53EF\u4EE5\u8F93\u5165\u5151\u6362\u7801\u5151\u6362\u4F1A\u5458\u3002",`\u8D2D\u4E70\u94FE\u63A5: ${n}`,`\u5151\u6362\u547D\u4EE4: ${i}`].join(`
|
|
2
|
+
`)}function h(t){return s(t.data)&&typeof t.data.vip_buy_link=="string"&&t.data.vip_buy_link.trim()?t.data.vip_buy_link.trim():t.message?.match(/https?:\/\/[^\s,。))]+/)?.[0]}export{f as XtzChoiceRequiredError,r as XtzError,d as raiseApiError};
|