feat(plugins): show plugin logs on detail page via Docs/Logs tablist

Add a Logs tab beside Documentation on the plugin detail page, showing
the output a plugin prints through the standard Python logger (per the
wiki style guide). Logs are captured from the plugin's stderr by the
plugin runtime and fetched on demand.

- Bump langbot-plugin pin to 0.4.4 (adds GET_PLUGIN_LOGS action)
- plugin_connector/handler: get_plugin_logs RPC client
- HTTP route GET /api/v1/plugins/<author>/<name>/logs (limit + level)
- Frontend: wrap detail right panel in Docs/Logs Tabs; PluginLogs
  component with level filter, manual + 3s auto refresh, bottom-follow
- i18n: 7 new keys across all 8 locales
This commit is contained in:
RockChinQ
2026-06-13 08:01:18 -04:00
parent a97d2040bb
commit 5bfa38cbf2
17 changed files with 328 additions and 7 deletions
+17
View File
@@ -55,6 +55,7 @@ import {
ApiRespSkill,
} from '@/app/infra/entities/api';
import { Plugin } from '@/app/infra/entities/plugin';
import type { PluginLogEntry } from '@/app/infra/entities/plugin';
import type { I18nObject } from '@/app/infra/entities/common';
import { GetBotLogsRequest } from '@/app/infra/http/requestParam/bots/GetBotLogsRequest';
import { GetBotLogsResponse } from '@/app/infra/http/requestParam/bots/GetBotLogsResponse';
@@ -604,6 +605,22 @@ export class BackendClient extends BaseHttpClient {
);
}
public getPluginLogs(
author: string,
name: string,
limit: number = 200,
level?: string,
): Promise<{ logs: PluginLogEntry[] }> {
const params = new URLSearchParams();
params.set('limit', String(limit));
if (level) {
params.set('level', level);
}
return this.get(
`/api/v1/plugins/${author}/${name}/logs?${params.toString()}`,
);
}
public getPluginAssetURL(
author: string,
name: string,