Skip to content

Commit 9c2a62a

Browse files
bluedbirdclaude
andcommitted
chore: remove dead code, eliminate thin layers, fix lint warnings
- Remove dead exports: detectClaudeCli, formatCost, KvStore (write-only) - Eliminate SessionManager layer — absorb addMessage into SessionStore - Inline agent context-builder and prompts into agent.ts - Deduplicate result-parsing in claude-code provider - Extract buildReplyAndProgress helper in telegram adapter - Fix all 7 noNonNullAssertion lint warnings - Wrap session message insert + update in db.transaction() Net: -281 lines, 77 tests pass, 0 lint warnings. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent dc0deeb commit 9c2a62a

26 files changed

Lines changed: 145 additions & 426 deletions

packages/agent/src/agent.ts

Lines changed: 37 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,28 @@
1-
import type { ProviderAdapter, UsageStats } from '@homie/core';
1+
import type {
2+
Message,
3+
ProgressCallback,
4+
ProviderAdapter,
5+
ProviderMessage,
6+
UsageStats,
7+
} from '@homie/core';
28
import { createLogger } from '@homie/observability';
3-
import { type AgentInput, buildMessages } from './context-builder';
49

510
const log = createLogger('agent');
611

12+
const SYSTEM_PROMPT = 'You are Homie. Keep responses concise (Telegram chat).';
13+
14+
export interface AgentInput {
15+
sessionId: string;
16+
text: string;
17+
history: Message[];
18+
/** When true, skip resume and send full history (e.g. after an interrupted run) */
19+
forceFullHistory?: boolean;
20+
userId?: string;
21+
onProgress?: ProgressCallback;
22+
/** Signal to abort the in-flight agent run */
23+
signal?: AbortSignal;
24+
}
25+
726
export interface AgentOutput {
827
text: string;
928
usage?: UsageStats;
@@ -50,3 +69,19 @@ export function createAgent(provider: ProviderAdapter, config: AgentConfig): Age
5069
},
5170
};
5271
}
72+
73+
function buildMessages(input: AgentInput): ProviderMessage[] {
74+
const messages: ProviderMessage[] = [{ role: 'system', content: SYSTEM_PROMPT }];
75+
76+
for (const msg of input.history) {
77+
if (msg.direction === 'in') {
78+
messages.push({ role: 'user', content: msg.text });
79+
} else if (msg.direction === 'out') {
80+
messages.push({ role: 'assistant', content: msg.text });
81+
}
82+
}
83+
84+
messages.push({ role: 'user', content: input.text });
85+
86+
return messages;
87+
}

packages/agent/src/context-builder.test.ts

Lines changed: 0 additions & 52 deletions
This file was deleted.

packages/agent/src/context-builder.ts

Lines changed: 0 additions & 32 deletions
This file was deleted.

packages/agent/src/index.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,7 @@
1-
export { type Agent, type AgentConfig, type AgentOutput, createAgent } from './agent';
2-
export { type AgentInput, buildMessages } from './context-builder';
1+
export {
2+
type Agent,
3+
type AgentConfig,
4+
type AgentInput,
5+
type AgentOutput,
6+
createAgent,
7+
} from './agent';

packages/agent/src/prompts.ts

Lines changed: 0 additions & 3 deletions
This file was deleted.

packages/channels/telegram/src/adapter.ts

Lines changed: 16 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -48,18 +48,18 @@ function toMarkdownV2(text: string): string {
4848
// `inline code`
4949
const inner = match[2].slice(1, -1);
5050
tokens.push({ raw: `\`${escapeV2Pre(inner)}\`` });
51-
} else if (match[3]) {
51+
} else if (match[3] && match[4]) {
5252
// **bold** → *bold*
53-
tokens.push({ raw: `*${escapeV2(match[4]!)}*` });
54-
} else if (match[5]) {
53+
tokens.push({ raw: `*${escapeV2(match[4])}*` });
54+
} else if (match[5] && match[6]) {
5555
// __italic__ → _italic_
56-
tokens.push({ raw: `_${escapeV2(match[6]!)}_` });
57-
} else if (match[7]) {
56+
tokens.push({ raw: `_${escapeV2(match[6])}_` });
57+
} else if (match[7] && match[8]) {
5858
// *italic* (single) — in standard markdown this is italic
59-
tokens.push({ raw: `_${escapeV2(match[8]!)}_` });
60-
} else if (match[9]) {
59+
tokens.push({ raw: `_${escapeV2(match[8])}_` });
60+
} else if (match[9] && match[10]) {
6161
// _italic_
62-
tokens.push({ raw: `_${escapeV2(match[10]!)}_` });
62+
tokens.push({ raw: `_${escapeV2(match[10])}_` });
6363
}
6464

6565
cursor = match.index + match[0].length;
@@ -210,11 +210,16 @@ export function createTelegramAdapter(opts: {
210210
return allowedChatIds.size === 0 || allowedChatIds.has(chatId);
211211
}
212212

213-
async function dispatch(event: ChatMessageEvent, chatId: string): Promise<void> {
213+
function buildReplyAndProgress(chatId: string) {
214214
const reply = async (replyText: string) => {
215215
await sendMessage({ chatId }, { text: replyText });
216216
};
217217
const progress = buildProgress(chatId);
218+
return { reply, progress };
219+
}
220+
221+
async function dispatch(event: ChatMessageEvent, chatId: string): Promise<void> {
222+
const { reply, progress } = buildReplyAndProgress(chatId);
218223
await handler(event, reply, progress);
219224
}
220225

@@ -234,17 +239,14 @@ export function createTelegramAdapter(opts: {
234239
const cmdMatch = text.match(/^\/(\w+)(?:\s+(.*))?$/s);
235240

236241
if (cmdMatch) {
237-
const reply = async (replyText: string) => {
238-
await sendMessage({ chatId }, { text: replyText });
239-
};
240-
const progress = buildProgress(chatId);
242+
const { reply, progress } = buildReplyAndProgress(chatId);
241243
await handler(
242244
{
243245
type: 'command',
244246
channel: 'telegram',
245247
chatId,
246248
userId,
247-
command: cmdMatch[1]!,
249+
command: cmdMatch[1] ?? '',
248250
args: (cmdMatch[2] ?? '').trim(),
249251
rawSourceId: messageId,
250252
},

packages/core/src/interfaces.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,12 @@ export interface ProviderAdapter {
7474
export interface SessionStore {
7575
getOrCreateByChat(channel: string, chatId: string, userId?: string | null): Promise<Session>;
7676
getById(sessionId: string): Promise<Session | null>;
77-
appendMessage(message: Message): Promise<void>;
77+
addMessage(
78+
sessionId: string,
79+
direction: Message['direction'],
80+
text: string,
81+
rawSourceId?: string | null,
82+
): Promise<Message>;
7883
listRecentMessages(sessionId: string, limit: number): Promise<Message[]>;
7984
setSessionStatus(sessionId: string, status: import('./types').SessionStatus): Promise<void>;
8085
resetStuckSessions(): Promise<number>;

packages/gateway/src/commands.test.ts

Lines changed: 6 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,11 @@
11
import { Database } from 'bun:sqlite';
22
import { afterEach, beforeEach, describe, expect, test } from 'bun:test';
33
import { createAgent } from '@homie/agent';
4-
import { AbortError, type Message, type ProviderAdapter } from '@homie/core';
4+
import { AbortError, type ProviderAdapter } from '@homie/core';
55
import { schema } from '@homie/persistence/src/migrations';
66
import { createSessionStore } from '@homie/persistence/src/session-store';
77
import { createTaskStore } from '@homie/persistence/src/task-store';
88
import { createUsageStore } from '@homie/persistence/src/usage-store';
9-
import { createSessionManager } from '@homie/sessions';
109
import { type CommandContext, createCommandHandler } from './commands';
1110
import { createTaskRunner } from './task-runner';
1211

@@ -43,34 +42,25 @@ describe('CommandHandler', () => {
4342

4443
/** Helper: create a message and return its ID */
4544
async function addMessage(text: string): Promise<string> {
46-
const msg: Message = {
47-
id: crypto.randomUUID(),
48-
sessionId,
49-
direction: 'in',
50-
text,
51-
createdAt: new Date().toISOString(),
52-
rawSourceId: null,
53-
};
54-
await sessionStore.appendMessage(msg);
45+
const msg = await sessionStore.addMessage(sessionId, 'in', text);
5546
return msg.id;
5647
}
5748

5849
beforeEach(async () => {
5950
db = createTestDb();
6051
sessionStore = createSessionStore(db);
61-
const sessionManager = createSessionManager(sessionStore);
6252
const usageStore = createUsageStore(db);
6353
taskStore = createTaskStore(db);
6454

65-
const session = await sessionManager.resolveSession('telegram', 'chat1', 'user1');
55+
const session = await sessionStore.getOrCreateByChat('telegram', 'chat1', 'user1');
6656
sessionId = session.id;
6757

6858
const provider: ProviderAdapter = {
6959
generate: async () => ({ content: 'ok', usage: undefined }),
7060
};
7161
const agent = createAgent(provider, { model: 'test' });
7262
const runner = createTaskRunner({
73-
sessionManager,
63+
sessionStore,
7464
agent,
7565
taskStore,
7666
usageStore,
@@ -209,10 +199,9 @@ describe('CommandHandler', () => {
209199
};
210200
const agent = createAgent(blockingProvider, { model: 'test' });
211201
const abortSessionStore = createSessionStore(db);
212-
const sessionManager = createSessionManager(abortSessionStore);
213202
const usageStore = createUsageStore(db);
214203
const blockingRunner = createTaskRunner({
215-
sessionManager,
204+
sessionStore: abortSessionStore,
216205
agent,
217206
taskStore,
218207
usageStore,
@@ -224,7 +213,7 @@ describe('CommandHandler', () => {
224213
usageStore,
225214
});
226215

227-
const session = await sessionManager.resolveSession('telegram', 'chat-abort', 'user1');
216+
const session = await abortSessionStore.getOrCreateByChat('telegram', 'chat-abort', 'user1');
228217
await blockingRunner.submit({
229218
channel: 'telegram',
230219
chatId: 'chat-abort',

packages/gateway/src/format.test.ts

Lines changed: 0 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import { describe, expect, test } from 'bun:test';
22
import {
33
elapsedSince,
4-
formatCost,
54
formatElapsed,
65
formatTokens,
76
shortId,
@@ -51,22 +50,6 @@ describe('timeSince', () => {
5150
});
5251
});
5352

54-
describe('formatCost', () => {
55-
test('zero', () => {
56-
expect(formatCost(0)).toBe('$0.00');
57-
});
58-
59-
test('small amounts use 4 decimals', () => {
60-
expect(formatCost(0.0042)).toBe('$0.0042');
61-
expect(formatCost(0.001)).toBe('$0.0010');
62-
});
63-
64-
test('larger amounts use 2 decimals', () => {
65-
expect(formatCost(0.12)).toBe('$0.12');
66-
expect(formatCost(1.5)).toBe('$1.50');
67-
});
68-
});
69-
7053
describe('formatTokens', () => {
7154
test('small counts', () => {
7255
expect(formatTokens(0)).toBe('0');

packages/gateway/src/format.ts

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,6 @@ export function timeSince(iso: string): string {
1818
return `${days}d`;
1919
}
2020

21-
/** Format USD cost (e.g. "$0.12", "$0.0042") */
22-
export function formatCost(usd: number): string {
23-
if (usd === 0) return '$0.00';
24-
if (usd < 0.01) return `$${usd.toFixed(4)}`;
25-
return `$${usd.toFixed(2)}`;
26-
}
27-
2821
/** Format token count (e.g. "45.2k", "1.2M") */
2922
export function formatTokens(count: number): string {
3023
if (count >= 1_000_000) return `${(count / 1_000_000).toFixed(1)}M`;

0 commit comments

Comments
 (0)