@aisa-one/cli 0.6.2 → 0.6.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/CHANGELOG.md +18 -1
- package/README.md +10 -3
- package/dist/catalog.d.ts +4 -3
- package/dist/catalog.js +6 -2
- package/dist/commands/api.js +36 -10
- package/dist/commands/chat.js +2 -1
- package/dist/commands/skills.js +2 -2
- package/dist/config.js +2 -2
- package/dist/constants.d.ts +3 -1
- package/dist/constants.js +3 -1
- package/dist/index.js +4 -4
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,22 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [0.6.3] — 2026-09-30
|
|
11
|
+
|
|
12
|
+
### Changed
|
|
13
|
+
|
|
14
|
+
- Default `aisa chat` to `deepseek-v4.1-flash` for new configurations and
|
|
15
|
+
when no model is configured. Preserve saved `defaultModel` and `--model` overrides.
|
|
16
|
+
|
|
17
|
+
### Fixed
|
|
18
|
+
|
|
19
|
+
- Display metered provider and endpoint catalog pricing as `usage-based` in
|
|
20
|
+
`api list` and `api show`, rather than treating `normal: 0` as free.
|
|
21
|
+
- Label the catalog price column `PRICING` and show usage-based details as
|
|
22
|
+
`Pricing: usage-based (cost varies)`, with guidance to request a quote.
|
|
23
|
+
- Include `pricing_note` with quote guidance on metered providers and endpoints
|
|
24
|
+
in catalog JSON, preserving the original pricing metadata and list structure.
|
|
25
|
+
|
|
10
26
|
## [0.6.2] — 2026-09-23
|
|
11
27
|
|
|
12
28
|
### Added
|
|
@@ -461,7 +477,8 @@ supports today; nothing here depends on a backend change.
|
|
|
461
477
|
- Config commands (`aisa config get|set|list|reset`) and auth
|
|
462
478
|
(`aisa login|logout|whoami`).
|
|
463
479
|
|
|
464
|
-
[Unreleased]: https://github.com/AIsa-team/cli/compare/v0.6.
|
|
480
|
+
[Unreleased]: https://github.com/AIsa-team/cli/compare/v0.6.3...HEAD
|
|
481
|
+
[0.6.3]: https://github.com/AIsa-team/cli/compare/v0.6.2...v0.6.3
|
|
465
482
|
[0.6.2]: https://github.com/AIsa-team/cli/compare/v0.6.1...v0.6.2
|
|
466
483
|
[0.6.1]: https://github.com/AIsa-team/cli/compare/v0.6.0...v0.6.1
|
|
467
484
|
[0.6.0]: https://github.com/AIsa-team/cli/compare/v0.5.2...v0.6.0
|
package/README.md
CHANGED
|
@@ -31,7 +31,7 @@ aisa quote --input '{"calls":[{"call_id":"c1","tool":"get_financial_company_fact
|
|
|
31
31
|
|
|
32
32
|
`aisa login` opens a browser, signs you in, and stores OAuth tokens. You do not
|
|
33
33
|
need to create or paste a key from the console. For CI or scripts, set
|
|
34
|
-
`AISA_API_KEY` or run `aisa login --key <key>`. New accounts receive $
|
|
34
|
+
`AISA_API_KEY` or run `aisa login --key <key>`. New accounts receive $1 in
|
|
35
35
|
free credits.
|
|
36
36
|
|
|
37
37
|
This first block does not run `aisa chat` or `aisa call`. Quote is a price
|
|
@@ -163,6 +163,13 @@ A provider **id is not always its URL slug** — `brave-search` serves
|
|
|
163
163
|
`/apis/v1/brave/...`, and `api show` prints the catalog path. The catalog
|
|
164
164
|
reports every method as `GET`; treat that as advisory.
|
|
165
165
|
|
|
166
|
+
Prices with `type: metered` display as `usage-based` (billing depends on usage),
|
|
167
|
+
even when the catalog returns `normal: 0`. Details show `usage-based (cost varies)`.
|
|
168
|
+
Use `aisa quote` for a request-specific estimate; JSON keeps the original pricing metadata.
|
|
169
|
+
In `--json` output, metered providers and endpoints also include `pricing_note`
|
|
170
|
+
with quote guidance, including endpoints nested in provider details. The list
|
|
171
|
+
remains an array, and the original `pricing` fields are unchanged.
|
|
172
|
+
|
|
166
173
|
The catalog is cached in `~/.aisa/cache` (override with `AISA_CACHE_DIR`). Pass
|
|
167
174
|
`--refresh` to any command to bypass it, or `aisa cache clear`.
|
|
168
175
|
|
|
@@ -172,7 +179,7 @@ GPT, Claude, Gemini, DeepSeek, Kimi, GLM, Qwen and the rest behind one
|
|
|
172
179
|
OpenAI-compatible endpoint.
|
|
173
180
|
|
|
174
181
|
```bash
|
|
175
|
-
aisa chat "your message" --model
|
|
182
|
+
aisa chat "your message" --model deepseek-v4.1-flash
|
|
176
183
|
aisa chat "explain this" --model claude-opus-4-6
|
|
177
184
|
aisa chat "respond in JSON" --model gemini-2.5-pro --json
|
|
178
185
|
echo "summarize this" | aisa chat # pipe support
|
|
@@ -340,7 +347,7 @@ aisa config reset
|
|
|
340
347
|
```
|
|
341
348
|
|
|
342
349
|
Settings:
|
|
343
|
-
- `defaultModel` — default model for `aisa chat` (default: `
|
|
350
|
+
- `defaultModel` — default model for `aisa chat` (default: `deepseek-v4.1-flash`). Existing saved model settings are preserved.
|
|
344
351
|
- `baseUrl` — platform root; the LLM (`/v1`), integration (`/apis/v1`), and
|
|
345
352
|
catalog bases are all derived from it
|
|
346
353
|
- `routerUrl` — Tool Router origin (default `https://tools.aisa.one`,
|
package/dist/catalog.d.ts
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
*/
|
|
12
12
|
export interface CatalogPricing {
|
|
13
13
|
type: string;
|
|
14
|
-
/** Dollars per request, as a float — not micros. */
|
|
14
|
+
/** Dollars per request, as a float — not micros. Metered prices may use 0 as a placeholder. */
|
|
15
15
|
normal: number;
|
|
16
16
|
}
|
|
17
17
|
export interface CatalogProvider {
|
|
@@ -66,8 +66,9 @@ export declare function toRunPath(path: string): string;
|
|
|
66
66
|
*/
|
|
67
67
|
export declare function runSlugOf(detail: CatalogDetail): string | undefined;
|
|
68
68
|
/**
|
|
69
|
-
* Format
|
|
69
|
+
* Format catalog pricing, keeping metered billing distinct from a free request.
|
|
70
|
+
* Fixed prices span $0.000001 to $0.08, so a fixed
|
|
70
71
|
* number of decimals either rounds the cheap endpoints to $0.00 or pads the
|
|
71
72
|
* rest with noise — keep two significant digits instead.
|
|
72
73
|
*/
|
|
73
|
-
export declare function formatPrice(
|
|
74
|
+
export declare function formatPrice(pricing?: CatalogPricing): string;
|
package/dist/catalog.js
CHANGED
|
@@ -62,11 +62,15 @@ export function runSlugOf(detail) {
|
|
|
62
62
|
return first ? toRunPath(first.path).split("/")[0] : undefined;
|
|
63
63
|
}
|
|
64
64
|
/**
|
|
65
|
-
* Format
|
|
65
|
+
* Format catalog pricing, keeping metered billing distinct from a free request.
|
|
66
|
+
* Fixed prices span $0.000001 to $0.08, so a fixed
|
|
66
67
|
* number of decimals either rounds the cheap endpoints to $0.00 or pads the
|
|
67
68
|
* rest with noise — keep two significant digits instead.
|
|
68
69
|
*/
|
|
69
|
-
export function formatPrice(
|
|
70
|
+
export function formatPrice(pricing) {
|
|
71
|
+
if (pricing?.type === "metered")
|
|
72
|
+
return "usage-based";
|
|
73
|
+
const usd = pricing?.normal;
|
|
70
74
|
if (usd == null)
|
|
71
75
|
return "—";
|
|
72
76
|
if (usd === 0)
|
package/dist/commands/api.js
CHANGED
|
@@ -4,6 +4,21 @@ import { error, formatJson, hint, table, truncate } from "../utils/display.js";
|
|
|
4
4
|
import { API_CATEGORIES, categoryOf } from "../constants.js";
|
|
5
5
|
import { getProviders, getProviderDetail, getHealth, flatEndpoints, toRunPath, runSlugOf, formatPrice, } from "../catalog.js";
|
|
6
6
|
const DEFAULT_ENDPOINT_LIMIT = 40;
|
|
7
|
+
const CATALOG_HINT = "Catalog paths and prices are browsing metadata. Use aisa schema for parameters and aisa quote for a request-specific estimate.";
|
|
8
|
+
const USAGE_BASED_PRICING_NOTE = "Usage-based billing. Use aisa quote for a request-specific estimate.";
|
|
9
|
+
function withPricingNote(item) {
|
|
10
|
+
return item.pricing?.type === "metered"
|
|
11
|
+
? { ...item, pricing_note: USAGE_BASED_PRICING_NOTE }
|
|
12
|
+
: item;
|
|
13
|
+
}
|
|
14
|
+
function pricingDescription(pricing, from = false) {
|
|
15
|
+
const price = formatPrice(pricing);
|
|
16
|
+
if (pricing?.type === "metered")
|
|
17
|
+
return `${price} (cost varies)`;
|
|
18
|
+
if (pricing?.normal == null)
|
|
19
|
+
return price;
|
|
20
|
+
return `${from && pricing.normal > 0 ? "from " : ""}${price} per request`;
|
|
21
|
+
}
|
|
7
22
|
function statusBadge(status) {
|
|
8
23
|
switch (status) {
|
|
9
24
|
case "healthy":
|
|
@@ -41,13 +56,13 @@ export async function apiListAction(options) {
|
|
|
41
56
|
}
|
|
42
57
|
if (options.json) {
|
|
43
58
|
console.log(formatJson(providers.map((p) => ({
|
|
44
|
-
...p,
|
|
59
|
+
...withPricingNote(p),
|
|
45
60
|
category: categoryOf(p.id),
|
|
46
61
|
...(options.health ? { health: healthById.get(p.id)?.status } : {}),
|
|
47
62
|
}))));
|
|
48
63
|
return;
|
|
49
64
|
}
|
|
50
|
-
const headers = ["API", "CATEGORY", "ENDPOINTS", "
|
|
65
|
+
const headers = ["API", "CATEGORY", "ENDPOINTS", "PRICING", "UPDATED"];
|
|
51
66
|
if (options.health)
|
|
52
67
|
headers.push("STATUS");
|
|
53
68
|
const rows = providers.map((p) => {
|
|
@@ -55,7 +70,9 @@ export async function apiListAction(options) {
|
|
|
55
70
|
p.id,
|
|
56
71
|
categoryOf(p.id),
|
|
57
72
|
String(p.endpoint_count),
|
|
58
|
-
|
|
73
|
+
p.pricing?.type !== "metered" && p.pricing?.normal != null && p.pricing.normal > 0
|
|
74
|
+
? `from ${formatPrice(p.pricing)}`
|
|
75
|
+
: formatPrice(p.pricing),
|
|
59
76
|
shortDate(p.updated_at),
|
|
60
77
|
];
|
|
61
78
|
if (options.health)
|
|
@@ -68,7 +85,7 @@ export async function apiListAction(options) {
|
|
|
68
85
|
console.log();
|
|
69
86
|
console.log(chalk.gray(` ${providers.length} APIs · ${total} endpoints`));
|
|
70
87
|
hint("Details: aisa api show <api>");
|
|
71
|
-
hint(
|
|
88
|
+
hint(CATALOG_HINT);
|
|
72
89
|
}
|
|
73
90
|
/** Resolve a provider by id, or by the URL slug its endpoints are served under. */
|
|
74
91
|
async function findProvider(idOrSlug, refresh) {
|
|
@@ -93,13 +110,13 @@ function printEndpointDetail(detail, endpoint) {
|
|
|
93
110
|
console.log(` ${endpoint.description}`);
|
|
94
111
|
console.log(`\n Path: ${endpoint.path}`);
|
|
95
112
|
console.log(` Provider: ${detail.id}`);
|
|
96
|
-
console.log(`
|
|
113
|
+
console.log(` Pricing: ${pricingDescription(endpoint.pricing)}`);
|
|
97
114
|
const params = [...runPath.matchAll(/\{([^}]+)\}/g)].map((m) => m[1]);
|
|
98
115
|
if (params.length > 0) {
|
|
99
116
|
console.log(` Path params: ${params.join(", ")}`);
|
|
100
117
|
}
|
|
101
118
|
console.log();
|
|
102
|
-
hint(
|
|
119
|
+
hint(CATALOG_HINT);
|
|
103
120
|
}
|
|
104
121
|
export async function apiShowAction(idOrSlug, path, options = {}) {
|
|
105
122
|
const spinner = ora(`Loading ${idOrSlug}...`).start();
|
|
@@ -140,21 +157,30 @@ export async function apiShowAction(idOrSlug, path, options = {}) {
|
|
|
140
157
|
return;
|
|
141
158
|
}
|
|
142
159
|
if (options.json) {
|
|
143
|
-
console.log(formatJson(matches[0]));
|
|
160
|
+
console.log(formatJson(withPricingNote(matches[0])));
|
|
144
161
|
return;
|
|
145
162
|
}
|
|
146
163
|
printEndpointDetail(detail, matches[0]);
|
|
147
164
|
return;
|
|
148
165
|
}
|
|
149
166
|
if (options.json) {
|
|
150
|
-
console.log(formatJson(
|
|
167
|
+
console.log(formatJson({
|
|
168
|
+
...withPricingNote(detail),
|
|
169
|
+
...(detail.endpoint_groups ? {
|
|
170
|
+
endpoint_groups: detail.endpoint_groups.map((group) => ({
|
|
171
|
+
...group,
|
|
172
|
+
...(group.endpoints ? { endpoints: group.endpoints.map(withPricingNote) } : {}),
|
|
173
|
+
})),
|
|
174
|
+
} : {}),
|
|
175
|
+
}));
|
|
151
176
|
return;
|
|
152
177
|
}
|
|
153
178
|
const health = options.health
|
|
154
179
|
? (await getHealth({ refresh: options.refresh })).find((h) => h.id === detail.id)
|
|
155
180
|
: undefined;
|
|
156
181
|
console.log(`\n ${chalk.cyan.bold(detail.id)} ${chalk.gray(`(${categoryOf(detail.id)})`)}`);
|
|
157
|
-
console.log(` ${detail.endpoint_count} endpoints
|
|
182
|
+
console.log(` ${detail.endpoint_count} endpoints`);
|
|
183
|
+
console.log(` Pricing: ${pricingDescription(detail.pricing, true)}`);
|
|
158
184
|
console.log(` Updated ${shortDate(detail.updated_at)}`);
|
|
159
185
|
if (health) {
|
|
160
186
|
// Health is tracked per provider, not per endpoint — the per-endpoint
|
|
@@ -185,6 +211,6 @@ export async function apiShowAction(idOrSlug, path, options = {}) {
|
|
|
185
211
|
if (runSlugOf(detail)) {
|
|
186
212
|
console.log();
|
|
187
213
|
hint(`Detail: aisa api show ${detail.id} <path>`);
|
|
188
|
-
hint(
|
|
214
|
+
hint(CATALOG_HINT);
|
|
189
215
|
}
|
|
190
216
|
}
|
package/dist/commands/chat.js
CHANGED
|
@@ -4,6 +4,7 @@ import { requireAccessToken, getConfig } from "../config.js";
|
|
|
4
4
|
import { apiRequest, apiRequestRaw } from "../api.js";
|
|
5
5
|
import { error } from "../utils/display.js";
|
|
6
6
|
import { handleSSEStream } from "../utils/streaming.js";
|
|
7
|
+
import { DEFAULT_CHAT_MODEL } from "../constants.js";
|
|
7
8
|
export async function chatAction(message, options) {
|
|
8
9
|
const key = await requireAccessToken();
|
|
9
10
|
// Read from stdin if no message provided
|
|
@@ -23,7 +24,7 @@ export async function chatAction(message, options) {
|
|
|
23
24
|
error("Empty message");
|
|
24
25
|
process.exit(1);
|
|
25
26
|
}
|
|
26
|
-
const model = options.model || getConfig("defaultModel") ||
|
|
27
|
+
const model = options.model || getConfig("defaultModel") || DEFAULT_CHAT_MODEL;
|
|
27
28
|
const stream = options.stream !== false; // default true
|
|
28
29
|
const messages = [];
|
|
29
30
|
if (options.system) {
|
package/dist/commands/skills.js
CHANGED
|
@@ -4,7 +4,7 @@ import { existsSync, mkdirSync, writeFileSync, readFileSync } from "node:fs";
|
|
|
4
4
|
import { join, resolve } from "node:path";
|
|
5
5
|
import { error, success, hint, truncate } from "../utils/display.js";
|
|
6
6
|
import { expandHome, ensureDir, writeSkillFiles, removeDir, detectAgents } from "../utils/file.js";
|
|
7
|
-
import { AGENT_DIRS } from "../constants.js";
|
|
7
|
+
import { AGENT_DIRS, DEFAULT_CHAT_MODEL } from "../constants.js";
|
|
8
8
|
import { SKILLS_REPO, getSkillIndex, listSkills, resolveSlug, leafName, fetchSkillFiles, fetchSkillMarkdown, parseSkillFrontmatter, } from "../skills-registry.js";
|
|
9
9
|
// --- Skill Templates (for init) ---
|
|
10
10
|
// Domain labels may stay; runnable steps use retained commands only.
|
|
@@ -74,7 +74,7 @@ export AISA_API_KEY=sk-your-key
|
|
|
74
74
|
## Chat Completion
|
|
75
75
|
|
|
76
76
|
\`\`\`bash
|
|
77
|
-
aisa chat "Your question here" --model
|
|
77
|
+
aisa chat "Your question here" --model ${DEFAULT_CHAT_MODEL}
|
|
78
78
|
\`\`\`
|
|
79
79
|
|
|
80
80
|
## Streaming
|
package/dist/config.js
CHANGED
|
@@ -5,7 +5,7 @@ import { join } from "node:path";
|
|
|
5
5
|
import lockfile from "proper-lockfile";
|
|
6
6
|
import { createHash, randomUUID } from "node:crypto";
|
|
7
7
|
import { httpFetch } from "./utils/http.js";
|
|
8
|
-
import { AUTH_SERVER, MISSING_API_KEY_GUIDANCE, ENV_VAR_NAME } from "./constants.js";
|
|
8
|
+
import { AUTH_SERVER, MISSING_API_KEY_GUIDANCE, ENV_VAR_NAME, DEFAULT_CHAT_MODEL } from "./constants.js";
|
|
9
9
|
// tokens.json is authoritative; conf is a write-only compatibility mirror.
|
|
10
10
|
const aisaDir = () => join(homedir(), ".aisa");
|
|
11
11
|
const keyFile = () => join(aisaDir(), "key");
|
|
@@ -118,7 +118,7 @@ const config = new Conf({
|
|
|
118
118
|
schema: {
|
|
119
119
|
tokens: { type: "object", default: {} },
|
|
120
120
|
apiKey: { type: "string", default: "" },
|
|
121
|
-
defaultModel: { type: "string", default:
|
|
121
|
+
defaultModel: { type: "string", default: DEFAULT_CHAT_MODEL },
|
|
122
122
|
baseUrl: { type: "string", default: "https://api.aisa.one/v1" },
|
|
123
123
|
routerUrl: { type: "string", default: "" },
|
|
124
124
|
outputFormat: { type: "string", default: "text" },
|
package/dist/constants.d.ts
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
export declare const VERSION = "0.6.
|
|
1
|
+
export declare const VERSION = "0.6.3";
|
|
2
|
+
/** Default for chat when no model is configured or supplied explicitly. */
|
|
3
|
+
export declare const DEFAULT_CHAT_MODEL = "deepseek-v4.1-flash";
|
|
2
4
|
/** Root of the platform. Per-surface bases are derived in api.ts#resolveBases. */
|
|
3
5
|
export declare const BASE_URL = "https://api.aisa.one";
|
|
4
6
|
export declare const ENV_VAR_NAME = "AISA_API_KEY";
|
package/dist/constants.js
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
export const VERSION = "0.6.
|
|
1
|
+
export const VERSION = "0.6.3";
|
|
2
|
+
/** Default for chat when no model is configured or supplied explicitly. */
|
|
3
|
+
export const DEFAULT_CHAT_MODEL = "deepseek-v4.1-flash";
|
|
2
4
|
/** Root of the platform. Per-surface bases are derived in api.ts#resolveBases. */
|
|
3
5
|
export const BASE_URL = "https://api.aisa.one";
|
|
4
6
|
export const ENV_VAR_NAME = "AISA_API_KEY";
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { Command, Option } from "commander";
|
|
3
|
-
import { VERSION } from "./constants.js";
|
|
3
|
+
import { VERSION, DEFAULT_CHAT_MODEL } from "./constants.js";
|
|
4
4
|
import { CliError } from "./cli-error.js";
|
|
5
5
|
// Auth
|
|
6
6
|
import { loginAction, logoutAction, whoamiAction } from "./commands/auth.js";
|
|
@@ -152,7 +152,7 @@ api
|
|
|
152
152
|
.description("List available APIs")
|
|
153
153
|
.option("--category <cat>", "Filter by category (client-side grouping): finance, search, social, productivity, other")
|
|
154
154
|
.option("--health", "Include provider health status")
|
|
155
|
-
.option("--json", "Output
|
|
155
|
+
.option("--json", "Output catalog JSON with pricing guidance")
|
|
156
156
|
.option("--refresh", "Bypass the cached catalog")
|
|
157
157
|
.action(wrap(apiListAction));
|
|
158
158
|
api
|
|
@@ -161,14 +161,14 @@ api
|
|
|
161
161
|
.option("--all", "Show every endpoint instead of the first 40")
|
|
162
162
|
.option("--group", "Group by the provider's raw endpoint groups")
|
|
163
163
|
.option("--health", "Include provider health status")
|
|
164
|
-
.option("--json", "Output
|
|
164
|
+
.option("--json", "Output catalog JSON with pricing guidance")
|
|
165
165
|
.option("--refresh", "Bypass the cached catalog")
|
|
166
166
|
.action(wrap(apiShowAction));
|
|
167
167
|
// ── Chat (LLM Gateway) ──
|
|
168
168
|
program
|
|
169
169
|
.command("chat [message]")
|
|
170
170
|
.description("Chat with AI models via the AIsa gateway")
|
|
171
|
-
.option("--model <model>",
|
|
171
|
+
.option("--model <model>", `Model ID (default: ${DEFAULT_CHAT_MODEL})`)
|
|
172
172
|
.option("--system <prompt>", "System prompt")
|
|
173
173
|
.option("--no-stream", "Disable streaming")
|
|
174
174
|
.option("--json", "Output raw JSON response")
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aisa-one/cli",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.3",
|
|
4
4
|
"description": "CLI for the AIsa unified AI infrastructure platform - one API key for 80+ LLMs and 900+ endpoints across finance, search, social, and video APIs",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|