codemaxxing 0.1.1 → 0.1.2
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/dist/index.js +32 -6
- package/package.json +1 -1
- package/src/index.tsx +47 -4
package/dist/index.js
CHANGED
|
@@ -9,7 +9,7 @@ import { loadConfig, detectLocalProvider, parseCLIArgs, applyOverrides, listMode
|
|
|
9
9
|
import { listSessions, getSession, loadMessages } from "./utils/sessions.js";
|
|
10
10
|
import { execSync } from "child_process";
|
|
11
11
|
import { isGitRepo, getBranch, getStatus, getDiff, undoLastCommit } from "./utils/git.js";
|
|
12
|
-
import { getTheme, THEMES, DEFAULT_THEME } from "./themes.js";
|
|
12
|
+
import { getTheme, listThemes, THEMES, DEFAULT_THEME } from "./themes.js";
|
|
13
13
|
const VERSION = "0.1.0";
|
|
14
14
|
// ── Helpers ──
|
|
15
15
|
function formatTimeAgo(date) {
|
|
@@ -102,6 +102,8 @@ function App() {
|
|
|
102
102
|
const [inputKey, setInputKey] = useState(0);
|
|
103
103
|
const [sessionPicker, setSessionPicker] = useState(null);
|
|
104
104
|
const [sessionPickerIndex, setSessionPickerIndex] = useState(0);
|
|
105
|
+
const [themePicker, setThemePicker] = useState(false);
|
|
106
|
+
const [themePickerIndex, setThemePickerIndex] = useState(0);
|
|
105
107
|
const [approval, setApproval] = useState(null);
|
|
106
108
|
// Listen for paste events from stdin interceptor
|
|
107
109
|
useEffect(() => {
|
|
@@ -329,10 +331,10 @@ function App() {
|
|
|
329
331
|
if (trimmed.startsWith("/theme")) {
|
|
330
332
|
const themeName = trimmed.replace("/theme", "").trim();
|
|
331
333
|
if (!themeName) {
|
|
332
|
-
const
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
334
|
+
const themeKeys = listThemes();
|
|
335
|
+
const currentIdx = themeKeys.indexOf(theme.name.toLowerCase());
|
|
336
|
+
setThemePicker(true);
|
|
337
|
+
setThemePickerIndex(currentIdx >= 0 ? currentIdx : 0);
|
|
336
338
|
return;
|
|
337
339
|
}
|
|
338
340
|
if (!THEMES[themeName]) {
|
|
@@ -485,6 +487,30 @@ function App() {
|
|
|
485
487
|
return;
|
|
486
488
|
}
|
|
487
489
|
}
|
|
490
|
+
// Theme picker navigation
|
|
491
|
+
if (themePicker) {
|
|
492
|
+
const themeKeys = listThemes();
|
|
493
|
+
if (key.upArrow) {
|
|
494
|
+
setThemePickerIndex((prev) => (prev - 1 + themeKeys.length) % themeKeys.length);
|
|
495
|
+
return;
|
|
496
|
+
}
|
|
497
|
+
if (key.downArrow) {
|
|
498
|
+
setThemePickerIndex((prev) => (prev + 1) % themeKeys.length);
|
|
499
|
+
return;
|
|
500
|
+
}
|
|
501
|
+
if (key.return) {
|
|
502
|
+
const selected = themeKeys[themePickerIndex];
|
|
503
|
+
setTheme(getTheme(selected));
|
|
504
|
+
setThemePicker(false);
|
|
505
|
+
addMsg("info", `✅ Switched to theme: ${THEMES[selected].name}`);
|
|
506
|
+
return;
|
|
507
|
+
}
|
|
508
|
+
if (key.escape) {
|
|
509
|
+
setThemePicker(false);
|
|
510
|
+
return;
|
|
511
|
+
}
|
|
512
|
+
return;
|
|
513
|
+
}
|
|
488
514
|
// Session picker navigation
|
|
489
515
|
if (sessionPicker) {
|
|
490
516
|
if (key.upArrow) {
|
|
@@ -616,7 +642,7 @@ function App() {
|
|
|
616
642
|
default:
|
|
617
643
|
return _jsx(Text, { children: msg.text }, msg.id);
|
|
618
644
|
}
|
|
619
|
-
}), loading && !approval && !streaming && _jsx(NeonSpinner, { message: spinnerMsg, colors: theme.colors }), streaming && !loading && _jsx(StreamingIndicator, { colors: theme.colors }), approval && (_jsxs(Box, { flexDirection: "column", borderStyle: "single", borderColor: theme.colors.warning, paddingX: 1, marginTop: 1, children: [_jsxs(Text, { bold: true, color: theme.colors.warning, children: ["\u26A0 Approve ", approval.tool, "?"] }), approval.tool === "write_file" && approval.args.path ? (_jsxs(Text, { color: theme.colors.muted, children: [" 📄 ", String(approval.args.path)] })) : null, approval.tool === "write_file" && approval.args.content ? (_jsxs(Text, { color: theme.colors.muted, children: [" ", String(approval.args.content).split("\n").length, " lines, ", String(approval.args.content).length, "B"] })) : null, approval.tool === "run_command" && approval.args.command ? (_jsxs(Text, { color: theme.colors.muted, children: [" $ ", String(approval.args.command)] })) : null, _jsxs(Text, { children: [_jsx(Text, { color: theme.colors.success, bold: true, children: " [y]" }), _jsx(Text, { children: "es " }), _jsx(Text, { color: theme.colors.error, bold: true, children: "[n]" }), _jsx(Text, { children: "o " }), _jsx(Text, { color: theme.colors.primary, bold: true, children: "[a]" }), _jsx(Text, { children: "lways" })] })] })), sessionPicker && (_jsxs(Box, { flexDirection: "column", borderStyle: "single", borderColor: theme.colors.secondary, paddingX: 1, marginBottom: 0, children: [_jsx(Text, { bold: true, color: theme.colors.secondary, children: "Resume a session:" }), sessionPicker.map((s, i) => (_jsxs(Text, { children: [i === sessionPickerIndex ? _jsx(Text, { color: theme.colors.suggestion, bold: true, children: "▸ " }) : _jsx(Text, { children: " " }), _jsx(Text, { color: i === sessionPickerIndex ? theme.colors.suggestion : theme.colors.muted, children: s.display })] }, s.id))), _jsx(Text, { dimColor: true, children: " ↑↓ navigate · Enter select · Esc cancel" })] })), showSuggestions && (_jsxs(Box, { flexDirection: "column", borderStyle: "single", borderColor: theme.colors.muted, paddingX: 1, marginBottom: 0, children: [cmdMatches.slice(0, 6).map((c, i) => (_jsxs(Text, { children: [i === cmdIndex ? _jsx(Text, { color: theme.colors.suggestion, bold: true, children: "▸ " }) : _jsx(Text, { children: " " }), _jsx(Text, { color: i === cmdIndex ? theme.colors.suggestion : theme.colors.primary, bold: true, children: c.cmd }), _jsxs(Text, { color: theme.colors.muted, children: [" — ", c.desc] })] }, i))), _jsx(Text, { dimColor: true, children: " ↑↓ navigate · Tab select" })] })), _jsxs(Box, { borderStyle: "single", borderColor: approval ? theme.colors.warning : theme.colors.border, paddingX: 1, children: [_jsx(Text, { color: theme.colors.secondary, bold: true, children: "> " }), approval ? (_jsx(Text, { color: theme.colors.warning, children: "waiting for approval..." })) : ready && !loading ? (_jsxs(Box, { children: [pastedChunks.map((p) => (_jsxs(Text, { color: theme.colors.muted, children: ["[Pasted text #", p.id, " +", p.lines, " lines]"] }, p.id))), _jsx(TextInput, { value: input, onChange: (v) => { setInput(v); setCmdIndex(0); }, onSubmit: handleSubmit }, inputKey)] })) : (_jsx(Text, { dimColor: true, children: loading ? "waiting for response..." : "initializing..." }))] }), agent && (_jsx(Box, { paddingX: 2, children: _jsxs(Text, { dimColor: true, children: ["💬 ", agent.getContextLength(), " messages · ~", (() => {
|
|
645
|
+
}), loading && !approval && !streaming && _jsx(NeonSpinner, { message: spinnerMsg, colors: theme.colors }), streaming && !loading && _jsx(StreamingIndicator, { colors: theme.colors }), approval && (_jsxs(Box, { flexDirection: "column", borderStyle: "single", borderColor: theme.colors.warning, paddingX: 1, marginTop: 1, children: [_jsxs(Text, { bold: true, color: theme.colors.warning, children: ["\u26A0 Approve ", approval.tool, "?"] }), approval.tool === "write_file" && approval.args.path ? (_jsxs(Text, { color: theme.colors.muted, children: [" 📄 ", String(approval.args.path)] })) : null, approval.tool === "write_file" && approval.args.content ? (_jsxs(Text, { color: theme.colors.muted, children: [" ", String(approval.args.content).split("\n").length, " lines, ", String(approval.args.content).length, "B"] })) : null, approval.tool === "run_command" && approval.args.command ? (_jsxs(Text, { color: theme.colors.muted, children: [" $ ", String(approval.args.command)] })) : null, _jsxs(Text, { children: [_jsx(Text, { color: theme.colors.success, bold: true, children: " [y]" }), _jsx(Text, { children: "es " }), _jsx(Text, { color: theme.colors.error, bold: true, children: "[n]" }), _jsx(Text, { children: "o " }), _jsx(Text, { color: theme.colors.primary, bold: true, children: "[a]" }), _jsx(Text, { children: "lways" })] })] })), themePicker && (_jsxs(Box, { flexDirection: "column", borderStyle: "single", borderColor: theme.colors.border, paddingX: 1, marginBottom: 0, children: [_jsx(Text, { bold: true, color: theme.colors.secondary, children: "Choose a theme:" }), listThemes().map((key, i) => (_jsxs(Text, { children: [i === themePickerIndex ? _jsx(Text, { color: theme.colors.suggestion, bold: true, children: "▸ " }) : _jsx(Text, { children: " " }), _jsx(Text, { color: i === themePickerIndex ? theme.colors.suggestion : theme.colors.primary, bold: true, children: key }), _jsxs(Text, { color: theme.colors.muted, children: [" — ", THEMES[key].description] }), key === theme.name.toLowerCase() ? _jsx(Text, { color: theme.colors.muted, children: " (current)" }) : null] }, key))), _jsx(Text, { dimColor: true, children: " ↑↓ navigate · Enter select · Esc cancel" })] })), sessionPicker && (_jsxs(Box, { flexDirection: "column", borderStyle: "single", borderColor: theme.colors.secondary, paddingX: 1, marginBottom: 0, children: [_jsx(Text, { bold: true, color: theme.colors.secondary, children: "Resume a session:" }), sessionPicker.map((s, i) => (_jsxs(Text, { children: [i === sessionPickerIndex ? _jsx(Text, { color: theme.colors.suggestion, bold: true, children: "▸ " }) : _jsx(Text, { children: " " }), _jsx(Text, { color: i === sessionPickerIndex ? theme.colors.suggestion : theme.colors.muted, children: s.display })] }, s.id))), _jsx(Text, { dimColor: true, children: " ↑↓ navigate · Enter select · Esc cancel" })] })), showSuggestions && (_jsxs(Box, { flexDirection: "column", borderStyle: "single", borderColor: theme.colors.muted, paddingX: 1, marginBottom: 0, children: [cmdMatches.slice(0, 6).map((c, i) => (_jsxs(Text, { children: [i === cmdIndex ? _jsx(Text, { color: theme.colors.suggestion, bold: true, children: "▸ " }) : _jsx(Text, { children: " " }), _jsx(Text, { color: i === cmdIndex ? theme.colors.suggestion : theme.colors.primary, bold: true, children: c.cmd }), _jsxs(Text, { color: theme.colors.muted, children: [" — ", c.desc] })] }, i))), _jsx(Text, { dimColor: true, children: " ↑↓ navigate · Tab select" })] })), _jsxs(Box, { borderStyle: "single", borderColor: approval ? theme.colors.warning : theme.colors.border, paddingX: 1, children: [_jsx(Text, { color: theme.colors.secondary, bold: true, children: "> " }), approval ? (_jsx(Text, { color: theme.colors.warning, children: "waiting for approval..." })) : ready && !loading ? (_jsxs(Box, { children: [pastedChunks.map((p) => (_jsxs(Text, { color: theme.colors.muted, children: ["[Pasted text #", p.id, " +", p.lines, " lines]"] }, p.id))), _jsx(TextInput, { value: input, onChange: (v) => { setInput(v); setCmdIndex(0); }, onSubmit: handleSubmit }, inputKey)] })) : (_jsx(Text, { dimColor: true, children: loading ? "waiting for response..." : "initializing..." }))] }), agent && (_jsx(Box, { paddingX: 2, children: _jsxs(Text, { dimColor: true, children: ["💬 ", agent.getContextLength(), " messages · ~", (() => {
|
|
620
646
|
const tokens = agent.estimateTokens();
|
|
621
647
|
return tokens >= 1000 ? `${(tokens / 1000).toFixed(1)}k` : String(tokens);
|
|
622
648
|
})(), " tokens", modelName ? ` · 🤖 ${modelName}` : ""] }) }))] }));
|
package/package.json
CHANGED
package/src/index.tsx
CHANGED
|
@@ -131,6 +131,8 @@ function App() {
|
|
|
131
131
|
const [inputKey, setInputKey] = useState(0);
|
|
132
132
|
const [sessionPicker, setSessionPicker] = useState<Array<{ id: string; display: string }> | null>(null);
|
|
133
133
|
const [sessionPickerIndex, setSessionPickerIndex] = useState(0);
|
|
134
|
+
const [themePicker, setThemePicker] = useState(false);
|
|
135
|
+
const [themePickerIndex, setThemePickerIndex] = useState(0);
|
|
134
136
|
const [approval, setApproval] = useState<{
|
|
135
137
|
tool: string;
|
|
136
138
|
args: Record<string, unknown>;
|
|
@@ -376,10 +378,10 @@ function App() {
|
|
|
376
378
|
if (trimmed.startsWith("/theme")) {
|
|
377
379
|
const themeName = trimmed.replace("/theme", "").trim();
|
|
378
380
|
if (!themeName) {
|
|
379
|
-
const
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
381
|
+
const themeKeys = listThemes();
|
|
382
|
+
const currentIdx = themeKeys.indexOf(theme.name.toLowerCase());
|
|
383
|
+
setThemePicker(true);
|
|
384
|
+
setThemePickerIndex(currentIdx >= 0 ? currentIdx : 0);
|
|
383
385
|
return;
|
|
384
386
|
}
|
|
385
387
|
if (!THEMES[themeName]) {
|
|
@@ -531,6 +533,31 @@ function App() {
|
|
|
531
533
|
}
|
|
532
534
|
}
|
|
533
535
|
|
|
536
|
+
// Theme picker navigation
|
|
537
|
+
if (themePicker) {
|
|
538
|
+
const themeKeys = listThemes();
|
|
539
|
+
if (key.upArrow) {
|
|
540
|
+
setThemePickerIndex((prev) => (prev - 1 + themeKeys.length) % themeKeys.length);
|
|
541
|
+
return;
|
|
542
|
+
}
|
|
543
|
+
if (key.downArrow) {
|
|
544
|
+
setThemePickerIndex((prev) => (prev + 1) % themeKeys.length);
|
|
545
|
+
return;
|
|
546
|
+
}
|
|
547
|
+
if (key.return) {
|
|
548
|
+
const selected = themeKeys[themePickerIndex];
|
|
549
|
+
setTheme(getTheme(selected));
|
|
550
|
+
setThemePicker(false);
|
|
551
|
+
addMsg("info", `✅ Switched to theme: ${THEMES[selected].name}`);
|
|
552
|
+
return;
|
|
553
|
+
}
|
|
554
|
+
if (key.escape) {
|
|
555
|
+
setThemePicker(false);
|
|
556
|
+
return;
|
|
557
|
+
}
|
|
558
|
+
return;
|
|
559
|
+
}
|
|
560
|
+
|
|
534
561
|
// Session picker navigation
|
|
535
562
|
if (sessionPicker) {
|
|
536
563
|
if (key.upArrow) {
|
|
@@ -737,6 +764,22 @@ function App() {
|
|
|
737
764
|
</Box>
|
|
738
765
|
)}
|
|
739
766
|
|
|
767
|
+
{/* ═══ THEME PICKER ═══ */}
|
|
768
|
+
{themePicker && (
|
|
769
|
+
<Box flexDirection="column" borderStyle="single" borderColor={theme.colors.border} paddingX={1} marginBottom={0}>
|
|
770
|
+
<Text bold color={theme.colors.secondary}>Choose a theme:</Text>
|
|
771
|
+
{listThemes().map((key, i) => (
|
|
772
|
+
<Text key={key}>
|
|
773
|
+
{i === themePickerIndex ? <Text color={theme.colors.suggestion} bold>{"▸ "}</Text> : <Text>{" "}</Text>}
|
|
774
|
+
<Text color={i === themePickerIndex ? theme.colors.suggestion : theme.colors.primary} bold>{key}</Text>
|
|
775
|
+
<Text color={theme.colors.muted}>{" — "}{THEMES[key].description}</Text>
|
|
776
|
+
{key === theme.name.toLowerCase() ? <Text color={theme.colors.muted}> (current)</Text> : null}
|
|
777
|
+
</Text>
|
|
778
|
+
))}
|
|
779
|
+
<Text dimColor>{" ↑↓ navigate · Enter select · Esc cancel"}</Text>
|
|
780
|
+
</Box>
|
|
781
|
+
)}
|
|
782
|
+
|
|
740
783
|
{/* ═══ SESSION PICKER ═══ */}
|
|
741
784
|
{sessionPicker && (
|
|
742
785
|
<Box flexDirection="column" borderStyle="single" borderColor={theme.colors.secondary} paddingX={1} marginBottom={0}>
|