@aisa-one/cli 0.6.9 → 0.6.10
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 +14 -1
- package/README.md +27 -26
- package/dist/commands/connect-shared.js +1 -44
- package/dist/commands/connect-t2.js +18 -83
- package/dist/commands/connect-terminal.js +5 -99
- package/dist/commands/connect.js +26 -31
- package/dist/commands/flow.d.ts +0 -46
- package/dist/commands/flow.js +11 -82
- package/dist/commands/mcp.d.ts +9 -42
- package/dist/commands/mcp.js +34 -84
- package/dist/commands/oauth-login.js +1 -1
- package/dist/constants.d.ts +3 -50
- package/dist/constants.js +3 -50
- package/dist/index.js +3 -3
- package/dist/utils/update-check.js +3 -5
- package/package.json +1 -1
package/dist/commands/connect.js
CHANGED
|
@@ -7,9 +7,9 @@ import { dirname, join } from "node:path";
|
|
|
7
7
|
import chalk from "chalk";
|
|
8
8
|
import { error } from "../utils/display.js";
|
|
9
9
|
import { expandHome } from "../utils/file.js";
|
|
10
|
-
import { MCP_CONFIGS,
|
|
10
|
+
import { MCP_CONFIGS, AISA_PROVIDER_ID } from "../constants.js";
|
|
11
11
|
import { getAccessToken, getConfig, setConfig } from "../config.js";
|
|
12
|
-
import {
|
|
12
|
+
import { getMcpServers, writeClientConfig, buildEntry, stripped, isUnifiedMcpSelection } from "./mcp.js";
|
|
13
13
|
import { INSTALLERS, installAgent, isInstalled, supported } from "./install.js";
|
|
14
14
|
import { writeCodexLLM, writeClaudeCodeLLM, writeOpencodeLLM, writeCodexAisaProfile, writeOpencodeAisaBackup, defaultModelsFor, patchCodexMCPAuth, DEFAULT_MODELS, } from "./llm-config.js";
|
|
15
15
|
import { writeClaudeAisaSettings, installWrappers } from "./wrappers.js";
|
|
@@ -257,6 +257,8 @@ export function cursorDeeplink(name, endpoint, key) {
|
|
|
257
257
|
return `cursor://anysphere.cursor-deeplink/mcp/install?name=${encodeURIComponent(name)}&config=${encodeURIComponent(config)}`;
|
|
258
258
|
}
|
|
259
259
|
async function applySelection(clientIds, chosen, key, dryRun, state) {
|
|
260
|
+
if (!isUnifiedMcpSelection(chosen))
|
|
261
|
+
throw new Error("Only the unified AIsa Router MCP can be configured");
|
|
260
262
|
const results = [];
|
|
261
263
|
for (const id of clientIds) {
|
|
262
264
|
if (id === "cursor" && state?.deeplinks) {
|
|
@@ -377,7 +379,7 @@ async function applySelection(clientIds, chosen, key, dryRun, state) {
|
|
|
377
379
|
}
|
|
378
380
|
else if (MCP_CONFIGS[id]) {
|
|
379
381
|
if (dryRun) {
|
|
380
|
-
results.push({ client: id, ok: true, message: `would write ${chosen.length
|
|
382
|
+
results.push({ client: id, ok: true, message: `would write ${chosen.length} entries to ${MCP_CONFIGS[id].path}` });
|
|
381
383
|
continue;
|
|
382
384
|
}
|
|
383
385
|
const r = writeClientConfig(id, chosen, key);
|
|
@@ -1131,14 +1133,13 @@ function renderPage(servers, clients, token, keyed, canInstall) {
|
|
|
1131
1133
|
.map(([cat, list]) => {
|
|
1132
1134
|
const rows = list
|
|
1133
1135
|
.map((s) => {
|
|
1134
|
-
const checked = MCP_DEFAULT_SLUGS.includes(s.slug) ? "checked" : "";
|
|
1135
1136
|
// The full manifest description, CSS-clamped to two lines; "more"
|
|
1136
1137
|
// expands it and is hidden by the page script when the text already
|
|
1137
1138
|
// fits — so short cards carry no dead link and long ones stay tidy.
|
|
1138
|
-
return `<label class="card
|
|
1139
|
-
<input type="checkbox" name="server" value="${s.slug}"
|
|
1139
|
+
return `<label class="card on" data-kind="server">
|
|
1140
|
+
<input type="checkbox" name="server" value="${s.slug}" checked disabled>
|
|
1140
1141
|
<span class="body"><span class="head"><span class="name">${stripped(s.name)}</span>
|
|
1141
|
-
|
|
1142
|
+
</span>
|
|
1142
1143
|
<span class="desc">${s.description}</span>
|
|
1143
1144
|
<span class="more" data-more>more</span></span></label>`;
|
|
1144
1145
|
})
|
|
@@ -1169,7 +1170,6 @@ function renderPage(servers, clients, token, keyed, canInstall) {
|
|
|
1169
1170
|
(rest.length
|
|
1170
1171
|
? `<div class="chips">${rest.map((c) => `${c.label} <i>· not found</i>`).join(" ")}</div>`
|
|
1171
1172
|
: "");
|
|
1172
|
-
const totalTools = servers.reduce((n, s) => n + s.toolCount, 0);
|
|
1173
1173
|
// Named per client so the page can say which model a pick actually gets.
|
|
1174
1174
|
const modelByClient = Object.fromEntries(clients.map((c) => [c.id, defaultModelsFor(c.id).model]));
|
|
1175
1175
|
const authCopy = keyed
|
|
@@ -1180,13 +1180,11 @@ function renderPage(servers, clients, token, keyed, canInstall) {
|
|
|
1180
1180
|
const body = `
|
|
1181
1181
|
<div class="eyebrow">Connect</div>
|
|
1182
1182
|
<h1><em>AIsa MCP</em> — powerful real-world reach for your agent</h1>
|
|
1183
|
-
<p class="lede">One connection
|
|
1184
|
-
X/Twitter, Reddit, Instagram, stocks, crypto, prediction markets and B2B data — inside the
|
|
1185
|
-
coding agent you already use. Pick what you need, press Connect, approve in the browser. Done.</p>
|
|
1183
|
+
<p class="lede">One connection gives your coding agent access to AIsa tools. Press Connect and approve in the browser. Done.</p>
|
|
1186
1184
|
|
|
1187
1185
|
<div class="cols">
|
|
1188
1186
|
<div class="left">
|
|
1189
|
-
<h2><span class="n">1</span>
|
|
1187
|
+
<h2><span class="n">1</span>Connect AIsa Router</h2>
|
|
1190
1188
|
${serverGroups}
|
|
1191
1189
|
</div>
|
|
1192
1190
|
|
|
@@ -1461,7 +1459,7 @@ machine except the OAuth you approve. The process exits when everything is conne
|
|
|
1461
1459
|
var servers = picked("server");
|
|
1462
1460
|
var chosen = document.querySelector('input[name="client"]:checked');
|
|
1463
1461
|
if (!servers.length || !chosen) {
|
|
1464
|
-
result.textContent = "
|
|
1462
|
+
result.textContent = "Choose a client to connect to AIsa Router."; return;
|
|
1465
1463
|
}
|
|
1466
1464
|
var clients = [chosen.value];
|
|
1467
1465
|
var install = chosen.dataset.install === "1" ? [chosen.value] : [];
|
|
@@ -1524,9 +1522,6 @@ export function renderDone(chosen, clientIds, steps, allServers, balanceMicros,
|
|
|
1524
1522
|
Fix the above, then run <code>npx @aisa-one/cli connect</code> again — it is
|
|
1525
1523
|
safe to re-run and picks up where things stand.</div></div>`
|
|
1526
1524
|
: "";
|
|
1527
|
-
const toolCount = chosen.reduce((n, s) => n + s.toolCount, 0);
|
|
1528
|
-
const remaining = allServers.length - chosen.length;
|
|
1529
|
-
const remainingTools = allServers.reduce((n, s) => n + s.toolCount, 0) - toolCount;
|
|
1530
1525
|
// A run that installed an agent is a much bigger deal than one that only
|
|
1531
1526
|
// added tools, and the headline must say so: the user walked in with
|
|
1532
1527
|
// nothing and walked out with a working coding agent on AIsa models.
|
|
@@ -1537,12 +1532,12 @@ export function renderDone(chosen, clientIds, steps, allServers, balanceMicros,
|
|
|
1537
1532
|
const model = defaultModelsFor(clientIds[0] ?? "");
|
|
1538
1533
|
const successHeadline = installedAgents.length
|
|
1539
1534
|
? `<h1>Congratulations — <em>${installedAgents.join(" & ")}</em> is installed and armed
|
|
1540
|
-
with <em
|
|
1535
|
+
with <em>AIsa tools</em></h1>
|
|
1541
1536
|
<p class="lede"><b>${installedAgents.join(" & ")}</b> is now on this machine, signed in to
|
|
1542
1537
|
AIsa${llmOk ? `, running on <b>${model.model}</b> through AIsa,` : ","} with
|
|
1543
1538
|
${chosen.length} MCP server${chosen.length > 1 ? "s" : ""} wired in — a complete AI setup,
|
|
1544
1539
|
nothing else to configure.</p>`
|
|
1545
|
-
: `<h1>Congratulations — your agent just got <em
|
|
1540
|
+
: `<h1>Congratulations — your agent just got <em>access to AIsa tools</em></h1>
|
|
1546
1541
|
<p class="lede">${chosen.length} AIsa MCP server${chosen.length > 1 ? "s are" : " is"} now
|
|
1547
1542
|
installed and signed in for <b>${clientNames}</b> — nothing else to configure.</p>`;
|
|
1548
1543
|
// Launchable only for the CLI agents, and only while the local process is
|
|
@@ -1618,7 +1613,7 @@ ${successHeadline}`;
|
|
|
1618
1613
|
const recap = `
|
|
1619
1614
|
<h2>Everything you just gained</h2>
|
|
1620
1615
|
<div class="recap">
|
|
1621
|
-
<div class="rsum"
|
|
1616
|
+
<div class="rsum">AIsa Router MCP · ${clientNames}</div>
|
|
1622
1617
|
${recapRows}
|
|
1623
1618
|
</div>`;
|
|
1624
1619
|
// ── the balance card: always shown, always with the top-up button — money
|
|
@@ -1696,10 +1691,7 @@ ${headline}
|
|
|
1696
1691
|
${mcpFailed
|
|
1697
1692
|
? failBlock + recap + balanceCard
|
|
1698
1693
|
: `<p class="lede" style="margin-top:.6rem">You are now connected to <b>AIsa</b> — a powerful capability layer for agents: one account for
|
|
1699
|
-
<b>Claude, GPT, Gemini, DeepSeek, Kimi, GLM</b> and the live data behind them: <b>Twitter, SimilarWeb, CoinGecko, Apollo, Polymarket</b> and more
|
|
1700
|
-
? ` ${remaining} more MCP server${remaining > 1 ? "s" : ""} (${remainingTools} tools) are one
|
|
1701
|
-
<code>npx @aisa-one/cli connect</code> away.`
|
|
1702
|
-
: ""}
|
|
1694
|
+
<b>Claude, GPT, Gemini, DeepSeek, Kimi, GLM</b> and the live data behind them: <b>Twitter, SimilarWeb, CoinGecko, Apollo, Polymarket</b> and more.
|
|
1703
1695
|
Explore the platform at <a href="https://aisa.one" target="_blank" rel="noopener noreferrer">aisa.one</a> ·
|
|
1704
1696
|
usage & billing at <a href="https://console.aisa.one" target="_blank" rel="noopener noreferrer">console.aisa.one</a>.</p>
|
|
1705
1697
|
${failBlock}
|
|
@@ -2246,14 +2238,17 @@ export async function connectAction(options) {
|
|
|
2246
2238
|
}
|
|
2247
2239
|
let servers;
|
|
2248
2240
|
try {
|
|
2249
|
-
servers = resumed ? resumed.servers :
|
|
2241
|
+
servers = resumed ? resumed.servers : getMcpServers();
|
|
2242
|
+
if (!isUnifiedMcpSelection(servers))
|
|
2243
|
+
throw new Error("This saved run uses retired MCP endpoints. Start again with aisa connect --force.");
|
|
2250
2244
|
}
|
|
2251
2245
|
catch (e) {
|
|
2252
|
-
log.line("fail", "Could not
|
|
2253
|
-
log.note("
|
|
2246
|
+
log.line("fail", "Could not prepare the unified MCP connection", e.message);
|
|
2247
|
+
log.note("Review your clients and models again with: aisa connect --force");
|
|
2254
2248
|
process.exitCode = 1;
|
|
2255
2249
|
return;
|
|
2256
2250
|
}
|
|
2251
|
+
log.note("Existing MCP entries are preserved. Remove old domain entries manually after connecting to aisa-router.");
|
|
2257
2252
|
const clients = resumed ? resumed.clients : detectClients();
|
|
2258
2253
|
// Rehearsal aid: in a dry run, pretend the listed clients are present so a
|
|
2259
2254
|
// page can be reviewed for a client this machine does not have. Never
|
|
@@ -2313,7 +2308,7 @@ export async function connectAction(options) {
|
|
|
2313
2308
|
// that never opens a browser starts from the same defaults rather than
|
|
2314
2309
|
// from nothing.
|
|
2315
2310
|
draft: {
|
|
2316
|
-
servers: servers.
|
|
2311
|
+
servers: servers.map((s) => s.slug),
|
|
2317
2312
|
clients: [],
|
|
2318
2313
|
install: [],
|
|
2319
2314
|
llmMode: "backup",
|
|
@@ -2715,7 +2710,7 @@ export async function connectAction(options) {
|
|
|
2715
2710
|
}
|
|
2716
2711
|
// Who started this decides whether there is an animation to wait for.
|
|
2717
2712
|
drivenByTerminal = req.headers["x-connect-source"] === "terminal";
|
|
2718
|
-
chosenServers = servers
|
|
2713
|
+
chosenServers = servers;
|
|
2719
2714
|
chosenClients = body.clients ?? [];
|
|
2720
2715
|
const wantInstall = new Set(body.install ?? []);
|
|
2721
2716
|
// Ticking "install" means "and connect it": nobody installs an agent
|
|
@@ -2995,7 +2990,7 @@ export async function connectAction(options) {
|
|
|
2995
2990
|
// the real problem.
|
|
2996
2991
|
if (resumed && state.selection) {
|
|
2997
2992
|
chosenClients = [...state.selection.clients];
|
|
2998
|
-
chosenServers = servers
|
|
2993
|
+
chosenServers = servers;
|
|
2999
2994
|
// llmMode is not a local here — the routes read state.llmMode, which
|
|
3000
2995
|
// travels with the run.
|
|
3001
2996
|
}
|
|
@@ -3006,7 +3001,7 @@ export async function connectAction(options) {
|
|
|
3006
3001
|
armRetry({
|
|
3007
3002
|
install: [...sel.install],
|
|
3008
3003
|
clients: [...sel.clients],
|
|
3009
|
-
servers: servers
|
|
3004
|
+
servers: servers,
|
|
3010
3005
|
key: liveKey(),
|
|
3011
3006
|
catcher: signInCatcher,
|
|
3012
3007
|
signinShown: signinShownP,
|
|
@@ -3126,7 +3121,7 @@ export async function connectAction(options) {
|
|
|
3126
3121
|
const missing = clients.filter((c) => !c.detected).map((c) => c.label);
|
|
3127
3122
|
if (missing.length)
|
|
3128
3123
|
log.record(`not found: ${missing.join(", ")}`);
|
|
3129
|
-
log.line("info",
|
|
3124
|
+
log.line("info", "AIsa Router MCP", "one connection for all published tools");
|
|
3130
3125
|
// The terminal walks the same six steps from the same definition. It is not
|
|
3131
3126
|
// a fallback: on a machine with no browser, printing a localhost URL is a
|
|
3132
3127
|
// dead end, and both surfaces share one draft so either can be used —
|
package/dist/commands/flow.d.ts
CHANGED
|
@@ -262,55 +262,13 @@ export declare const STEP_CAPS: {
|
|
|
262
262
|
en: string;
|
|
263
263
|
zh: string;
|
|
264
264
|
};
|
|
265
|
-
pickArea: {
|
|
266
|
-
en: string;
|
|
267
|
-
zh: string;
|
|
268
|
-
};
|
|
269
|
-
selectAll: {
|
|
270
|
-
en: string;
|
|
271
|
-
zh: string;
|
|
272
|
-
};
|
|
273
|
-
/**
|
|
274
|
-
* The counts sentence as one string, because punctuation is not shared
|
|
275
|
-
* between languages: joining "N", "areas", ", " in code produced
|
|
276
|
-
* "2 个领域, 2 个 server, 48 个工具." — Chinese text with ASCII commas and a
|
|
277
|
-
* full stop. Whatever varies goes in as a placeholder instead.
|
|
278
|
-
*/
|
|
279
265
|
counts: {
|
|
280
266
|
en: string;
|
|
281
267
|
zh: string;
|
|
282
268
|
};
|
|
283
|
-
/** Category tile meta: "3 servers · 47 tools". */
|
|
284
|
-
tileMeta: {
|
|
285
|
-
en: string;
|
|
286
|
-
zh: string;
|
|
287
|
-
};
|
|
288
|
-
/**
|
|
289
|
-
* A placeholder both renderers can fill. The page used to carry
|
|
290
|
-
* <b id="mModel"></b> here and fill it with script — which left the
|
|
291
|
-
* terminal printing "AIsa()" with nothing inside, because stripping tags is
|
|
292
|
-
* all it can do with markup meant for the other surface.
|
|
293
|
-
*/
|
|
294
|
-
serversWord: {
|
|
295
|
-
en: string;
|
|
296
|
-
zh: string;
|
|
297
|
-
};
|
|
298
|
-
serverWord: {
|
|
299
|
-
en: string;
|
|
300
|
-
zh: string;
|
|
301
|
-
};
|
|
302
|
-
toolsWord: {
|
|
303
|
-
en: string;
|
|
304
|
-
zh: string;
|
|
305
|
-
};
|
|
306
269
|
};
|
|
307
270
|
/** Shown for a file-configured client that has no note of its own. */
|
|
308
271
|
export declare const FILE_MODEL_FALLBACK: Text;
|
|
309
|
-
export declare const CATEGORY_BLURB: Record<string, Text>;
|
|
310
|
-
/** New host categories remain visible without waiting for a client release. */
|
|
311
|
-
export declare function categoryBlurb(category: string, servers: Array<{
|
|
312
|
-
name: string;
|
|
313
|
-
}>): Text;
|
|
314
272
|
export declare const STEP_INSTALL: {
|
|
315
273
|
h1: {
|
|
316
274
|
en: string;
|
|
@@ -344,10 +302,6 @@ export declare const STEP_DONE: {
|
|
|
344
302
|
};
|
|
345
303
|
};
|
|
346
304
|
export declare const RUNTIME_COPY: {
|
|
347
|
-
readonly nothingSelected: {
|
|
348
|
-
readonly en: "Nothing selected yet — pick at least one server.";
|
|
349
|
-
readonly zh: "还没有选择 —— 至少选一个 server。";
|
|
350
|
-
};
|
|
351
305
|
readonly planBackup: {
|
|
352
306
|
readonly "claude-code": {
|
|
353
307
|
readonly en: "Install the claude-aisa command";
|
package/dist/commands/flow.js
CHANGED
|
@@ -136,12 +136,12 @@ export const AGENT_NOTES = {
|
|
|
136
136
|
zh: "每个 server 一次点击:最后一步会给出 <b>Add to Cursor</b> 链接。Cursor 会打开、把确切的配置内容给你看,你确认后由它自己写进 MCP 设置。模型保持原样 —— Cursor 用它自己的。",
|
|
137
137
|
},
|
|
138
138
|
"claude-desktop": {
|
|
139
|
-
en: "Claude Desktop's config file only takes MCP servers over stdio, so
|
|
140
|
-
zh: "Claude Desktop 的配置文件只接受 stdio 形式的 MCP server
|
|
139
|
+
en: "Claude Desktop's config file only takes MCP servers over stdio, so the AIsa Router is written in as a small <code>mcp-remote</code> bridge carrying your key. The bridge lives and dies with the app — no background service, no open ports. Models cannot be changed: Claude Desktop runs Anthropic's own. Restart the app and the Router appears under its tools menu.",
|
|
140
|
+
zh: "Claude Desktop 的配置文件只接受 stdio 形式的 MCP server,所以 AIsa Router 写成一个带你 key 的 <code>mcp-remote</code> 小桥接。桥接随 app 启停 —— 没有后台服务,不开端口。模型无法更改:Claude Desktop 跑的是 Anthropic 自家模型。重启 app 后就能在工具菜单里看到 AIsa Router。",
|
|
141
141
|
},
|
|
142
142
|
"claude-ai": {
|
|
143
|
-
en: "Nothing is installed. claude.ai takes remote MCP servers as <b>Connectors</b>: on the last step you get
|
|
144
|
-
zh: "不安装任何东西。claude.ai 以 <b>Connectors</b> 的形式接受远程 MCP server
|
|
143
|
+
en: "Nothing is installed. claude.ai takes remote MCP servers as <b>Connectors</b>: on the last step you get the Router URL with a Copy button, and add it under <b>Settings → Connectors → Add custom connector</b>, then press Connect — claude.ai runs the AIsa sign-in itself. Models cannot be changed: claude.ai runs Anthropic's own.",
|
|
144
|
+
zh: "不安装任何东西。claude.ai 以 <b>Connectors</b> 的形式接受远程 MCP server:最后一步会给出 Router 的 URL 和复制按钮,在 <b>Settings → Connectors → Add custom connector</b> 里添加,然后点 Connect —— claude.ai 会自己跑 AIsa 的登录流程。模型无法更改:claude.ai 跑的是 Anthropic 自家模型。",
|
|
145
145
|
},
|
|
146
146
|
};
|
|
147
147
|
/**
|
|
@@ -176,8 +176,8 @@ export const AGENT_HAVE_NOTES = {
|
|
|
176
176
|
zh: "你原有的东西一样都不会被替换。那两个文件里其他的 MCP server 和模型分组保持原样;只有 <code>aisa-*</code> 条目和 AIsa 那个分组是我们写的,要移除就是删掉它们。",
|
|
177
177
|
},
|
|
178
178
|
cursor: {
|
|
179
|
-
en: "Nothing of yours is replaced. Cursor adds
|
|
180
|
-
zh: "你原有的东西一样都不会被替换。Cursor
|
|
179
|
+
en: "Nothing of yours is replaced. Cursor adds the AIsa Router beside your existing MCP entries under the <code>aisa-router</code> name, and you approve it inside Cursor first.",
|
|
180
|
+
zh: "你原有的东西一样都不会被替换。Cursor 会把 AIsa Router 以 <code>aisa-router</code> 命名加在你已有的 MCP 条目旁边,并需要你在 Cursor 里先确认。",
|
|
181
181
|
},
|
|
182
182
|
};
|
|
183
183
|
// ── the rail: every step's name ─────────────────────────────────────────────
|
|
@@ -325,88 +325,21 @@ export const BACKUP_COPY = {
|
|
|
325
325
|
};
|
|
326
326
|
// ── step 4: capabilities ────────────────────────────────────────────────────
|
|
327
327
|
export const STEP_CAPS = {
|
|
328
|
-
h1: { en: "
|
|
328
|
+
h1: { en: "Connect AIsa tools", zh: "连接 AIsa 工具" },
|
|
329
329
|
ledeTail: {
|
|
330
|
-
en: "
|
|
331
|
-
zh: "
|
|
330
|
+
en: "One Router MCP connects your agent to AIsa tools. Existing MCP entries stay unchanged; remove old domain entries manually.",
|
|
331
|
+
zh: "通过一个 Router MCP 接入 AIsa 工具。已有 MCP 条目保持不变;旧的领域条目请自行删除。",
|
|
332
332
|
},
|
|
333
|
-
pickArea: { en: "Pick an area above", zh: "先在上面选一个领域" },
|
|
334
|
-
selectAll: { en: "Select all in this area", zh: "全选这个领域" },
|
|
335
|
-
/**
|
|
336
|
-
* The counts sentence as one string, because punctuation is not shared
|
|
337
|
-
* between languages: joining "N", "areas", ", " in code produced
|
|
338
|
-
* "2 个领域, 2 个 server, 48 个工具." — Chinese text with ASCII commas and a
|
|
339
|
-
* full stop. Whatever varies goes in as a placeholder instead.
|
|
340
|
-
*/
|
|
341
333
|
counts: {
|
|
342
|
-
en: "
|
|
343
|
-
zh: "
|
|
344
|
-
},
|
|
345
|
-
/** Category tile meta: "3 servers · 47 tools". */
|
|
346
|
-
tileMeta: {
|
|
347
|
-
en: "{n} {noun} · {tools} tools",
|
|
348
|
-
zh: "{n} 个 {noun} · {tools} 个工具",
|
|
334
|
+
en: "One unified AIsa MCP connection.",
|
|
335
|
+
zh: "一个统一的 AIsa MCP 连接。",
|
|
349
336
|
},
|
|
350
|
-
/**
|
|
351
|
-
* A placeholder both renderers can fill. The page used to carry
|
|
352
|
-
* <b id="mModel"></b> here and fill it with script — which left the
|
|
353
|
-
* terminal printing "AIsa()" with nothing inside, because stripping tags is
|
|
354
|
-
* all it can do with markup meant for the other surface.
|
|
355
|
-
*/
|
|
356
|
-
serversWord: { en: "servers", zh: "server" },
|
|
357
|
-
serverWord: { en: "server", zh: "server" },
|
|
358
|
-
toolsWord: { en: "tools", zh: "个工具" },
|
|
359
337
|
};
|
|
360
338
|
/** Shown for a file-configured client that has no note of its own. */
|
|
361
339
|
export const FILE_MODEL_FALLBACK = {
|
|
362
340
|
en: "This client picks its own models inside the app, so nothing is changed here — only the MCP servers are added.",
|
|
363
341
|
zh: "这个客户端在它自己的应用里选模型,所以这一步不做改动 —— 只添加 MCP server。",
|
|
364
342
|
};
|
|
365
|
-
export const CATEGORY_BLURB = {
|
|
366
|
-
"Search & Research": {
|
|
367
|
-
en: "Ranked web results with page text already extracted, plus YouTube.",
|
|
368
|
-
zh: "带排序的网页搜索结果,正文已经抽好,另有 YouTube。",
|
|
369
|
-
},
|
|
370
|
-
Finance: {
|
|
371
|
-
en: "US equities, crypto, prediction markets and what X is saying about a ticker.",
|
|
372
|
-
zh: "美股、加密货币、预测市场,以及 X 上关于某只票的讨论。",
|
|
373
|
-
},
|
|
374
|
-
Social: {
|
|
375
|
-
en: "Public X/Twitter, Reddit, Instagram and Pinterest — profiles, posts, engagement.",
|
|
376
|
-
zh: "公开的 X/Twitter、Reddit、Instagram 和 Pinterest —— 资料、帖子、互动数据。",
|
|
377
|
-
},
|
|
378
|
-
Sales: {
|
|
379
|
-
en: "Apollo B2B data — enrich people and companies, find prospects.",
|
|
380
|
-
zh: "Apollo 的 B2B 数据 —— 补全人和公司信息、找潜在客户。",
|
|
381
|
-
},
|
|
382
|
-
"SEO & Search Data": {
|
|
383
|
-
en: "Keywords, rankings, backlinks and on-page checks — and how a brand shows up in AI answers.",
|
|
384
|
-
zh: "关键词、排名、外链、页面检查 —— 还有一个品牌在 AI 回答里的露出情况。",
|
|
385
|
-
},
|
|
386
|
-
Communication: {
|
|
387
|
-
en: "An inbox an agent can actually use — its own address, sending and receiving.",
|
|
388
|
-
zh: "agent 能真正用起来的邮箱 —— 自己的地址,能收能发。",
|
|
389
|
-
},
|
|
390
|
-
Creators: {
|
|
391
|
-
en: "Find creators by audience, topic and reach, across platforms.",
|
|
392
|
-
zh: "按受众、话题和影响力找创作者,跨平台。",
|
|
393
|
-
},
|
|
394
|
-
Search: {
|
|
395
|
-
en: "YouTube search on its own.",
|
|
396
|
-
zh: "单独的 YouTube 搜索。",
|
|
397
|
-
},
|
|
398
|
-
"Market Intelligence": {
|
|
399
|
-
en: "Similarweb data — a site's traffic, engagement and where its visitors come from.",
|
|
400
|
-
zh: "Similarweb 数据 —— 网站流量、互动情况,以及访客从哪来。",
|
|
401
|
-
},
|
|
402
|
-
};
|
|
403
|
-
/** New host categories remain visible without waiting for a client release. */
|
|
404
|
-
export function categoryBlurb(category, servers) {
|
|
405
|
-
if (Object.hasOwn(CATEGORY_BLURB, category))
|
|
406
|
-
return CATEGORY_BLURB[category];
|
|
407
|
-
const names = servers.map((server) => server.name).filter(Boolean).join(", ");
|
|
408
|
-
return { en: `Explore ${names || category}.`, zh: `查看 ${names || category} 的接口。` };
|
|
409
|
-
}
|
|
410
343
|
// ── step 5: install ─────────────────────────────────────────────────────────
|
|
411
344
|
export const STEP_INSTALL = {
|
|
412
345
|
h1: { en: "Ready to connect", zh: "准备接线" },
|
|
@@ -433,10 +366,6 @@ export const STEP_DONE = {
|
|
|
433
366
|
// Resolved to the current language and injected as a single object, because
|
|
434
367
|
// the browser has no access to this file. Same source, one hop later.
|
|
435
368
|
export const RUNTIME_COPY = {
|
|
436
|
-
nothingSelected: {
|
|
437
|
-
en: "Nothing selected yet — pick at least one server.",
|
|
438
|
-
zh: "还没有选择 —— 至少选一个 server。",
|
|
439
|
-
},
|
|
440
369
|
planBackup: {
|
|
441
370
|
"claude-code": { en: "Install the claude-aisa command", zh: "安装 claude-aisa 命令" },
|
|
442
371
|
codex: { en: "Add the aisa profile and codex-aisa", zh: "添加 aisa profile 和 codex-aisa" },
|
package/dist/commands/mcp.d.ts
CHANGED
|
@@ -1,47 +1,19 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* `aisa mcp setup` — write real, per-client MCP entries from the live manifest.
|
|
3
|
-
*
|
|
4
|
-
* Three rules, each one a lesson from the version this replaces:
|
|
5
|
-
*
|
|
6
|
-
* 1. The server list comes from the platform's discovery manifest at setup
|
|
7
|
-
* time, never from this file. Servers ship without a CLI release.
|
|
8
|
-
* 2. Nothing is written unless the manifest was actually fetched. The old
|
|
9
|
-
* command wrote first and verified never, which is how a dead hostname
|
|
10
|
-
* sat in users' configs across releases.
|
|
11
|
-
* 3. Each client gets the shape it executes: `{url}` for clients that dial
|
|
12
|
-
* HTTP themselves, an `npx mcp-remote` stdio bridge for the ones that only
|
|
13
|
-
* spawn processes. One shape for all three was the old bug.
|
|
14
|
-
*
|
|
15
|
-
* Auth is a choice the user already made: with an API key configured, entries
|
|
16
|
-
* carry it as a Bearer header (zero-interaction, but the key lands in each
|
|
17
|
-
* client's config file); without one, entries carry no credentials and the
|
|
18
|
-
* server's 401 challenge drives the client through the Clerk OAuth flow.
|
|
19
|
-
*/
|
|
1
|
+
/** Configure the unified Router MCP. Existing client entries are preserved. */
|
|
20
2
|
export interface LiveServer {
|
|
21
3
|
slug: string;
|
|
22
4
|
name: string;
|
|
23
5
|
endpoint: string;
|
|
24
|
-
toolCount
|
|
25
|
-
/**
|
|
26
|
-
* source of truth for what a server does; rendered on the connect page. */
|
|
6
|
+
toolCount?: number;
|
|
7
|
+
/** Capability description rendered on the connect page. */
|
|
27
8
|
description: string;
|
|
28
9
|
category: string;
|
|
29
10
|
}
|
|
30
11
|
export declare const stripped: (name: string) => string;
|
|
31
|
-
/**
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
* it was three servers and 72 tools behind what the host was actually serving.
|
|
37
|
-
* Anything derived from a running process cannot drift that way.
|
|
38
|
-
*
|
|
39
|
-
* The fallback is not defensive padding — the index is newer than some
|
|
40
|
-
* deployments, and a self-hosted gateway configured through `baseUrl` may
|
|
41
|
-
* never grow one. A user in either case should still get a working setup from
|
|
42
|
-
* a slightly stale list rather than an error.
|
|
43
|
-
*/
|
|
44
|
-
export declare function fetchLiveServers(): Promise<LiveServer[]>;
|
|
12
|
+
/** Router's fixed public MCP contract, independent of the legacy module catalog. */
|
|
13
|
+
export declare function unifiedMcpServer(): LiveServer;
|
|
14
|
+
export declare function isUnifiedMcpSelection(servers: LiveServer[]): boolean;
|
|
15
|
+
/** The unified entry is fixed; setup does not depend on a directory service. */
|
|
16
|
+
export declare function getMcpServers(): LiveServer[];
|
|
45
17
|
/** One config entry in the shape the client actually executes. */
|
|
46
18
|
export declare function buildEntry(shape: "url" | "stdio", endpoint: string, key: string | undefined): Record<string, unknown>;
|
|
47
19
|
export type WriteResult = {
|
|
@@ -51,12 +23,7 @@ export type WriteResult = {
|
|
|
51
23
|
ok: false;
|
|
52
24
|
reason: string;
|
|
53
25
|
};
|
|
54
|
-
/**
|
|
55
|
-
* Write the chosen servers (plus the docs server) into one client's config
|
|
56
|
-
* file. Shared by `aisa mcp setup` and `aisa connect` so the two entry points
|
|
57
|
-
* cannot drift in how they treat existing files: unparseable JSON is refused,
|
|
58
|
-
* never replaced, and only the known-dead legacy entry is cleaned up.
|
|
59
|
-
*/
|
|
26
|
+
/** Add the unified entry without deleting old AIsa, docs, or unrelated entries. */
|
|
60
27
|
export declare function writeClientConfig(agent: string, chosen: LiveServer[], key: string | undefined): WriteResult;
|
|
61
28
|
export declare function mcpSetupAction(options: {
|
|
62
29
|
agent?: string;
|