feat: ClawTap v0.1.0 — initial release
Multi-adapter mobile UI for AI coding assistants. Supports Claude Code, Codex CLI, and Gemini CLI through one interface. Features: - Real-time bidirectional sync via tmux + WebSocket - Cross-AI review (send one AI's output to another for review) - Multi-review tabs with minimize/expand - Push notifications (PWA) with smart session-aware filtering - Three-channel event system (hooks, file watcher, pane monitor) - Voice input, image paste, draft persistence - Terminal-native design (JetBrains Mono, dark theme, pixel art claw) - CLI with --adapter flag on every command - Zero-overhead fire-and-forget hooks
This commit is contained in:
@@ -0,0 +1,62 @@
|
||||
/** A content block within a Codex message */
|
||||
export interface CodexContentBlock {
|
||||
type: 'input_text' | 'output_text' | 'input_image' | string;
|
||||
text?: string;
|
||||
image?: { url: string };
|
||||
[key: string]: unknown;
|
||||
}
|
||||
|
||||
/** Standard normalized content block (matches claw-tap frontend format) */
|
||||
export interface NormalizedBlock {
|
||||
type: string;
|
||||
text?: string;
|
||||
[key: string]: unknown;
|
||||
}
|
||||
|
||||
const SYSTEM_PATTERNS: RegExp[] = [
|
||||
/<permissions instructions>/i,
|
||||
/<environment_context>/i,
|
||||
/AGENTS\.md/,
|
||||
];
|
||||
|
||||
/**
|
||||
* Convert a Codex content block to the standard format used by claw-tap.
|
||||
*
|
||||
* - `input_text` → `{ type: 'text', text }`
|
||||
* - `output_text` → `{ type: 'text', text }`
|
||||
* - Unknown types are passed through as-is.
|
||||
*/
|
||||
export function normalizeContentBlock(block: CodexContentBlock): NormalizedBlock {
|
||||
if (block.type === 'input_text' || block.type === 'output_text') {
|
||||
return { type: 'text', text: block.text };
|
||||
}
|
||||
return { ...block } as NormalizedBlock;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract readable text from an array of Codex content blocks.
|
||||
* Concatenates all text-bearing blocks (input_text / output_text) with newlines.
|
||||
*/
|
||||
export function extractText(content: CodexContentBlock[]): string {
|
||||
return content
|
||||
.filter((b) => b.type === 'input_text' || b.type === 'output_text')
|
||||
.map((b) => b.text ?? '')
|
||||
.join('\n');
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if this message should be filtered out as a system message.
|
||||
*
|
||||
* Matches:
|
||||
* - `role === 'developer'`
|
||||
* - Text containing `<permissions instructions>`, `<environment_context>`, or `AGENTS.md`
|
||||
*/
|
||||
export function isSystemMessage(role: string, content: CodexContentBlock[]): boolean {
|
||||
if (role === 'developer') return true;
|
||||
|
||||
const text = extractText(content);
|
||||
for (const pattern of SYSTEM_PATTERNS) {
|
||||
if (pattern.test(text)) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
Reference in New Issue
Block a user