codebay 0.3.0 → 0.4.0
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/.mochi/manifest.json +297 -269
- package/.mochi/svelte-client/HydratableIsland-79z9xq4b.js +1 -0
- package/.mochi/svelte-client/_hydrate-AppShell_2rtnxn6pgp2rh-f5rzyjm8.js +2 -0
- package/.mochi/svelte-client/{_hydrate-AvatarsView_257s9yq1wwr4f-3w16y9jh.js → _hydrate-AvatarsView_257s9yq1wwr4f-fxyd5qx4.js} +2 -2
- package/.mochi/svelte-client/_hydrate-InstanceView_2ma45l9bybfhl-nv31ptdp.js +1 -0
- package/.mochi/svelte-client/_hydrate-SettingsView_8hmarwmf8onq-r9vvc7rx.js +28 -0
- package/.mochi/svelte-client/chunk-6eexkr6p.js +2 -0
- package/.mochi/svelte-client/chunk-7znwaf7t.js +2 -0
- package/.mochi/svelte-client/chunk-dz1019cy.js +1 -0
- package/.mochi/svelte-client/{chunk-qxwt25hn.js → chunk-nmf4dq86.js} +1 -1
- package/.mochi/svelte-client/{chunk-0jtmkpx4.js → chunk-ssa0ad2f.js} +2 -2
- package/.mochi/svelte-client/chunk-zmmb1c4b.js +2 -0
- package/.mochi/svelte-compile/{App-f0q5n4rk.server.js → App-9qjy14bc.server.js} +38 -23
- package/.mochi/svelte-compile/{Avatars-p8gfef7x.server.js → Avatars-sq8mjn6k.server.js} +2 -2
- package/.mochi/svelte-compile/{Instance-atjwsczx.server.js → Instance-13j59daw.server.js} +2 -2
- package/.mochi/svelte-compile/{Settings-q88xw6h8.server.js → Settings-p0s2awg1.server.js} +404 -103
- package/.mochi/svelte-compile/{chunk-9bjk7yx6.js → chunk-6ghzacpg.js} +1 -1
- package/.mochi/svelte-compile/{chunk-4kwy539a.js → chunk-bacb4b0r.js} +1 -1
- package/.mochi/svelte-compile/{chunk-sxqys3nw.js → chunk-dfe2km6a.js} +5 -2
- package/.mochi/svelte-compile/{chunk-v6796ga4.js → chunk-fpe16ywq.js} +28 -6
- package/.mochi/svelte-css/Brand-1bh2b800g5vrn.css +1 -0
- package/.mochi/svelte-css/SettingsView-3uycxa8z548m4.css +1 -0
- package/README.md +4 -0
- package/package.json +8 -8
- package/src/avatars/index.ts +5 -0
- package/src/components/AppBar.svelte +8 -1
- package/src/components/AppShell.svelte +17 -3
- package/src/components/Brand.svelte +15 -4
- package/src/components/DashboardView.svelte +5 -2
- package/src/components/IdeBar.svelte +9 -1
- package/src/components/InstanceCard.svelte +7 -3
- package/src/components/InstanceView.svelte +4 -1
- package/src/components/SettingsCog.svelte +9 -1
- package/src/components/SettingsView.svelte +476 -18
- package/src/components/TopBar.svelte +4 -1
- package/src/container-injections/claude-code-models.ts +74 -0
- package/src/container-injections/git-identity.ts +30 -3
- package/src/lib/injections.server.ts +3 -0
- package/src/lib/instances.server.ts +10 -1
- package/src/lib/popup-nav.ts +37 -0
- package/src/pages/App.svelte +10 -3
- package/src/pages/Settings.svelte +31 -0
- package/src/routes.ts +88 -2
- package/.mochi/svelte-client/HydratableIsland-wrq79y0w.js +0 -1
- package/.mochi/svelte-client/_hydrate-AppShell_2rtnxn6pgp2rh-faqf4hmc.js +0 -2
- package/.mochi/svelte-client/_hydrate-InstanceView_2ma45l9bybfhl-5g8meb6a.js +0 -1
- package/.mochi/svelte-client/_hydrate-SettingsView_8hmarwmf8onq-jsw4edxb.js +0 -23
- package/.mochi/svelte-client/chunk-04qv4w6w.js +0 -2
- package/.mochi/svelte-client/chunk-597d17x0.js +0 -1
- package/.mochi/svelte-client/chunk-5p31aqh0.js +0 -2
- package/.mochi/svelte-client/chunk-gjjhya9m.js +0 -2
- package/.mochi/svelte-css/Brand-1la7zw5uhcbl4.css +0 -1
- package/.mochi/svelte-css/SettingsView-1nfdwnm16cpp2.css +0 -1
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
import Power from '@lucide/svelte/icons/power';
|
|
5
5
|
import RotateCcw from '@lucide/svelte/icons/rotate-ccw';
|
|
6
6
|
import Volume2 from '@lucide/svelte/icons/volume-2';
|
|
7
|
+
import PawPrint from '@lucide/svelte/icons/paw-print';
|
|
7
8
|
import SunMoon from '@lucide/svelte/icons/sun-moon';
|
|
8
9
|
import ThemePicker from './ThemePicker.svelte';
|
|
9
10
|
import Layers from '@lucide/svelte/icons/layers';
|
|
@@ -11,6 +12,8 @@
|
|
|
11
12
|
import Trash2 from '@lucide/svelte/icons/trash-2';
|
|
12
13
|
import Hammer from '@lucide/svelte/icons/hammer';
|
|
13
14
|
import KeyRound from '@lucide/svelte/icons/key-round';
|
|
15
|
+
import UserCog from '@lucide/svelte/icons/user-cog';
|
|
16
|
+
import Cpu from '@lucide/svelte/icons/cpu';
|
|
14
17
|
import Variable from '@lucide/svelte/icons/variable';
|
|
15
18
|
import Plus from '@lucide/svelte/icons/plus';
|
|
16
19
|
import X from '@lucide/svelte/icons/x';
|
|
@@ -22,16 +25,23 @@
|
|
|
22
25
|
import { playChime, unlockAudio } from '../sound.ts';
|
|
23
26
|
import Button from './Button.svelte';
|
|
24
27
|
import CoinButton from './CoinButton.svelte';
|
|
28
|
+
import Avatar from './Avatar.svelte';
|
|
29
|
+
import { avatars, findAvatar, type AvatarArt } from '../avatars/index.ts';
|
|
30
|
+
import { installPopupBackTrap } from '../lib/popup-nav.ts';
|
|
25
31
|
|
|
26
32
|
/** Every settings form action fails with the same `{ error }` shape. */
|
|
27
33
|
type ActionFailure = { error: string };
|
|
28
34
|
|
|
29
35
|
let {
|
|
36
|
+
pet,
|
|
30
37
|
defaultImage,
|
|
31
38
|
builtinImage,
|
|
32
39
|
disableBuildCache,
|
|
33
40
|
copyIgnorePatterns,
|
|
34
41
|
builtinCopyIgnore,
|
|
42
|
+
gitIdentityEnabled,
|
|
43
|
+
gitIdentityName,
|
|
44
|
+
gitIdentityEmail,
|
|
35
45
|
dockerArch,
|
|
36
46
|
manualTokensEnabled,
|
|
37
47
|
githubTokenSet,
|
|
@@ -44,16 +54,26 @@
|
|
|
44
54
|
customEndpointHaikuModel,
|
|
45
55
|
customEndpointSmallFastModel,
|
|
46
56
|
customEndpointModel,
|
|
57
|
+
manualModelOverrideEnabled,
|
|
58
|
+
manualOpusModel,
|
|
59
|
+
manualSonnetModel,
|
|
60
|
+
manualHaikuModel,
|
|
61
|
+
manualSmallFastModel,
|
|
62
|
+
manualModel,
|
|
47
63
|
hostEnvVarsEnabled,
|
|
48
64
|
hostEnvVarNames,
|
|
49
65
|
hostEnvVarPresence,
|
|
50
66
|
version
|
|
51
67
|
}: {
|
|
68
|
+
pet?: AvatarArt;
|
|
52
69
|
defaultImage: string;
|
|
53
70
|
builtinImage: string;
|
|
54
71
|
disableBuildCache: boolean;
|
|
55
72
|
copyIgnorePatterns: string;
|
|
56
73
|
builtinCopyIgnore: string;
|
|
74
|
+
gitIdentityEnabled: boolean;
|
|
75
|
+
gitIdentityName: string;
|
|
76
|
+
gitIdentityEmail: string;
|
|
57
77
|
dockerArch: string | null;
|
|
58
78
|
manualTokensEnabled: boolean;
|
|
59
79
|
githubTokenSet: boolean;
|
|
@@ -66,6 +86,12 @@
|
|
|
66
86
|
customEndpointHaikuModel: string;
|
|
67
87
|
customEndpointSmallFastModel: string;
|
|
68
88
|
customEndpointModel: string;
|
|
89
|
+
manualModelOverrideEnabled: boolean;
|
|
90
|
+
manualOpusModel: string;
|
|
91
|
+
manualSonnetModel: string;
|
|
92
|
+
manualHaikuModel: string;
|
|
93
|
+
manualSmallFastModel: string;
|
|
94
|
+
manualModel: string;
|
|
69
95
|
hostEnvVarsEnabled: boolean;
|
|
70
96
|
hostEnvVarNames: string[];
|
|
71
97
|
hostEnvVarPresence: Record<string, boolean>;
|
|
@@ -75,8 +101,16 @@
|
|
|
75
101
|
// Defaults to on during SSR, where localStorage doesn't exist.
|
|
76
102
|
let sound = $state(soundEnabled());
|
|
77
103
|
|
|
104
|
+
// DB-backed, so it initializes from the prop. Undefined is the off state — the header keeps its box logo.
|
|
105
|
+
// svelte-ignore state_referenced_locally
|
|
106
|
+
let petArt = $state(pet);
|
|
107
|
+
let savingPet = $state(false);
|
|
108
|
+
let petError = $state<string | null>(null);
|
|
109
|
+
|
|
78
110
|
let shuttingDown = $state(false);
|
|
79
111
|
|
|
112
|
+
$effect(() => installPopupBackTrap());
|
|
113
|
+
|
|
80
114
|
/** Reused by every plain save form below; only the per-control state setters differ. */
|
|
81
115
|
function saveOpts<Success extends Record<string, unknown> = Record<string, unknown>>(handlers: {
|
|
82
116
|
setSaving: (v: boolean) => void;
|
|
@@ -186,6 +220,37 @@
|
|
|
186
220
|
copyIgnoreFormEl?.requestSubmit();
|
|
187
221
|
}
|
|
188
222
|
|
|
223
|
+
// svelte-ignore state_referenced_locally
|
|
224
|
+
let gitIdentity = $state(gitIdentityEnabled);
|
|
225
|
+
let savingGitToggle = $state(false);
|
|
226
|
+
let gitToggleError = $state<string | null>(null);
|
|
227
|
+
|
|
228
|
+
const gitIdentityToggleOpts = toggleOpts({
|
|
229
|
+
set: (v) => (gitIdentity = v),
|
|
230
|
+
setSaving: (v) => (savingGitToggle = v),
|
|
231
|
+
setError: (v) => (gitToggleError = v)
|
|
232
|
+
});
|
|
233
|
+
|
|
234
|
+
// Both fields must be saved together — a lone name or email doesn't count as an override.
|
|
235
|
+
// svelte-ignore state_referenced_locally
|
|
236
|
+
let gitName = $state(gitIdentityName);
|
|
237
|
+
// svelte-ignore state_referenced_locally
|
|
238
|
+
let gitEmail = $state(gitIdentityEmail);
|
|
239
|
+
let savingGitIdentity = $state(false);
|
|
240
|
+
let gitIdentityError = $state<string | null>(null);
|
|
241
|
+
let gitIdentitySaved = $state(false);
|
|
242
|
+
|
|
243
|
+
const gitIdentityOpts = saveOpts<{ name: string; email: string }>({
|
|
244
|
+
setSaving: (v) => (savingGitIdentity = v),
|
|
245
|
+
setError: (v) => (gitIdentityError = v),
|
|
246
|
+
setMsg: (v) => (gitIdentitySaved = !!v),
|
|
247
|
+
onSuccess: (data) => {
|
|
248
|
+
gitName = data?.name ?? gitName;
|
|
249
|
+
gitEmail = data?.email ?? gitEmail;
|
|
250
|
+
gitIdentitySaved = true;
|
|
251
|
+
}
|
|
252
|
+
});
|
|
253
|
+
|
|
189
254
|
// DB-backed rather than localStorage, so it initializes from the prop.
|
|
190
255
|
// svelte-ignore state_referenced_locally
|
|
191
256
|
let noCache = $state(disableBuildCache);
|
|
@@ -291,7 +356,11 @@
|
|
|
291
356
|
const customEndpointToggleOpts = toggleOpts({
|
|
292
357
|
set: (v) => (customEndpoint = v),
|
|
293
358
|
setSaving: (v) => (savingCustomToggle = v),
|
|
294
|
-
setError: (v) => (customToggleError = v)
|
|
359
|
+
setError: (v) => (customToggleError = v),
|
|
360
|
+
// Enabling LiteLLM disables the manual override server-side; keep the UI in sync.
|
|
361
|
+
onSuccess: (data) => {
|
|
362
|
+
if ((data as { enabled?: boolean } | undefined)?.enabled) manualModelOverride = false;
|
|
363
|
+
}
|
|
295
364
|
});
|
|
296
365
|
|
|
297
366
|
// svelte-ignore state_referenced_locally
|
|
@@ -350,6 +419,49 @@
|
|
|
350
419
|
}
|
|
351
420
|
});
|
|
352
421
|
|
|
422
|
+
// svelte-ignore state_referenced_locally
|
|
423
|
+
let manualModelOverride = $state(manualModelOverrideEnabled);
|
|
424
|
+
let savingManualModelToggle = $state(false);
|
|
425
|
+
let manualModelToggleError = $state<string | null>(null);
|
|
426
|
+
|
|
427
|
+
const manualModelToggleOpts = toggleOpts({
|
|
428
|
+
set: (v) => (manualModelOverride = v),
|
|
429
|
+
setSaving: (v) => (savingManualModelToggle = v),
|
|
430
|
+
setError: (v) => (manualModelToggleError = v),
|
|
431
|
+
// Enabling this disables LiteLLM server-side; mirror that here so the UI stays consistent.
|
|
432
|
+
onSuccess: (data) => {
|
|
433
|
+
if ((data as { enabled?: boolean } | undefined)?.enabled) customEndpoint = false;
|
|
434
|
+
}
|
|
435
|
+
});
|
|
436
|
+
|
|
437
|
+
// svelte-ignore state_referenced_locally
|
|
438
|
+
let manualOpus = $state(manualOpusModel);
|
|
439
|
+
// svelte-ignore state_referenced_locally
|
|
440
|
+
let manualSonnet = $state(manualSonnetModel);
|
|
441
|
+
// svelte-ignore state_referenced_locally
|
|
442
|
+
let manualHaiku = $state(manualHaikuModel);
|
|
443
|
+
// svelte-ignore state_referenced_locally
|
|
444
|
+
let manualSmallFast = $state(manualSmallFastModel);
|
|
445
|
+
// svelte-ignore state_referenced_locally
|
|
446
|
+
let manualDefault = $state(manualModel);
|
|
447
|
+
let savingManualModels = $state(false);
|
|
448
|
+
let manualModelsMsg = $state<string | null>(null);
|
|
449
|
+
let manualModelsError = $state<string | null>(null);
|
|
450
|
+
|
|
451
|
+
const manualModelsOpts = saveOpts({
|
|
452
|
+
setSaving: (v) => (savingManualModels = v),
|
|
453
|
+
setError: (v) => (manualModelsError = v),
|
|
454
|
+
setMsg: (v) => (manualModelsMsg = v),
|
|
455
|
+
onSuccess: () => {
|
|
456
|
+
manualModelsMsg = 'Saved.';
|
|
457
|
+
}
|
|
458
|
+
});
|
|
459
|
+
|
|
460
|
+
// LiteLLM is incompatible with both manual tokens and the manual model override.
|
|
461
|
+
let litellmBlocker = $derived(
|
|
462
|
+
manualTokens ? 'Set tokens manually' : manualModelOverride ? 'Override models manually' : null
|
|
463
|
+
);
|
|
464
|
+
|
|
353
465
|
// Only names round-trip; `hostEnvPresence` is refreshed from each save response so a
|
|
354
466
|
// newly-added name doesn't read as "missing" until the next full page load.
|
|
355
467
|
// svelte-ignore state_referenced_locally
|
|
@@ -443,6 +555,34 @@
|
|
|
443
555
|
if (on) playChime('done');
|
|
444
556
|
}
|
|
445
557
|
|
|
558
|
+
// State is object-shaped (the chosen sprite), so this can't reuse the boolean `toggleOpts`.
|
|
559
|
+
const petToggleOpts: MochiEnhanceOptions<{ enabled: boolean; name?: string }, ActionFailure> = {
|
|
560
|
+
onPending: (v) => (savingPet = v),
|
|
561
|
+
submit: () => {
|
|
562
|
+
petError = null;
|
|
563
|
+
return ({ result }) => {
|
|
564
|
+
if (result.type === 'success') {
|
|
565
|
+
petArt = result.data?.name ? findAvatar(result.data.name) : undefined;
|
|
566
|
+
return;
|
|
567
|
+
}
|
|
568
|
+
petError =
|
|
569
|
+
result.type === 'failure'
|
|
570
|
+
? (result.data?.error ?? 'Request failed')
|
|
571
|
+
: 'Network error. Try again.';
|
|
572
|
+
};
|
|
573
|
+
}
|
|
574
|
+
};
|
|
575
|
+
|
|
576
|
+
function petChooseOpts(art: AvatarArt) {
|
|
577
|
+
return saveOpts<{ name: string }>({
|
|
578
|
+
setSaving: (v) => (savingPet = v),
|
|
579
|
+
setError: (v) => (petError = v),
|
|
580
|
+
onSuccess: (data) => {
|
|
581
|
+
petArt = (data?.name ? findAvatar(data.name) : undefined) ?? art;
|
|
582
|
+
}
|
|
583
|
+
});
|
|
584
|
+
}
|
|
585
|
+
|
|
446
586
|
// The server exits mid-flight, so a dropped connection means success here too.
|
|
447
587
|
const shutdownOpts: MochiEnhanceOptions<Record<string, never>, ActionFailure> = {
|
|
448
588
|
submit: ({ cancel }) => {
|
|
@@ -474,7 +614,7 @@
|
|
|
474
614
|
{@attach enhance(imageOpts)}
|
|
475
615
|
>
|
|
476
616
|
<div class="label">
|
|
477
|
-
<Container size={
|
|
617
|
+
<Container size={20} />
|
|
478
618
|
<div class="text">
|
|
479
619
|
<div class="name">
|
|
480
620
|
Default container image
|
|
@@ -535,7 +675,7 @@
|
|
|
535
675
|
{@attach enhance(copyIgnoreOpts)}
|
|
536
676
|
>
|
|
537
677
|
<div class="label">
|
|
538
|
-
<FolderMinus size={
|
|
678
|
+
<FolderMinus size={20} />
|
|
539
679
|
<div class="text">
|
|
540
680
|
<div class="name">Skip when copying a local folder</div>
|
|
541
681
|
<div class="desc">
|
|
@@ -574,6 +714,98 @@
|
|
|
574
714
|
</form>
|
|
575
715
|
</section>
|
|
576
716
|
|
|
717
|
+
<section class="card">
|
|
718
|
+
<form
|
|
719
|
+
class="row"
|
|
720
|
+
method="POST"
|
|
721
|
+
action="?/gitIdentityToggle"
|
|
722
|
+
{@attach enhance(gitIdentityToggleOpts)}
|
|
723
|
+
>
|
|
724
|
+
<div class="label">
|
|
725
|
+
<UserCog size={20} />
|
|
726
|
+
<div class="text">
|
|
727
|
+
<div class="name">Override git identity</div>
|
|
728
|
+
<div class="desc">
|
|
729
|
+
Inject a name and email as <code>git config --global user.name/user.email</code> in every
|
|
730
|
+
new container, taking precedence over the host's own git config. When off, each container
|
|
731
|
+
falls back to the host's identity.
|
|
732
|
+
</div>
|
|
733
|
+
</div>
|
|
734
|
+
</div>
|
|
735
|
+
<label class="switch">
|
|
736
|
+
<input
|
|
737
|
+
type="checkbox"
|
|
738
|
+
name="enabled"
|
|
739
|
+
checked={gitIdentity}
|
|
740
|
+
disabled={savingGitToggle}
|
|
741
|
+
onchange={(e) => {
|
|
742
|
+
gitIdentity = e.currentTarget.checked;
|
|
743
|
+
e.currentTarget.form?.requestSubmit();
|
|
744
|
+
}}
|
|
745
|
+
/>
|
|
746
|
+
<span class="track"><span class="thumb"></span></span>
|
|
747
|
+
</label>
|
|
748
|
+
</form>
|
|
749
|
+
{#if gitToggleError}
|
|
750
|
+
<div class="sub"><div class="msg error">{gitToggleError}</div></div>
|
|
751
|
+
{/if}
|
|
752
|
+
|
|
753
|
+
{#if gitIdentity}
|
|
754
|
+
<form
|
|
755
|
+
class="row divided token-row"
|
|
756
|
+
method="POST"
|
|
757
|
+
action="?/gitIdentityOverride"
|
|
758
|
+
{@attach enhance(gitIdentityOpts)}
|
|
759
|
+
>
|
|
760
|
+
<div class="label">
|
|
761
|
+
<div class="text">
|
|
762
|
+
<div class="name">Identity</div>
|
|
763
|
+
<div class="desc">
|
|
764
|
+
Both fields are required — leave either blank and the container falls back to the
|
|
765
|
+
host's identity.
|
|
766
|
+
</div>
|
|
767
|
+
</div>
|
|
768
|
+
</div>
|
|
769
|
+
<div class="model-fields">
|
|
770
|
+
<label class="model-row">
|
|
771
|
+
<span class="model-label">Name</span>
|
|
772
|
+
<input
|
|
773
|
+
type="text"
|
|
774
|
+
name="name"
|
|
775
|
+
class="image-input"
|
|
776
|
+
bind:value={gitName}
|
|
777
|
+
spellcheck="false"
|
|
778
|
+
autocapitalize="off"
|
|
779
|
+
autocorrect="off"
|
|
780
|
+
placeholder="Jane Doe"
|
|
781
|
+
/>
|
|
782
|
+
</label>
|
|
783
|
+
<label class="model-row">
|
|
784
|
+
<span class="model-label">Email</span>
|
|
785
|
+
<input
|
|
786
|
+
type="text"
|
|
787
|
+
name="email"
|
|
788
|
+
class="image-input"
|
|
789
|
+
bind:value={gitEmail}
|
|
790
|
+
spellcheck="false"
|
|
791
|
+
autocapitalize="off"
|
|
792
|
+
autocorrect="off"
|
|
793
|
+
placeholder="jane@example.com"
|
|
794
|
+
/>
|
|
795
|
+
</label>
|
|
796
|
+
<div class="model-save-row">
|
|
797
|
+
<Button type="submit" disabled={savingGitIdentity}>Save</Button>
|
|
798
|
+
</div>
|
|
799
|
+
</div>
|
|
800
|
+
{#if gitIdentityError}
|
|
801
|
+
<div class="msg error">{gitIdentityError}</div>
|
|
802
|
+
{:else if gitIdentitySaved}
|
|
803
|
+
<div class="msg ok">Saved.</div>
|
|
804
|
+
{/if}
|
|
805
|
+
</form>
|
|
806
|
+
{/if}
|
|
807
|
+
</section>
|
|
808
|
+
|
|
577
809
|
<section class="card">
|
|
578
810
|
<form
|
|
579
811
|
class="row"
|
|
@@ -582,7 +814,7 @@
|
|
|
582
814
|
{@attach enhance(buildCacheToggleOpts)}
|
|
583
815
|
>
|
|
584
816
|
<div class="label">
|
|
585
|
-
<Layers size={
|
|
817
|
+
<Layers size={20} />
|
|
586
818
|
<div class="text">
|
|
587
819
|
<div class="name">Disable build cache</div>
|
|
588
820
|
<div class="desc">
|
|
@@ -616,7 +848,7 @@
|
|
|
616
848
|
{@attach enhance(clearCacheOpts)}
|
|
617
849
|
>
|
|
618
850
|
<div class="label">
|
|
619
|
-
<Trash2 size={
|
|
851
|
+
<Trash2 size={20} />
|
|
620
852
|
<div class="text">
|
|
621
853
|
<div class="name">Clear build cache</div>
|
|
622
854
|
<div class="desc">
|
|
@@ -642,7 +874,7 @@
|
|
|
642
874
|
{@attach enhance(rebuildAllOpts)}
|
|
643
875
|
>
|
|
644
876
|
<div class="label">
|
|
645
|
-
<Hammer size={
|
|
877
|
+
<Hammer size={20} />
|
|
646
878
|
<div class="text">
|
|
647
879
|
<div class="name">Rebuild running containers (no cache)</div>
|
|
648
880
|
<div class="desc">
|
|
@@ -670,7 +902,7 @@
|
|
|
670
902
|
{@attach enhance(manualTokensToggleOpts)}
|
|
671
903
|
>
|
|
672
904
|
<div class="label">
|
|
673
|
-
<KeyRound size={
|
|
905
|
+
<KeyRound size={20} />
|
|
674
906
|
<div class="text">
|
|
675
907
|
<div class="name">
|
|
676
908
|
Set tokens manually
|
|
@@ -791,7 +1023,7 @@
|
|
|
791
1023
|
{/if}
|
|
792
1024
|
</section>
|
|
793
1025
|
|
|
794
|
-
<section class="card" class:disabled-card={
|
|
1026
|
+
<section class="card" class:disabled-card={litellmBlocker}>
|
|
795
1027
|
<form
|
|
796
1028
|
class="row"
|
|
797
1029
|
method="POST"
|
|
@@ -799,17 +1031,17 @@
|
|
|
799
1031
|
{@attach enhance(customEndpointToggleOpts)}
|
|
800
1032
|
>
|
|
801
1033
|
<div class="label">
|
|
802
|
-
<KeyRound size={
|
|
1034
|
+
<KeyRound size={20} />
|
|
803
1035
|
<div class="text">
|
|
804
1036
|
<div class="name">
|
|
805
1037
|
LiteLLM + Bedrock
|
|
806
|
-
{#if
|
|
807
|
-
<span class="arch" title="Disabled while
|
|
1038
|
+
{#if litellmBlocker}
|
|
1039
|
+
<span class="arch" title="Disabled while {litellmBlocker} is on">disabled</span>
|
|
808
1040
|
{/if}
|
|
809
1041
|
</div>
|
|
810
1042
|
<div class="desc">
|
|
811
|
-
{#if
|
|
812
|
-
Not available while "
|
|
1043
|
+
{#if litellmBlocker}
|
|
1044
|
+
Not available while "{litellmBlocker}" is enabled — these modes are mutually
|
|
813
1045
|
incompatible.
|
|
814
1046
|
{:else}
|
|
815
1047
|
Route <code>claude</code> through a LiteLLM proxy fronting AWS Bedrock instead of Anthropic's
|
|
@@ -824,7 +1056,7 @@
|
|
|
824
1056
|
type="checkbox"
|
|
825
1057
|
name="enabled"
|
|
826
1058
|
checked={customEndpoint}
|
|
827
|
-
disabled={savingCustomToggle ||
|
|
1059
|
+
disabled={savingCustomToggle || !!litellmBlocker}
|
|
828
1060
|
onchange={(e) => {
|
|
829
1061
|
customEndpoint = e.currentTarget.checked;
|
|
830
1062
|
e.currentTarget.form?.requestSubmit();
|
|
@@ -1005,6 +1237,149 @@
|
|
|
1005
1237
|
{/if}
|
|
1006
1238
|
</section>
|
|
1007
1239
|
|
|
1240
|
+
<section class="card" class:disabled-card={customEndpoint}>
|
|
1241
|
+
<form
|
|
1242
|
+
class="row"
|
|
1243
|
+
method="POST"
|
|
1244
|
+
action="?/manualModelToggle"
|
|
1245
|
+
{@attach enhance(manualModelToggleOpts)}
|
|
1246
|
+
>
|
|
1247
|
+
<div class="label">
|
|
1248
|
+
<Cpu size={18} />
|
|
1249
|
+
<div class="text">
|
|
1250
|
+
<div class="name">
|
|
1251
|
+
Override models manually
|
|
1252
|
+
{#if customEndpoint}
|
|
1253
|
+
<span class="arch" title="Disabled while LiteLLM + Bedrock is on">disabled</span>
|
|
1254
|
+
{/if}
|
|
1255
|
+
</div>
|
|
1256
|
+
<div class="desc">
|
|
1257
|
+
{#if customEndpoint}
|
|
1258
|
+
Not available while "LiteLLM + Bedrock" is enabled — these modes are mutually
|
|
1259
|
+
incompatible.
|
|
1260
|
+
{:else}
|
|
1261
|
+
Pin which model <code>claude</code> uses on the standard (subscription) path. Only
|
|
1262
|
+
the fields you fill are injected into new containers as
|
|
1263
|
+
<code>ANTHROPIC_*_MODEL</code>
|
|
1264
|
+
variables; blanks fall through to Claude Code's own defaults.
|
|
1265
|
+
{/if}
|
|
1266
|
+
</div>
|
|
1267
|
+
</div>
|
|
1268
|
+
</div>
|
|
1269
|
+
<label class="switch">
|
|
1270
|
+
<input
|
|
1271
|
+
type="checkbox"
|
|
1272
|
+
name="enabled"
|
|
1273
|
+
checked={manualModelOverride}
|
|
1274
|
+
disabled={savingManualModelToggle || customEndpoint}
|
|
1275
|
+
onchange={(e) => {
|
|
1276
|
+
manualModelOverride = e.currentTarget.checked;
|
|
1277
|
+
e.currentTarget.form?.requestSubmit();
|
|
1278
|
+
}}
|
|
1279
|
+
/>
|
|
1280
|
+
<span class="track"><span class="thumb"></span></span>
|
|
1281
|
+
</label>
|
|
1282
|
+
</form>
|
|
1283
|
+
{#if manualModelToggleError}
|
|
1284
|
+
<div class="sub"><div class="msg error">{manualModelToggleError}</div></div>
|
|
1285
|
+
{/if}
|
|
1286
|
+
|
|
1287
|
+
{#if manualModelOverride}
|
|
1288
|
+
<form
|
|
1289
|
+
class="row divided token-row"
|
|
1290
|
+
method="POST"
|
|
1291
|
+
action="?/manualModels"
|
|
1292
|
+
{@attach enhance(manualModelsOpts)}
|
|
1293
|
+
>
|
|
1294
|
+
<div class="label">
|
|
1295
|
+
<div class="text">
|
|
1296
|
+
<div class="name">Model IDs</div>
|
|
1297
|
+
<div class="desc">
|
|
1298
|
+
A model name or alias per tier, e.g. <code>opusplan</code>, <code>opus</code>,
|
|
1299
|
+
<code>sonnet</code>, or a full
|
|
1300
|
+
<code>claude-…</code> id. Leave a field blank to skip it.
|
|
1301
|
+
</div>
|
|
1302
|
+
</div>
|
|
1303
|
+
</div>
|
|
1304
|
+
<div class="model-fields">
|
|
1305
|
+
<label class="model-row">
|
|
1306
|
+
<span class="model-label">Opus</span>
|
|
1307
|
+
<input
|
|
1308
|
+
type="text"
|
|
1309
|
+
name="opusModel"
|
|
1310
|
+
class="image-input"
|
|
1311
|
+
bind:value={manualOpus}
|
|
1312
|
+
spellcheck="false"
|
|
1313
|
+
autocapitalize="off"
|
|
1314
|
+
autocorrect="off"
|
|
1315
|
+
autocomplete="off"
|
|
1316
|
+
/>
|
|
1317
|
+
</label>
|
|
1318
|
+
<label class="model-row">
|
|
1319
|
+
<span class="model-label">Sonnet</span>
|
|
1320
|
+
<input
|
|
1321
|
+
type="text"
|
|
1322
|
+
name="sonnetModel"
|
|
1323
|
+
class="image-input"
|
|
1324
|
+
bind:value={manualSonnet}
|
|
1325
|
+
spellcheck="false"
|
|
1326
|
+
autocapitalize="off"
|
|
1327
|
+
autocorrect="off"
|
|
1328
|
+
autocomplete="off"
|
|
1329
|
+
/>
|
|
1330
|
+
</label>
|
|
1331
|
+
<label class="model-row">
|
|
1332
|
+
<span class="model-label">Haiku</span>
|
|
1333
|
+
<input
|
|
1334
|
+
type="text"
|
|
1335
|
+
name="haikuModel"
|
|
1336
|
+
class="image-input"
|
|
1337
|
+
bind:value={manualHaiku}
|
|
1338
|
+
spellcheck="false"
|
|
1339
|
+
autocapitalize="off"
|
|
1340
|
+
autocorrect="off"
|
|
1341
|
+
autocomplete="off"
|
|
1342
|
+
/>
|
|
1343
|
+
</label>
|
|
1344
|
+
<label class="model-row">
|
|
1345
|
+
<span class="model-label">Small/fast</span>
|
|
1346
|
+
<input
|
|
1347
|
+
type="text"
|
|
1348
|
+
name="smallFastModel"
|
|
1349
|
+
class="image-input"
|
|
1350
|
+
bind:value={manualSmallFast}
|
|
1351
|
+
spellcheck="false"
|
|
1352
|
+
autocapitalize="off"
|
|
1353
|
+
autocorrect="off"
|
|
1354
|
+
autocomplete="off"
|
|
1355
|
+
/>
|
|
1356
|
+
</label>
|
|
1357
|
+
<label class="model-row">
|
|
1358
|
+
<span class="model-label">Default</span>
|
|
1359
|
+
<input
|
|
1360
|
+
type="text"
|
|
1361
|
+
name="defaultModel"
|
|
1362
|
+
class="image-input"
|
|
1363
|
+
bind:value={manualDefault}
|
|
1364
|
+
spellcheck="false"
|
|
1365
|
+
autocapitalize="off"
|
|
1366
|
+
autocorrect="off"
|
|
1367
|
+
autocomplete="off"
|
|
1368
|
+
/>
|
|
1369
|
+
</label>
|
|
1370
|
+
<div class="model-save-row">
|
|
1371
|
+
<Button type="submit" disabled={savingManualModels}>Save models</Button>
|
|
1372
|
+
</div>
|
|
1373
|
+
</div>
|
|
1374
|
+
{#if manualModelsError}
|
|
1375
|
+
<div class="msg error">{manualModelsError}</div>
|
|
1376
|
+
{:else if manualModelsMsg}
|
|
1377
|
+
<div class="msg ok">{manualModelsMsg}</div>
|
|
1378
|
+
{/if}
|
|
1379
|
+
</form>
|
|
1380
|
+
{/if}
|
|
1381
|
+
</section>
|
|
1382
|
+
|
|
1008
1383
|
<section class="card">
|
|
1009
1384
|
<form
|
|
1010
1385
|
class="row"
|
|
@@ -1013,7 +1388,7 @@
|
|
|
1013
1388
|
{@attach enhance(hostEnvVarsToggleOpts)}
|
|
1014
1389
|
>
|
|
1015
1390
|
<div class="label">
|
|
1016
|
-
<Variable size={
|
|
1391
|
+
<Variable size={20} />
|
|
1017
1392
|
<div class="text">
|
|
1018
1393
|
<div class="name">Host environment variables</div>
|
|
1019
1394
|
<div class="desc">
|
|
@@ -1111,7 +1486,7 @@
|
|
|
1111
1486
|
<section class="card">
|
|
1112
1487
|
<div class="row">
|
|
1113
1488
|
<div class="label">
|
|
1114
|
-
<SunMoon size={
|
|
1489
|
+
<SunMoon size={20} />
|
|
1115
1490
|
<div class="text">
|
|
1116
1491
|
<div class="name">Theme</div>
|
|
1117
1492
|
<div class="desc">
|
|
@@ -1126,7 +1501,7 @@
|
|
|
1126
1501
|
<section class="card">
|
|
1127
1502
|
<div class="row">
|
|
1128
1503
|
<div class="label">
|
|
1129
|
-
<Volume2 size={
|
|
1504
|
+
<Volume2 size={20} />
|
|
1130
1505
|
<div class="text">
|
|
1131
1506
|
<div class="name">Attention sound</div>
|
|
1132
1507
|
<div class="desc">
|
|
@@ -1145,10 +1520,55 @@
|
|
|
1145
1520
|
</div>
|
|
1146
1521
|
</section>
|
|
1147
1522
|
|
|
1523
|
+
<section class="card">
|
|
1524
|
+
<form class="row" method="POST" action="?/petToggle" {@attach enhance(petToggleOpts)}>
|
|
1525
|
+
<div class="label">
|
|
1526
|
+
<PawPrint size={18} />
|
|
1527
|
+
<div class="text">
|
|
1528
|
+
<div class="name">Pet logo</div>
|
|
1529
|
+
<div class="desc">Swap the box in the header for a pixel pet.</div>
|
|
1530
|
+
</div>
|
|
1531
|
+
</div>
|
|
1532
|
+
<label class="switch">
|
|
1533
|
+
<input
|
|
1534
|
+
type="checkbox"
|
|
1535
|
+
name="enabled"
|
|
1536
|
+
checked={!!petArt}
|
|
1537
|
+
disabled={savingPet}
|
|
1538
|
+
onchange={(e) => e.currentTarget.form?.requestSubmit()}
|
|
1539
|
+
/>
|
|
1540
|
+
<span class="track"><span class="thumb"></span></span>
|
|
1541
|
+
</label>
|
|
1542
|
+
</form>
|
|
1543
|
+
{#if petError}
|
|
1544
|
+
<div class="sub"><div class="msg error">{petError}</div></div>
|
|
1545
|
+
{/if}
|
|
1546
|
+
{#if petArt}
|
|
1547
|
+
<div class="sub pets">
|
|
1548
|
+
{#each avatars as art (art.name)}
|
|
1549
|
+
<form method="POST" action="?/petChoose" {@attach enhance(petChooseOpts(art))}>
|
|
1550
|
+
<input type="hidden" name="name" value={art.name} />
|
|
1551
|
+
<button
|
|
1552
|
+
type="submit"
|
|
1553
|
+
class="pet"
|
|
1554
|
+
class:selected={art.name === petArt.name}
|
|
1555
|
+
disabled={savingPet}
|
|
1556
|
+
title={art.name}
|
|
1557
|
+
aria-label={art.name}
|
|
1558
|
+
aria-pressed={art.name === petArt.name}
|
|
1559
|
+
>
|
|
1560
|
+
<Avatar {art} name={art.name} scale={4} />
|
|
1561
|
+
</button>
|
|
1562
|
+
</form>
|
|
1563
|
+
{/each}
|
|
1564
|
+
</div>
|
|
1565
|
+
{/if}
|
|
1566
|
+
</section>
|
|
1567
|
+
|
|
1148
1568
|
<section class="card danger-card">
|
|
1149
1569
|
<form class="row" method="POST" action="?/shutdown" {@attach enhance(shutdownOpts)}>
|
|
1150
1570
|
<div class="label">
|
|
1151
|
-
<Power size={
|
|
1571
|
+
<Power size={20} />
|
|
1152
1572
|
<div class="text">
|
|
1153
1573
|
<div class="name">Delete database, containers, and shut down</div>
|
|
1154
1574
|
<div class="desc">
|
|
@@ -1270,6 +1690,10 @@
|
|
|
1270
1690
|
color: var(--ink);
|
|
1271
1691
|
min-width: 0;
|
|
1272
1692
|
}
|
|
1693
|
+
/* Keep the leading icon at its intrinsic size; the flex row would otherwise shrink busier glyphs below 18px. */
|
|
1694
|
+
.label > :global(svg) {
|
|
1695
|
+
flex: none;
|
|
1696
|
+
}
|
|
1273
1697
|
.text {
|
|
1274
1698
|
min-width: 0;
|
|
1275
1699
|
}
|
|
@@ -1351,6 +1775,40 @@
|
|
|
1351
1775
|
.msg.ok {
|
|
1352
1776
|
color: var(--ink-soft);
|
|
1353
1777
|
}
|
|
1778
|
+
/* auto-fill so the grid reflows as the catalog grows, with no column count to keep in sync. */
|
|
1779
|
+
.pets {
|
|
1780
|
+
display: grid;
|
|
1781
|
+
grid-template-columns: repeat(auto-fill, minmax(44px, 1fr));
|
|
1782
|
+
gap: 6px;
|
|
1783
|
+
}
|
|
1784
|
+
/* Each pet is wrapped in its own form; let the button stay the grid item. */
|
|
1785
|
+
.pets form {
|
|
1786
|
+
display: contents;
|
|
1787
|
+
}
|
|
1788
|
+
.pet:disabled {
|
|
1789
|
+
cursor: progress;
|
|
1790
|
+
}
|
|
1791
|
+
.pet {
|
|
1792
|
+
display: flex;
|
|
1793
|
+
align-items: center;
|
|
1794
|
+
justify-content: center;
|
|
1795
|
+
padding: 4px;
|
|
1796
|
+
appearance: none;
|
|
1797
|
+
background: transparent;
|
|
1798
|
+
border: 1px solid transparent;
|
|
1799
|
+
cursor: pointer;
|
|
1800
|
+
}
|
|
1801
|
+
.pet:hover {
|
|
1802
|
+
border-color: var(--rule);
|
|
1803
|
+
}
|
|
1804
|
+
.pet.selected {
|
|
1805
|
+
border-color: var(--attn-done);
|
|
1806
|
+
background: var(--switch-on-bg);
|
|
1807
|
+
}
|
|
1808
|
+
.pet:focus-visible {
|
|
1809
|
+
outline: 2px solid var(--ink);
|
|
1810
|
+
outline-offset: 1px;
|
|
1811
|
+
}
|
|
1354
1812
|
.switch {
|
|
1355
1813
|
position: relative;
|
|
1356
1814
|
flex: none;
|