mirror of
https://github.com/thedotmack/claude-mem
synced 2026-04-25 17:15:04 +02:00
polish: claude-review iteration 7 feedback
- claude-code adapter: add 128-char safety cap on agent_id/agent_type so a malformed Claude Code payload cannot balloon DB rows. Empty strings now also treated as absent. - migration010: state-aware debug log lists only columns actually added; idempotent re-runs log "already present; ensured indexes". - Add 3 adapter tests covering the length cap boundary and empty-string rejection. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
File diff suppressed because one or more lines are too long
@@ -2,6 +2,13 @@ import type { PlatformAdapter, NormalizedHookInput, HookResult } from '../types.
|
||||
|
||||
// Maps Claude Code stdin format (session_id, cwd, tool_name, etc.)
|
||||
// SessionStart hooks receive no stdin, so we must handle undefined input gracefully
|
||||
|
||||
// Defensive cap: Claude Code's agent identifiers are short (e.g., "agent-abc123", "Explore").
|
||||
// Ignore anything longer than 128 chars so a malformed payload cannot balloon DB rows.
|
||||
const MAX_AGENT_FIELD_LEN = 128;
|
||||
const pickAgentField = (v: unknown): string | undefined =>
|
||||
typeof v === 'string' && v.length > 0 && v.length <= MAX_AGENT_FIELD_LEN ? v : undefined;
|
||||
|
||||
export const claudeCodeAdapter: PlatformAdapter = {
|
||||
normalizeInput(raw) {
|
||||
const r = (raw ?? {}) as any;
|
||||
@@ -13,8 +20,8 @@ export const claudeCodeAdapter: PlatformAdapter = {
|
||||
toolInput: r.tool_input,
|
||||
toolResponse: r.tool_response,
|
||||
transcriptPath: r.transcript_path,
|
||||
agentId: typeof r.agent_id === 'string' ? r.agent_id : undefined,
|
||||
agentType: typeof r.agent_type === 'string' ? r.agent_type : undefined,
|
||||
agentId: pickAgentField(r.agent_id),
|
||||
agentType: pickAgentField(r.agent_type),
|
||||
};
|
||||
},
|
||||
formatOutput(result) {
|
||||
|
||||
@@ -584,14 +584,18 @@ export const migration009: Migration = {
|
||||
export const migration010: Migration = {
|
||||
version: 27,
|
||||
up: (db: Database) => {
|
||||
const added: string[] = [];
|
||||
|
||||
const obsColumns = db.prepare('PRAGMA table_info(observations)').all() as Array<{ name: string }>;
|
||||
const obsHasAgentType = obsColumns.some(c => c.name === 'agent_type');
|
||||
const obsHasAgentId = obsColumns.some(c => c.name === 'agent_id');
|
||||
if (!obsHasAgentType) {
|
||||
db.run('ALTER TABLE observations ADD COLUMN agent_type TEXT');
|
||||
added.push('observations.agent_type');
|
||||
}
|
||||
if (!obsHasAgentId) {
|
||||
db.run('ALTER TABLE observations ADD COLUMN agent_id TEXT');
|
||||
added.push('observations.agent_id');
|
||||
}
|
||||
db.run('CREATE INDEX IF NOT EXISTS idx_observations_agent_type ON observations(agent_type)');
|
||||
db.run('CREATE INDEX IF NOT EXISTS idx_observations_agent_id ON observations(agent_id)');
|
||||
@@ -604,13 +608,20 @@ export const migration010: Migration = {
|
||||
const pendingHasAgentId = pendingColumns.some(c => c.name === 'agent_id');
|
||||
if (!pendingHasAgentType) {
|
||||
db.run('ALTER TABLE pending_messages ADD COLUMN agent_type TEXT');
|
||||
added.push('pending_messages.agent_type');
|
||||
}
|
||||
if (!pendingHasAgentId) {
|
||||
db.run('ALTER TABLE pending_messages ADD COLUMN agent_id TEXT');
|
||||
added.push('pending_messages.agent_id');
|
||||
}
|
||||
}
|
||||
|
||||
logger.debug('DB', '[migration010] Added agent_type, agent_id columns to observations and pending_messages');
|
||||
logger.debug(
|
||||
'DB',
|
||||
added.length > 0
|
||||
? `[migration010] Added columns: ${added.join(', ')}`
|
||||
: '[migration010] Subagent identity columns already present; ensured indexes'
|
||||
);
|
||||
},
|
||||
down: (_db: Database) => {
|
||||
// SQLite DROP COLUMN not fully supported; no-op
|
||||
|
||||
@@ -79,4 +79,42 @@ describe('claudeCodeAdapter.normalizeInput — subagent fields', () => {
|
||||
expect(normalizedUndef.agentId).toBeUndefined();
|
||||
expect(normalizedUndef.agentType).toBeUndefined();
|
||||
});
|
||||
|
||||
it('drops agent fields that exceed the 128-char safety cap', () => {
|
||||
const oversized = 'a'.repeat(129);
|
||||
const normalized = claudeCodeAdapter.normalizeInput({
|
||||
session_id: 's1',
|
||||
cwd: '/tmp',
|
||||
agent_id: oversized,
|
||||
agent_type: oversized,
|
||||
});
|
||||
|
||||
expect(normalized.agentId).toBeUndefined();
|
||||
expect(normalized.agentType).toBeUndefined();
|
||||
});
|
||||
|
||||
it('keeps agent fields exactly at the 128-char boundary', () => {
|
||||
const atLimit = 'a'.repeat(128);
|
||||
const normalized = claudeCodeAdapter.normalizeInput({
|
||||
session_id: 's1',
|
||||
cwd: '/tmp',
|
||||
agent_id: atLimit,
|
||||
agent_type: atLimit,
|
||||
});
|
||||
|
||||
expect(normalized.agentId).toBe(atLimit);
|
||||
expect(normalized.agentType).toBe(atLimit);
|
||||
});
|
||||
|
||||
it('drops empty-string agent fields (treat as absent)', () => {
|
||||
const normalized = claudeCodeAdapter.normalizeInput({
|
||||
session_id: 's1',
|
||||
cwd: '/tmp',
|
||||
agent_id: '',
|
||||
agent_type: '',
|
||||
});
|
||||
|
||||
expect(normalized.agentId).toBeUndefined();
|
||||
expect(normalized.agentType).toBeUndefined();
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user