flyspace-cli 0.1.41 → 0.1.43
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/dist/cli.js +148 -70
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -19487,7 +19487,7 @@ async function runAuthCmd(args) {
|
|
|
19487
19487
|
|
|
19488
19488
|
// ../api/src/version.ts
|
|
19489
19489
|
import { readFileSync as readFileSync8 } from "fs";
|
|
19490
|
-
var CLI_VERSION = true ? "0.1.
|
|
19490
|
+
var CLI_VERSION = true ? "0.1.43" : devVersion();
|
|
19491
19491
|
function isOlderVersion(a, b) {
|
|
19492
19492
|
const parse = (v) => v.replace(/^v/, "").split("-")[0].split(".").map(Number);
|
|
19493
19493
|
const [pa, pb] = [parse(a), parse(b)];
|
|
@@ -19672,9 +19672,9 @@ import { tmpdir } from "os";
|
|
|
19672
19672
|
import { promisify } from "util";
|
|
19673
19673
|
var execAsync = promisify(execFile);
|
|
19674
19674
|
var exec = (cmd, args, opts) => {
|
|
19675
|
-
const
|
|
19676
|
-
|
|
19677
|
-
return
|
|
19675
|
+
const run5 = execAsync(cmd, args, opts);
|
|
19676
|
+
run5.child.stdin?.end();
|
|
19677
|
+
return run5;
|
|
19678
19678
|
};
|
|
19679
19679
|
var BOLD3 = "\x1B[1m";
|
|
19680
19680
|
var DIM3 = "\x1B[2m";
|
|
@@ -20079,6 +20079,10 @@ function installTarget(entry) {
|
|
|
20079
20079
|
if (at > 0) return { prefix: real.slice(0, at), nodeBin: join11(real.slice(0, at), "bin") };
|
|
20080
20080
|
} catch {
|
|
20081
20081
|
}
|
|
20082
|
+
const prefix = entry.endsWith("/bin/flyspace") ? dirname5(dirname5(entry)) : void 0;
|
|
20083
|
+
if (prefix && existsSync9(join11(prefix, "lib", "node_modules", "flyspace-cli"))) {
|
|
20084
|
+
return { prefix, nodeBin: join11(prefix, "bin") };
|
|
20085
|
+
}
|
|
20082
20086
|
return void 0;
|
|
20083
20087
|
}
|
|
20084
20088
|
function installTargets() {
|
|
@@ -20111,12 +20115,15 @@ function npmEnv(target) {
|
|
|
20111
20115
|
return nodeBin ? { ...process.env, PATH: `${nodeBin}:${process.env.PATH ?? ""}` } : process.env;
|
|
20112
20116
|
}
|
|
20113
20117
|
async function runUpgrade() {
|
|
20114
|
-
const current = "0.1.
|
|
20118
|
+
const current = "0.1.43";
|
|
20115
20119
|
console.log(`Current version: ${current}`);
|
|
20116
20120
|
console.log("Checking for updates...\n");
|
|
20117
20121
|
try {
|
|
20118
20122
|
const latest2 = execSync6(`npm view ${"flyspace-cli"} version`, { encoding: "utf-8", env: npmEnv() }).trim();
|
|
20119
|
-
const
|
|
20123
|
+
const own = installTarget(process.argv[1] ?? "")?.prefix;
|
|
20124
|
+
const stale = installTargets().filter(
|
|
20125
|
+
(t) => installedVersion(t) !== latest2 || t.prefix === own && current !== latest2
|
|
20126
|
+
);
|
|
20120
20127
|
if (stale.length === 0) {
|
|
20121
20128
|
if (current === latest2) {
|
|
20122
20129
|
console.log(`Already on the latest version (${current}).`);
|
|
@@ -25331,9 +25338,9 @@ async function synthesizeWithRetry(script, voice) {
|
|
|
25331
25338
|
}
|
|
25332
25339
|
var renderQueue = Promise.resolve();
|
|
25333
25340
|
function queued(job) {
|
|
25334
|
-
const
|
|
25335
|
-
renderQueue =
|
|
25336
|
-
return
|
|
25341
|
+
const run5 = renderQueue.then(job, job);
|
|
25342
|
+
renderQueue = run5.catch(() => void 0);
|
|
25343
|
+
return run5;
|
|
25337
25344
|
}
|
|
25338
25345
|
function renderArticleAudio(title, content, lang) {
|
|
25339
25346
|
return queued(() => renderArticleAudioNow(title, content, lang));
|
|
@@ -25407,12 +25414,12 @@ function queueShareAudio(share) {
|
|
|
25407
25414
|
}
|
|
25408
25415
|
const current = inFlight2.get(share.id);
|
|
25409
25416
|
if (current?.hash === hash) return current.done;
|
|
25410
|
-
const
|
|
25417
|
+
const run5 = () => runShareAudioJob(share, hash).catch((err) => {
|
|
25411
25418
|
console.error(`share audio job crashed (${share.id}):`, err);
|
|
25412
25419
|
}).finally(() => {
|
|
25413
25420
|
if (inFlight2.get(share.id)?.hash === hash) inFlight2.delete(share.id);
|
|
25414
25421
|
});
|
|
25415
|
-
const done = current ? current.done.then(
|
|
25422
|
+
const done = current ? current.done.then(run5) : run5();
|
|
25416
25423
|
inFlight2.set(share.id, { hash, done });
|
|
25417
25424
|
return done;
|
|
25418
25425
|
}
|
|
@@ -29973,22 +29980,13 @@ function createTranscribeRouter() {
|
|
|
29973
29980
|
import { Hono as Hono19 } from "hono";
|
|
29974
29981
|
var GROQ_API_URL8 = "https://api.groq.com/openai/v1/chat/completions";
|
|
29975
29982
|
var MODEL2 = "openai/gpt-oss-120b";
|
|
29976
|
-
var
|
|
29977
|
-
var
|
|
29983
|
+
var MAX_REPLY_CHARS = 4e3;
|
|
29984
|
+
var MAX_EARLIER_CHARS = 1500;
|
|
29978
29985
|
var THREAD_TAIL_REPLIES = 5;
|
|
29979
|
-
var
|
|
29980
|
-
|
|
29981
|
-
|
|
29982
|
-
|
|
29983
|
-
Never add greetings, thanks, pleasantries, filler, or generic chat phrases. Never repeat the draft.
|
|
29984
|
-
Output ONLY the continuation text (one sentence at most), no quotes or explanation, in the draft's language. Start with a space if the continuation needs one.
|
|
29985
|
-
If you cannot predict a specific, useful continuation, output nothing.`;
|
|
29986
|
-
function hasIntent(before) {
|
|
29987
|
-
const paragraph = before.split("\n").pop() ?? "";
|
|
29988
|
-
const cjk = paragraph.match(/[\u3400-\u9fff]/g)?.length ?? 0;
|
|
29989
|
-
const words = paragraph.match(/[A-Za-z0-9]+/g)?.length ?? 0;
|
|
29990
|
-
return cjk >= MIN_CJK_CHARS || words >= MIN_WORDS || cjk + words * 2 >= MIN_CJK_CHARS;
|
|
29991
|
-
}
|
|
29986
|
+
var RULES2 = `You predict the next message a user will send in a chat thread, right after the AI agent's last reply, like Claude Code's prompt suggestions. The composer is empty; you suggest the whole message.
|
|
29987
|
+
Base it on the agent's last reply: answer a question it asked, approve or pick an option it offered, or ask for the obvious next step (commit, deploy, run the tests, check a specific file or feature it named). Use specific nouns from the reply.
|
|
29988
|
+
Keep it short (under 15 words), in the language the user writes in. No greetings, thanks or filler.
|
|
29989
|
+
Output ONLY the message text, no quotes or explanation. If there is no clear next step, output nothing.`;
|
|
29992
29990
|
function createAutocompleteRouter() {
|
|
29993
29991
|
const app = new Hono19();
|
|
29994
29992
|
app.post("/autocomplete", async (c) => {
|
|
@@ -29997,15 +29995,14 @@ function createAutocompleteRouter() {
|
|
|
29997
29995
|
const apiKey = process.env["GROQ_API_KEY"];
|
|
29998
29996
|
if (!apiKey) return c.json({ error: "autocomplete is not configured" }, 503);
|
|
29999
29997
|
const body = await c.req.json().catch(() => null);
|
|
30000
|
-
const before = typeof body?.before === "string" ? body.before.slice(-MAX_BEFORE_CHARS) : "";
|
|
30001
|
-
if (!hasIntent(before)) return c.json({ text: "" });
|
|
30002
29998
|
const channel = typeof body?.channelId === "string" ? getChannelRegistry().find((ch) => ch.id === body.channelId) : void 0;
|
|
30003
|
-
|
|
30004
|
-
|
|
30005
|
-
const
|
|
30006
|
-
|
|
30007
|
-
${
|
|
30008
|
-
` : ""
|
|
29999
|
+
if (!channel || !canSeeChannel(channel, c.get("auth")) || typeof body?.threadId !== "string")
|
|
30000
|
+
return c.json({ text: "" });
|
|
30001
|
+
const thread = await threadContext(channel, body.threadId);
|
|
30002
|
+
if (!thread) return c.json({ text: "" });
|
|
30003
|
+
const context = `Channel: #${channel.name}${channel.prompt ? `
|
|
30004
|
+
Channel instructions: ${channel.prompt.slice(0, 500)}` : ""}
|
|
30005
|
+
${thread}`;
|
|
30009
30006
|
const res = await fetch(GROQ_API_URL8, {
|
|
30010
30007
|
method: "POST",
|
|
30011
30008
|
headers: { Authorization: `Bearer ${apiKey}`, "Content-Type": "application/json" },
|
|
@@ -30019,8 +30016,7 @@ ${thread}
|
|
|
30019
30016
|
temperature: 0.2,
|
|
30020
30017
|
messages: [
|
|
30021
30018
|
{ role: "system", content: RULES2 },
|
|
30022
|
-
{ role: "user", content:
|
|
30023
|
-
${before}` }
|
|
30019
|
+
{ role: "user", content: context }
|
|
30024
30020
|
]
|
|
30025
30021
|
})
|
|
30026
30022
|
}).catch(() => null);
|
|
@@ -30041,15 +30037,18 @@ async function threadContext(channel, threadId) {
|
|
|
30041
30037
|
]);
|
|
30042
30038
|
const channelId = thread.data?.channel_id;
|
|
30043
30039
|
if (!channelId || channelId !== channel.id && channelId !== channel.externalChannelId) return "";
|
|
30040
|
+
const [last, ...older] = tail.data ?? [];
|
|
30041
|
+
if (!last || last.author !== AGENT_AUTHOR) return "";
|
|
30044
30042
|
const rows = [...opener.data ?? []];
|
|
30045
|
-
for (const r of (
|
|
30046
|
-
|
|
30047
|
-
const text = rows.map((r) => `${r.author}: ${r.body}`).join("\n\n").slice(-MAX_THREAD_CHARS);
|
|
30043
|
+
for (const r of older.reverse()) if (!rows.some((x) => x.id === r.id)) rows.push(r);
|
|
30044
|
+
const earlier = rows.filter((r) => r.id !== last.id).map((r) => `${r.author}: ${r.body}`).join("\n\n").slice(-MAX_EARLIER_CHARS);
|
|
30048
30045
|
const title = thread.data?.title ? `Thread title: ${thread.data.title}
|
|
30049
30046
|
` : "";
|
|
30050
|
-
return
|
|
30051
|
-
${
|
|
30052
|
-
|
|
30047
|
+
return `${title}Earlier messages:
|
|
30048
|
+
${earlier}
|
|
30049
|
+
|
|
30050
|
+
Agent's last reply:
|
|
30051
|
+
${last.body.slice(-MAX_REPLY_CHARS)}`;
|
|
30053
30052
|
}
|
|
30054
30053
|
|
|
30055
30054
|
// ../api/src/dashboard/avatars-routes.ts
|
|
@@ -31782,10 +31781,10 @@ async function buildChannelUsageReport(channelId, days, labelChannel) {
|
|
|
31782
31781
|
}
|
|
31783
31782
|
}
|
|
31784
31783
|
var COMPACT_THRESHOLD_TOKENS = Number(process.env["SESSION_COMPACT_THRESHOLD_TOKENS"]) || 14e4;
|
|
31785
|
-
function contextOf(
|
|
31786
|
-
if (!
|
|
31787
|
-
const total =
|
|
31788
|
-
const turns =
|
|
31784
|
+
function contextOf(run5) {
|
|
31785
|
+
if (!run5) return void 0;
|
|
31786
|
+
const total = run5.inputTokens + run5.cacheReadTokens + run5.cacheCreationTokens;
|
|
31787
|
+
const turns = run5.numTurns ?? 1;
|
|
31789
31788
|
return Math.round(turns > 0 ? total / turns : total);
|
|
31790
31789
|
}
|
|
31791
31790
|
async function buildThreadUsage(threadTs) {
|
|
@@ -32587,6 +32586,12 @@ function registerDataRoutes(api, agent = {}) {
|
|
|
32587
32586
|
if (!res) return c.json({ error: "Host is offline" }, 503);
|
|
32588
32587
|
return c.json(res, 202);
|
|
32589
32588
|
});
|
|
32589
|
+
api.get("/mcp-servers", async (c) => {
|
|
32590
|
+
const auth = c.get("auth");
|
|
32591
|
+
if (!await isHostOwner(auth)) return c.json({ error: "only the Host owner can view MCP servers" }, 403);
|
|
32592
|
+
const res = await agent.listMcpServers?.();
|
|
32593
|
+
return c.json(res ?? { servers: null });
|
|
32594
|
+
});
|
|
32590
32595
|
api.get("/channels", async (c) => {
|
|
32591
32596
|
const auth = c.get("auth");
|
|
32592
32597
|
const channels = getProfileChannelRegistry().filter((ch) => canSeeChannel(ch, auth));
|
|
@@ -32645,17 +32650,17 @@ function registerDataRoutes(api, agent = {}) {
|
|
|
32645
32650
|
const auto = loadEffectiveAutomations();
|
|
32646
32651
|
const runs2 = /* @__PURE__ */ new Map();
|
|
32647
32652
|
try {
|
|
32648
|
-
for (const [name,
|
|
32649
|
-
runs2.set(name, { lastRun:
|
|
32653
|
+
for (const [name, run5] of await lastRunsForWorkspace(getProfile())) {
|
|
32654
|
+
runs2.set(name, { lastRun: run5.lastRunAt.toISOString(), lastStatus: run5.lastStatus });
|
|
32650
32655
|
}
|
|
32651
32656
|
} catch {
|
|
32652
32657
|
const runStore = existsSync20(paths.DB_FILE) ? getLocalCache().openAutomationRunStore(paths.DB_FILE) : null;
|
|
32653
32658
|
if (runStore) {
|
|
32654
32659
|
try {
|
|
32655
|
-
for (const
|
|
32656
|
-
runs2.set(
|
|
32657
|
-
lastRun:
|
|
32658
|
-
lastStatus:
|
|
32660
|
+
for (const run5 of runStore.listLastRuns()) {
|
|
32661
|
+
runs2.set(run5.name, {
|
|
32662
|
+
lastRun: run5.lastRunAt.toISOString(),
|
|
32663
|
+
lastStatus: run5.lastStatus
|
|
32659
32664
|
});
|
|
32660
32665
|
}
|
|
32661
32666
|
} finally {
|
|
@@ -32846,17 +32851,17 @@ function registerDataRoutes(api, agent = {}) {
|
|
|
32846
32851
|
}
|
|
32847
32852
|
const threadLinks = await resolveThreadLinks(raw);
|
|
32848
32853
|
const sessions2 = raw.map((s) => {
|
|
32849
|
-
const
|
|
32850
|
-
const turns =
|
|
32851
|
-
const total =
|
|
32854
|
+
const run5 = latest2.get(s.threadTs);
|
|
32855
|
+
const turns = run5?.numTurns ?? 1;
|
|
32856
|
+
const total = run5 ? run5.inputTokens + run5.cacheReadTokens + run5.cacheCreationTokens : void 0;
|
|
32852
32857
|
const link = s.channelId.startsWith("chat:") ? threadLinks.chat.get(s.threadTs) : threadLinks.external.get(`${s.channelId}:${s.threadTs}`);
|
|
32853
32858
|
return {
|
|
32854
32859
|
...s,
|
|
32855
32860
|
channelLabel: channelLabel(s.channelId),
|
|
32856
|
-
model:
|
|
32857
|
-
numTurns:
|
|
32861
|
+
model: run5?.model,
|
|
32862
|
+
numTurns: run5?.numTurns,
|
|
32858
32863
|
contextTokens: total !== void 0 ? Math.round(total / (turns > 0 ? turns : 1)) : void 0,
|
|
32859
|
-
rolledOver:
|
|
32864
|
+
rolledOver: run5?.label === "rollover",
|
|
32860
32865
|
threadTitle: link?.title ?? void 0,
|
|
32861
32866
|
chatChannelId: link?.chatChannelId,
|
|
32862
32867
|
chatThreadId: link?.chatThreadId,
|
|
@@ -34880,21 +34885,21 @@ var ChatAgent = class {
|
|
|
34880
34885
|
* kill.
|
|
34881
34886
|
*/
|
|
34882
34887
|
async maybeSupersede(msg) {
|
|
34883
|
-
const
|
|
34884
|
-
if (!
|
|
34888
|
+
const run5 = this.activeRuns.get(msg.threadId);
|
|
34889
|
+
if (!run5 || run5.msg.author !== msg.author || run5.msg.replyId === msg.replyId) return;
|
|
34885
34890
|
try {
|
|
34886
|
-
if (!await this.shouldInterrupt(
|
|
34891
|
+
if (!await this.shouldInterrupt(run5.msg.body, msg.body)) return;
|
|
34887
34892
|
} catch (err) {
|
|
34888
34893
|
console.error("[chat-agent] interrupt classifier failed:", err.message);
|
|
34889
34894
|
return;
|
|
34890
34895
|
}
|
|
34891
|
-
if (this.activeRuns.get(msg.threadId) !==
|
|
34896
|
+
if (this.activeRuns.get(msg.threadId) !== run5) return;
|
|
34892
34897
|
console.log(
|
|
34893
34898
|
`[chat-agent] follow-up supersedes in-flight run \u2014 aborting. thread=${msg.threadId}`
|
|
34894
34899
|
);
|
|
34895
|
-
|
|
34900
|
+
run5.superseded = true;
|
|
34896
34901
|
this.supersedingReplies.add(msg.replyId);
|
|
34897
|
-
|
|
34902
|
+
run5.abort.abort();
|
|
34898
34903
|
}
|
|
34899
34904
|
/**
|
|
34900
34905
|
* Picks up messages nobody answered. `handleMessage` is fire-and-forget and
|
|
@@ -35102,11 +35107,11 @@ var ChatAgent = class {
|
|
|
35102
35107
|
* continue with `--resume`. Returns whether a run was actually in flight —
|
|
35103
35108
|
* a queued-but-not-started message is not affected. */
|
|
35104
35109
|
cancel(threadId) {
|
|
35105
|
-
const
|
|
35106
|
-
if (!
|
|
35107
|
-
|
|
35108
|
-
this.stoppedReplies.set(threadId,
|
|
35109
|
-
|
|
35110
|
+
const run5 = this.activeRuns.get(threadId);
|
|
35111
|
+
if (!run5) return false;
|
|
35112
|
+
run5.superseded = true;
|
|
35113
|
+
this.stoppedReplies.set(threadId, run5.msg.replyId);
|
|
35114
|
+
run5.abort.abort();
|
|
35110
35115
|
return true;
|
|
35111
35116
|
}
|
|
35112
35117
|
/**
|
|
@@ -38023,6 +38028,78 @@ function startHostUpgrade() {
|
|
|
38023
38028
|
return { started: true };
|
|
38024
38029
|
}
|
|
38025
38030
|
|
|
38031
|
+
// src/dashboard/mcp-servers-host.ts
|
|
38032
|
+
import { execFile as execFile2 } from "child_process";
|
|
38033
|
+
import { homedir as homedir11 } from "os";
|
|
38034
|
+
import { promisify as promisify2 } from "util";
|
|
38035
|
+
|
|
38036
|
+
// ../api/src/dashboard/mcp-servers.ts
|
|
38037
|
+
var LINE = /^(.+?): (.+) - [✔✘!✓✗] ?(.*)$/u;
|
|
38038
|
+
function redactTarget(raw) {
|
|
38039
|
+
const typed = raw.match(/^(.*) \((HTTP|SSE)\)$/);
|
|
38040
|
+
const value = typed ? typed[1] : raw;
|
|
38041
|
+
if (/^https?:\/\//.test(value)) {
|
|
38042
|
+
try {
|
|
38043
|
+
const url = new URL(value);
|
|
38044
|
+
return {
|
|
38045
|
+
transport: typed?.[2] === "SSE" ? "sse" : "http",
|
|
38046
|
+
target: `${url.origin}${url.pathname}`
|
|
38047
|
+
};
|
|
38048
|
+
} catch {
|
|
38049
|
+
return { transport: "http", target: "" };
|
|
38050
|
+
}
|
|
38051
|
+
}
|
|
38052
|
+
const command = value.split(/\s+/)[0] ?? "";
|
|
38053
|
+
return { transport: "stdio", target: command.split("/").pop() ?? "" };
|
|
38054
|
+
}
|
|
38055
|
+
function statusOf(text) {
|
|
38056
|
+
if (/^connected/i.test(text)) return "connected";
|
|
38057
|
+
if (/auth/i.test(text)) return "needs-auth";
|
|
38058
|
+
if (/fail|error|closed/i.test(text)) return "failed";
|
|
38059
|
+
return "unknown";
|
|
38060
|
+
}
|
|
38061
|
+
function parseMcpList(output) {
|
|
38062
|
+
const servers = [];
|
|
38063
|
+
for (const line of output.split("\n")) {
|
|
38064
|
+
const m = line.trim().match(LINE);
|
|
38065
|
+
if (!m) continue;
|
|
38066
|
+
const name = m[1].trim();
|
|
38067
|
+
const detail = m[3].trim();
|
|
38068
|
+
const source = name.startsWith("claude.ai ") ? "claude.ai" : name.startsWith("plugin:") ? "plugin" : "local";
|
|
38069
|
+
servers.push({
|
|
38070
|
+
name: source === "claude.ai" ? name.slice("claude.ai ".length) : name,
|
|
38071
|
+
...redactTarget(m[2].trim()),
|
|
38072
|
+
status: statusOf(detail),
|
|
38073
|
+
detail,
|
|
38074
|
+
source
|
|
38075
|
+
});
|
|
38076
|
+
}
|
|
38077
|
+
return servers;
|
|
38078
|
+
}
|
|
38079
|
+
|
|
38080
|
+
// src/dashboard/mcp-servers-host.ts
|
|
38081
|
+
var run4 = promisify2(execFile2);
|
|
38082
|
+
async function listMcpServers() {
|
|
38083
|
+
const env = { ...process.env };
|
|
38084
|
+
const pinned = pinnedClaudeConfigDir(profileClaudeConfigDir());
|
|
38085
|
+
if (pinned) env["CLAUDE_CONFIG_DIR"] = pinned;
|
|
38086
|
+
else delete env["CLAUDE_CONFIG_DIR"];
|
|
38087
|
+
const token = profileOauthToken();
|
|
38088
|
+
if (token) env["CLAUDE_CODE_OAUTH_TOKEN"] = token;
|
|
38089
|
+
else delete env["CLAUDE_CODE_OAUTH_TOKEN"];
|
|
38090
|
+
try {
|
|
38091
|
+
const { stdout } = await run4("claude", ["mcp", "list"], {
|
|
38092
|
+
cwd: homedir11(),
|
|
38093
|
+
env,
|
|
38094
|
+
timeout: 45e3
|
|
38095
|
+
});
|
|
38096
|
+
return { servers: parseMcpList(stdout) };
|
|
38097
|
+
} catch (err) {
|
|
38098
|
+
console.error(`[mcp-servers] claude mcp list failed: ${err.message}`);
|
|
38099
|
+
return { servers: [], error: "Could not run `claude mcp list` on the Host." };
|
|
38100
|
+
}
|
|
38101
|
+
}
|
|
38102
|
+
|
|
38026
38103
|
// src/dashboard/agent-bridge-host.ts
|
|
38027
38104
|
var HOSTED_DATA_SOCKET_ORIGIN = "wss://flyspace-api.fly.dev";
|
|
38028
38105
|
function dataSocketUrl() {
|
|
@@ -38067,6 +38144,7 @@ function localAgentCallbacks(chatAgent) {
|
|
|
38067
38144
|
docsRequest: (req) => handleDocsRequest(req),
|
|
38068
38145
|
hostRequest: (req) => handleHostRequest(req),
|
|
38069
38146
|
listSessions: () => listLocalSessions(),
|
|
38147
|
+
listMcpServers: () => listMcpServers(),
|
|
38070
38148
|
upgradeHost: () => startHostUpgrade(),
|
|
38071
38149
|
scanOnboarding: (slug) => scanOnboarding(slug),
|
|
38072
38150
|
linkProjectFolders: (slug, items) => linkProjectFolders(slug, items),
|
|
@@ -38961,7 +39039,7 @@ async function main() {
|
|
|
38961
39039
|
break;
|
|
38962
39040
|
case "-v":
|
|
38963
39041
|
case "--version":
|
|
38964
|
-
printRaw("0.1.
|
|
39042
|
+
printRaw("0.1.43");
|
|
38965
39043
|
break;
|
|
38966
39044
|
case "-h":
|
|
38967
39045
|
case "--help":
|