feat: show session ID in dashboard status display

Add session label (last 8 chars) next to each group status.
Export buildStatusContent and DashboardOptions for testing.
This commit is contained in:
Eyejoker
2026-03-16 05:36:30 +09:00
parent 6f38f1cd63
commit ea03956d0a
5 changed files with 70 additions and 6 deletions

View File

@@ -20,9 +20,11 @@ export const ASSISTANT_HAS_OWN_NUMBER =
(process.env.ASSISTANT_HAS_OWN_NUMBER ||
envConfig.ASSISTANT_HAS_OWN_NUMBER) === 'true';
export const SESSION_COMMAND_USER_IDS = new Set(
(process.env.SESSION_COMMAND_USER_IDS ||
(
process.env.SESSION_COMMAND_USER_IDS ||
envConfig.SESSION_COMMAND_USER_IDS ||
'')
''
)
.split(',')
.map((id) => id.trim())
.filter(Boolean),

49
src/dashboard.test.ts Normal file
View File

@@ -0,0 +1,49 @@
import { describe, expect, it } from 'vitest';
import { buildStatusContent, type DashboardOptions } from './dashboard.js';
function makeOptions(sessionId?: string): DashboardOptions {
const sessions: Record<string, string> = sessionId
? { 'group-folder': sessionId }
: {};
return {
assistantName: 'Test',
channels: [],
getSessions: () => sessions,
queue: {
getStatuses: () => [
{
jid: 'dc:123',
status: 'inactive',
elapsedMs: null,
pendingMessages: false,
pendingTasks: 0,
},
],
} as unknown as DashboardOptions['queue'],
registeredGroups: () => ({
'dc:123': {
name: 'clone-test',
folder: 'group-folder',
trigger: '@bot',
added_at: '2026-03-16T00:00:00.000Z',
},
}),
statusChannelId: 'status',
statusUpdateInterval: 60000,
usageUpdateInterval: 60000,
};
}
describe('buildStatusContent', () => {
it('shows cleared sessions as empty', () => {
const content = buildStatusContent(makeOptions());
expect(content).toContain('세션 없음');
});
it('shows a shortened session id when a session exists', () => {
const content = buildStatusContent(makeOptions('session-1234567890'));
expect(content).toContain('세션 34567890');
});
});

View File

@@ -8,9 +8,10 @@ import { GroupQueue, GroupStatus } from './group-queue.js';
import { logger } from './logger.js';
import { Channel, ChannelMeta, RegisteredGroup } from './types.js';
interface DashboardOptions {
export interface DashboardOptions {
assistantName: string;
channels: Channel[];
getSessions: () => Record<string, string>;
queue: GroupQueue;
registeredGroups: () => Record<string, RegisteredGroup>;
statusChannelId: string;
@@ -114,8 +115,16 @@ function getStatusLabel(status: GroupStatus): string {
return '비활성';
}
function buildStatusContent(opts: DashboardOptions): string {
function getSessionLabel(sessionId: string | undefined): string {
if (!sessionId) return '세션 없음';
const shortId = sessionId.length > 8 ? sessionId.slice(-8) : sessionId;
return `세션 ${shortId}`;
}
/** @internal - exported for testing */
export function buildStatusContent(opts: DashboardOptions): string {
const registeredGroups = opts.registeredGroups();
const sessions = opts.getSessions();
const jids = Object.keys(registeredGroups);
const statuses = opts.queue.getStatuses(jids);
@@ -153,8 +162,9 @@ function buildStatusContent(opts: DashboardOptions): string {
const lines = categoryEntries.map((entry) => {
const icon = STATUS_ICONS[entry.status.status] || '⚪';
const label = getStatusLabel(entry.status);
const sessionLabel = getSessionLabel(sessions[entry.group.folder]);
const name = entry.meta?.name ? `#${entry.meta.name}` : entry.group.name;
return ` ${icon} **${name}** — ${label}`;
return ` ${icon} **${name}** — ${label} · ${sessionLabel}`;
});
if (channelMetaCache.size > 0 && categoryName !== '기타') {

View File

@@ -256,6 +256,7 @@ async function main(): Promise<void> {
const dashboardOpts = {
assistantName: ASSISTANT_NAME,
channels,
getSessions: () => sessions,
queue,
registeredGroups: () => registeredGroups,
statusChannelId: STATUS_CHANNEL_ID,

View File

@@ -238,7 +238,9 @@ describe('handleSessionCommand', () => {
isAdminSender: vi.fn().mockReturnValue(true),
});
const result = await handleSessionCommand({
missedMessages: [makeMsg('/clear', { is_from_me: false, sender: 'discord-user-1' })],
missedMessages: [
makeMsg('/clear', { is_from_me: false, sender: 'discord-user-1' }),
],
isMainGroup: false,
groupName: 'test',
triggerPattern: trigger,