bingocode 1.1.103 → 1.1.105
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 +1 -1
- package/src/manager/CliMenuManager.tsx +1238 -1234
- package/src/manager/CliMenuUi.tsx +1 -1
- package/src/manager/TopToolbar.tsx +128 -111
- package/.claude/settings.local.json +0 -9
|
@@ -1,111 +1,128 @@
|
|
|
1
|
-
//@C:M ID=M.UI.TopToolbar;K=M;V=1.2;P=top toolbar;D=CLI;M=cli;S=ui
|
|
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.2;P=top toolbar;D=CLI;M=cli;S=ui
|
|
2
|
+
import React, { memo, useMemo } from 'react';
|
|
3
|
+
import { Box } 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
|
+
export const TopToolbar: React.FC<Props> = memo(({ ready, page, animEnabled, tipsEnabled }) => {
|
|
57
|
+
const [theme] = useTheme();
|
|
58
|
+
|
|
59
|
+
// Polling for window count
|
|
60
|
+
const [windowCount, setWindowCount] = React.useState(0);
|
|
61
|
+
React.useEffect(() => {
|
|
62
|
+
const update = () => setWindowCount(countLeases());
|
|
63
|
+
update();
|
|
64
|
+
const id = setInterval(update, 10000);
|
|
65
|
+
return () => clearInterval(id);
|
|
66
|
+
}, []);
|
|
67
|
+
|
|
68
|
+
// Only read config when ready
|
|
69
|
+
const { projectName } = useMemo(() => {
|
|
70
|
+
if (!ready) {
|
|
71
|
+
return { projectName: '' };
|
|
72
|
+
}
|
|
73
|
+
const _cwd = getCwd();
|
|
74
|
+
let _projectName = '';
|
|
75
|
+
try {
|
|
76
|
+
const prj = getCurrentProjectConfig();
|
|
77
|
+
_projectName = (prj && (prj.name || prj.projectName || prj.id)) || (typeof _cwd === 'string' ? basename(_cwd) : '');
|
|
78
|
+
} catch {
|
|
79
|
+
_projectName = typeof _cwd === 'string' ? basename(_cwd) : '';
|
|
80
|
+
}
|
|
81
|
+
return { projectName: _projectName };
|
|
82
|
+
}, [ready]);
|
|
83
|
+
|
|
84
|
+
// Theme name
|
|
85
|
+
const themeLabel = String(theme || (ready ? (getGlobalConfig()?.theme ?? 'system') : '…'));
|
|
86
|
+
|
|
87
|
+
// Static Clawd pose
|
|
88
|
+
const clawdPose: ClawdPose = useMemo(() => {
|
|
89
|
+
if (!ready) return 'default';
|
|
90
|
+
if (page === null) return animEnabled ? 'arms-up' : 'default';
|
|
91
|
+
return tipsEnabled ? 'look-left' : 'look-right';
|
|
92
|
+
}, [ready, page, animEnabled, tipsEnabled]);
|
|
93
|
+
|
|
94
|
+
const uiTone = (String(theme) === 'dark') ? 'accent' : (String(theme) === 'highContrast' ? 'warning' : 'info');
|
|
95
|
+
|
|
96
|
+
return (
|
|
97
|
+
<Box flexDirection="row" width="100%" alignItems="center" justifyContent="space-between" minHeight={3}>
|
|
98
|
+
{/* Left: Clawd Icon + Window Indicators */}
|
|
99
|
+
<Box alignItems="center">
|
|
100
|
+
<Box marginRight={2}>
|
|
101
|
+
{animEnabled ? <AnimatedClawd /> : <Clawd pose={clawdPose} />}
|
|
102
|
+
</Box>
|
|
103
|
+
|
|
104
|
+
{/* Visual Window Grid (Mini-mobs) */}
|
|
105
|
+
<Box flexDirection="row" flexWrap="wrap">
|
|
106
|
+
{Array.from({ length: windowCount }).map((_, i) => (
|
|
107
|
+
<Box key={i} marginRight={1}>
|
|
108
|
+
<Clawd pose="default" />
|
|
109
|
+
</Box>
|
|
110
|
+
))}
|
|
111
|
+
</Box>
|
|
112
|
+
</Box>
|
|
113
|
+
|
|
114
|
+
{/* Right: Status Info Chips */}
|
|
115
|
+
<Box flexDirection="row">
|
|
116
|
+
<Chip label="Theme" value={themeLabel} tone="accent" />
|
|
117
|
+
<Chip label="Project" value={projectName || '—'} tone="info" />
|
|
118
|
+
<Chip
|
|
119
|
+
label="UI"
|
|
120
|
+
value={`Anim ${animEnabled ? 'On' : 'Off'} · Tips ${tipsEnabled ? 'On' : 'Off'}`}
|
|
121
|
+
tone={uiTone as any}
|
|
122
|
+
/>
|
|
123
|
+
</Box>
|
|
124
|
+
</Box>
|
|
125
|
+
);
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
export default TopToolbar;
|