claude-think 0.3.0 → 0.3.1

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 CHANGED
@@ -5,6 +5,14 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [0.3.1] - 2025-02-05
9
+
10
+ ### Fixed
11
+ - Responsive TUI - adapts to terminal width:
12
+ - Narrow terminals (<80 cols): compact nav labels, shorter status
13
+ - Very narrow (<50 cols): minimal header, single nav indicator
14
+ - Footer shortcuts adjust to available space
15
+
8
16
  ## [0.3.0] - 2025-02-05
9
17
 
10
18
  ### Added
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-think",
3
- "version": "0.3.0",
3
+ "version": "0.3.1",
4
4
  "description": "Personal context manager for Claude - manage your preferences, patterns, and memory",
5
5
  "author": "Amit Feldman",
6
6
  "license": "MIT",
package/src/tui/App.tsx CHANGED
@@ -1,5 +1,5 @@
1
1
  import React, { useState, useEffect } from "react";
2
- import { Box, Text, useInput, useApp } from "ink";
2
+ import { Box, Text, useInput, useApp, useStdout } from "ink";
3
3
  import { Navigation } from "./components/Navigation";
4
4
  import { Profile } from "./components/Profile";
5
5
  import { Preferences } from "./components/Preferences";
@@ -30,11 +30,17 @@ type Modal = "none" | "help" | "actions" | "preview" | "search";
30
30
 
31
31
  export function App() {
32
32
  const { exit } = useApp();
33
+ const { stdout } = useStdout();
33
34
  const [section, setSection] = useState<Section>("profile");
34
35
  const [modal, setModal] = useState<Modal>("none");
35
36
  const [statusMessage, setStatusMessage] = useState<string | undefined>();
36
37
  const [initialized, setInitialized] = useState(false);
37
38
 
39
+ // Get terminal dimensions
40
+ const width = stdout?.columns ?? 80;
41
+ const isNarrow = width < 80;
42
+ const isVeryNarrow = width < 50;
43
+
38
44
  useEffect(() => {
39
45
  setInitialized(existsSync(CONFIG.thinkDir));
40
46
  }, []);
@@ -97,7 +103,7 @@ export function App() {
97
103
  if (modal === "actions") {
98
104
  return (
99
105
  <Box flexDirection="column" padding={1}>
100
- <Header />
106
+ <Header width={width} />
101
107
  <QuickActions
102
108
  onMessage={handleMessage}
103
109
  onClose={() => setModal("none")}
@@ -109,7 +115,7 @@ export function App() {
109
115
  if (modal === "preview") {
110
116
  return (
111
117
  <Box flexDirection="column" padding={1}>
112
- <Header />
118
+ <Header width={width} />
113
119
  <Preview onClose={() => setModal("none")} />
114
120
  </Box>
115
121
  );
@@ -118,7 +124,7 @@ export function App() {
118
124
  if (modal === "search") {
119
125
  return (
120
126
  <Box flexDirection="column" padding={1}>
121
- <Header />
127
+ <Header width={width} />
122
128
  <Search onClose={() => setModal("none")} />
123
129
  </Box>
124
130
  );
@@ -147,7 +153,7 @@ export function App() {
147
153
 
148
154
  return (
149
155
  <Box flexDirection="column">
150
- <Header />
156
+ <Header width={width} />
151
157
 
152
158
  <Navigation currentSection={section} onSectionChange={setSection} />
153
159
 
@@ -168,20 +174,33 @@ export function App() {
168
174
 
169
175
  <Box marginTop={1}>
170
176
  <Text color="gray">
171
- Tab: sections | a: actions | p: preview | /: search | ?: help | q: quit
177
+ {isNarrow
178
+ ? "Tab:nav a:act p:prev /:search ?:help q:quit"
179
+ : "Tab: sections | a: actions | p: preview | /: search | ?: help | q: quit"}
172
180
  </Text>
173
181
  </Box>
174
182
  </Box>
175
183
  );
176
184
  }
177
185
 
178
- function Header() {
186
+ function Header({ width }: { width: number }) {
187
+ // Full banner needs ~45 chars, compact needs ~25
188
+ if (width >= 50) {
189
+ return (
190
+ <Box marginBottom={1}>
191
+ <Text color="green" bold>
192
+ ▀█▀ █░█ █ █▄░█ █▄▀
193
+ </Text>
194
+ <Text color="gray"> Personal Context for Claude</Text>
195
+ </Box>
196
+ );
197
+ }
198
+
199
+ // Compact header for narrow terminals
179
200
  return (
180
201
  <Box marginBottom={1}>
181
- <Text color="green" bold>
182
- ▀█▀ █░█ █▄░█ █▄▀
183
- </Text>
184
- <Text color="gray"> Personal Context for Claude</Text>
202
+ <Text color="green" bold>think</Text>
203
+ <Text color="gray"> - Claude Context</Text>
185
204
  </Box>
186
205
  );
187
206
  }
@@ -1,5 +1,5 @@
1
1
  import React from "react";
2
- import { Box, Text, useInput } from "ink";
2
+ import { Box, Text, useInput, useStdout } from "ink";
3
3
 
4
4
  type Section =
5
5
  | "profile"
@@ -15,38 +15,76 @@ interface NavigationProps {
15
15
  onSectionChange: (section: Section) => void;
16
16
  }
17
17
 
18
- const sections: { key: Section; label: string }[] = [
19
- { key: "profile", label: "Profile" },
20
- { key: "preferences", label: "Preferences" },
21
- { key: "memory", label: "Memory" },
22
- { key: "permissions", label: "Permissions" },
23
- { key: "skills", label: "Skills" },
24
- { key: "agents", label: "Agents" },
25
- { key: "automation", label: "Automation" },
18
+ const sections: { key: Section; label: string; short: string }[] = [
19
+ { key: "profile", label: "Profile", short: "Prof" },
20
+ { key: "preferences", label: "Preferences", short: "Pref" },
21
+ { key: "memory", label: "Memory", short: "Mem" },
22
+ { key: "permissions", label: "Permissions", short: "Perm" },
23
+ { key: "skills", label: "Skills", short: "Skill" },
24
+ { key: "agents", label: "Agents", short: "Agent" },
25
+ { key: "automation", label: "Automation", short: "Auto" },
26
26
  ];
27
27
 
28
28
  export function Navigation({
29
29
  currentSection,
30
30
  onSectionChange,
31
31
  }: NavigationProps) {
32
+ const { stdout } = useStdout();
33
+ const width = stdout?.columns ?? 80;
34
+ const isNarrow = width < 80;
35
+ const isVeryNarrow = width < 50;
36
+
32
37
  useInput((input, key) => {
33
38
  if (key.tab) {
34
39
  const currentIndex = sections.findIndex((s) => s.key === currentSection);
35
40
  const nextIndex = key.shift
36
41
  ? (currentIndex - 1 + sections.length) % sections.length
37
42
  : (currentIndex + 1) % sections.length;
38
- onSectionChange(sections[nextIndex].key);
43
+ onSectionChange(sections[nextIndex]!.key);
39
44
  }
40
45
 
41
46
  // Number keys for quick navigation
42
47
  const num = parseInt(input);
43
48
  if (num >= 1 && num <= sections.length) {
44
- onSectionChange(sections[num - 1].key);
49
+ onSectionChange(sections[num - 1]!.key);
45
50
  }
46
51
  });
47
52
 
53
+ // Very narrow: show only current + numbers
54
+ if (isVeryNarrow) {
55
+ const currentIdx = sections.findIndex((s) => s.key === currentSection);
56
+ const current = sections[currentIdx]!;
57
+ return (
58
+ <Box>
59
+ <Text color="green" bold>
60
+ [{currentIdx + 1}/{sections.length}] {current.label}
61
+ </Text>
62
+ <Text color="gray"> (Tab/1-7)</Text>
63
+ </Box>
64
+ );
65
+ }
66
+
67
+ // Narrow: use short labels
68
+ if (isNarrow) {
69
+ return (
70
+ <Box flexWrap="wrap">
71
+ {sections.map((section, index) => (
72
+ <Box key={section.key} marginRight={1}>
73
+ <Text
74
+ color={currentSection === section.key ? "green" : "gray"}
75
+ bold={currentSection === section.key}
76
+ >
77
+ {index + 1}.{section.short}
78
+ </Text>
79
+ </Box>
80
+ ))}
81
+ </Box>
82
+ );
83
+ }
84
+
85
+ // Full width: show full labels with indicator
48
86
  return (
49
- <Box>
87
+ <Box flexWrap="wrap">
50
88
  {sections.map((section, index) => (
51
89
  <Box key={section.key} marginRight={1}>
52
90
  <Text
@@ -1,5 +1,5 @@
1
1
  import React, { useState, useEffect } from "react";
2
- import { Box, Text } from "ink";
2
+ import { Box, Text, useStdout } from "ink";
3
3
  import { existsSync, statSync } from "fs";
4
4
  import { readFile } from "fs/promises";
5
5
  import { CONFIG, thinkPath } from "../../core/config";
@@ -43,6 +43,10 @@ export function StatusBar({ message }: StatusBarProps) {
43
43
  }
44
44
  }
45
45
 
46
+ const { stdout } = useStdout();
47
+ const width = stdout?.columns ?? 80;
48
+ const isNarrow = width < 60;
49
+
46
50
  return (
47
51
  <Box borderStyle="single" borderColor="gray" paddingX={1}>
48
52
  <Box flexGrow={1}>
@@ -52,18 +56,18 @@ export function StatusBar({ message }: StatusBarProps) {
52
56
  <Text color="gray">Ready</Text>
53
57
  )}
54
58
  </Box>
55
- <Box marginLeft={2}>
59
+ <Box marginLeft={1}>
56
60
  <Text color="green">{learningsCount}</Text>
57
- <Text color="gray"> learnings</Text>
61
+ <Text color="gray">{isNarrow ? "L" : " learnings"}</Text>
58
62
  </Box>
59
63
  {pendingCount > 0 && (
60
- <Box marginLeft={2}>
64
+ <Box marginLeft={1}>
61
65
  <Text color="yellow">{pendingCount}</Text>
62
- <Text color="gray"> pending</Text>
66
+ <Text color="gray">{isNarrow ? "P" : " pending"}</Text>
63
67
  </Box>
64
68
  )}
65
- {lastSync && (
66
- <Box marginLeft={2}>
69
+ {lastSync && !isNarrow && (
70
+ <Box marginLeft={1}>
67
71
  <Text color="gray">synced {lastSync}</Text>
68
72
  </Box>
69
73
  )}