opencode-tbot 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/dist/plugin.js +174 -105
- package/dist/plugin.js.map +1 -1
- package/package.json +1 -1
package/dist/plugin.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { i as preparePluginConfiguration, s as loadAppConfig } from "./assets/plugin-config-BYsYAzvx.js";
|
|
2
|
-
import { mkdir, readFile, rename, writeFile } from "node:fs/promises";
|
|
3
|
-
import { basename, dirname, extname } from "node:path";
|
|
2
|
+
import { mkdir, readFile, rename, stat, writeFile } from "node:fs/promises";
|
|
3
|
+
import { basename, dirname, extname, join } from "node:path";
|
|
4
4
|
import { parse, printParseErrorCode } from "jsonc-parser";
|
|
5
5
|
import { z } from "zod";
|
|
6
6
|
import { OpenRouter } from "@openrouter/sdk";
|
|
@@ -8,6 +8,8 @@ import { createOpencodeClient } from "@opencode-ai/sdk/v2/client";
|
|
|
8
8
|
import { randomUUID } from "node:crypto";
|
|
9
9
|
import { run } from "@grammyjs/runner";
|
|
10
10
|
import { Bot, InlineKeyboard } from "grammy";
|
|
11
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
12
|
+
import { fileURLToPath } from "node:url";
|
|
11
13
|
//#region src/infra/utils/redact.ts
|
|
12
14
|
var REDACTED = "[REDACTED]";
|
|
13
15
|
var DEFAULT_PREVIEW_LENGTH = 160;
|
|
@@ -960,11 +962,14 @@ var GetPathUseCase = class {
|
|
|
960
962
|
//#endregion
|
|
961
963
|
//#region src/use-cases/get-status.usecase.ts
|
|
962
964
|
var GetStatusUseCase = class {
|
|
963
|
-
constructor(getHealthUseCase, getPathUseCase, listLspUseCase, listMcpUseCase) {
|
|
965
|
+
constructor(getHealthUseCase, getPathUseCase, listLspUseCase, listMcpUseCase, listSessionsUseCase, sessionRepo, voiceTranscriptionEnabled) {
|
|
964
966
|
this.getHealthUseCase = getHealthUseCase;
|
|
965
967
|
this.getPathUseCase = getPathUseCase;
|
|
966
968
|
this.listLspUseCase = listLspUseCase;
|
|
967
969
|
this.listMcpUseCase = listMcpUseCase;
|
|
970
|
+
this.listSessionsUseCase = listSessionsUseCase;
|
|
971
|
+
this.sessionRepo = sessionRepo;
|
|
972
|
+
this.voiceTranscriptionEnabled = voiceTranscriptionEnabled;
|
|
968
973
|
}
|
|
969
974
|
async execute(input) {
|
|
970
975
|
const [health, path, lsp, mcp] = await Promise.allSettled([
|
|
@@ -974,10 +979,13 @@ var GetStatusUseCase = class {
|
|
|
974
979
|
this.listMcpUseCase.execute({ chatId: input.chatId })
|
|
975
980
|
]);
|
|
976
981
|
const pathResult = mapSettledResult(path);
|
|
982
|
+
const [plugins, workspace] = await Promise.all([loadConfiguredPluginsResult(pathResult), loadWorkspaceStatusResult(input.chatId, pathResult, this.listSessionsUseCase, this.sessionRepo)]);
|
|
977
983
|
return {
|
|
978
984
|
health: mapSettledResult(health),
|
|
979
985
|
path: pathResult,
|
|
980
|
-
plugins
|
|
986
|
+
plugins,
|
|
987
|
+
voiceRecognition: { enabled: this.voiceTranscriptionEnabled },
|
|
988
|
+
workspace,
|
|
981
989
|
lsp: mapSettledResult(lsp),
|
|
982
990
|
mcp: mapSettledResult(mcp)
|
|
983
991
|
};
|
|
@@ -1011,12 +1019,13 @@ async function loadConfiguredPluginsResult(path) {
|
|
|
1011
1019
|
}
|
|
1012
1020
|
}
|
|
1013
1021
|
async function loadConfiguredPlugins(configFilePath) {
|
|
1022
|
+
const resolvedConfigFilePath = await resolveOpenCodeConfigFilePath(configFilePath);
|
|
1014
1023
|
let content;
|
|
1015
1024
|
try {
|
|
1016
|
-
content = await readFile(
|
|
1025
|
+
content = await readFile(resolvedConfigFilePath, "utf8");
|
|
1017
1026
|
} catch (error) {
|
|
1018
1027
|
if (isMissingFileError(error)) return {
|
|
1019
|
-
configFilePath,
|
|
1028
|
+
configFilePath: resolvedConfigFilePath,
|
|
1020
1029
|
plugins: []
|
|
1021
1030
|
};
|
|
1022
1031
|
throw error;
|
|
@@ -1025,18 +1034,52 @@ async function loadConfiguredPlugins(configFilePath) {
|
|
|
1025
1034
|
const parsed = parse(content, parseErrors, { allowTrailingComma: true });
|
|
1026
1035
|
if (parseErrors.length > 0) {
|
|
1027
1036
|
const errorSummary = parseErrors.map((error) => printParseErrorCode(error.error)).join(", ");
|
|
1028
|
-
throw new Error(`Failed to parse ${
|
|
1037
|
+
throw new Error(`Failed to parse ${resolvedConfigFilePath}: ${errorSummary}`);
|
|
1029
1038
|
}
|
|
1030
1039
|
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return {
|
|
1031
|
-
configFilePath,
|
|
1040
|
+
configFilePath: resolvedConfigFilePath,
|
|
1032
1041
|
plugins: []
|
|
1033
1042
|
};
|
|
1034
1043
|
const pluginSpecs = Array.isArray(parsed.plugin) ? parsed.plugin : [];
|
|
1035
1044
|
return {
|
|
1036
|
-
configFilePath,
|
|
1045
|
+
configFilePath: resolvedConfigFilePath,
|
|
1037
1046
|
plugins: [...new Set(pluginSpecs.filter((value) => typeof value === "string").map((value) => value.trim()).filter((value) => value.length > 0))]
|
|
1038
1047
|
};
|
|
1039
1048
|
}
|
|
1049
|
+
async function loadWorkspaceStatusResult(chatId, path, listSessionsUseCase, sessionRepo) {
|
|
1050
|
+
if (path.status === "error") return {
|
|
1051
|
+
error: path.error,
|
|
1052
|
+
status: "error"
|
|
1053
|
+
};
|
|
1054
|
+
const binding = await sessionRepo.getByChatId(chatId);
|
|
1055
|
+
let currentProject = path.data.directory;
|
|
1056
|
+
let currentSession = binding?.sessionId ?? null;
|
|
1057
|
+
try {
|
|
1058
|
+
const sessions = await listSessionsUseCase.execute({ chatId });
|
|
1059
|
+
currentProject = sessions.currentDirectory;
|
|
1060
|
+
currentSession = sessions.currentSessionId ? formatSessionStatusLabel(sessions.sessions.find((session) => session.id === sessions.currentSessionId) ?? null, sessions.currentSessionId) : null;
|
|
1061
|
+
} catch {}
|
|
1062
|
+
return {
|
|
1063
|
+
data: {
|
|
1064
|
+
currentProject,
|
|
1065
|
+
currentSession
|
|
1066
|
+
},
|
|
1067
|
+
status: "ok"
|
|
1068
|
+
};
|
|
1069
|
+
}
|
|
1070
|
+
function formatSessionStatusLabel(session, fallbackId) {
|
|
1071
|
+
if (!session) return fallbackId;
|
|
1072
|
+
const title = session.title.trim() || session.slug || session.id;
|
|
1073
|
+
return title === session.slug ? title : `${title} (${session.slug})`;
|
|
1074
|
+
}
|
|
1075
|
+
async function resolveOpenCodeConfigFilePath(configPath) {
|
|
1076
|
+
try {
|
|
1077
|
+
return (await stat(configPath)).isDirectory() ? join(configPath, "opencode.json") : configPath;
|
|
1078
|
+
} catch (error) {
|
|
1079
|
+
if (isMissingFileError(error)) return configPath;
|
|
1080
|
+
throw error;
|
|
1081
|
+
}
|
|
1082
|
+
}
|
|
1040
1083
|
function isMissingFileError(error) {
|
|
1041
1084
|
return error instanceof Error && "code" in error && error.code === "ENOENT";
|
|
1042
1085
|
}
|
|
@@ -1559,9 +1602,9 @@ function createContainer(config, opencodeClient, logger) {
|
|
|
1559
1602
|
const listAgentsUseCase = new ListAgentsUseCase(sessionRepo, opencodeClient);
|
|
1560
1603
|
const listLspUseCase = new ListLspUseCase(sessionRepo, opencodeClient);
|
|
1561
1604
|
const listMcpUseCase = new ListMcpUseCase(sessionRepo, opencodeClient);
|
|
1562
|
-
const getStatusUseCase = new GetStatusUseCase(getHealthUseCase, getPathUseCase, listLspUseCase, listMcpUseCase);
|
|
1563
|
-
const listModelsUseCase = new ListModelsUseCase(sessionRepo, opencodeClient);
|
|
1564
1605
|
const listSessionsUseCase = new ListSessionsUseCase(sessionRepo, opencodeClient);
|
|
1606
|
+
const getStatusUseCase = new GetStatusUseCase(getHealthUseCase, getPathUseCase, listLspUseCase, listMcpUseCase, listSessionsUseCase, sessionRepo, config.openrouter.configured);
|
|
1607
|
+
const listModelsUseCase = new ListModelsUseCase(sessionRepo, opencodeClient);
|
|
1565
1608
|
const renameSessionUseCase = new RenameSessionUseCase(sessionRepo, opencodeClient, logger);
|
|
1566
1609
|
const sendPromptUseCase = new SendPromptUseCase(sessionRepo, opencodeClient, logger, foregroundSessionTracker);
|
|
1567
1610
|
const switchAgentUseCase = new SwitchAgentUseCase(sessionRepo, opencodeClient, logger);
|
|
@@ -2564,6 +2607,23 @@ function stringifyUnknown(value) {
|
|
|
2564
2607
|
}
|
|
2565
2608
|
}
|
|
2566
2609
|
//#endregion
|
|
2610
|
+
//#region src/app/package-info.ts
|
|
2611
|
+
var OPENCODE_TBOT_VERSION = resolvePackageVersion();
|
|
2612
|
+
function resolvePackageVersion() {
|
|
2613
|
+
let directory = dirname(fileURLToPath(import.meta.url));
|
|
2614
|
+
while (true) {
|
|
2615
|
+
const packageFilePath = join(directory, "package.json");
|
|
2616
|
+
if (existsSync(packageFilePath)) try {
|
|
2617
|
+
const parsed = JSON.parse(readFileSync(packageFilePath, "utf8"));
|
|
2618
|
+
if (typeof parsed.version === "string" && parsed.version.trim().length > 0) return parsed.version;
|
|
2619
|
+
} catch {}
|
|
2620
|
+
const parentDirectory = dirname(directory);
|
|
2621
|
+
if (parentDirectory === directory) break;
|
|
2622
|
+
directory = parentDirectory;
|
|
2623
|
+
}
|
|
2624
|
+
return "unknown";
|
|
2625
|
+
}
|
|
2626
|
+
//#endregion
|
|
2567
2627
|
//#region src/bot/presenters/message.presenter.ts
|
|
2568
2628
|
var VARIANT_ORDER = [
|
|
2569
2629
|
"minimal",
|
|
@@ -2577,26 +2637,22 @@ var VARIANT_ORDER = [
|
|
|
2577
2637
|
function presentStatusMessage(input, copy = BOT_COPY) {
|
|
2578
2638
|
const layout = getStatusLayoutCopy(copy);
|
|
2579
2639
|
const sections = [
|
|
2580
|
-
presentStatusPlainSection(layout.
|
|
2640
|
+
presentStatusPlainSection(layout.overviewTitle, presentStatusPlainOverviewLines(input, copy, layout)),
|
|
2581
2641
|
presentStatusPlainSection(layout.workspaceTitle, presentStatusPlainWorkspaceLines(input, copy, layout)),
|
|
2582
2642
|
presentStatusPlainSection(layout.pluginsTitle, presentStatusPlainPluginLines(input, copy, layout)),
|
|
2583
2643
|
presentStatusPlainSection(layout.mcpTitle, presentStatusPlainMcpLines(input, copy, layout)),
|
|
2584
|
-
presentStatusPlainSection(layout.lspTitle, presentStatusPlainLspLines(input, copy, layout))
|
|
2585
|
-
layout.divider,
|
|
2586
|
-
`${layout.lastUpdatedLabel}: ${formatStatusDate(/* @__PURE__ */ new Date())}`
|
|
2644
|
+
presentStatusPlainSection(layout.lspTitle, presentStatusPlainLspLines(input, copy, layout))
|
|
2587
2645
|
];
|
|
2588
2646
|
return presentStatusSections(layout.pageTitle, sections);
|
|
2589
2647
|
}
|
|
2590
2648
|
function presentStatusMarkdownMessage(input, copy = BOT_COPY) {
|
|
2591
2649
|
const layout = getStatusLayoutCopy(copy);
|
|
2592
2650
|
const sections = [
|
|
2593
|
-
presentStatusMarkdownSection(layout.
|
|
2651
|
+
presentStatusMarkdownSection(layout.overviewTitle, presentStatusMarkdownOverviewLines(input, copy, layout)),
|
|
2594
2652
|
presentStatusMarkdownSection(layout.workspaceTitle, presentStatusMarkdownWorkspaceLines(input, copy, layout)),
|
|
2595
2653
|
presentStatusMarkdownSection(layout.pluginsTitle, presentStatusMarkdownPluginLines(input, copy, layout)),
|
|
2596
2654
|
presentStatusMarkdownSection(layout.mcpTitle, presentStatusMarkdownMcpLines(input, copy, layout)),
|
|
2597
|
-
presentStatusMarkdownSection(layout.lspTitle, presentStatusMarkdownLspLines(input, copy, layout))
|
|
2598
|
-
layout.divider,
|
|
2599
|
-
`_${layout.lastUpdatedLabel}: ${formatStatusDate(/* @__PURE__ */ new Date())}_`
|
|
2655
|
+
presentStatusMarkdownSection(layout.lspTitle, presentStatusMarkdownLspLines(input, copy, layout))
|
|
2600
2656
|
];
|
|
2601
2657
|
return presentStatusSections(`# ${layout.pageTitle}`, sections);
|
|
2602
2658
|
}
|
|
@@ -2613,48 +2669,56 @@ function presentStatusPlainSection(title, lines) {
|
|
|
2613
2669
|
function presentStatusMarkdownSection(title, lines) {
|
|
2614
2670
|
return [`## ${title}`, ...lines].join("\n");
|
|
2615
2671
|
}
|
|
2616
|
-
function
|
|
2617
|
-
|
|
2618
|
-
|
|
2672
|
+
function presentStatusPlainOverviewLines(input, copy, layout) {
|
|
2673
|
+
const lines = [presentPlainStatusBullet(layout.connectivityLabel, input.health.status === "error" ? layout.errorStatus : formatHealthBadge(input.health.data.healthy, layout)), presentPlainStatusBullet(layout.voiceRecognitionLabel, formatVoiceRecognitionBadge(input.voiceRecognition.enabled))];
|
|
2674
|
+
if (input.health.status === "error") return [
|
|
2675
|
+
...lines,
|
|
2676
|
+
...presentStatusPlainErrorDetailLines(input.health.error, copy, layout),
|
|
2677
|
+
presentPlainStatusBullet(layout.tbotVersionLabel, OPENCODE_TBOT_VERSION)
|
|
2678
|
+
];
|
|
2679
|
+
return [
|
|
2680
|
+
...lines,
|
|
2681
|
+
presentPlainStatusBullet(layout.openCodeVersionLabel, input.health.data.version),
|
|
2682
|
+
presentPlainStatusBullet(layout.tbotVersionLabel, OPENCODE_TBOT_VERSION)
|
|
2683
|
+
];
|
|
2619
2684
|
}
|
|
2620
|
-
function
|
|
2621
|
-
|
|
2622
|
-
|
|
2685
|
+
function presentStatusMarkdownOverviewLines(input, copy, layout) {
|
|
2686
|
+
const lines = [presentMarkdownStatusBullet(layout.connectivityLabel, input.health.status === "error" ? layout.errorStatus : formatHealthBadge(input.health.data.healthy, layout)), presentMarkdownStatusBullet(layout.voiceRecognitionLabel, formatVoiceRecognitionBadge(input.voiceRecognition.enabled))];
|
|
2687
|
+
if (input.health.status === "error") return [
|
|
2688
|
+
...lines,
|
|
2689
|
+
...presentStatusMarkdownErrorDetailLines(input.health.error, copy, layout),
|
|
2690
|
+
presentMarkdownStatusBullet(layout.tbotVersionLabel, OPENCODE_TBOT_VERSION)
|
|
2691
|
+
];
|
|
2692
|
+
return [
|
|
2693
|
+
...lines,
|
|
2694
|
+
presentMarkdownStatusBullet(layout.openCodeVersionLabel, input.health.data.version),
|
|
2695
|
+
presentMarkdownStatusBullet(layout.tbotVersionLabel, OPENCODE_TBOT_VERSION)
|
|
2696
|
+
];
|
|
2623
2697
|
}
|
|
2624
2698
|
function presentStatusPlainWorkspaceLines(input, copy, layout) {
|
|
2625
|
-
if (input.
|
|
2626
|
-
return [presentPlainStatusBullet(layout.
|
|
2699
|
+
if (input.workspace.status === "error") return presentStatusPlainErrorLines(input.workspace.error, copy, layout);
|
|
2700
|
+
return [presentPlainStatusBullet(layout.currentProjectLabel, input.workspace.data.currentProject), presentPlainStatusBullet(layout.currentSessionLabel, input.workspace.data.currentSession ?? layout.defaultSessionValue)];
|
|
2627
2701
|
}
|
|
2628
2702
|
function presentStatusMarkdownWorkspaceLines(input, copy, layout) {
|
|
2629
|
-
if (input.
|
|
2630
|
-
return [presentMarkdownStatusBullet(layout.
|
|
2703
|
+
if (input.workspace.status === "error") return presentStatusMarkdownErrorLines(input.workspace.error, copy, layout);
|
|
2704
|
+
return [presentMarkdownStatusBullet(layout.currentProjectLabel, input.workspace.data.currentProject, { codeValue: true }), presentMarkdownStatusBullet(layout.currentSessionLabel, input.workspace.data.currentSession ?? layout.defaultSessionValue)];
|
|
2631
2705
|
}
|
|
2632
2706
|
function presentStatusPlainPluginLines(input, copy, layout) {
|
|
2633
2707
|
if (input.plugins.status === "error") return presentStatusPlainErrorLines(input.plugins.error, copy, layout);
|
|
2634
|
-
|
|
2635
|
-
|
|
2636
|
-
return [
|
|
2637
|
-
...lines,
|
|
2638
|
-
`- ${layout.configuredPluginsLabel}:`,
|
|
2639
|
-
...input.plugins.data.plugins.map((plugin) => ` - ${plugin}`)
|
|
2640
|
-
];
|
|
2708
|
+
if (input.plugins.data.plugins.length === 0) return [...presentPlainEmptyStatusLines(layout.noPluginsMessage, layout)];
|
|
2709
|
+
return input.plugins.data.plugins.map((plugin) => `- ${plugin}`);
|
|
2641
2710
|
}
|
|
2642
2711
|
function presentStatusMarkdownPluginLines(input, copy, layout) {
|
|
2643
2712
|
if (input.plugins.status === "error") return presentStatusMarkdownErrorLines(input.plugins.error, copy, layout);
|
|
2644
|
-
|
|
2645
|
-
|
|
2646
|
-
return [
|
|
2647
|
-
...lines,
|
|
2648
|
-
`- **${layout.configuredPluginsLabel}:**`,
|
|
2649
|
-
...input.plugins.data.plugins.map((plugin) => ` - \`${plugin}\``)
|
|
2650
|
-
];
|
|
2713
|
+
if (input.plugins.data.plugins.length === 0) return [...presentMarkdownEmptyStatusLines(layout.noPluginsMessage, layout)];
|
|
2714
|
+
return input.plugins.data.plugins.map((plugin) => `- \`${plugin}\``);
|
|
2651
2715
|
}
|
|
2652
2716
|
function presentStatusPlainLspLines(input, copy, layout) {
|
|
2653
2717
|
if (input.lsp.status === "error") return presentStatusPlainErrorLines(input.lsp.error, copy, layout);
|
|
2654
2718
|
if (input.lsp.data.statuses.length === 0) return presentPlainEmptyStatusLines(copy.lsp.none, layout);
|
|
2655
2719
|
return input.lsp.data.statuses.flatMap((status) => presentPlainStatusGroup(status.name, [{
|
|
2656
2720
|
label: layout.statusLabel,
|
|
2657
|
-
value: formatLspStatusBadge(status
|
|
2721
|
+
value: formatLspStatusBadge(status)
|
|
2658
2722
|
}, {
|
|
2659
2723
|
codeValue: !!status.root,
|
|
2660
2724
|
label: layout.rootLabel,
|
|
@@ -2666,7 +2730,7 @@ function presentStatusMarkdownLspLines(input, copy, layout) {
|
|
|
2666
2730
|
if (input.lsp.data.statuses.length === 0) return presentMarkdownEmptyStatusLines(copy.lsp.none, layout);
|
|
2667
2731
|
return input.lsp.data.statuses.flatMap((status) => presentMarkdownStatusGroup(status.name, [{
|
|
2668
2732
|
label: layout.statusLabel,
|
|
2669
|
-
value: formatLspStatusBadge(status
|
|
2733
|
+
value: formatLspStatusBadge(status)
|
|
2670
2734
|
}, {
|
|
2671
2735
|
codeValue: !!status.root,
|
|
2672
2736
|
label: layout.rootLabel,
|
|
@@ -2676,32 +2740,24 @@ function presentStatusMarkdownLspLines(input, copy, layout) {
|
|
|
2676
2740
|
function presentStatusPlainMcpLines(input, copy, layout) {
|
|
2677
2741
|
if (input.mcp.status === "error") return presentStatusPlainErrorLines(input.mcp.error, copy, layout);
|
|
2678
2742
|
if (input.mcp.data.statuses.length === 0) return presentPlainEmptyStatusLines(copy.mcp.none, layout);
|
|
2679
|
-
return input.mcp.data.statuses.flatMap(({ name, status }) => presentPlainStatusGroup(name,
|
|
2680
|
-
label: layout.statusLabel,
|
|
2681
|
-
value: formatMcpStatusBadge(status, copy, layout)
|
|
2682
|
-
}, {
|
|
2683
|
-
label: layout.mcpNotesLabel,
|
|
2684
|
-
value: formatMcpStatusNotes(status, layout)
|
|
2685
|
-
}]));
|
|
2743
|
+
return input.mcp.data.statuses.flatMap(({ name, status }) => presentPlainStatusGroup(name, getMcpStatusDetailLines(status, copy, layout)));
|
|
2686
2744
|
}
|
|
2687
2745
|
function presentStatusMarkdownMcpLines(input, copy, layout) {
|
|
2688
2746
|
if (input.mcp.status === "error") return presentStatusMarkdownErrorLines(input.mcp.error, copy, layout);
|
|
2689
2747
|
if (input.mcp.data.statuses.length === 0) return presentMarkdownEmptyStatusLines(copy.mcp.none, layout);
|
|
2690
|
-
return input.mcp.data.statuses.flatMap(({ name, status }) => presentMarkdownStatusGroup(name,
|
|
2691
|
-
label: layout.statusLabel,
|
|
2692
|
-
value: formatMcpStatusBadge(status, copy, layout)
|
|
2693
|
-
}, {
|
|
2694
|
-
label: layout.mcpNotesLabel,
|
|
2695
|
-
value: formatMcpStatusNotes(status, layout)
|
|
2696
|
-
}], { codeName: true }));
|
|
2748
|
+
return input.mcp.data.statuses.flatMap(({ name, status }) => presentMarkdownStatusGroup(name, getMcpStatusDetailLines(status, copy, layout), { codeName: true }));
|
|
2697
2749
|
}
|
|
2698
2750
|
function presentStatusPlainErrorLines(error, copy, layout) {
|
|
2699
|
-
|
|
2700
|
-
|
|
2751
|
+
return [presentPlainStatusBullet(layout.statusLabel, layout.errorStatus), ...presentStatusPlainErrorDetailLines(error, copy, layout)];
|
|
2752
|
+
}
|
|
2753
|
+
function presentStatusPlainErrorDetailLines(error, copy, layout) {
|
|
2754
|
+
return splitStatusLines(presentError(error, copy)).map((line) => presentPlainStatusBullet(layout.detailsLabel, line));
|
|
2701
2755
|
}
|
|
2702
2756
|
function presentStatusMarkdownErrorLines(error, copy, layout) {
|
|
2703
|
-
|
|
2704
|
-
|
|
2757
|
+
return [presentMarkdownStatusBullet(layout.statusLabel, layout.errorStatus), ...presentStatusMarkdownErrorDetailLines(error, copy, layout)];
|
|
2758
|
+
}
|
|
2759
|
+
function presentStatusMarkdownErrorDetailLines(error, copy, layout) {
|
|
2760
|
+
return splitStatusLines(presentError(error, copy)).map((line) => presentMarkdownStatusBullet(layout.detailsLabel, line));
|
|
2705
2761
|
}
|
|
2706
2762
|
function presentPlainEmptyStatusLines(message, layout) {
|
|
2707
2763
|
return [presentPlainStatusBullet(layout.statusLabel, layout.noneStatus), presentPlainStatusBullet(layout.detailsLabel, message)];
|
|
@@ -2725,38 +2781,51 @@ function splitStatusLines(text) {
|
|
|
2725
2781
|
return text.split("\n").map((line) => line.trim()).filter((line) => line.length > 0);
|
|
2726
2782
|
}
|
|
2727
2783
|
function formatHealthBadge(healthy, layout) {
|
|
2728
|
-
return healthy ?
|
|
2784
|
+
return healthy ? "🟢" : layout.errorStatus;
|
|
2785
|
+
}
|
|
2786
|
+
function formatVoiceRecognitionBadge(enabled) {
|
|
2787
|
+
return enabled ? "🟢" : "⚪";
|
|
2729
2788
|
}
|
|
2730
|
-
function formatLspStatusBadge(status
|
|
2789
|
+
function formatLspStatusBadge(status) {
|
|
2731
2790
|
switch (status.status) {
|
|
2732
|
-
case "connected": return
|
|
2733
|
-
case "error": return
|
|
2791
|
+
case "connected": return "🟢";
|
|
2792
|
+
case "error": return "🔴";
|
|
2734
2793
|
}
|
|
2735
2794
|
return status.status;
|
|
2736
2795
|
}
|
|
2737
|
-
function formatMcpStatusBadge(status,
|
|
2796
|
+
function formatMcpStatusBadge(status, layout) {
|
|
2738
2797
|
switch (status.status) {
|
|
2739
|
-
case "connected": return
|
|
2740
|
-
case "disabled": return
|
|
2741
|
-
case "needs_auth": return
|
|
2798
|
+
case "connected": return "🟢";
|
|
2799
|
+
case "disabled": return "⚪";
|
|
2800
|
+
case "needs_auth": return "🟡";
|
|
2742
2801
|
case "failed": return layout.mcpFailedStatus;
|
|
2743
2802
|
case "needs_client_registration": return layout.mcpRegistrationRequiredStatus;
|
|
2744
2803
|
}
|
|
2745
2804
|
return status;
|
|
2746
2805
|
}
|
|
2747
|
-
function
|
|
2806
|
+
function getMcpStatusDetailLines(status, copy, layout) {
|
|
2807
|
+
const notes = formatMcpStatusNotes(status, copy, layout);
|
|
2808
|
+
return notes ? [{
|
|
2809
|
+
label: layout.statusLabel,
|
|
2810
|
+
value: formatMcpStatusBadge(status, layout)
|
|
2811
|
+
}, {
|
|
2812
|
+
label: layout.mcpNotesLabel,
|
|
2813
|
+
value: notes
|
|
2814
|
+
}] : [{
|
|
2815
|
+
label: layout.statusLabel,
|
|
2816
|
+
value: formatMcpStatusBadge(status, layout)
|
|
2817
|
+
}];
|
|
2818
|
+
}
|
|
2819
|
+
function formatMcpStatusNotes(status, copy, layout) {
|
|
2748
2820
|
switch (status.status) {
|
|
2749
2821
|
case "connected": return layout.okLabel;
|
|
2750
|
-
case "disabled": return
|
|
2751
|
-
case "needs_auth": return
|
|
2822
|
+
case "disabled": return null;
|
|
2823
|
+
case "needs_auth": return copy.mcp.needsAuth;
|
|
2752
2824
|
case "failed": return status.error;
|
|
2753
2825
|
case "needs_client_registration": return status.error;
|
|
2754
2826
|
}
|
|
2755
2827
|
return status;
|
|
2756
2828
|
}
|
|
2757
|
-
function formatStatusDate(value) {
|
|
2758
|
-
return value.toISOString().slice(0, 10);
|
|
2759
|
-
}
|
|
2760
2829
|
function formatStatusValue(value) {
|
|
2761
2830
|
const normalized = value.replace(/\r\n?/g, "\n").split("\n").map((line) => line.trim()).filter((line) => line.length > 0).join(" / ");
|
|
2762
2831
|
return normalized.length > 0 ? normalized : "-";
|
|
@@ -2766,53 +2835,53 @@ function normalizeStatusInlineValue(value) {
|
|
|
2766
2835
|
}
|
|
2767
2836
|
function getStatusLayoutCopy(copy) {
|
|
2768
2837
|
if (copy.systemStatus.title === BOT_COPY.systemStatus.title) return {
|
|
2769
|
-
|
|
2770
|
-
|
|
2771
|
-
|
|
2838
|
+
connectivityLabel: "Connectivity",
|
|
2839
|
+
currentProjectLabel: "Current Project",
|
|
2840
|
+
currentSessionLabel: "Current Session",
|
|
2841
|
+
defaultSessionValue: "OpenCode Default",
|
|
2772
2842
|
detailsLabel: "Details",
|
|
2773
|
-
|
|
2774
|
-
|
|
2775
|
-
|
|
2776
|
-
lastUpdatedLabel: "Last updated",
|
|
2777
|
-
lspTitle: "🧠 LSP (Language Server)",
|
|
2778
|
-
mcpFailedStatus: "🔴 Failed",
|
|
2843
|
+
errorStatus: "🔴",
|
|
2844
|
+
lspTitle: "🧠 LSP",
|
|
2845
|
+
mcpFailedStatus: "🔴",
|
|
2779
2846
|
mcpNotesLabel: "Notes",
|
|
2780
|
-
mcpRegistrationRequiredStatus: "🟡
|
|
2781
|
-
mcpTitle: "🔌 MCP
|
|
2847
|
+
mcpRegistrationRequiredStatus: "🟡",
|
|
2848
|
+
mcpTitle: "🔌 MCP",
|
|
2782
2849
|
noPluginsMessage: "No plugins configured in the OpenCode config.",
|
|
2783
|
-
noneStatus: "⚪
|
|
2850
|
+
noneStatus: "⚪",
|
|
2851
|
+
openCodeVersionLabel: "OpenCode Version",
|
|
2784
2852
|
okLabel: "OK",
|
|
2853
|
+
overviewTitle: "🖥️ Overview",
|
|
2785
2854
|
pageTitle: "📊 Service Status",
|
|
2786
2855
|
pluginsTitle: "🧩 Plugins",
|
|
2787
2856
|
rootLabel: "Root",
|
|
2788
|
-
serverTitle: "🖥️ Server",
|
|
2789
2857
|
statusLabel: "Status",
|
|
2790
|
-
|
|
2858
|
+
tbotVersionLabel: "opencode-tbot Version",
|
|
2859
|
+
voiceRecognitionLabel: "Voice Recognition",
|
|
2791
2860
|
workspaceTitle: "📁 Workspace"
|
|
2792
2861
|
};
|
|
2793
2862
|
return {
|
|
2794
|
-
|
|
2795
|
-
|
|
2796
|
-
|
|
2863
|
+
connectivityLabel: "连通性",
|
|
2864
|
+
currentProjectLabel: "当前项目",
|
|
2865
|
+
currentSessionLabel: "当前会话",
|
|
2866
|
+
defaultSessionValue: "OpenCode 默认",
|
|
2797
2867
|
detailsLabel: "详情",
|
|
2798
|
-
|
|
2799
|
-
|
|
2800
|
-
|
|
2801
|
-
lastUpdatedLabel: "最后更新",
|
|
2802
|
-
lspTitle: "🧠 LSP (Language Server)",
|
|
2803
|
-
mcpFailedStatus: "🔴 失败",
|
|
2868
|
+
errorStatus: "🔴",
|
|
2869
|
+
lspTitle: "🧠 LSP",
|
|
2870
|
+
mcpFailedStatus: "🔴",
|
|
2804
2871
|
mcpNotesLabel: "说明",
|
|
2805
|
-
mcpRegistrationRequiredStatus: "🟡
|
|
2806
|
-
mcpTitle: "🔌 MCP
|
|
2872
|
+
mcpRegistrationRequiredStatus: "🟡",
|
|
2873
|
+
mcpTitle: "🔌 MCP",
|
|
2807
2874
|
noPluginsMessage: "当前 OpenCode 配置中未配置插件。",
|
|
2808
|
-
noneStatus: "⚪
|
|
2875
|
+
noneStatus: "⚪",
|
|
2876
|
+
openCodeVersionLabel: "OpenCode版本",
|
|
2809
2877
|
okLabel: "正常",
|
|
2878
|
+
overviewTitle: "🖥️ 概览",
|
|
2810
2879
|
pageTitle: "📊 服务状态",
|
|
2811
2880
|
pluginsTitle: "🧩 插件",
|
|
2812
2881
|
rootLabel: "根目录",
|
|
2813
|
-
serverTitle: "🖥️ 服务端",
|
|
2814
2882
|
statusLabel: "状态",
|
|
2815
|
-
|
|
2883
|
+
tbotVersionLabel: "opencode-tbot版本",
|
|
2884
|
+
voiceRecognitionLabel: "语音识别",
|
|
2816
2885
|
workspaceTitle: "📁 工作区"
|
|
2817
2886
|
};
|
|
2818
2887
|
}
|