bingocode 1.1.104 → 1.1.106
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/package.json
CHANGED
|
@@ -933,9 +933,9 @@ export const CliMenuManager: React.FC = () => {
|
|
|
933
933
|
<Box paddingX={2}>
|
|
934
934
|
<WelcomeV2 />
|
|
935
935
|
</Box>
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
936
|
+
<Box flexGrow={1} flexDirection="column" alignItems="flex-end" paddingRight={4}>
|
|
937
|
+
<Text dimColor>(version information)</Text>
|
|
938
|
+
</Box>
|
|
939
939
|
</Box>
|
|
940
940
|
{!apiUrl && !bootErr && (
|
|
941
941
|
<StateDisplay type="loading" message="Starting server..." />
|
|
@@ -1195,7 +1195,7 @@ export const CliMenuManager: React.FC = () => {
|
|
|
1195
1195
|
height={TOP_H}
|
|
1196
1196
|
homeLogo={<LogoV2 />}
|
|
1197
1197
|
compactLogo={<CondensedLogo />}
|
|
1198
|
-
ip={apiUrl ? apiUrl.replace(/^https?:\/\//, '') : undefined}
|
|
1198
|
+
ip={apiUrl ? apiUrl.replace(/^https?:\/\//, '').replace(':',' ') : undefined}
|
|
1199
1199
|
toolbar={
|
|
1200
1200
|
<TopToolbar
|
|
1201
1201
|
ready={configReady}
|
|
@@ -273,17 +273,10 @@ export const TopBar: React.FC<{
|
|
|
273
273
|
<Box width={width - 4} flexDirection="row" alignItems="flex-start">
|
|
274
274
|
{/* Left Section: Welcome Text & IP */}
|
|
275
275
|
<Box flexDirection="column" width={20} marginRight={2}>
|
|
276
|
-
|
|
277
|
-
<Box flexDirection="column">
|
|
278
|
-
<Text bold color="cyan">Welcome Bingo</Text>
|
|
279
|
-
<Text bold color="cyan">Code</Text>
|
|
280
|
-
</Box>
|
|
281
|
-
) : (
|
|
282
|
-
<Text bold color="cyan">Bingo Code</Text>
|
|
283
|
-
)}
|
|
276
|
+
<Text bold color="cyan">{isHome ? 'Welcome Bingo\nCode' : 'Bingo Code'}</Text>
|
|
284
277
|
{ip ? (
|
|
285
278
|
<Box marginTop={1}>
|
|
286
|
-
<Text color="
|
|
279
|
+
<Text color="green">IP: {ip.replace(' ','\n ')}</Text>
|
|
287
280
|
</Box>
|
|
288
281
|
) : null}
|
|
289
282
|
</Box>
|
|
@@ -1,111 +1,137 @@
|
|
|
1
|
-
//@C:M ID=M.UI.TopToolbar;K=M;V=1.
|
|
2
|
-
import React, { memo, useMemo } from 'react';
|
|
3
|
-
import { Box } from 'ink';
|
|
4
|
-
import { Chip
|
|
5
|
-
import { useTheme } from '../components/design-system/ThemeProvider.
|
|
6
|
-
import { getGlobalConfig, getCurrentProjectConfig
|
|
7
|
-
import { getCwd } from '../utils/cwd.js';
|
|
8
|
-
|
|
9
|
-
import
|
|
10
|
-
import {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
|
|
1
|
+
//@C:M ID=M.UI.TopToolbar;K=M;V=1.3;P=top toolbar;D=CLI;M=cli;S=ui
|
|
2
|
+
import React, { memo, useMemo } from 'react';
|
|
3
|
+
import { Box, Text } from 'ink';
|
|
4
|
+
import { Chip } from './CliMenuUi.tsx';
|
|
5
|
+
import { useTheme } from '../components/design-system/ThemeProvider.tsx';
|
|
6
|
+
import { getGlobalConfig, getCurrentProjectConfig } from '../utils/config.ts';
|
|
7
|
+
import { getCwd } from '../utils/cwd.js';
|
|
8
|
+
import type { ClawdPose } from '../components/LogoV2/Clawd.tsx';
|
|
9
|
+
import { Clawd } from '../components/LogoV2/Clawd.tsx';
|
|
10
|
+
import { AnimatedClawd } from '../components/LogoV2/AnimatedClawd.tsx';
|
|
11
|
+
|
|
12
|
+
import fs from 'fs';
|
|
13
|
+
import path from 'path';
|
|
14
|
+
import os from 'os';
|
|
15
|
+
|
|
16
|
+
type Props = {
|
|
17
|
+
ready: boolean;
|
|
18
|
+
page: string | null;
|
|
19
|
+
animEnabled: boolean;
|
|
20
|
+
tipsEnabled: boolean;
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
function countLeases(): number {
|
|
24
|
+
try {
|
|
25
|
+
const LEASES_DIR = path.join(os.homedir(), '.claude-cli', 'runtime', 'leases');
|
|
26
|
+
if (!fs.existsSync(LEASES_DIR)) return 0;
|
|
27
|
+
const files = fs.readdirSync(LEASES_DIR);
|
|
28
|
+
let alive = 0;
|
|
29
|
+
for (const f of files) {
|
|
30
|
+
try {
|
|
31
|
+
const p = path.join(LEASES_DIR, f);
|
|
32
|
+
const raw = fs.readFileSync(p, 'utf-8');
|
|
33
|
+
const data = JSON.parse(raw);
|
|
34
|
+
if (data?.pid) {
|
|
35
|
+
try {
|
|
36
|
+
process.kill(data.pid, 0);
|
|
37
|
+
alive++;
|
|
38
|
+
} catch {
|
|
39
|
+
// PID not alive
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
} catch {}
|
|
43
|
+
}
|
|
44
|
+
return alive;
|
|
45
|
+
} catch {
|
|
46
|
+
return 0;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function basename(p: string) {
|
|
51
|
+
if (!p) return '';
|
|
52
|
+
const parts = p.split(/[/\\]/).filter(Boolean);
|
|
53
|
+
return parts[parts.length - 1] || p;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Compact 1/6 size Mini-Clawd mascot string.
|
|
58
|
+
* Approx 3x2 characters.
|
|
59
|
+
*/
|
|
60
|
+
const MiniClawd = () => (
|
|
61
|
+
<Box flexDirection="column" marginRight={1}>
|
|
62
|
+
<Text color="cyan">▟█▙</Text>
|
|
63
|
+
<Text color="cyan">▜██</Text>
|
|
64
|
+
</Box>
|
|
65
|
+
);
|
|
66
|
+
|
|
67
|
+
export const TopToolbar: React.FC<Props> = memo(({ ready, page, animEnabled, tipsEnabled }) => {
|
|
68
|
+
const [theme] = useTheme();
|
|
69
|
+
|
|
70
|
+
// Polling for window count
|
|
71
|
+
const [windowCount, setWindowCount] = React.useState(0);
|
|
72
|
+
React.useEffect(() => {
|
|
73
|
+
const update = () => setWindowCount(countLeases());
|
|
74
|
+
update();
|
|
75
|
+
const id = setInterval(update, 10000); // 10s poll
|
|
76
|
+
return () => clearInterval(id);
|
|
77
|
+
}, []);
|
|
78
|
+
|
|
79
|
+
// Only read config when ready
|
|
80
|
+
const { projectName } = useMemo(() => {
|
|
81
|
+
if (!ready) {
|
|
82
|
+
return { projectName: '' };
|
|
83
|
+
}
|
|
84
|
+
const _cwd = getCwd();
|
|
85
|
+
let _projectName = '';
|
|
86
|
+
try {
|
|
87
|
+
const prj = getCurrentProjectConfig();
|
|
88
|
+
_projectName = (prj && (prj.name || prj.projectName || prj.id)) || (typeof _cwd === 'string' ? basename(_cwd) : '');
|
|
89
|
+
} catch {
|
|
90
|
+
_projectName = typeof _cwd === 'string' ? basename(_cwd) : '';
|
|
91
|
+
}
|
|
92
|
+
return { projectName: _projectName };
|
|
93
|
+
}, [ready]);
|
|
94
|
+
|
|
95
|
+
// Theme name
|
|
96
|
+
const themeLabel = String(theme || (ready ? (getGlobalConfig()?.theme ?? 'system') : '…'));
|
|
97
|
+
|
|
98
|
+
// Static Clawd pose
|
|
99
|
+
const clawdPose: ClawdPose = useMemo(() => {
|
|
100
|
+
if (!ready) return 'default';
|
|
101
|
+
if (page === null) return animEnabled ? 'arms-up' : 'default';
|
|
102
|
+
return tipsEnabled ? 'look-left' : 'look-right';
|
|
103
|
+
}, [ready, page, animEnabled, tipsEnabled]);
|
|
104
|
+
|
|
105
|
+
const uiTone = (String(theme) === 'dark') ? 'accent' : (String(theme) === 'highContrast' ? 'warning' : 'info');
|
|
106
|
+
|
|
107
|
+
return (
|
|
108
|
+
<Box flexDirection="row" width="100%" alignItems="flex-start" justifyContent="space-between">
|
|
109
|
+
{/* Left: Main Mascot + Compact Grid */}
|
|
110
|
+
<Box alignItems="flex-start">
|
|
111
|
+
<Box marginRight={2}>
|
|
112
|
+
{animEnabled ? <AnimatedClawd /> : <Clawd pose={clawdPose} />}
|
|
113
|
+
</Box>
|
|
114
|
+
|
|
115
|
+
{/* Visual Window Grid (Mini-mascots 1/6 size) */}
|
|
116
|
+
<Box flexDirection="row" flexWrap="wrap" maxWidth={40}>
|
|
117
|
+
{Array.from({ length: windowCount }).map((_, i) => (
|
|
118
|
+
<MiniClawd key={i} />
|
|
119
|
+
))}
|
|
120
|
+
</Box>
|
|
121
|
+
</Box>
|
|
122
|
+
|
|
123
|
+
{/* Right: Status Info Chips (Vertical Stack) */}
|
|
124
|
+
<Box flexDirection="column" alignItems="flex-end">
|
|
125
|
+
<Chip label="Theme" value={themeLabel} tone="accent" />
|
|
126
|
+
<Chip label="Project" value={projectName || '—'} tone="info" />
|
|
127
|
+
<Chip
|
|
128
|
+
label="UI"
|
|
129
|
+
value={tipsEnabled ? 'Tips On' : 'Tips Off'}
|
|
130
|
+
tone={uiTone as any}
|
|
131
|
+
/>
|
|
132
|
+
</Box>
|
|
133
|
+
</Box>
|
|
134
|
+
);
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
export default TopToolbar;
|