drexler 0.2.2 → 0.2.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +8 -0
- package/package.json +1 -1
- package/src/ui/App.tsx +2 -9
- package/src/ui/TranscriptViewport.tsx +56 -11
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.2.4
|
|
4
|
+
|
|
5
|
+
- Improved transcript readability with distinct user and Drexler turn blocks, role-specific accents, and clearer body markers.
|
|
6
|
+
|
|
7
|
+
## 0.2.3
|
|
8
|
+
|
|
9
|
+
- Restored full-terminal-width interactive chrome, including the chat input bar.
|
|
10
|
+
|
|
3
11
|
## 0.2.2
|
|
4
12
|
|
|
5
13
|
- Added argument suggestions in the slash command palette for `/theme`, `/startup`, `/retry`, `/export`, and `/model`.
|
package/package.json
CHANGED
package/src/ui/App.tsx
CHANGED
|
@@ -41,7 +41,6 @@ import { ThemeProvider } from "./ThemeContext.tsx";
|
|
|
41
41
|
import { TranscriptViewport } from "./TranscriptViewport.tsx";
|
|
42
42
|
import { getActiveTheme, THEMES } from "./themes.ts";
|
|
43
43
|
|
|
44
|
-
const MAX_INPUT_WIDTH = 80;
|
|
45
44
|
const TRANSCRIPT_CHROME_ROWS = 12;
|
|
46
45
|
|
|
47
46
|
export function transcriptRowsForTerminalRows(rows: number): number {
|
|
@@ -111,14 +110,8 @@ export function App({ conversation, config, mood = "neutral", fetchFn }: AppProp
|
|
|
111
110
|
};
|
|
112
111
|
}, [stdout]);
|
|
113
112
|
const mode = useMemo(() => pickLayout(cols), [cols]);
|
|
114
|
-
const inputWidth = useMemo(
|
|
115
|
-
|
|
116
|
-
[cols],
|
|
117
|
-
);
|
|
118
|
-
const chromeWidth = useMemo(
|
|
119
|
-
() => Math.max(1, Math.min(cols, MAX_INPUT_WIDTH)),
|
|
120
|
-
[cols],
|
|
121
|
-
);
|
|
113
|
+
const inputWidth = useMemo(() => Math.max(1, cols), [cols]);
|
|
114
|
+
const chromeWidth = useMemo(() => Math.max(1, cols), [cols]);
|
|
122
115
|
const statusBarWidth = useMemo(() => Math.max(1, inputWidth - 2), [inputWidth]);
|
|
123
116
|
const isCompact = mode === "very-narrow";
|
|
124
117
|
const maxTranscriptRows = useMemo(
|
|
@@ -35,6 +35,18 @@ const ROLE_LABELS: Record<TranscriptViewportItem["role"], string> = {
|
|
|
35
35
|
system: "SYSTEM",
|
|
36
36
|
};
|
|
37
37
|
|
|
38
|
+
const ROLE_DETAILS: Record<TranscriptViewportItem["role"], string> = {
|
|
39
|
+
user: "incoming memo",
|
|
40
|
+
assistant: "response ledger",
|
|
41
|
+
system: "system notice",
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
const ROLE_MARKERS: Record<TranscriptViewportItem["role"], string> = {
|
|
45
|
+
user: "›",
|
|
46
|
+
assistant: "│",
|
|
47
|
+
system: "!",
|
|
48
|
+
};
|
|
49
|
+
|
|
38
50
|
function lineCount(input: string): number {
|
|
39
51
|
if (input.length === 0) return 1;
|
|
40
52
|
return input.split("\n").length;
|
|
@@ -42,17 +54,30 @@ function lineCount(input: string): number {
|
|
|
42
54
|
|
|
43
55
|
function itemRows(item: TranscriptViewportItem, compact: boolean): number {
|
|
44
56
|
if (compact) return 1;
|
|
45
|
-
return
|
|
57
|
+
return 2 + lineCount(item.content);
|
|
46
58
|
}
|
|
47
59
|
|
|
48
|
-
function
|
|
60
|
+
function roleAccentColor(
|
|
49
61
|
role: TranscriptViewportItem["role"],
|
|
50
62
|
theme: ReturnType<typeof useTheme>,
|
|
51
63
|
): string {
|
|
52
64
|
if (role === "system") return theme.warning;
|
|
65
|
+
if (role === "user") return theme.warning;
|
|
53
66
|
return theme.primaryLight;
|
|
54
67
|
}
|
|
55
68
|
|
|
69
|
+
function roleBodyColor(
|
|
70
|
+
role: TranscriptViewportItem["role"],
|
|
71
|
+
theme: ReturnType<typeof useTheme>,
|
|
72
|
+
): string {
|
|
73
|
+
if (role === "system") return theme.dim;
|
|
74
|
+
return theme.text;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function rule(char: string, width: number): string {
|
|
78
|
+
return char.repeat(Math.max(0, width));
|
|
79
|
+
}
|
|
80
|
+
|
|
56
81
|
function DefaultTranscriptItem({
|
|
57
82
|
item,
|
|
58
83
|
compact,
|
|
@@ -64,18 +89,20 @@ function DefaultTranscriptItem({
|
|
|
64
89
|
}) {
|
|
65
90
|
const t = useTheme();
|
|
66
91
|
const label = ROLE_LABELS[item.role];
|
|
92
|
+
const accent = roleAccentColor(item.role, t);
|
|
67
93
|
|
|
68
94
|
if (compact) {
|
|
69
|
-
const
|
|
95
|
+
const marker = item.role === "assistant" ? "◆" : ROLE_MARKERS[item.role];
|
|
96
|
+
const prefix = `${label} ${marker} `;
|
|
70
97
|
const budget = Math.max(1, cols - displayWidth(prefix));
|
|
71
98
|
const firstLine = item.content.split("\n")[0] ?? "";
|
|
72
99
|
return (
|
|
73
100
|
<Box width={cols} flexShrink={1}>
|
|
74
|
-
<Text color={
|
|
101
|
+
<Text color={accent} bold>
|
|
75
102
|
{fitDisplayText(prefix, cols)}
|
|
76
103
|
</Text>
|
|
77
104
|
{displayWidth(prefix) < cols ? (
|
|
78
|
-
<Text color={item.role
|
|
105
|
+
<Text color={roleBodyColor(item.role, t)} wrap="truncate">
|
|
79
106
|
{fitDisplayText(firstLine, budget)}
|
|
80
107
|
</Text>
|
|
81
108
|
) : null}
|
|
@@ -83,20 +110,38 @@ function DefaultTranscriptItem({
|
|
|
83
110
|
);
|
|
84
111
|
}
|
|
85
112
|
|
|
86
|
-
const
|
|
113
|
+
const detail = ROLE_DETAILS[item.role];
|
|
114
|
+
const headerPrefix = `╭─ ${label} `;
|
|
115
|
+
const headerSuffix = ` ${detail}`;
|
|
116
|
+
const headerRuleWidth = Math.max(
|
|
117
|
+
0,
|
|
118
|
+
cols - displayWidth(headerPrefix) - displayWidth(headerSuffix),
|
|
119
|
+
);
|
|
120
|
+
const footerWidth = Math.max(1, cols - 1);
|
|
121
|
+
const bodyPrefix = `${ROLE_MARKERS[item.role]} `;
|
|
122
|
+
const contentWidth = Math.max(1, cols - displayWidth(bodyPrefix));
|
|
123
|
+
|
|
87
124
|
return (
|
|
88
125
|
<Box flexDirection="column" width={cols} flexShrink={1}>
|
|
89
|
-
<Text color={
|
|
90
|
-
{fitDisplayText(
|
|
126
|
+
<Text color={accent} bold wrap="truncate">
|
|
127
|
+
{fitDisplayText(
|
|
128
|
+
`${headerPrefix}${rule("─", headerRuleWidth)}${headerSuffix}`,
|
|
129
|
+
cols,
|
|
130
|
+
)}
|
|
91
131
|
</Text>
|
|
92
132
|
{item.content.split("\n").map((line, index) => (
|
|
93
|
-
<Box key={index}
|
|
94
|
-
<Text color={
|
|
95
|
-
|
|
133
|
+
<Box key={index} width={cols} flexShrink={1}>
|
|
134
|
+
<Text color={accent} bold={item.role === "user"}>
|
|
135
|
+
{bodyPrefix}
|
|
136
|
+
</Text>
|
|
137
|
+
<Text color={roleBodyColor(item.role, t)} wrap="truncate">
|
|
96
138
|
{fitDisplayText(line, contentWidth)}
|
|
97
139
|
</Text>
|
|
98
140
|
</Box>
|
|
99
141
|
))}
|
|
142
|
+
<Text color={item.role === "assistant" ? t.primaryDim : t.dim} wrap="truncate">
|
|
143
|
+
{fitDisplayText(`╰${rule("─", footerWidth)}`, cols)}
|
|
144
|
+
</Text>
|
|
100
145
|
</Box>
|
|
101
146
|
);
|
|
102
147
|
}
|