bloby-bot 0.47.9 → 0.47.10

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.
@@ -46,10 +46,10 @@ const ACCESS_LABELS: Record<AccessMethod, string> = {
46
46
  /* ── Provider config ── */
47
47
 
48
48
  const PROVIDERS = [
49
- { id: 'pi', name: 'Pi', subtitle: 'Bring your own model', icon: '/icons/pi.svg', comingSoon: false },
50
- { id: 'bloby', name: 'Bloby', subtitle: 'Coming Soon..', icon: '/bloby-icon-192.png', comingSoon: true },
51
- { id: 'anthropic', name: 'Claude', subtitle: 'by Anthropic', icon: '/icons/claude.png', comingSoon: false },
52
- { id: 'openai', name: 'OpenAI Codex', subtitle: 'ChatGPT Plus / Pro', icon: '/icons/codex.png', comingSoon: false },
49
+ { id: 'pi', name: 'Pi', subtitle: 'Bring your own\nmodel', icon: '/pi-logo.svg', comingSoon: false },
50
+ { id: 'bloby', name: 'Bloby', subtitle: 'Coming Soon..', icon: '/bloby.png', comingSoon: true },
51
+ { id: 'anthropic', name: 'Claude', subtitle: 'by\nAnthropic', icon: '/icons/claude.png', comingSoon: false },
52
+ { id: 'openai', name: 'OpenAI Codex', subtitle: 'ChatGPT\nPlus / Pro', icon: '/icons/codex.png', comingSoon: false },
53
53
  ] as const;
54
54
 
55
55
  const MODELS: Record<string, { id: string; label: string }[]> = {
@@ -113,17 +113,17 @@ function ModelDropdown({ models, value, onChange }: { models: { id: string; labe
113
113
  const selected = models.find((m) => m.id === value);
114
114
 
115
115
  return (
116
- <div className="relative">
116
+ <div className="relative min-w-0">
117
117
  <button
118
118
  ref={btnRef}
119
119
  type="button"
120
120
  onClick={() => setOpen((o) => !o)}
121
- className="w-full flex items-center justify-between bg-white/[0.03] border border-white/[0.08] text-white rounded-xl px-4 py-2.5 text-[13px] outline-none hover:border-white/15 focus:border-[#AF27E3]/30 transition-colors"
121
+ className="w-full flex items-center justify-between gap-2 bg-white/[0.03] border border-white/[0.08] text-white rounded-xl px-4 py-2.5 text-[13px] outline-none hover:border-white/15 focus:border-[#AF27E3]/30 transition-colors overflow-hidden"
122
122
  >
123
- <span className={selected ? 'text-white' : 'text-white/20'}>
123
+ <span className={`min-w-0 truncate text-left ${selected ? 'text-white' : 'text-white/20'}`}>
124
124
  {selected ? selected.label : 'Choose a model...'}
125
125
  </span>
126
- <ChevronDown className={`h-4 w-4 text-white/30 transition-transform ${open ? 'rotate-180' : ''}`} />
126
+ <ChevronDown className={`h-4 w-4 shrink-0 text-white/30 transition-transform ${open ? 'rotate-180' : ''}`} />
127
127
  </button>
128
128
  {open && pos && createPortal(
129
129
  <div
@@ -279,6 +279,10 @@ export default function OnboardWizard({ onComplete, isInitialSetup = false, onSa
279
279
  const [portalOldPassError, setPortalOldPassError] = useState('');
280
280
  const [portalOldPassVerified, setPortalOldPassVerified] = useState(false);
281
281
  const [portalVerifying, setPortalVerifying] = useState(false);
282
+ // When the portal already has credentials, password fields are hidden by
283
+ // default so the user doesn't think they must re-authenticate to proceed.
284
+ // Toggling this opens the change-password sub-form.
285
+ const [portalChangeMode, setPortalChangeMode] = useState(false);
282
286
 
283
287
  // Whisper (step 5)
284
288
  const [whisperEnabled, setWhisperEnabled] = useState(false);
@@ -1696,29 +1700,65 @@ export default function OnboardWizard({ onComplete, isInitialSetup = false, onSa
1696
1700
  transition={{ duration: 0.15 }}
1697
1701
  >
1698
1702
  <h1 className="text-xl font-bold text-white tracking-tight">
1699
- Set a password
1703
+ {portalExists ? 'Password & 2FA' : 'Set a password'}
1700
1704
  </h1>
1701
1705
  <p className="text-white/40 text-[13px] mt-1.5 leading-relaxed">
1702
- You'll need this password to access your agent's chat. Keep it safe — anyone with your URL will need it to log in.
1706
+ {portalExists
1707
+ ? "Your portal password is already set — you can keep it as-is or change it below."
1708
+ : "You'll need this password to access your agent's chat. Keep it safe — anyone with your URL will need it to log in."}
1703
1709
  </p>
1704
1710
 
1705
- {portalExists && (
1706
- <div className="mt-4 bg-white/[0.02] border border-white/[0.06] rounded-xl px-4 py-2.5">
1707
- <p className="text-white/40 text-[12px]">Password already set. Leave fields empty to keep your current password, or enter your current password to change it.</p>
1711
+ {/* ── Existing-password collapsed state: just a "Change password" pill ── */}
1712
+ {portalExists && !portalChangeMode && (
1713
+ <div className="mt-5 flex items-center justify-between bg-white/[0.02] border border-white/[0.06] rounded-xl px-4 py-3">
1714
+ <div>
1715
+ <p className="text-white/70 text-[13px] font-medium">Portal password</p>
1716
+ <p className="text-white/30 text-[11px] mt-0.5">Already configured — click to change it.</p>
1717
+ </div>
1718
+ <button
1719
+ type="button"
1720
+ onClick={() => {
1721
+ setPortalChangeMode(true);
1722
+ setPortalOldPass('');
1723
+ setPortalOldPassError('');
1724
+ setPortalOldPassVerified(false);
1725
+ setPortalPass('');
1726
+ setPortalPassConfirm('');
1727
+ }}
1728
+ className="shrink-0 px-3.5 py-2 bg-white/[0.04] hover:bg-white/[0.08] text-white/70 hover:text-white text-[12px] font-medium rounded-lg transition-colors"
1729
+ >
1730
+ Change password
1731
+ </button>
1708
1732
  </div>
1709
1733
  )}
1710
1734
 
1711
- {portalExists && (
1735
+ {/* ── Existing-password expanded: current password verify step ── */}
1736
+ {portalExists && portalChangeMode && (
1712
1737
  <div className="mt-5">
1713
- <label className="text-[12px] text-white/40 font-medium mb-1.5 block">Current password</label>
1738
+ <div className="flex items-center justify-between mb-1.5">
1739
+ <label className="text-[12px] text-white/40 font-medium">Current password</label>
1740
+ <button
1741
+ type="button"
1742
+ onClick={() => {
1743
+ setPortalChangeMode(false);
1744
+ setPortalOldPass('');
1745
+ setPortalOldPassError('');
1746
+ setPortalOldPassVerified(false);
1747
+ setPortalPass('');
1748
+ setPortalPassConfirm('');
1749
+ }}
1750
+ className="text-white/30 hover:text-white/60 text-[11px] transition-colors"
1751
+ >
1752
+ Cancel
1753
+ </button>
1754
+ </div>
1714
1755
  <div className="flex items-center gap-2">
1715
1756
  <input
1716
1757
  type="password"
1717
1758
  value={portalOldPass}
1718
1759
  onChange={(e) => { setPortalOldPass(e.target.value); setPortalOldPassError(''); setPortalOldPassVerified(false); }}
1719
- placeholder="Enter current password to change it"
1760
+ placeholder="Enter your current password"
1720
1761
  autoComplete="current-password"
1721
- autoFocus
1722
1762
  className={inputCls + ' flex-1'}
1723
1763
  />
1724
1764
  {portalOldPass.length > 0 && !portalOldPassVerified && (
@@ -1762,7 +1802,8 @@ export default function OnboardWizard({ onComplete, isInitialSetup = false, onSa
1762
1802
  </div>
1763
1803
  )}
1764
1804
 
1765
- {(!portalExists || portalOldPassVerified) && (
1805
+ {/* ── New-password fields: first-time onboard OR verified change-mode ── */}
1806
+ {(!portalExists || (portalChangeMode && portalOldPassVerified)) && (
1766
1807
  <>
1767
1808
  <div className={portalExists ? 'mt-3' : 'mt-5'}>
1768
1809
  <label className="text-[12px] text-white/40 font-medium mb-1.5 block">
@@ -1816,6 +1857,16 @@ export default function OnboardWizard({ onComplete, isInitialSetup = false, onSa
1816
1857
  setTotpEnabled(true);
1817
1858
  setTotpError('');
1818
1859
  setTotpCode('');
1860
+ // Enabling 2FA on an existing portal requires the current
1861
+ // password to authenticate the setup call. If the user hasn't
1862
+ // entered it yet, open change-mode so the current-password
1863
+ // field becomes visible and surface a clear error.
1864
+ if (portalExists && !portalOldPassVerified) {
1865
+ setPortalChangeMode(true);
1866
+ setTotpError('Enter your current portal password above first, then toggle 2FA again.');
1867
+ setTotpEnabled(false);
1868
+ return;
1869
+ }
1819
1870
  // Fetch QR if not already loaded
1820
1871
  if (!totpQrUri) {
1821
1872
  try {
@@ -2194,15 +2245,15 @@ export default function OnboardWizard({ onComplete, isInitialSetup = false, onSa
2194
2245
  >
2195
2246
  <div className="flex flex-col items-center gap-1.5 py-0.5">
2196
2247
  {p.icon ? (
2197
- <img src={p.icon} alt={p.name} className="w-8 h-8 rounded-lg" />
2248
+ <img src={p.icon} alt={p.name} className="w-9 h-9 object-contain" />
2198
2249
  ) : (
2199
- <div className="w-8 h-8 rounded-lg bg-white/[0.06] flex items-center justify-center text-white/50 text-sm font-bold">
2250
+ <div className="w-9 h-9 rounded-lg bg-white/[0.06] flex items-center justify-center text-white/50 text-sm font-bold">
2200
2251
  O
2201
2252
  </div>
2202
2253
  )}
2203
2254
  <div className="text-center">
2204
2255
  <div className="text-[13px] font-medium text-white">{p.name}</div>
2205
- <div className="text-[10px] text-white/30">{p.subtitle}</div>
2256
+ <div className="text-[10px] text-white/30 whitespace-pre-line leading-tight">{p.subtitle}</div>
2206
2257
  </div>
2207
2258
  </div>
2208
2259
  {authState[p.id] === 'connected' ? (
@@ -40,6 +40,8 @@ const PLATFORM_ASSETS = new Set([
40
40
  '/bloby-badge.png',
41
41
  '/bloby-favicon.png',
42
42
  '/bloby_frame1.png',
43
+ '/bloby.png',
44
+ '/pi-logo.svg',
43
45
  '/manifest.json',
44
46
  ]);
45
47
 
Binary file
@@ -0,0 +1,20 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 800 800">
3
+ <path fill="#fff" fill-rule="evenodd" d="
4
+ M165.29 165.29
5
+ H517.36
6
+ V400
7
+ H400
8
+ V517.36
9
+ H282.65
10
+ V634.72
11
+ H165.29
12
+ Z
13
+ M282.65 282.65
14
+ V400
15
+ H400
16
+ V282.65
17
+ Z
18
+ "/>
19
+ <path fill="#fff" d="M517.36 400 H634.72 V634.72 H517.36 Z"/>
20
+ </svg>
@@ -1 +0,0 @@
1
- import{i as e}from"./bloby-BOSem5eq.js";export{e as Mermaid};