Fix markdown list text wrapping on Android
- Add custom list rendering rules in message.tsx for proper flex layout - Remove flexWrap from list content styles (causes Android clipping) - Use flex: 1 and flexShrink: 1 for natural text wrapping - Add minWidth: 0 to content containers for proper shrinking 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.5
parent
09f130408b
commit
37da13a38b
@@ -599,6 +599,111 @@ function PermissionRequestCard({
|
|||||||
[theme]
|
[theme]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const markdownRules = useMemo(() => {
|
||||||
|
return {
|
||||||
|
text: (
|
||||||
|
node: any,
|
||||||
|
_children: React.ReactNode[],
|
||||||
|
_parent: any,
|
||||||
|
styles: any,
|
||||||
|
inheritedStyles: any = {}
|
||||||
|
) => (
|
||||||
|
<Text key={node.key} style={[inheritedStyles, styles.text]} selectable>
|
||||||
|
{node.content}
|
||||||
|
</Text>
|
||||||
|
),
|
||||||
|
textgroup: (
|
||||||
|
node: any,
|
||||||
|
children: React.ReactNode[],
|
||||||
|
_parent: any,
|
||||||
|
styles: any,
|
||||||
|
inheritedStyles: any = {}
|
||||||
|
) => (
|
||||||
|
<Text key={node.key} style={[inheritedStyles, styles.textgroup]} selectable>
|
||||||
|
{children}
|
||||||
|
</Text>
|
||||||
|
),
|
||||||
|
code_block: (
|
||||||
|
node: any,
|
||||||
|
_children: React.ReactNode[],
|
||||||
|
_parent: any,
|
||||||
|
styles: any,
|
||||||
|
inheritedStyles: any = {}
|
||||||
|
) => (
|
||||||
|
<Text key={node.key} style={[inheritedStyles, styles.code_block]} selectable>
|
||||||
|
{node.content}
|
||||||
|
</Text>
|
||||||
|
),
|
||||||
|
fence: (
|
||||||
|
node: any,
|
||||||
|
_children: React.ReactNode[],
|
||||||
|
_parent: any,
|
||||||
|
styles: any,
|
||||||
|
inheritedStyles: any = {}
|
||||||
|
) => (
|
||||||
|
<Text key={node.key} style={[inheritedStyles, styles.fence]} selectable>
|
||||||
|
{node.content}
|
||||||
|
</Text>
|
||||||
|
),
|
||||||
|
code_inline: (
|
||||||
|
node: any,
|
||||||
|
_children: React.ReactNode[],
|
||||||
|
_parent: any,
|
||||||
|
styles: any,
|
||||||
|
inheritedStyles: any = {}
|
||||||
|
) => (
|
||||||
|
<Text key={node.key} style={[inheritedStyles, styles.code_inline]} selectable>
|
||||||
|
{node.content}
|
||||||
|
</Text>
|
||||||
|
),
|
||||||
|
bullet_list: (
|
||||||
|
node: any,
|
||||||
|
children: React.ReactNode[],
|
||||||
|
_parent: any,
|
||||||
|
styles: any
|
||||||
|
) => (
|
||||||
|
<View key={node.key} style={styles.bullet_list}>
|
||||||
|
{children}
|
||||||
|
</View>
|
||||||
|
),
|
||||||
|
ordered_list: (
|
||||||
|
node: any,
|
||||||
|
children: React.ReactNode[],
|
||||||
|
_parent: any,
|
||||||
|
styles: any
|
||||||
|
) => (
|
||||||
|
<View key={node.key} style={styles.ordered_list}>
|
||||||
|
{children}
|
||||||
|
</View>
|
||||||
|
),
|
||||||
|
list_item: (
|
||||||
|
node: any,
|
||||||
|
children: React.ReactNode[],
|
||||||
|
parent: any,
|
||||||
|
styles: any
|
||||||
|
) => {
|
||||||
|
const isOrdered = parent?.type === "ordered_list";
|
||||||
|
const index = parent?.children?.indexOf(node) ?? 0;
|
||||||
|
const bullet = isOrdered ? `${index + 1}.` : "•";
|
||||||
|
const iconStyle = isOrdered
|
||||||
|
? styles.ordered_list_icon
|
||||||
|
: styles.bullet_list_icon;
|
||||||
|
const contentStyle = isOrdered
|
||||||
|
? styles.ordered_list_content
|
||||||
|
: styles.bullet_list_content;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<View key={node.key} style={[styles.list_item, { flexShrink: 0 }]}>
|
||||||
|
<Text style={iconStyle}>{bullet}</Text>
|
||||||
|
<Text style={[contentStyle, { flex: 1, flexShrink: 1, minWidth: 0 }]} selectable>
|
||||||
|
{children}
|
||||||
|
</Text>
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}, []);
|
||||||
|
|
||||||
const permissionResponse = useDaemonRequest<
|
const permissionResponse = useDaemonRequest<
|
||||||
{ agentId: string; requestId: string; response: AgentPermissionResponse },
|
{ agentId: string; requestId: string; response: AgentPermissionResponse },
|
||||||
{ agentId: string; requestId: string },
|
{ agentId: string; requestId: string },
|
||||||
@@ -675,7 +780,7 @@ function PermissionRequestCard({
|
|||||||
},
|
},
|
||||||
]}
|
]}
|
||||||
>
|
>
|
||||||
<Markdown style={markdownStyles}>{planMarkdown}</Markdown>
|
<Markdown style={markdownStyles} rules={markdownRules}>{planMarkdown}</Markdown>
|
||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
) : null}
|
) : null}
|
||||||
@@ -986,6 +1091,8 @@ const permissionStyles = StyleSheet.create((theme) => ({
|
|||||||
padding: theme.spacing[3],
|
padding: theme.spacing[3],
|
||||||
borderRadius: theme.borderRadius.lg,
|
borderRadius: theme.borderRadius.lg,
|
||||||
borderWidth: theme.borderWidth[1],
|
borderWidth: theme.borderWidth[1],
|
||||||
|
flexShrink: 1,
|
||||||
|
minWidth: 0,
|
||||||
},
|
},
|
||||||
metadataRow: {
|
metadataRow: {
|
||||||
marginBottom: theme.spacing[2],
|
marginBottom: theme.spacing[2],
|
||||||
|
|||||||
@@ -234,6 +234,8 @@ const expandableBadgeStylesheet = StyleSheet.create((theme) => ({
|
|||||||
backgroundColor: theme.colors.background,
|
backgroundColor: theme.colors.background,
|
||||||
padding: theme.spacing[2],
|
padding: theme.spacing[2],
|
||||||
gap: theme.spacing[2],
|
gap: theme.spacing[2],
|
||||||
|
flexShrink: 1,
|
||||||
|
minWidth: 0,
|
||||||
},
|
},
|
||||||
}));
|
}));
|
||||||
|
|
||||||
@@ -417,6 +419,51 @@ export const AssistantMessage = memo(function AssistantMessage({
|
|||||||
</Text>
|
</Text>
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
bullet_list: (
|
||||||
|
node: any,
|
||||||
|
children: ReactNode[],
|
||||||
|
_parent: any,
|
||||||
|
styles: any
|
||||||
|
) => (
|
||||||
|
<View key={node.key} style={styles.bullet_list}>
|
||||||
|
{children}
|
||||||
|
</View>
|
||||||
|
),
|
||||||
|
ordered_list: (
|
||||||
|
node: any,
|
||||||
|
children: ReactNode[],
|
||||||
|
_parent: any,
|
||||||
|
styles: any
|
||||||
|
) => (
|
||||||
|
<View key={node.key} style={styles.ordered_list}>
|
||||||
|
{children}
|
||||||
|
</View>
|
||||||
|
),
|
||||||
|
list_item: (
|
||||||
|
node: any,
|
||||||
|
children: ReactNode[],
|
||||||
|
parent: any,
|
||||||
|
styles: any
|
||||||
|
) => {
|
||||||
|
const isOrdered = parent?.type === "ordered_list";
|
||||||
|
const index = parent?.children?.indexOf(node) ?? 0;
|
||||||
|
const bullet = isOrdered ? `${index + 1}.` : "•";
|
||||||
|
const iconStyle = isOrdered
|
||||||
|
? styles.ordered_list_icon
|
||||||
|
: styles.bullet_list_icon;
|
||||||
|
const contentStyle = isOrdered
|
||||||
|
? styles.ordered_list_content
|
||||||
|
: styles.bullet_list_content;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<View key={node.key} style={styles.list_item}>
|
||||||
|
<Text style={iconStyle}>{bullet}</Text>
|
||||||
|
<View style={[contentStyle, { flex: 1, flexShrink: 1, minWidth: 0 }]}>
|
||||||
|
{children}
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
},
|
||||||
};
|
};
|
||||||
}, [onInlinePathPress]);
|
}, [onInlinePathPress]);
|
||||||
|
|
||||||
@@ -1007,6 +1054,51 @@ export function AgentThoughtMessage({ message, status = "ready" }: AgentThoughtM
|
|||||||
{node.content}
|
{node.content}
|
||||||
</Text>
|
</Text>
|
||||||
),
|
),
|
||||||
|
bullet_list: (
|
||||||
|
node: any,
|
||||||
|
children: ReactNode[],
|
||||||
|
_parent: any,
|
||||||
|
styles: any
|
||||||
|
) => (
|
||||||
|
<View key={node.key} style={styles.bullet_list}>
|
||||||
|
{children}
|
||||||
|
</View>
|
||||||
|
),
|
||||||
|
ordered_list: (
|
||||||
|
node: any,
|
||||||
|
children: ReactNode[],
|
||||||
|
_parent: any,
|
||||||
|
styles: any
|
||||||
|
) => (
|
||||||
|
<View key={node.key} style={styles.ordered_list}>
|
||||||
|
{children}
|
||||||
|
</View>
|
||||||
|
),
|
||||||
|
list_item: (
|
||||||
|
node: any,
|
||||||
|
children: ReactNode[],
|
||||||
|
parent: any,
|
||||||
|
styles: any
|
||||||
|
) => {
|
||||||
|
const isOrdered = parent?.type === "ordered_list";
|
||||||
|
const index = parent?.children?.indexOf(node) ?? 0;
|
||||||
|
const bullet = isOrdered ? `${index + 1}.` : "•";
|
||||||
|
const iconStyle = isOrdered
|
||||||
|
? styles.ordered_list_icon
|
||||||
|
: styles.bullet_list_icon;
|
||||||
|
const contentStyle = isOrdered
|
||||||
|
? styles.ordered_list_content
|
||||||
|
: styles.bullet_list_content;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<View key={node.key} style={styles.list_item}>
|
||||||
|
<Text style={iconStyle}>{bullet}</Text>
|
||||||
|
<View style={[contentStyle, { flex: 1, flexShrink: 1, minWidth: 0 }]}>
|
||||||
|
{children}
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
},
|
||||||
};
|
};
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
|||||||
@@ -215,13 +215,13 @@ export function createMarkdownStyles(theme: Theme) {
|
|||||||
|
|
||||||
bullet_list: {
|
bullet_list: {
|
||||||
marginVertical: theme.spacing[2],
|
marginVertical: theme.spacing[2],
|
||||||
paddingLeft: theme.spacing[1],
|
paddingLeft: 0,
|
||||||
width: "100%" as const,
|
width: "100%" as const,
|
||||||
},
|
},
|
||||||
|
|
||||||
ordered_list: {
|
ordered_list: {
|
||||||
marginVertical: theme.spacing[2],
|
marginVertical: theme.spacing[2],
|
||||||
paddingLeft: theme.spacing[1],
|
paddingLeft: 0,
|
||||||
width: "100%" as const,
|
width: "100%" as const,
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -229,36 +229,33 @@ export function createMarkdownStyles(theme: Theme) {
|
|||||||
marginBottom: theme.spacing[1],
|
marginBottom: theme.spacing[1],
|
||||||
flexDirection: "row" as const,
|
flexDirection: "row" as const,
|
||||||
alignItems: "flex-start" as const,
|
alignItems: "flex-start" as const,
|
||||||
width: "100%" as const,
|
|
||||||
flexShrink: 1,
|
flexShrink: 1,
|
||||||
},
|
},
|
||||||
|
|
||||||
bullet_list_content: {
|
bullet_list_content: {
|
||||||
flex: 1,
|
flex: 1,
|
||||||
flexShrink: 1,
|
flexShrink: 1,
|
||||||
flexWrap: "wrap" as const,
|
|
||||||
},
|
},
|
||||||
|
|
||||||
ordered_list_content: {
|
ordered_list_content: {
|
||||||
flex: 1,
|
flex: 1,
|
||||||
flexShrink: 1,
|
flexShrink: 1,
|
||||||
flexWrap: "wrap" as const,
|
|
||||||
},
|
},
|
||||||
|
|
||||||
bullet_list_icon: {
|
bullet_list_icon: {
|
||||||
color: theme.colors.mutedForeground,
|
color: theme.colors.mutedForeground,
|
||||||
marginRight: theme.spacing[2],
|
marginRight: 4,
|
||||||
fontSize: theme.fontSize.base,
|
fontSize: theme.fontSize.base,
|
||||||
lineHeight: 22,
|
lineHeight: 22,
|
||||||
},
|
},
|
||||||
|
|
||||||
ordered_list_icon: {
|
ordered_list_icon: {
|
||||||
color: theme.colors.mutedForeground,
|
color: theme.colors.mutedForeground,
|
||||||
marginRight: theme.spacing[2],
|
marginRight: 4,
|
||||||
fontSize: theme.fontSize.base,
|
fontSize: theme.fontSize.base,
|
||||||
fontWeight: theme.fontWeight.semibold,
|
fontWeight: theme.fontWeight.semibold,
|
||||||
lineHeight: 22,
|
lineHeight: 22,
|
||||||
minWidth: 20,
|
minWidth: 12,
|
||||||
},
|
},
|
||||||
|
|
||||||
// =========================================================================
|
// =========================================================================
|
||||||
|
|||||||
@@ -5,48 +5,47 @@
|
|||||||
*/
|
*/
|
||||||
export function getOrchestratorModeInstructions(): string {
|
export function getOrchestratorModeInstructions(): string {
|
||||||
return `
|
return `
|
||||||
|
<orchestrator-mode>
|
||||||
|
Activation:
|
||||||
|
- Only activate if the user explicitly says "go into orchestrator mode" (or similar).
|
||||||
|
- Otherwise, do work directly yourself; do not spawn agents.
|
||||||
|
|
||||||
## Orchestrator Mode Instructions
|
Core rules:
|
||||||
|
- In orchestrator mode, you accomplish tasks only by managing agents; do not perform the work yourself.
|
||||||
|
- Always prefix agent titles (e.g., "🎭 Feature Implementation", "🎭 Design Discussion").
|
||||||
|
- Set cwd to the repository root and choose the most permissive mode available.
|
||||||
|
- If an agent control call fails, list agents before launching another; it may just be a wait timeout.
|
||||||
|
|
||||||
When asked to go into orchestrator mode, you must **only accomplish tasks by managing other agents**. Do NOT perform the work yourself.
|
Context management:
|
||||||
|
- Reuse an existing agent when the next step needs the same context (same files/module/folder or immediate follow-up like investigate → fix in the same area).
|
||||||
|
- Start a new agent when switching to a different area/module, or when an agent has run long and its context feels stale.
|
||||||
|
- Prefer sending follow-up prompts to an existing agent to avoid reloading context.
|
||||||
|
- Use multiple agents when roles diverge (e.g., one for refactor, one for external validation), but default to reuse when context overlaps.
|
||||||
|
|
||||||
### Agent Control Best Practices
|
Conversation with agents:
|
||||||
|
- Engage actively: ask pointed questions, probe risks, and request clarifications before accepting proposals.
|
||||||
|
- Encourage agents to validate assumptions, consider edge cases, and describe how they will test/verify.
|
||||||
|
|
||||||
- **When agent control tool calls fail**, make sure you list agents before trying to launch another one. It could just be a wait timeout.
|
Agent selection guidance:
|
||||||
- **Always prefix agent titles** so we can tell which ones are running under you (e.g., "🎭 Feature Implementation", "🎭 Design Discussion").
|
- Codex: methodical and slower; great for deep debugging, tracing code paths, refactoring, complex features, and design discussions.
|
||||||
- **Launch agents in the most permissive mode**: Use full access or bypass permissions mode.
|
- Claude: fast; strong at tool use (e.g., Playwright MCP, web search), agentic control, and managing other agents; may jump to conclusions—ask it to verify.
|
||||||
- **Set cwd to the repository root** - The agent's working directory should usually be the repo root.
|
- For debugging with UI/Playwright: Claude can drive Playwright MCP and logging; Codex can audit code and propose fixes.
|
||||||
|
|
||||||
### Agent Use Cases
|
Clarifying ambiguous requests:
|
||||||
|
- Research first to understand the current state.
|
||||||
|
- Ask clarifying questions about what the user wants.
|
||||||
|
- Present options with trade-offs.
|
||||||
|
- Get explicit confirmation; never assume.
|
||||||
|
|
||||||
You can run agents to:
|
Investigation vs Implementation:
|
||||||
- **Implement a task** - Spawn an agent to write code and implement features
|
- Investigate only unless explicitly asked to implement.
|
||||||
- **Have a design discussion** - Discuss architecture and design decisions
|
- Report findings clearly.
|
||||||
- **Have a pairing session** - Collaborate on problem-solving
|
- After investigation, ask for direction before implementing.
|
||||||
- **Test some feature** - Run tests and verify functionality
|
|
||||||
- **Do investigation** - Research and explore the codebase
|
|
||||||
|
|
||||||
### Clarifying Ambiguous Requests
|
Tool usage discipline:
|
||||||
|
- Do not ask users to run commands—run them yourself.
|
||||||
**CRITICAL:** When user requests are ambiguous or unclear:
|
- Do not repeat the user’s instructions verbatim—summarize them in your own words.
|
||||||
|
- Be explicit about results—tell the user what happened after every command.
|
||||||
1. **Research first** - Spawn an investigation agent to understand the current state
|
</orchestrator-mode>
|
||||||
2. **Ask clarifying questions** - After research, ask the user specific questions about what they want
|
|
||||||
3. **Present options** - Offer multiple approaches with trade-offs
|
|
||||||
4. **Get explicit confirmation** - Never assume what the user wants
|
|
||||||
|
|
||||||
### Investigation vs Implementation
|
|
||||||
|
|
||||||
**CRITICAL:** When asked to investigate:
|
|
||||||
|
|
||||||
- **Investigate only** - Do not implement fixes during investigation unless explicitly requested
|
|
||||||
- **Report findings** - Share discovered information clearly
|
|
||||||
- **Ask for direction** - After investigation, ask the user what to do next
|
|
||||||
|
|
||||||
### Tool Usage Discipline
|
|
||||||
|
|
||||||
- **Do not ask users to run commands** — Always run the commands yourself.
|
|
||||||
- **Do not repeat the user’s instructions verbatim** — Summarize them in your own words.
|
|
||||||
- **Be explicit about results** — Tell the user what happened after every command.
|
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user