@aisa-one/cli 0.1.1 → 0.1.3

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
@@ -187,6 +187,10 @@ Settings:
187
187
 
188
188
  Environment variable `AISA_API_KEY` takes precedence over stored key.
189
189
 
190
+ ## Known Issues
191
+
192
+ **GPT-4.1 streaming returns empty output.** The AISA gateway currently strips `choices[].delta.content` from GPT model SSE chunks, so streaming mode produces blank output for GPT models. Workaround: use `--no-stream` or switch to Claude/Qwen models which stream correctly. Non-streaming GPT works fine.
193
+
190
194
  ## Development
191
195
 
192
196
  ```bash
@@ -198,6 +202,24 @@ npm run dev # watch mode
198
202
  npm test # run tests
199
203
  ```
200
204
 
205
+ ## Appendix: Architecture Notes for Contributors
206
+
207
+ **Two base URLs.** The AISA platform uses separate base paths:
208
+ - LLM endpoints (chat, models): `https://api.aisa.one/v1/`
209
+ - Domain API endpoints (search, finance, twitter, video): `https://api.aisa.one/apis/v1/`
210
+
211
+ The `domain: true` option in `RequestOptions` (see `src/api.ts`) selects which base URL to use. The `run` command auto-detects based on the slug prefix.
212
+
213
+ **Parameter naming varies by endpoint.** Smart/full search uses `q`, scholar uses `query`, finance uses `ticker` (not `symbol`), Twitter uses `userName` (camelCase). Always check the [API Reference](https://docs.aisa.one/reference) for exact parameter names.
214
+
215
+ **Video generation is async.** POST to `/services/aigc/video-generation/video-synthesis` with header `X-DashScope-Async: enable`, then poll `GET /services/aigc/tasks?task_id=<id>` for status. Response shape uses `output.task_id`, `output.task_status`, `output.video_url`.
216
+
217
+ **Twitter write operations require login cookies.** `create_tweet_v2` and other action endpoints need `login_cookies` and `proxy` fields — they don't work with just the API key.
218
+
219
+ **Models API follows OpenAI format.** The `/v1/models` endpoint returns `owned_by` (not `provider`) and has no `name`, `pricing`, or `contextWindow` fields.
220
+
221
+ **Some financial endpoints return empty data.** `financial/prices` and `financial/financial-metrics/snapshot` may return `{}` for certain tickers. `financial/insider-trades`, `financial/news`, and `financial/filings` work reliably.
222
+
201
223
  ## License
202
224
 
203
225
  MIT
package/dist/api.d.ts CHANGED
@@ -6,6 +6,8 @@ export interface RequestOptions {
6
6
  body?: unknown;
7
7
  stream?: boolean;
8
8
  headers?: Record<string, string>;
9
+ /** Use domain API base URL (/apis/v1) instead of LLM base (/v1) */
10
+ domain?: boolean;
9
11
  }
10
12
  export declare function apiRequest<T = unknown>(apiKey: string, endpoint: string, options?: RequestOptions): Promise<ApiResponse<T>>;
11
13
  export declare function apiRequestRaw(apiKey: string, endpoint: string, options?: RequestOptions): Promise<Response>;
package/dist/api.js CHANGED
@@ -1,13 +1,13 @@
1
1
  import fetch from "node-fetch";
2
- import { CLI_BASE_URL } from "./constants.js";
2
+ import { CLI_BASE_URL, APIS_BASE_URL } from "./constants.js";
3
3
  import { getConfig } from "./config.js";
4
4
  function getBaseUrl() {
5
5
  const custom = getConfig("baseUrl");
6
6
  return custom || CLI_BASE_URL;
7
7
  }
8
8
  export async function apiRequest(apiKey, endpoint, options = {}) {
9
- const { method = "GET", query, body, headers: extraHeaders } = options;
10
- const baseUrl = getBaseUrl();
9
+ const { method = "GET", query, body, headers: extraHeaders, domain } = options;
10
+ const baseUrl = domain ? APIS_BASE_URL : getBaseUrl();
11
11
  let url = `${baseUrl}/${endpoint}`;
12
12
  if (query) {
13
13
  const params = new URLSearchParams(query);
@@ -40,8 +40,8 @@ export async function apiRequest(apiKey, endpoint, options = {}) {
40
40
  return { success: true, data };
41
41
  }
42
42
  export async function apiRequestRaw(apiKey, endpoint, options = {}) {
43
- const { method = "GET", query, body, headers: extraHeaders } = options;
44
- const baseUrl = getBaseUrl();
43
+ const { method = "GET", query, body, headers: extraHeaders, domain } = options;
44
+ const baseUrl = domain ? APIS_BASE_URL : getBaseUrl();
45
45
  let url = `${baseUrl}/${endpoint}`;
46
46
  if (query) {
47
47
  const params = new URLSearchParams(query);
@@ -3,12 +3,14 @@ import { requireApiKey } from "../config.js";
3
3
  import { apiRequest } from "../api.js";
4
4
  import { error, formatJson } from "../utils/display.js";
5
5
  const FIELD_ENDPOINTS = {
6
- price: "stock/price",
7
- earnings: "analyst-estimates",
8
- financials: "financial-statements",
9
- filings: "filings",
10
- insider: "insider-trades",
11
- institutional: "institutional-ownership",
6
+ price: "financial/prices",
7
+ earnings: "financial/earnings/press-releases",
8
+ financials: "financial/financials",
9
+ filings: "financial/filings",
10
+ insider: "financial/insider-trades",
11
+ institutional: "financial/institutional-ownership",
12
+ metrics: "financial/financial-metrics/snapshot",
13
+ news: "financial/news",
12
14
  };
13
15
  export async function stockAction(symbol, options) {
14
16
  const key = requireApiKey();
@@ -19,8 +21,21 @@ export async function stockAction(symbol, options) {
19
21
  return;
20
22
  }
21
23
  const spinner = ora(`Fetching ${field} for ${symbol.toUpperCase()}...`).start();
24
+ const query = { ticker: symbol.toUpperCase() };
25
+ // Price endpoint needs additional params for sensible defaults
26
+ if (field === "price") {
27
+ const end = new Date();
28
+ const start = new Date();
29
+ start.setDate(start.getDate() - 30);
30
+ query.interval = "day";
31
+ query.interval_multiplier = "1";
32
+ query.start_date = start.toISOString().split("T")[0];
33
+ query.end_date = end.toISOString().split("T")[0];
34
+ query.limit = "30";
35
+ }
22
36
  const res = await apiRequest(key, endpoint, {
23
- query: { symbol: symbol.toUpperCase() },
37
+ query,
38
+ domain: true,
24
39
  });
25
40
  if (!res.success) {
26
41
  spinner.fail(`Failed to fetch ${field}`);
@@ -38,13 +53,25 @@ export async function stockAction(symbol, options) {
38
53
  export async function cryptoAction(symbol, options) {
39
54
  const key = requireApiKey();
40
55
  const spinner = ora(`Fetching ${symbol.toUpperCase()}...`).start();
41
- const query = { symbol: symbol.toUpperCase() };
42
- if (options.period)
43
- query.period = options.period;
44
- const endpoint = options.period && options.period !== "current"
45
- ? "crypto/price"
46
- : "crypto/price/snapshot";
47
- const res = await apiRequest(key, endpoint, { query });
56
+ // Format ticker: BTC BTC-USD
57
+ const ticker = symbol.toUpperCase().includes("-") ? symbol.toUpperCase() : `${symbol.toUpperCase()}-USD`;
58
+ let endpoint;
59
+ const query = { ticker };
60
+ if (!options.period || options.period === "current") {
61
+ endpoint = "financial/crypto/prices/snapshot";
62
+ }
63
+ else {
64
+ endpoint = "financial/crypto/prices";
65
+ const end = new Date();
66
+ const start = new Date();
67
+ const periodMap = { "1d": 1, "7d": 7, "30d": 30, "1y": 365 };
68
+ start.setDate(start.getDate() - (periodMap[options.period] || 30));
69
+ query.interval = "day";
70
+ query.interval_multiplier = "1";
71
+ query.start_date = start.toISOString().split("T")[0];
72
+ query.end_date = end.toISOString().split("T")[0];
73
+ }
74
+ const res = await apiRequest(key, endpoint, { query, domain: true });
48
75
  if (!res.success) {
49
76
  spinner.fail("Failed to fetch crypto price");
50
77
  error(res.error || "Unknown error");
@@ -61,14 +88,22 @@ export async function cryptoAction(symbol, options) {
61
88
  export async function screenerAction(options) {
62
89
  const key = requireApiKey();
63
90
  const spinner = ora("Running stock screener...").start();
64
- const body = {};
65
- if (options.sector)
66
- body.sector = options.sector;
91
+ const body = {
92
+ filters: [],
93
+ };
94
+ if (options.sector) {
95
+ body.filters.push({
96
+ field: "sector",
97
+ operator: "eq",
98
+ value: options.sector,
99
+ });
100
+ }
67
101
  if (options.limit)
68
102
  body.limit = parseInt(options.limit);
69
- const res = await apiRequest(key, "search/financials", {
103
+ const res = await apiRequest(key, "financial/financials/search", {
70
104
  method: "POST",
71
105
  body,
106
+ domain: true,
72
107
  });
73
108
  if (!res.success) {
74
109
  spinner.fail("Screener failed");
@@ -6,25 +6,27 @@ import { error, badge } from "../utils/display.js";
6
6
  export async function modelsListAction(options) {
7
7
  const key = requireApiKey();
8
8
  const spinner = ora("Fetching models...").start();
9
- const query = {};
10
- if (options.provider)
11
- query.provider = options.provider;
12
- const res = await apiRequest(key, "models", { query });
9
+ const res = await apiRequest(key, "models");
13
10
  if (!res.success || !res.data) {
14
11
  spinner.fail("Failed to fetch models");
15
12
  error(res.error || "Unknown error");
16
13
  return;
17
14
  }
18
15
  spinner.stop();
19
- const models = res.data.data;
16
+ let models = res.data.data;
17
+ // Filter by provider if specified
18
+ if (options.provider) {
19
+ const filter = options.provider.toLowerCase();
20
+ models = models.filter((m) => m.owned_by?.toLowerCase().includes(filter));
21
+ }
20
22
  if (models.length === 0) {
21
23
  console.log(" No models found.");
22
24
  return;
23
25
  }
24
- // Group by provider
26
+ // Group by owned_by (provider)
25
27
  const grouped = {};
26
28
  for (const m of models) {
27
- const p = m.provider || "other";
29
+ const p = m.owned_by || "other";
28
30
  if (!grouped[p])
29
31
  grouped[p] = [];
30
32
  grouped[p].push(m);
@@ -49,17 +51,13 @@ export async function modelsShowAction(modelId) {
49
51
  }
50
52
  spinner.stop();
51
53
  const m = res.data;
52
- console.log(`\n ${chalk.cyan.bold(m.name)} ${badge(m.provider)}`);
53
- console.log(` ID: ${m.id}`);
54
- if (m.contextWindow)
55
- console.log(` Context: ${(m.contextWindow / 1000).toFixed(0)}k tokens`);
56
- if (m.maxTokens)
57
- console.log(` Max output: ${(m.maxTokens / 1000).toFixed(0)}k tokens`);
58
- if (m.pricing) {
59
- console.log(` Pricing: $${m.pricing.input}/M input, $${m.pricing.output}/M output`);
60
- }
61
- if (m.capabilities?.length) {
62
- console.log(` Capabilities: ${m.capabilities.join(", ")}`);
54
+ console.log(`\n ${chalk.cyan.bold(m.id)} ${badge(m.owned_by)}`);
55
+ if (m.owned_by)
56
+ console.log(` Provider: ${m.owned_by}`);
57
+ if (m.created)
58
+ console.log(` Created: ${new Date(m.created * 1000).toLocaleDateString()}`);
59
+ if (m.supported_endpoint_types?.length) {
60
+ console.log(` Endpoints: ${m.supported_endpoint_types.join(", ")}`);
63
61
  }
64
62
  console.log(chalk.gray(`\n Use: aisa chat "message" --model ${m.id}`));
65
63
  }
@@ -32,6 +32,9 @@ export async function runAction(slug, path, options) {
32
32
  // Detect method
33
33
  const method = (options.method || (body ? "POST" : "GET")).toUpperCase();
34
34
  const endpoint = `${slug}${path}`;
35
+ // Auto-detect domain API vs LLM API based on slug
36
+ const domainSlugs = ["financial", "search", "youtube", "scholar", "tavily", "querit", "twitter", "services", "crypto"];
37
+ const isDomain = domainSlugs.some((s) => slug.startsWith(s));
35
38
  // Streaming mode
36
39
  if (options.stream) {
37
40
  const res = await apiRequestRaw(key, endpoint, {
@@ -39,6 +42,7 @@ export async function runAction(slug, path, options) {
39
42
  query: Object.keys(query).length > 0 ? query : undefined,
40
43
  body,
41
44
  headers: { Accept: "text/event-stream" },
45
+ domain: isDomain,
42
46
  });
43
47
  if (!res.ok) {
44
48
  const text = await res.text();
@@ -54,6 +58,7 @@ export async function runAction(slug, path, options) {
54
58
  method,
55
59
  query: Object.keys(query).length > 0 ? query : undefined,
56
60
  body,
61
+ domain: isDomain,
57
62
  });
58
63
  if (!res.success) {
59
64
  spinner.fail("API call failed");
@@ -1,4 +1,5 @@
1
1
  import ora from "ora";
2
+ import chalk from "chalk";
2
3
  import { requireApiKey } from "../config.js";
3
4
  import { apiRequest } from "../api.js";
4
5
  import { error, formatJson } from "../utils/display.js";
@@ -7,11 +8,11 @@ export async function webSearchAction(query, options) {
7
8
  const type = options.type || "smart";
8
9
  const spinner = ora(`Searching (${type})...`).start();
9
10
  const endpointMap = {
10
- smart: { endpoint: "search/smart", method: "GET" },
11
- full: { endpoint: "search/full", method: "GET" },
12
- youtube: { endpoint: "youtube/search", method: "GET" },
13
- scholar: { endpoint: "scholar/search", method: "POST" },
14
- tavily: { endpoint: "tavily/search", method: "POST" },
11
+ smart: { endpoint: "search/smart", method: "GET", paramStyle: "query" },
12
+ full: { endpoint: "search/full", method: "GET", paramStyle: "query" },
13
+ youtube: { endpoint: "youtube/search", method: "GET", paramStyle: "query" },
14
+ scholar: { endpoint: "scholar/search/scholar", method: "POST", paramStyle: "query" },
15
+ tavily: { endpoint: "tavily/search", method: "POST", paramStyle: "body" },
15
16
  };
16
17
  const config = endpointMap[type];
17
18
  if (!config) {
@@ -19,12 +20,27 @@ export async function webSearchAction(query, options) {
19
20
  error("Valid types: smart, full, youtube, scholar, tavily");
20
21
  return;
21
22
  }
22
- const res = await apiRequest(key, config.endpoint, {
23
+ // Build request options
24
+ const reqOpts = {
23
25
  method: config.method,
24
- ...(config.method === "GET"
25
- ? { query: { query, ...(options.limit ? { limit: options.limit } : {}) } }
26
- : { body: { query, limit: parseInt(options.limit || "10") } }),
27
- });
26
+ domain: true,
27
+ };
28
+ if (config.paramStyle === "query") {
29
+ // GET-style search endpoints use 'q' for smart/full/youtube, 'query' for scholar
30
+ const qParam = type === "scholar" ? "query" : "q";
31
+ reqOpts.query = { [qParam]: query };
32
+ if (options.limit) {
33
+ reqOpts.query[type === "scholar" ? "max_num_results" : "count"] = options.limit;
34
+ }
35
+ }
36
+ else {
37
+ // Tavily uses POST body
38
+ reqOpts.body = {
39
+ query,
40
+ ...(options.limit ? { max_results: parseInt(options.limit) } : {}),
41
+ };
42
+ }
43
+ const res = await apiRequest(key, config.endpoint, reqOpts);
28
44
  if (!res.success) {
29
45
  spinner.fail("Search failed");
30
46
  error(res.error || "Unknown error");
@@ -35,6 +51,23 @@ export async function webSearchAction(query, options) {
35
51
  console.log(JSON.stringify(res.data));
36
52
  }
37
53
  else {
54
+ // Format search results nicely
55
+ const data = res.data;
56
+ // Smart/Full search format
57
+ if (data?.webPages && typeof data.webPages === "object") {
58
+ const pages = data.webPages;
59
+ if (pages.value) {
60
+ for (const result of pages.value) {
61
+ console.log(`\n ${chalk.cyan.bold(result.name)}`);
62
+ console.log(` ${chalk.gray(result.url)}`);
63
+ if (result.snippet)
64
+ console.log(` ${result.snippet}`);
65
+ }
66
+ console.log(chalk.gray(`\n ${pages.value.length} results`));
67
+ return;
68
+ }
69
+ }
70
+ // Fallback to generic JSON display
38
71
  console.log(formatJson(res.data));
39
72
  }
40
73
  }
@@ -6,16 +6,24 @@ import { error, formatJson } from "../utils/display.js";
6
6
  export async function tweetAction(text, options) {
7
7
  const key = requireApiKey();
8
8
  const spinner = ora("Posting tweet...").start();
9
- const body = { text };
9
+ const body = { tweet_text: text };
10
10
  if (options.replyTo)
11
- body.reply_to = options.replyTo;
12
- const res = await apiRequest(key, "twitter/create-tweet-v2", {
11
+ body.reply_to_tweet_id = options.replyTo;
12
+ // Note: create_tweet_v2 requires login_cookies and proxy
13
+ // This will fail without those - provide a helpful message
14
+ const res = await apiRequest(key, "twitter/create_tweet_v2", {
13
15
  method: "POST",
14
16
  body,
17
+ domain: true,
15
18
  });
16
19
  if (!res.success) {
17
20
  spinner.fail("Failed to post tweet");
18
- error(res.error || "Unknown error");
21
+ if (res.error?.includes("login_cookies")) {
22
+ error("Tweet creation requires Twitter login cookies. See: https://docs.aisa.one");
23
+ }
24
+ else {
25
+ error(res.error || "Unknown error");
26
+ }
19
27
  return;
20
28
  }
21
29
  spinner.stop();
@@ -30,10 +38,13 @@ export async function tweetAction(text, options) {
30
38
  export async function twitterSearchAction(query, options) {
31
39
  const key = requireApiKey();
32
40
  const spinner = ora(`Searching tweets: "${query}"...`).start();
33
- const q = { query };
41
+ const q = { query, queryType: "Latest" };
34
42
  if (options.limit)
35
- q.limit = options.limit;
36
- const res = await apiRequest(key, "twitter/tweet/advanced-search", { query: q });
43
+ q.cursor = "";
44
+ const res = await apiRequest(key, "twitter/tweet/advanced_search", {
45
+ query: q,
46
+ domain: true,
47
+ });
37
48
  if (!res.success) {
38
49
  spinner.fail("Twitter search failed");
39
50
  error(res.error || "Unknown error");
@@ -51,7 +62,8 @@ export async function twitterUserAction(username, options) {
51
62
  const key = requireApiKey();
52
63
  const spinner = ora(`Fetching @${username}...`).start();
53
64
  const res = await apiRequest(key, "twitter/user/info", {
54
- query: { username },
65
+ query: { userName: username },
66
+ domain: true,
55
67
  });
56
68
  if (!res.success) {
57
69
  spinner.fail("Failed to fetch user");
@@ -63,13 +75,31 @@ export async function twitterUserAction(username, options) {
63
75
  console.log(JSON.stringify(res.data));
64
76
  }
65
77
  else {
66
- console.log(formatJson(res.data));
78
+ const data = res.data;
79
+ const user = data?.data;
80
+ if (user) {
81
+ console.log(`\n ${chalk.cyan.bold(user.name)} ${chalk.gray(`@${user.userName}`)}`);
82
+ if (user.description)
83
+ console.log(` ${user.description}`);
84
+ console.log(` ${chalk.white(String(user.followers))} followers · ${chalk.white(String(user.following))} following`);
85
+ if (user.isBlueVerified)
86
+ console.log(` ${chalk.blue("✓ Verified")}`);
87
+ if (user.location)
88
+ console.log(` ${chalk.gray(user.location)}`);
89
+ }
90
+ else {
91
+ console.log(formatJson(res.data));
92
+ }
67
93
  }
68
94
  }
69
95
  export async function twitterTrendsAction(options) {
70
96
  const key = requireApiKey();
71
97
  const spinner = ora("Fetching trends...").start();
72
- const res = await apiRequest(key, "twitter/trends");
98
+ // woeid 1 = worldwide
99
+ const res = await apiRequest(key, "twitter/trends", {
100
+ query: { woeid: "1", count: "30" },
101
+ domain: true,
102
+ });
73
103
  if (!res.success) {
74
104
  spinner.fail("Failed to fetch trends");
75
105
  error(res.error || "Unknown error");
@@ -2,57 +2,72 @@ import ora from "ora";
2
2
  import chalk from "chalk";
3
3
  import { requireApiKey } from "../config.js";
4
4
  import { apiRequest } from "../api.js";
5
- import { error, success } from "../utils/display.js";
5
+ import { error, formatJson, success } from "../utils/display.js";
6
6
  export async function videoCreateAction(prompt, options) {
7
7
  const key = requireApiKey();
8
8
  const spinner = ora("Creating video generation task...").start();
9
- const body = { prompt };
10
- if (options.model)
11
- body.model = options.model;
9
+ const body = {
10
+ model: options.model || "wan2.6-t2v",
11
+ input: { prompt },
12
+ parameters: { resolution: "720P", duration: 5 },
13
+ };
12
14
  const res = await apiRequest(key, "services/aigc/video-generation/video-synthesis", {
13
15
  method: "POST",
14
16
  body,
17
+ headers: { "X-DashScope-Async": "enable" },
18
+ domain: true,
15
19
  });
16
20
  if (!res.success || !res.data) {
17
21
  spinner.fail("Failed to create video task");
18
22
  error(res.error || "Unknown error");
19
23
  return;
20
24
  }
21
- const task = res.data;
22
25
  spinner.stop();
23
- success(`Task created: ${task.taskId}`);
26
+ const taskId = res.data.output?.task_id || res.data.taskId;
27
+ if (!taskId) {
28
+ console.log(formatJson(res.data));
29
+ return;
30
+ }
31
+ success(`Task created: ${taskId}`);
24
32
  if (!options.wait) {
25
- console.log(chalk.gray(` Check status: aisa video status ${task.taskId}`));
33
+ console.log(chalk.gray(` Check status: aisa video status ${taskId}`));
26
34
  return;
27
35
  }
28
36
  // Poll for completion
29
37
  const pollSpinner = ora("Generating video...").start();
30
- let result = task;
31
- while (result.status === "pending" || result.status === "processing") {
38
+ let status = "PENDING";
39
+ while (status === "PENDING" || status === "RUNNING") {
32
40
  await new Promise((r) => setTimeout(r, 5000));
33
- const pollRes = await apiRequest(key, `services/aigc/tasks/${result.taskId}`);
41
+ const pollRes = await apiRequest(key, "services/aigc/tasks", {
42
+ query: { task_id: taskId },
43
+ domain: true,
44
+ });
34
45
  if (!pollRes.success || !pollRes.data) {
35
46
  pollSpinner.fail("Failed to check status");
36
47
  error(pollRes.error || "Unknown error");
37
48
  return;
38
49
  }
39
- result = pollRes.data;
40
- pollSpinner.text = `Generating video... (${result.status})`;
50
+ status = pollRes.data.output?.task_status || pollRes.data.status || "UNKNOWN";
51
+ pollSpinner.text = `Generating video... (${status})`;
41
52
  }
42
- if (result.status === "completed") {
53
+ if (status === "SUCCEEDED" || status === "completed") {
43
54
  pollSpinner.succeed("Video generated!");
44
- if (result.resultUrl) {
45
- console.log(` URL: ${chalk.cyan(result.resultUrl)}`);
55
+ const videoUrl = res.data.output?.video_url || res.data.resultUrl;
56
+ if (videoUrl) {
57
+ console.log(` URL: ${chalk.cyan(videoUrl)}`);
46
58
  }
47
59
  }
48
60
  else {
49
- pollSpinner.fail(`Video generation ${result.status}`);
61
+ pollSpinner.fail(`Video generation failed: ${status}`);
50
62
  }
51
63
  }
52
64
  export async function videoStatusAction(taskId, options) {
53
65
  const key = requireApiKey();
54
66
  const spinner = ora("Checking status...").start();
55
- const res = await apiRequest(key, `services/aigc/tasks/${taskId}`);
67
+ const res = await apiRequest(key, "services/aigc/tasks", {
68
+ query: { task_id: taskId },
69
+ domain: true,
70
+ });
56
71
  if (!res.success || !res.data) {
57
72
  spinner.fail("Failed to check status");
58
73
  error(res.error || "Unknown error");
@@ -63,11 +78,15 @@ export async function videoStatusAction(taskId, options) {
63
78
  console.log(JSON.stringify(res.data));
64
79
  }
65
80
  else {
66
- const t = res.data;
67
- console.log(` Task: ${t.taskId}`);
68
- console.log(` Status: ${t.status}`);
69
- console.log(` Prompt: ${t.prompt}`);
70
- if (t.resultUrl)
71
- console.log(` URL: ${chalk.cyan(t.resultUrl)}`);
81
+ const d = res.data;
82
+ const status = d.output?.task_status || d.status || "unknown";
83
+ const id = d.output?.task_id || d.taskId || taskId;
84
+ const videoUrl = d.output?.video_url || d.resultUrl;
85
+ console.log(` Task: ${id}`);
86
+ console.log(` Status: ${status}`);
87
+ if (videoUrl)
88
+ console.log(` URL: ${chalk.cyan(videoUrl)}`);
89
+ if (d.request_id)
90
+ console.log(` Request: ${chalk.gray(d.request_id)}`);
72
91
  }
73
92
  }
@@ -1,6 +1,7 @@
1
- export declare const VERSION = "0.1.1";
1
+ export declare const VERSION = "0.1.3";
2
2
  export declare const BASE_URL = "https://api.aisa.one";
3
3
  export declare const CLI_BASE_URL = "https://api.aisa.one/v1";
4
+ export declare const APIS_BASE_URL = "https://api.aisa.one/apis/v1";
4
5
  export declare const ENV_VAR_NAME = "AISA_API_KEY";
5
6
  export declare const MCP_URL = "https://docs.aisa.one/mcp";
6
7
  export declare const AGENT_DIRS: Record<string, string>;
package/dist/constants.js CHANGED
@@ -1,6 +1,7 @@
1
- export const VERSION = "0.1.1";
1
+ export const VERSION = "0.1.3";
2
2
  export const BASE_URL = "https://api.aisa.one";
3
3
  export const CLI_BASE_URL = `${BASE_URL}/v1`;
4
+ export const APIS_BASE_URL = `${BASE_URL}/apis/v1`;
4
5
  export const ENV_VAR_NAME = "AISA_API_KEY";
5
6
  export const MCP_URL = "https://docs.aisa.one/mcp";
6
7
  export const AGENT_DIRS = {
package/dist/index.js CHANGED
@@ -143,7 +143,7 @@ program
143
143
  program
144
144
  .command("stock <symbol>")
145
145
  .description("Look up stock data")
146
- .option("--field <field>", "Data field: price, earnings, financials, filings, insider, institutional", "price")
146
+ .option("--field <field>", "Data field: price, earnings, financials, filings, insider, institutional, metrics, news", "price")
147
147
  .option("--raw", "Raw JSON output")
148
148
  .action(wrap(stockAction));
149
149
  program
package/dist/types.d.ts CHANGED
@@ -20,15 +20,10 @@ export interface ApiGroup {
20
20
  }
21
21
  export interface Model {
22
22
  id: string;
23
- name: string;
24
- provider: string;
25
- contextWindow: number;
26
- maxTokens: number;
27
- pricing: {
28
- input: number;
29
- output: number;
30
- };
31
- capabilities: string[];
23
+ object: string;
24
+ created: number;
25
+ owned_by: string;
26
+ supported_endpoint_types?: string[] | null;
32
27
  }
33
28
  export interface SkillMeta {
34
29
  name: string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aisa-one/cli",
3
- "version": "0.1.1",
3
+ "version": "0.1.3",
4
4
  "description": "CLI for the AISA unified AI infrastructure platform - access 70+ LLMs, web search, finance, Twitter, and video generation APIs",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",