codebay 0.2.1 → 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.
Files changed (52) hide show
  1. package/.mochi/manifest.json +274 -246
  2. package/.mochi/svelte-client/HydratableIsland-79z9xq4b.js +1 -0
  3. package/.mochi/svelte-client/_hydrate-AppShell_2rtnxn6pgp2rh-f5rzyjm8.js +2 -0
  4. package/.mochi/svelte-client/{_hydrate-AvatarsView_257s9yq1wwr4f-3cnbjpz2.js → _hydrate-AvatarsView_257s9yq1wwr4f-fxyd5qx4.js} +1 -1
  5. package/.mochi/svelte-client/_hydrate-InstanceView_2ma45l9bybfhl-nv31ptdp.js +1 -0
  6. package/.mochi/svelte-client/_hydrate-SettingsView_8hmarwmf8onq-r9vvc7rx.js +28 -0
  7. package/.mochi/svelte-client/chunk-6eexkr6p.js +2 -0
  8. package/.mochi/svelte-client/chunk-7znwaf7t.js +2 -0
  9. package/.mochi/svelte-client/{chunk-hcztrd75.js → chunk-dz1019cy.js} +1 -1
  10. package/.mochi/svelte-client/{chunk-qxwt25hn.js → chunk-nmf4dq86.js} +1 -1
  11. package/.mochi/svelte-client/{chunk-tr67wtwn.js → chunk-ssa0ad2f.js} +1 -1
  12. package/.mochi/svelte-client/{chunk-5jnepvzx.js → chunk-zmmb1c4b.js} +1 -1
  13. package/.mochi/svelte-compile/{App-f0q5n4rk.server.js → App-9qjy14bc.server.js} +38 -23
  14. package/.mochi/svelte-compile/{Avatars-p8gfef7x.server.js → Avatars-sq8mjn6k.server.js} +2 -2
  15. package/.mochi/svelte-compile/{Instance-atjwsczx.server.js → Instance-13j59daw.server.js} +2 -2
  16. package/.mochi/svelte-compile/{Settings-q88xw6h8.server.js → Settings-p0s2awg1.server.js} +404 -103
  17. package/.mochi/svelte-compile/{chunk-9bjk7yx6.js → chunk-6ghzacpg.js} +1 -1
  18. package/.mochi/svelte-compile/{chunk-4kwy539a.js → chunk-bacb4b0r.js} +1 -1
  19. package/.mochi/svelte-compile/{chunk-sxqys3nw.js → chunk-dfe2km6a.js} +5 -2
  20. package/.mochi/svelte-compile/{chunk-v6796ga4.js → chunk-fpe16ywq.js} +28 -6
  21. package/.mochi/svelte-css/Brand-1bh2b800g5vrn.css +1 -0
  22. package/.mochi/svelte-css/SettingsView-3uycxa8z548m4.css +1 -0
  23. package/README.md +4 -0
  24. package/bin/codebay.ts +42 -1
  25. package/package.json +8 -8
  26. package/src/avatars/index.ts +5 -0
  27. package/src/components/AppBar.svelte +8 -1
  28. package/src/components/AppShell.svelte +17 -3
  29. package/src/components/Brand.svelte +15 -4
  30. package/src/components/DashboardView.svelte +5 -2
  31. package/src/components/IdeBar.svelte +9 -1
  32. package/src/components/InstanceCard.svelte +7 -3
  33. package/src/components/InstanceView.svelte +4 -1
  34. package/src/components/SettingsCog.svelte +9 -1
  35. package/src/components/SettingsView.svelte +476 -18
  36. package/src/components/TopBar.svelte +4 -1
  37. package/src/container-injections/claude-code-models.ts +74 -0
  38. package/src/container-injections/git-identity.ts +30 -3
  39. package/src/lib/injections.server.ts +3 -0
  40. package/src/lib/instances.server.ts +10 -1
  41. package/src/lib/popup-nav.ts +37 -0
  42. package/src/pages/App.svelte +10 -3
  43. package/src/pages/Settings.svelte +31 -0
  44. package/src/routes.ts +88 -2
  45. package/.mochi/svelte-client/HydratableIsland-wrq79y0w.js +0 -1
  46. package/.mochi/svelte-client/_hydrate-AppShell_2rtnxn6pgp2rh-7xgbmxxg.js +0 -2
  47. package/.mochi/svelte-client/_hydrate-InstanceView_2ma45l9bybfhl-2ntmdm3e.js +0 -1
  48. package/.mochi/svelte-client/_hydrate-SettingsView_8hmarwmf8onq-t08spym1.js +0 -23
  49. package/.mochi/svelte-client/chunk-04qv4w6w.js +0 -2
  50. package/.mochi/svelte-client/chunk-sjmcgh7f.js +0 -2
  51. package/.mochi/svelte-css/Brand-1la7zw5uhcbl4.css +0 -1
  52. package/.mochi/svelte-css/SettingsView-1nfdwnm16cpp2.css +0 -1
@@ -3,6 +3,7 @@
3
3
  import Component from '@lucide/svelte/icons/component';
4
4
  import { isDev } from 'mochi-framework';
5
5
  import type { AuthProvider } from '../types.ts';
6
+ import type { AvatarArt } from '../avatars/index.ts';
6
7
  import Brand from './Brand.svelte';
7
8
  import SettingsCog from './SettingsCog.svelte';
8
9
  import CredMenu from './CredMenu.svelte';
@@ -11,6 +12,7 @@
11
12
  // Action state is injected so the bar stays presentational and reusable on /debug.
12
13
  let {
13
14
  auth,
15
+ pet,
14
16
  canDelete = false,
15
17
  ready = true,
16
18
  creating = false,
@@ -18,6 +20,7 @@
18
20
  onDeleteAll
19
21
  }: {
20
22
  auth: AuthProvider[];
23
+ pet?: AvatarArt;
21
24
  canDelete?: boolean;
22
25
  ready?: boolean;
23
26
  creating?: boolean;
@@ -27,7 +30,7 @@
27
30
  </script>
28
31
 
29
32
  <header class="topbar">
30
- <Brand />
33
+ <Brand {pet} />
31
34
  <div class="topbar-actions">
32
35
  {#if isDev}
33
36
  <Button variant="default" size="sm" icon={Component} href="/debug">Debug</Button>
@@ -0,0 +1,74 @@
1
+ import { getOption } from '../lib/db.server.ts';
2
+ import { execInContainer } from '../lib/exec.server.ts';
3
+ import type { ContainerTarget, Injection } from '../lib/injections.server.ts';
4
+
5
+ /** The option key → Claude env var mapping; order is the field order in Settings. */
6
+ const MODEL_ENV: Array<[key: string, env: string]> = [
7
+ ['manual_opus_model', 'ANTHROPIC_DEFAULT_OPUS_MODEL'],
8
+ ['manual_sonnet_model', 'ANTHROPIC_DEFAULT_SONNET_MODEL'],
9
+ ['manual_haiku_model', 'ANTHROPIC_DEFAULT_HAIKU_MODEL'],
10
+ ['manual_small_fast_model', 'ANTHROPIC_SMALL_FAST_MODEL'],
11
+ ['manual_model', 'ANTHROPIC_MODEL']
12
+ ];
13
+
14
+ /**
15
+ * Only for the standard (subscription) path — null when disabled, when LiteLLM
16
+ * owns the models instead, or when no field is filled (nothing to export).
17
+ */
18
+ export function manualModelConfig(): Record<string, string> | null {
19
+ if (getOption('manual_model_override_enabled') !== '1') return null;
20
+ if (getOption('custom_endpoint_enabled') === '1') return null;
21
+ const filled: Record<string, string> = {};
22
+ for (const [key, env] of MODEL_ENV) {
23
+ const value = getOption(key)?.trim();
24
+ if (value) filled[env] = value;
25
+ }
26
+ return Object.keys(filled).length ? filled : null;
27
+ }
28
+
29
+ const ENV_FILE = '~/.codebay-claude-models-env';
30
+
31
+ /** Model IDs are non-secret, so every value rides `args` ($1, $2, …) — no stdin. */
32
+ async function injectModels(
33
+ target: ContainerTarget,
34
+ config: Record<string, string>
35
+ ): Promise<{ ok: boolean; error?: string }> {
36
+ const entries = Object.entries(config);
37
+ const writes = entries.map(([env], i) => `printf 'export ${env}=%s\\n' "$${i + 1}"; `).join('');
38
+ const script =
39
+ 'set -e; f=$(eval echo "' +
40
+ ENV_FILE +
41
+ '"); ' +
42
+ '{ ' +
43
+ writes +
44
+ '} > "$f"; chmod 600 "$f"; ' +
45
+ // The grep guard keeps a re-apply from stacking duplicate source lines.
46
+ 'h=$(eval echo ~$(id -un)); src="[ -f \\"$f\\" ] && . \\"$f\\""; ' +
47
+ 'for rc in "$h/.bashrc" "$h/.zshrc"; do ' +
48
+ 'grep -qF "$src" "$rc" 2>/dev/null || printf \'%s\\n\' "$src" >> "$rc"; ' +
49
+ 'done';
50
+
51
+ const res = await execInContainer(target, {
52
+ script,
53
+ args: ['claude-models', ...entries.map(([, value]) => value)]
54
+ });
55
+ return res.ok ? { ok: true } : { ok: false, error: res.error };
56
+ }
57
+
58
+ /** Sets Claude model env vars on the standard path; skipped when LiteLLM is active. */
59
+ export const claudeCodeModels: Injection = {
60
+ id: 'claude-code-models',
61
+ label: 'Model override',
62
+
63
+ async apply(target, log) {
64
+ const config = manualModelConfig();
65
+ if (!config) return;
66
+ log(`Injecting Claude model override (${Object.keys(config).join(', ')})…\n`);
67
+ const result = await injectModels(target, config);
68
+ log(
69
+ result.ok
70
+ ? '✓ Claude model override configured in container\n'
71
+ : `⚠ Claude model override injection failed: ${result.error}\n`
72
+ );
73
+ }
74
+ };
@@ -1,5 +1,6 @@
1
1
  import { checkPresence, execInContainer } from '../lib/exec.server.ts';
2
2
  import { spawnCapture } from '../lib/spawn.server.ts';
3
+ import { getOption } from '../lib/db.server.ts';
3
4
  import type { Injection } from '../lib/injections.server.ts';
4
5
 
5
6
  interface GitIdentity {
@@ -11,8 +12,29 @@ function readGitConfig(key: string): Promise<string | null> {
11
12
  return spawnCapture(['git', 'config', '--global', '--get', key]);
12
13
  }
13
14
 
14
- /** `--global` so this reads the host user's identity, not the manager checkout's override. */
15
- async function readGitIdentity(): Promise<GitIdentity | null> {
15
+ /**
16
+ * The toggle is the source of truth, but predates the option: an unset value falls
17
+ * back to "on when both fields are already filled" so existing overrides keep working.
18
+ */
19
+ export function gitIdentityEnabled(): boolean {
20
+ const explicit = getOption('git_identity_enabled');
21
+ if (explicit === '1') return true;
22
+ if (explicit === '0') return false;
23
+ return !!(getOption('git_identity_name')?.trim() && getOption('git_identity_email')?.trim());
24
+ }
25
+
26
+ /** Both fields are required together — a lone name or email is treated as not configured. */
27
+ function overrideIdentity(): GitIdentity | null {
28
+ if (!gitIdentityEnabled()) return null;
29
+ const name = getOption('git_identity_name')?.trim() || '';
30
+ const email = getOption('git_identity_email')?.trim() || '';
31
+ return name && email ? { name, email } : null;
32
+ }
33
+
34
+ /** `--global` so the host fallback reads the host user's identity, not the manager checkout's. */
35
+ export async function readGitIdentity(): Promise<GitIdentity | null> {
36
+ const override = overrideIdentity();
37
+ if (override) return override;
16
38
  const [name, email] = await Promise.all([
17
39
  readGitConfig('user.name'),
18
40
  readGitConfig('user.email')
@@ -30,7 +52,12 @@ export const gitIdentity: Injection = {
30
52
  async status() {
31
53
  const identity = await readGitIdentity();
32
54
  return identity
33
- ? { available: true, source: `git config — ${identity.name}` }
55
+ ? {
56
+ available: true,
57
+ source: overrideIdentity()
58
+ ? `Settings override — ${identity.name}`
59
+ : `git config — ${identity.name}`
60
+ }
34
61
  : { available: false, source: null };
35
62
  }
36
63
  },
@@ -6,6 +6,7 @@ import { tmux } from '../container-injections/tmux.ts';
6
6
  import { gitIdentity } from '../container-injections/git-identity.ts';
7
7
  import { claudeCodeCredentials } from '../container-injections/claude-code-credentials.ts';
8
8
  import { claudeCodeCustom } from '../container-injections/claude-code-custom.ts';
9
+ import { claudeCodeModels } from '../container-injections/claude-code-models.ts';
9
10
  import { githubCredentials } from '../container-injections/github-credentials.ts';
10
11
  import { attentionHooks } from '../container-injections/attention-hooks.ts';
11
12
  import { claudeStatusline } from '../container-injections/claude-statusline.ts';
@@ -48,6 +49,8 @@ const BASE_INJECTIONS_HEAD: Injection[] = [
48
49
  ];
49
50
 
50
51
  const BASE_INJECTIONS_TAIL: Injection[] = [
52
+ // Self-skips unless manual override is on and LiteLLM off, so it's safe in the always-run tail.
53
+ claudeCodeModels,
51
54
  githubCredentials,
52
55
  attentionHooks,
53
56
  claudeStatusline,
@@ -104,7 +104,9 @@ export function subscribeLogs(id: string, onChunk: (chunk: string) => void): ()
104
104
  export type StreamEvent =
105
105
  | { type: 'instances'; data: Instance[] }
106
106
  | { type: 'health'; data: { id: string; health: InstanceHealth } }
107
- | { type: 'preflight'; data: { docker: boolean; cli: boolean } };
107
+ | { type: 'preflight'; data: { docker: boolean; cli: boolean } }
108
+ // `name` is the chosen sprite, or null for the default box logo. Lets the header swap live.
109
+ | { type: 'pet'; data: { name: string | null } };
108
110
 
109
111
  interface StreamHub {
110
112
  sockets: Set<ServerWebSocket<unknown>>;
@@ -150,6 +152,11 @@ export function broadcastHealth(id: string, health: InstanceHealth): void {
150
152
  broadcast({ type: 'health', data: { id, health } });
151
153
  }
152
154
 
155
+ /** Called from the settings action so every open dashboard swaps its header logo without a reload. */
156
+ export function broadcastPet(name: string | null): void {
157
+ broadcast({ type: 'pet', data: { name } });
158
+ }
159
+
153
160
  async function reconcileInstances(force = false): Promise<void> {
154
161
  const list = await listInstances();
155
162
  const listJson = JSON.stringify(list);
@@ -189,6 +196,8 @@ export function streamOpen(ws: ServerWebSocket<unknown>): void {
189
196
  void listInstances().then((list) => sendTo(ws, { type: 'instances', data: list }));
190
197
  for (const snap of currentHealthSnapshots()) sendTo(ws, { type: 'health', data: snap });
191
198
  void backgroundPreflight().then((pf) => sendTo(ws, { type: 'preflight', data: pf }));
199
+ // Keeps a reconnecting client correct even if the pet changed while it was away.
200
+ sendTo(ws, { type: 'pet', data: { name: getOption('pet') || null } });
192
201
  }
193
202
 
194
203
  export function streamClose(ws: ServerWebSocket<unknown>): void {
@@ -0,0 +1,37 @@
1
+ const POPUP_PARAM = 'popup';
2
+
3
+ /** Assumes `href` has no existing query string. */
4
+ export function withPopupMarker(href: string): string {
5
+ return `${href}?${POPUP_PARAM}=1`;
6
+ }
7
+
8
+ export function isPopupPage(): boolean {
9
+ return new URLSearchParams(location.search).has(POPUP_PARAM);
10
+ }
11
+
12
+ function closeOrGoHome() {
13
+ window.close();
14
+ // Runs only if close() was refused (tab wasn't opened by script) — window.close()
15
+ // tears the page down near-instantly when it succeeds, so this never fires then.
16
+ setTimeout(() => {
17
+ location.href = '/';
18
+ }, 100);
19
+ }
20
+
21
+ export function onBackLinkClick(e: MouseEvent) {
22
+ if (e.defaultPrevented || e.button !== 0 || e.metaKey || e.ctrlKey || e.shiftKey || e.altKey)
23
+ return;
24
+ if (!isPopupPage()) return;
25
+ e.preventDefault();
26
+ closeOrGoHome();
27
+ }
28
+
29
+ export function installPopupBackTrap(): () => void {
30
+ if (!isPopupPage()) return () => {};
31
+ // A fresh popup tab has one history entry, so back is otherwise a no-op the
32
+ // browser just disables — push a duplicate so the first back press fires popstate.
33
+ history.pushState({}, '', location.href);
34
+ const onPop = () => closeOrGoHome();
35
+ window.addEventListener('popstate', onPop);
36
+ return () => window.removeEventListener('popstate', onPop);
37
+ }
@@ -3,12 +3,19 @@
3
3
  import '@fontsource-variable/jetbrains-mono';
4
4
  import AppShell from '../components/AppShell.svelte';
5
5
  import type { Instance, Preflight } from '../types.ts';
6
+ import type { AvatarArt } from '../avatars/index.ts';
6
7
 
7
8
  let {
8
9
  preflight,
9
10
  initialPath,
10
- snapshot
11
- }: { preflight: Preflight; initialPath: string; snapshot: Instance[] } = $props();
11
+ snapshot,
12
+ pet
13
+ }: {
14
+ preflight: Preflight;
15
+ initialPath: string;
16
+ snapshot: Instance[];
17
+ pet?: AvatarArt;
18
+ } = $props();
12
19
  </script>
13
20
 
14
- <AppShell {preflight} {initialPath} {snapshot} mochi:hydrate />
21
+ <AppShell {preflight} {initialPath} {snapshot} {pet} mochi:hydrate />
@@ -2,13 +2,18 @@
2
2
  import '@fontsource-variable/doto';
3
3
  import '@fontsource-variable/jetbrains-mono';
4
4
  import SettingsView from '../components/SettingsView.svelte';
5
+ import type { AvatarArt } from '../avatars/index.ts';
5
6
 
6
7
  let {
8
+ pet,
7
9
  defaultImage,
8
10
  builtinImage,
9
11
  disableBuildCache,
10
12
  copyIgnorePatterns,
11
13
  builtinCopyIgnore,
14
+ gitIdentityEnabled,
15
+ gitIdentityName,
16
+ gitIdentityEmail,
12
17
  dockerArch,
13
18
  manualTokensEnabled,
14
19
  githubTokenSet,
@@ -21,16 +26,26 @@
21
26
  customEndpointHaikuModel,
22
27
  customEndpointSmallFastModel,
23
28
  customEndpointModel,
29
+ manualModelOverrideEnabled,
30
+ manualOpusModel,
31
+ manualSonnetModel,
32
+ manualHaikuModel,
33
+ manualSmallFastModel,
34
+ manualModel,
24
35
  hostEnvVarsEnabled,
25
36
  hostEnvVarNames,
26
37
  hostEnvVarPresence,
27
38
  version
28
39
  }: {
40
+ pet?: AvatarArt;
29
41
  defaultImage: string;
30
42
  builtinImage: string;
31
43
  disableBuildCache: boolean;
32
44
  copyIgnorePatterns: string;
33
45
  builtinCopyIgnore: string;
46
+ gitIdentityEnabled: boolean;
47
+ gitIdentityName: string;
48
+ gitIdentityEmail: string;
34
49
  dockerArch: string | null;
35
50
  manualTokensEnabled: boolean;
36
51
  githubTokenSet: boolean;
@@ -43,6 +58,12 @@
43
58
  customEndpointHaikuModel: string;
44
59
  customEndpointSmallFastModel: string;
45
60
  customEndpointModel: string;
61
+ manualModelOverrideEnabled: boolean;
62
+ manualOpusModel: string;
63
+ manualSonnetModel: string;
64
+ manualHaikuModel: string;
65
+ manualSmallFastModel: string;
66
+ manualModel: string;
46
67
  hostEnvVarsEnabled: boolean;
47
68
  hostEnvVarNames: string[];
48
69
  hostEnvVarPresence: Record<string, boolean>;
@@ -51,11 +72,15 @@
51
72
  </script>
52
73
 
53
74
  <SettingsView
75
+ {pet}
54
76
  {defaultImage}
55
77
  {builtinImage}
56
78
  {disableBuildCache}
57
79
  {copyIgnorePatterns}
58
80
  {builtinCopyIgnore}
81
+ {gitIdentityEnabled}
82
+ {gitIdentityName}
83
+ {gitIdentityEmail}
59
84
  {dockerArch}
60
85
  {manualTokensEnabled}
61
86
  {githubTokenSet}
@@ -68,6 +93,12 @@
68
93
  {customEndpointHaikuModel}
69
94
  {customEndpointSmallFastModel}
70
95
  {customEndpointModel}
96
+ {manualModelOverrideEnabled}
97
+ {manualOpusModel}
98
+ {manualSonnetModel}
99
+ {manualHaikuModel}
100
+ {manualSmallFastModel}
101
+ {manualModel}
71
102
  {hostEnvVarsEnabled}
72
103
  {hostEnvVarNames}
73
104
  {hostEnvVarPresence}
package/src/routes.ts CHANGED
@@ -19,10 +19,13 @@ import {
19
19
  DEFAULT_SONNET_MODEL
20
20
  } from './container-injections/claude-code-custom.ts';
21
21
  import { hostEnvVarPresence, parseHostEnvVarNames } from './container-injections/host-env-vars.ts';
22
+ import { gitIdentityEnabled } from './container-injections/git-identity.ts';
22
23
  import { browse } from './lib/picker.server.ts';
23
24
  import { pickNamePrompt } from './avatars/name-prompts.ts';
25
+ import { avatars, findAvatar } from './avatars/index.ts';
24
26
  import {
25
27
  addForwardedPort,
28
+ broadcastPet,
26
29
  createInstance,
27
30
  deleteAllInstances,
28
31
  deleteDatabaseAndShutdown,
@@ -75,6 +78,11 @@ async function preflight() {
75
78
  return { docker, cli, auth };
76
79
  }
77
80
 
81
+ /** The header pet logo, resolved from the DB option. A name that left the catalog reads as "off". */
82
+ function currentPet() {
83
+ return findAvatar(getOption('pet') ?? undefined);
84
+ }
85
+
78
86
  /** Lets a route handler just `throw` for both validation and business-logic failures. */
79
87
  async function mutate(fn: () => Promise<unknown> | unknown): Promise<Response> {
80
88
  try {
@@ -111,7 +119,8 @@ export const routes: Record<string, MochiRouteValue> = {
111
119
  serverProps: async () => ({
112
120
  preflight: await preflight(),
113
121
  initialPath: '/',
114
- snapshot: await listInstances()
122
+ snapshot: await listInstances(),
123
+ pet: currentPet()
115
124
  })
116
125
  }),
117
126
 
@@ -121,7 +130,8 @@ export const routes: Record<string, MochiRouteValue> = {
121
130
  return {
122
131
  preflight: await preflight(),
123
132
  initialPath: `/ide/${params.id}`,
124
- snapshot: await listInstances()
133
+ snapshot: await listInstances(),
134
+ pet: currentPet()
125
135
  };
126
136
  }
127
137
  }),
@@ -158,12 +168,18 @@ export const routes: Record<string, MochiRouteValue> = {
158
168
  // Only names ever reach the client; presence is sent separately, values never.
159
169
  const hostEnvVarNames = parseHostEnvVarNames(getOption('host_env_var_names'));
160
170
  return {
171
+ pet: currentPet(),
161
172
  defaultImage: getOption('default_image') ?? DEFAULT_IMAGE,
162
173
  builtinImage: DEFAULT_IMAGE,
163
174
  disableBuildCache: getOption('disable_build_cache') === '1',
164
175
  // An explicit empty string (as opposed to unset) means "copy everything".
165
176
  copyIgnorePatterns: getOption('copy_ignore_patterns') ?? DEFAULT_COPY_IGNORE,
166
177
  builtinCopyIgnore: DEFAULT_COPY_IGNORE,
178
+ // Not secrets, so the actual values (not just a "set" flag) go to the client.
179
+ // Blank means "no override" — fall back to the host's git config.
180
+ gitIdentityEnabled: gitIdentityEnabled(),
181
+ gitIdentityName: getOption('git_identity_name') ?? '',
182
+ gitIdentityEmail: getOption('git_identity_email') ?? '',
167
183
  dockerArch: await dockerArch(),
168
184
  // Only whether each token is set — the page renders a placeholder from that.
169
185
  manualTokensEnabled: getOption('manual_tokens_enabled') === '1',
@@ -182,6 +198,14 @@ export const routes: Record<string, MochiRouteValue> = {
182
198
  customEndpointSmallFastModel:
183
199
  getOption('custom_endpoint_small_fast_model') ?? DEFAULT_SMALL_FAST_MODEL,
184
200
  customEndpointModel: getOption('custom_endpoint_model') ?? DEFAULT_MODEL,
201
+ // Manual model override (standard subscription path): toggle + five blank-by-default
202
+ // model IDs — only the ones the user fills get injected, so no Bedrock-default seeding.
203
+ manualModelOverrideEnabled: getOption('manual_model_override_enabled') === '1',
204
+ manualOpusModel: getOption('manual_opus_model') ?? '',
205
+ manualSonnetModel: getOption('manual_sonnet_model') ?? '',
206
+ manualHaikuModel: getOption('manual_haiku_model') ?? '',
207
+ manualSmallFastModel: getOption('manual_small_fast_model') ?? '',
208
+ manualModel: getOption('manual_model') ?? '',
185
209
  hostEnvVarsEnabled: getOption('host_env_vars_enabled') === '1',
186
210
  hostEnvVarNames,
187
211
  hostEnvVarPresence: hostEnvVarPresence(hostEnvVarNames),
@@ -203,6 +227,32 @@ export const routes: Record<string, MochiRouteValue> = {
203
227
  return success({ enabled });
204
228
  },
205
229
 
230
+ // Turning the pet on with none chosen lands on a random sprite, so there's always one to adjust.
231
+ petToggle: ({ formData }) => {
232
+ const enabled = onChecked(formData, 'enabled');
233
+ if (!enabled) {
234
+ setOption('pet', '');
235
+ broadcastPet(null);
236
+ return success({ enabled: false });
237
+ }
238
+ const current = getOption('pet');
239
+ const name =
240
+ current && findAvatar(current)
241
+ ? current
242
+ : avatars[Math.floor(Math.random() * avatars.length)]!.name;
243
+ setOption('pet', name);
244
+ broadcastPet(name);
245
+ return success({ enabled: true, name });
246
+ },
247
+
248
+ petChoose: ({ formData }) => {
249
+ const name = str(formData, 'name');
250
+ if (!findAvatar(name)) return fail(400, { error: 'Unknown pet' });
251
+ setOption('pet', name);
252
+ broadcastPet(name);
253
+ return success({ name });
254
+ },
255
+
206
256
  // Unlike defaultImage, an empty value is valid — it means "copy everything".
207
257
  copyIgnorePatterns: ({ formData }) => {
208
258
  const patterns = str(formData, 'patterns');
@@ -210,6 +260,24 @@ export const routes: Record<string, MochiRouteValue> = {
210
260
  return success({ patterns });
211
261
  },
212
262
 
263
+ gitIdentityToggle: ({ formData }) => {
264
+ const enabled = onChecked(formData, 'enabled');
265
+ setOption('git_identity_enabled', enabled ? '1' : '0');
266
+ return success({ enabled });
267
+ },
268
+ // Both fields are required — the toggle governs whether the override applies, so a
269
+ // half-filled or empty identity is never a valid saved state.
270
+ gitIdentityOverride: ({ formData }) => {
271
+ const name = str(formData, 'name');
272
+ const email = str(formData, 'email');
273
+ if (!name || !email) {
274
+ return fail(400, { error: 'Both name and email are required.' });
275
+ }
276
+ setOption('git_identity_name', name);
277
+ setOption('git_identity_email', email);
278
+ return success({ name, email });
279
+ },
280
+
213
281
  // Tokens are stored plaintext in the options table and never sent back to the client.
214
282
  manualTokensToggle: ({ formData }) => {
215
283
  const enabled = onChecked(formData, 'enabled');
@@ -230,6 +298,8 @@ export const routes: Record<string, MochiRouteValue> = {
230
298
  customEndpointToggle: ({ formData }) => {
231
299
  const enabled = onChecked(formData, 'enabled');
232
300
  setOption('custom_endpoint_enabled', enabled ? '1' : '0');
301
+ // LiteLLM and the manual model override own the same env vars — never both.
302
+ if (enabled) setOption('manual_model_override_enabled', '0');
233
303
  return success({ enabled });
234
304
  },
235
305
  customBaseUrl: ({ formData }) => {
@@ -251,6 +321,22 @@ export const routes: Record<string, MochiRouteValue> = {
251
321
  return success({});
252
322
  },
253
323
 
324
+ manualModelToggle: ({ formData }) => {
325
+ const enabled = onChecked(formData, 'enabled');
326
+ setOption('manual_model_override_enabled', enabled ? '1' : '0');
327
+ // Reciprocal of customEndpointToggle — the two can't both drive model env vars.
328
+ if (enabled) setOption('custom_endpoint_enabled', '0');
329
+ return success({ enabled });
330
+ },
331
+ manualModels: ({ formData }) => {
332
+ setOption('manual_opus_model', str(formData, 'opusModel'));
333
+ setOption('manual_sonnet_model', str(formData, 'sonnetModel'));
334
+ setOption('manual_haiku_model', str(formData, 'haikuModel'));
335
+ setOption('manual_small_fast_model', str(formData, 'smallFastModel'));
336
+ setOption('manual_model', str(formData, 'defaultModel'));
337
+ return success({});
338
+ },
339
+
254
340
  // Only names are stored; a value is never persisted nor accepted from the client.
255
341
  hostEnvVarsToggle: ({ formData }) => {
256
342
  const enabled = onChecked(formData, 'enabled');
@@ -1 +0,0 @@
1
- import{Ua as a}from"/_mochi/client/chunk-qxwt25hn.js";export{a as registerComponent};
@@ -1,2 +0,0 @@
1
- import{a as je,b as Ie,c as zt,d as He,e as Ee,f as Je,h as ei}from"/_mochi/client/chunk-5jnepvzx.js";import{i as $e,l as Ut,m as ti}from"/_mochi/client/chunk-tr67wtwn.js";import{n as Yt}from"/_mochi/client/chunk-hcztrd75.js";import{t as Gt,u as ft,v as qe,w as Xt,x as Ge}from"/_mochi/client/chunk-sjmcgh7f.js";import{y as q}from"/_mochi/client/chunk-04qv4w6w.js";import{B as l,Ba as gt,C as X,Ea as Pt,G as dt,H as ot,Ha as rt,Ja as Tt,Ka as Ze,Ma as U,N as se,Na as j,O as Se,Oa as Et,P,R as ee,S as h,Sa as Ye,U as n,Ua as ii,V as lt,W as Lt,X as d,Y as xt,Z as s,_ as $t,ba as A,ca as he,da as ue,ea as Wt,fa as Qe,ga as t,ja as Ue,ka as Dt,la as Q,ma as Bt,na as c,pa as st,qa as oe,ra as o,sa as Z,ta as N,ua as Xe,va as mt,ya as Oe}from"/_mochi/client/chunk-qxwt25hn.js";var Fe=!1;class xe extends Date{#t=h(super.getTime());#e=new Map;#i=he;constructor(...i){super(...i);if(!Fe)this.#a()}#a(){Fe=!0;var i=xe.prototype,e=Date.prototype,a=Object.getOwnPropertyNames(e);for(let r of a){if(r.startsWith("get")||r.startsWith("to")||r==="valueOf")i[r]=function(...v){if(v.length>0)return t(this.#t),e[r].apply(this,v);var p=this.#e.get(r);if(p===void 0){let S=he;ue(this.#i),p=P(()=>{return t(this.#t),e[r].apply(this,v)}),this.#e.set(r,p),ue(S)}return t(p)};if(r.startsWith("set"))i[r]=function(...v){var p=e[r].apply(this,v);return n(this.#t,e.getTime.call(this)),p}}}}var ri=["forEach","isDisjointFrom","isSubsetOf","isSupersetOf"],ni=["difference","intersection","symmetricDifference","union"],ke=!1;class Mt extends Set{#t=new Map;#e=h(0);#i=h(0);#a=Wt||-1;constructor(i){super();if(i){for(var e of i)super.add(e);this.#i.v=super.size}if(!ke)this.#n()}#r(i){return Wt===this.#a?h(i):ee(i)}#n(){ke=!0;var i=Mt.prototype,e=Set.prototype;for(let a of ri)i[a]=function(...r){return t(this.#e),e[a].apply(this,r)};for(let a of ni)i[a]=function(...r){t(this.#e);var v=e[a].apply(this,r);return new Mt(v)}}has(i){var e=super.has(i),a=this.#t,r=a.get(i);if(r===void 0){if(!e)return t(this.#e),!1;r=this.#r(!0),a.set(i,r)}return t(r),e}add(i){if(!super.has(i))super.add(i),n(this.#i,super.size),lt(this.#e);return this}delete(i){var e=super.delete(i),a=this.#t,r=a.get(i);if(r!==void 0)a.delete(i),n(r,!1);if(e)n(this.#i,super.size),lt(this.#e);return e}clear(){if(super.size===0)return;super.clear();var i=this.#t;for(var e of i.values())n(e,!1);i.clear(),n(this.#i,0),lt(this.#e)}keys(){return this.values()}values(){return t(this.#e),super.values()}entries(){return t(this.#e),super.entries()}[Symbol.iterator](){return this.keys()}get size(){return t(this.#i)}}class Re extends Map{#t=new Map;#e=h(0);#i=h(0);#a=Wt||-1;constructor(i){super();if(i){for(var[e,a]of i)super.set(e,a);this.#i.v=super.size}}#r(i){return Wt===this.#a?h(i):ee(i)}has(i){var e=this.#t,a=e.get(i);if(a===void 0)if(super.has(i))a=this.#r(0),e.set(i,a);else return t(this.#e),!1;return t(a),!0}forEach(i,e){this.#n(),super.forEach(i,e)}get(i){var e=this.#t,a=e.get(i);if(a===void 0)if(super.has(i))a=this.#r(0),e.set(i,a);else{t(this.#e);return}return t(a),super.get(i)}set(i,e){var a=this.#t,r=a.get(i),v=super.get(i),p=super.set(i,e),S=this.#e;if(r===void 0)r=this.#r(0),a.set(i,r),n(this.#i,super.size),lt(S);else if(v!==e){lt(r);var C=S.reactions===null?null:new Set(S.reactions),w=C===null||!r.reactions?.every((R)=>C.has(R));if(w)lt(S)}return p}delete(i){var e=this.#t,a=e.get(i),r=super.delete(i);if(a!==void 0)e.delete(i),n(a,-1);if(r)n(this.#i,super.size),lt(this.#e);return r}clear(){if(super.size===0)return;super.clear();var i=this.#t;n(this.#i,0);for(var e of i.values())n(e,-1);lt(this.#e),i.clear()}#n(){t(this.#e);var i=this.#t;if(this.#i.v!==i.size){for(var e of super.keys())if(!i.has(e)){var a=this.#r(0);i.set(e,a)}}for([,a]of this.#t)t(a)}keys(){return t(this.#e),super.keys()}values(){return this.#n(),super.values()}entries(){return this.#n(),super.entries()}[Symbol.iterator](){return this.entries()}get size(){return t(this.#i),super.size}}var ie=Symbol("replace");class ae extends URLSearchParams{#t=h(0);#e=_e();#i=!1;#a(){if(!this.#e||this.#i)return;this.#i=!0;let i=this.toString();this.#e.search=i&&`?${i}`,this.#i=!1}[ie](i){if(this.#i)return;if(i.toString()===super.toString())return;this.#i=!0;for(let e of[...super.keys()])super.delete(e);for(let[e,a]of i)super.append(e,a);lt(this.#t),this.#i=!1}append(i,e){super.append(i,e),this.#a(),lt(this.#t)}delete(i,e){var a=super.has(i,e);if(super.delete(i,e),a)this.#a(),lt(this.#t)}get(i){return t(this.#t),super.get(i)}getAll(i){return t(this.#t),super.getAll(i)}has(i,e){return t(this.#t),super.has(i,e)}keys(){return t(this.#t),super.keys()}forEach(i,e){t(this.#t),super.forEach(i,e)}set(i,e){var a=super.getAll(i);super.set(i,e);var r=super.getAll(i);if(a.length!==r.length||a.some((v,p)=>v!==r[p]))this.#a(),lt(this.#t)}sort(){super.sort(),this.#a(),lt(this.#t)}toString(){return t(this.#t),super.toString()}values(){return t(this.#t),super.values()}entries(){return t(this.#t),super.entries()}[Symbol.iterator](){return this.entries()}get size(){return t(this.#t),super.size}}var be=null;function _e(){return be}class ye extends URL{#t=h(super.protocol);#e=h(super.username);#i=h(super.password);#a=h(super.hostname);#r=h(super.port);#n=h(super.pathname);#l=h(super.hash);#d=h(super.search);#o;constructor(i,e){i=new URL(i,e);super(i);be=this,this.#o=new ae(i.searchParams),be=null}get hash(){return t(this.#l)}set hash(i){super.hash=i,n(this.#l,super.hash)}get host(){return t(this.#a),t(this.#r),super.host}set host(i){super.host=i,n(this.#a,super.hostname),n(this.#r,super.port)}get hostname(){return t(this.#a)}set hostname(i){super.hostname=i,n(this.#a,super.hostname)}get href(){return t(this.#t),t(this.#e),t(this.#i),t(this.#a),t(this.#r),t(this.#n),t(this.#l),t(this.#d),super.href}set href(i){super.href=i,n(this.#t,super.protocol),n(this.#e,super.username),n(this.#i,super.password),n(this.#a,super.hostname),n(this.#r,super.port),n(this.#n,super.pathname),n(this.#l,super.hash),n(this.#d,super.search),this.#o[ie](super.searchParams)}get password(){return t(this.#i)}set password(i){super.password=i,n(this.#i,super.password)}get pathname(){return t(this.#n)}set pathname(i){super.pathname=i,n(this.#n,super.pathname)}get port(){return t(this.#r)}set port(i){super.port=i,n(this.#r,super.port)}get protocol(){return t(this.#t)}set protocol(i){super.protocol=i,n(this.#t,super.protocol)}get search(){return t(this.#d)}set search(i){super.search=i,n(this.#d,super.search),this.#o[ie](super.searchParams)}get username(){return t(this.#e)}set username(i){super.username=i,n(this.#e,super.username)}get origin(){return t(this.#t),t(this.#a),t(this.#r),super.origin}get searchParams(){return this.#o}toString(){return this.href}toJSON(){return this.href}}class We{#t;#e;constructor(i,e){this.#t=i,this.#e=Se(e)}get current(){return this.#e(),this.#t()}}var Ke=/^[A-Za-z0-9._-]+$/;function di(i){let e=i.trim();if(!e)return null;let a,r,v=e.match(/^[A-Za-z0-9._-]+@([A-Za-z0-9.-]+):(.+)$/);if(v)a=v[1],r=v[2];else if(/^[a-z][a-z0-9+.-]*:\/\//i.test(e)){let w;try{w=new URL(e)}catch{return null}if(w.protocol!=="http:"&&w.protocol!=="https:"&&w.protocol!=="ssh:")return null;a=w.hostname,r=w.pathname}else{let w=e.match(/^([A-Za-z0-9-]+\.[A-Za-z0-9.-]+)\/(.+)$/);if(!w)return null;a=w[1],r=w[2]}if(!a||!r)return null;let p=r.replace(/\.git$/i,"").split("/").filter(Boolean),[S,C]=p;if(!S||!C||!Ke.test(S)||!Ke.test(C))return null;return{host:a,owner:S,repo:C,cloneUrl:`https://${a}/${S}/${C}.git`}}function we(i){return di(i)!==null}var oi=new Set(["$$slots","$$events","$$legacy"]);function re(i,e){let a=U(e,oi),r=[["path",{d:"M16 14v2.2l1.6 1"}],["path",{d:"M7 20H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h3.9a2 2 0 0 1 1.69.9l.81 1.2a2 2 0 0 0 1.67.9H20a2 2 0 0 1 2 2"}],["circle",{cx:"16",cy:"16",r:"6"}]];q(i,j({name:"folder-clock"},()=>a,{get iconNode(){return r}}))}var si=new Set(["$$slots","$$events","$$legacy"]);function Kt(i,e){let a=U(e,si),r=[["path",{d:"M15 6a9 9 0 0 0-9 9V3"}],["circle",{cx:"18",cy:"6",r:"3"}],["circle",{cx:"6",cy:"18",r:"3"}]];q(i,j({name:"git-branch"},()=>a,{get iconNode(){return r}}))}var fi=new Set(["$$slots","$$events","$$legacy"]);function ne(i,e){let a=U(e,fi),r=[["path",{d:"m5 12 7-7 7 7"}],["path",{d:"M12 19V5"}]];q(i,j({name:"arrow-up"},()=>a,{get iconNode(){return r}}))}var ci=new Set(["$$slots","$$events","$$legacy"]);function le(i,e){let a=U(e,ci),r=[["path",{d:"M20 20a2 2 0 0 0 2-2V8a2 2 0 0 0-2-2h-7.9a2 2 0 0 1-1.69-.9L9.6 3.9A2 2 0 0 0 7.93 3H4a2 2 0 0 0-2 2v13a2 2 0 0 0 2 2Z"}]];q(i,j({name:"folder"},()=>a,{get iconNode(){return r}}))}var mi=new Set(["$$slots","$$events","$$legacy"]);function Qt(i,e){let a=U(e,mi),r=[["path",{d:"m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3"}],["path",{d:"M12 9v4"}],["path",{d:"M12 17h.01"}]];q(i,j({name:"triangle-alert"},()=>a,{get iconNode(){return r}}))}var $i=c('<div class="recent-row svelte-oq97c4"><button class="recent-pick svelte-oq97c4"><span class="icon svelte-oq97c4"><!></span> <span class="recent-text svelte-oq97c4"><span class="recent-name svelte-oq97c4"> </span> <span class="recent-path svelte-oq97c4"> </span></span></button> <button class="recent-x svelte-oq97c4" title="Remove from history"><!></button></div>'),gi=c('<button class="recent-toggle svelte-oq97c4"> </button>'),vi=c('<div class="recent svelte-oq97c4"><div class="recent-label svelte-oq97c4">Recent</div> <!> <!></div>'),pi=c('<div class="muted svelte-oq97c4">Loading…</div>'),hi=c('<div class="muted err svelte-oq97c4"> </div>'),ui=c('<div class="row svelte-oq97c4"><button class="nav svelte-oq97c4"><span class="icon svelte-oq97c4"><!></span> <span class="ename svelte-oq97c4">..</span></button></div>'),xi=c('<div class="muted svelte-oq97c4"> </div>'),bi=c('<span class="badge svelte-oq97c4">devcontainer</span>'),Si=c('<div><button class="nav svelte-oq97c4"><span class="icon svelte-oq97c4"><!></span> <span class="ename svelte-oq97c4"> </span> <!></button> <button class="pick-inline svelte-oq97c4">Select</button></div>'),wi=c("<!> <!> <!>",1),Ii=c(`<div class="warn svelte-oq97c4"><!> <span>No <code class="svelte-oq97c4">devcontainer.json</code> in this folder — a default image will be used if you select
2
- it.</span></div>`),Ni=c('<div class="overlay svelte-oq97c4" role="button" tabindex="0"><div class="modal panel svelte-oq97c4" role="dialog" aria-modal="true" aria-label="Pick a project folder" tabindex="-1"><div class="head svelte-oq97c4"><h2 class="svelte-oq97c4">Pick a project folder</h2> <button class="x svelte-oq97c4" aria-label="Close"><!></button></div> <div class="clone svelte-oq97c4"><div class="clone-label svelte-oq97c4">Clone a Git repository</div> <div class="clone-row svelte-oq97c4"><input class="clone-url svelte-oq97c4" type="text" placeholder="https://github.com/owner/repo" spellcheck="false" autocomplete="off"/> <input class="clone-branch svelte-oq97c4" type="text" placeholder="branch (optional)" spellcheck="false" autocomplete="off"/> <button class="clone-btn svelte-oq97c4">Clone</button></div></div> <div class="crumbs svelte-oq97c4"><code class="svelte-oq97c4"> </code></div> <!> <div class="search svelte-oq97c4"><input type="text" placeholder="Filter folders…" spellcheck="false" autocomplete="off" class="svelte-oq97c4"/></div> <div class="list svelte-oq97c4"><!></div> <!> <div class="foot svelte-oq97c4"><span class="hint svelte-oq97c4">Browse to a folder, then select this folder or any subfolder.</span> <button class="primary svelte-oq97c4">Select this folder</button></div></div></div>');function Ne(i,e){dt(e,!0);let a=h(null),r=h(!0),v=h(null),p=h(""),S=h(null),C=h(Lt([])),w=h(!1),R=h(""),z=h(""),V=P(()=>we(t(R)));function F(){if(!t(V))return;e.onpick(t(R).trim(),{branch:t(z).trim()||void 0})}let $=P(()=>t(a)?t(a).entries.filter((g)=>g.name.toLowerCase().includes(t(p).trim().toLowerCase())):[]),E=P(()=>t(w)?t(C):t(C).slice(0,5));async function u(){try{let g=await Ie("/api/history");n(C,g.history??[],!0)}catch{}}async function D(g){let K=t(C);n(C,t(C).filter((ut)=>ut.source_path!==g),!0);try{await He("/api/history",{sourcePath:g})}catch{n(C,K,!0)}}async function M(g=null){n(r,!0),n(v,null),n(p,"");try{let K=g?`/api/browse?path=${encodeURIComponent(g)}`:"/api/browse";n(a,await Ie(K,void 0,"Could not list folder"),!0)}catch(K){n(v,K.message,!0)}finally{n(r,!1)}await Qe(),t(S)?.focus()}$t(()=>{M(),u()});var k=Ni(),T=d(k),W=d(T),Y=s(d(W),2),O=d(Y);Yt(O,{size:16}),l(Y),l(W);var et=s(W,2),St=s(d(et),2),wt=d(St);Pt(wt);var bt=s(wt,2);Pt(bt);var I=s(bt,2);l(St),l(et);var L=s(et,2),H=d(L),f=d(H,!0);l(H),l(L);var x=s(L,2);{var B=(g)=>{var K=vi(),ut=s(d(K),2);mt(ut,17,()=>t(E),(It)=>It.source_path,(It,ct)=>{var tt=$i(),y=d(tt),at=d(y),Nt=d(at);{var Rt=(Ct)=>{Kt(Ct,{size:16})},_t=P(()=>we(t(ct).source_path)),Ot=(Ct)=>{re(Ct,{size:16})};N(Nt,(Ct)=>{if(t(_t))Ct(Rt);else Ct(Ot,-1)})}l(at);var jt=s(at,2),Vt=d(jt),ve=d(Vt,!0);l(Vt);var qt=s(Vt,2),pe=d(qt,!0);l(qt),l(jt),l(y);var yt=s(y,2),Ft=d(yt);Yt(Ft,{size:14}),l(yt),l(tt),A(()=>{Z(ve,t(ct).name),Z(pe,t(ct).source_path),rt(yt,"aria-label",`Remove ${t(ct).name??""} from history`)}),Q("click",y,()=>e.onpick(t(ct).source_path)),Q("click",yt,(Ct)=>{Ct.stopPropagation(),D(t(ct).source_path)}),o(It,tt)});var Jt=s(ut,2);{var kt=(It)=>{var ct=gi(),tt=d(ct,!0);l(ct),A(()=>Z(tt,t(w)?"Show fewer":`Show all (${t(C).length})`)),Q("click",ct,()=>n(w,!t(w))),o(It,ct)};N(Jt,(It)=>{if(t(C).length>5)It(kt)})}l(K),o(g,K)};N(x,(g)=>{if(t(C).length>0)g(B)})}var J=s(x,2),nt=d(J);Pt(nt),Ze(nt,(g)=>n(S,g),()=>t(S)),l(J);var m=s(J,2),b=d(m);{var it=(g)=>{var K=pi();o(g,K)},vt=(g)=>{var K=hi(),ut=d(K,!0);l(K),A(()=>Z(ut,t(v))),o(g,K)},pt=(g)=>{var K=wi(),ut=xt(K);{var Jt=(tt)=>{var y=ui(),at=d(y),Nt=d(at),Rt=d(Nt);ne(Rt,{size:16}),l(Nt),X(2),l(at),l(y),Q("click",at,()=>M(t(a)?.parent??null)),o(tt,y)};N(ut,(tt)=>{if(t(a).parent&&!t(p))tt(Jt)})}var kt=s(ut,2);{var It=(tt)=>{var y=xi(),at=d(y,!0);l(y),A(()=>Z(at,t(p)?"No folders match.":"No subfolders here.")),o(tt,y)};N(kt,(tt)=>{if(t($).length===0)tt(It)})}var ct=s(kt,2);mt(ct,19,()=>t($),(tt)=>tt.path,(tt,y,at)=>{var Nt=Si();let Rt;var _t=d(Nt),Ot=d(_t),jt=d(Ot);le(jt,{size:16}),l(Ot);var Vt=s(Ot,2),ve=d(Vt,!0);l(Vt);var qt=s(Vt,2);{var pe=(Ft)=>{var Ct=bi();o(Ft,Ct)};N(qt,(Ft)=>{if(t(y).hasDevcontainer)Ft(pe)})}l(_t);var yt=s(_t,2);l(Nt),A((Ft)=>{Rt=gt(Nt,1,"row svelte-oq97c4",null,Rt,Ft),Z(ve,t(y).name)},[()=>({"first-match":t(p).trim()&&t(at)===0})]),Q("click",_t,()=>M(t(y).path)),Q("click",yt,()=>e.onpick(t(y).path)),o(tt,Nt)}),o(g,K)};N(b,(g)=>{if(t(r))g(it);else if(t(v))g(vt,1);else if(t(a))g(pt,2)})}l(m);var _=s(m,2);{var ht=(g)=>{var K=Ii(),ut=d(K);Qt(ut,{size:15}),X(2),l(K),o(g,K)};N(_,(g)=>{if(t(a)&&!t(a).hasDevcontainer)g(ht)})}var At=s(_,2),Ht=s(d(At),2);l(At),l(T),l(k),A(()=>{I.disabled=!t(V),Z(f,t(a)?.path??"…"),Ht.disabled=!t(a)}),Q("click",k,function(...g){e.onclose?.apply(this,g)}),Q("keydown",k,(g)=>g.key==="Escape"&&e.onclose()),Q("click",T,(g)=>g.stopPropagation()),Q("keydown",T,()=>{}),Q("click",Y,function(...g){e.onclose?.apply(this,g)}),Q("keydown",wt,(g)=>{if(g.key==="Enter")g.preventDefault(),F()}),Tt(wt,()=>t(R),(g)=>n(R,g)),Q("keydown",bt,(g)=>{if(g.key==="Enter")g.preventDefault(),F()}),Tt(bt,()=>t(z),(g)=>n(z,g)),Q("click",I,F),Q("keydown",nt,(g)=>{let K=t($)[0];if(g.key==="Enter"&&K)g.preventDefault(),M(K.path)}),Tt(nt,()=>t(p),(g)=>n(p,g)),Q("click",Ht,()=>t(a)&&e.onpick(t(a).path)),o(i,k),ot()}Bt(["click","keydown"]);var Ci=c('<div class="branch svelte-jv8lut" title="Branch checked out in the container"><!><span class="svelte-jv8lut"> </span></div>');function Ce(i,e){var a=Ci(),r=d(a);Kt(r,{size:12});var v=s(r),p=d(v,!0);l(v),l(a),A(()=>Z(p,e.branch)),o(i,a)}var Ei=new Set(["$$slots","$$events","$$legacy"]);function de(i,e){let a=U(e,Ei),r=[["path",{d:"M17 19a1 1 0 0 1-1-1v-2a2 2 0 0 1 2-2h2a2 2 0 0 1 2 2v2a1 1 0 0 1-1 1z"}],["path",{d:"M17 21v-2"}],["path",{d:"M19 14V6.5a1 1 0 0 0-7 0v11a1 1 0 0 1-7 0V10"}],["path",{d:"M21 21v-2"}],["path",{d:"M3 5V3"}],["path",{d:"M4 10a2 2 0 0 1-2-2V6a1 1 0 0 1 1-1h4a1 1 0 0 1 1 1v2a2 2 0 0 1-2 2z"}],["path",{d:"M7 5V3"}]];q(i,j({name:"cable"},()=>a,{get iconNode(){return r}}))}var Mi=c('<a target="_blank" rel="noopener"> </a>'),Li=c('<div class="fports svelte-1uaz383" title="Forwarded ports — click to open"><!> <span class="list svelte-1uaz383"></span></div>');function Me(i,e){dt(e,!0);var a=oe(),r=xt(a);{var v=(p)=>{var S=Li(),C=d(S);de(C,{size:12});var w=s(C,2);mt(w,21,()=>e.ports,(R)=>R.container_port,(R,z)=>{var V=Mi();let F;var $=d(V,!0);l(V),A((E,u)=>{F=gt(V,1,"fport svelte-1uaz383",null,F,{open:t(z).open}),rt(V,"href",E),rt(V,"title",u),Z($,t(z).container_port)},[()=>Ee(t(z).host_port),()=>`container :${t(z).container_port} → ${Ee(t(z).host_port)} ${t(z).open?"(open)":"(not published yet)"}`]),o(R,V)}),l(w),l(S),o(p,S)};N(r,(p)=>{if(e.ports.length)p(v)})}o(i,a),ot()}var Pi=c('<input class="name-edit svelte-13338y7"/>'),Ti=c('<button class="name svelte-13338y7" title="Click to rename"> </button>'),Bi=c("<span></span>"),Di=c('<div class="card-error svelte-13338y7"> </div>'),zi=c("<!> <!>",1),Ai=c('<li class="card panel svelte-13338y7"><div class="card-head svelte-13338y7"><!> <!> <!> <!></div> <div class="path svelte-13338y7"> </div> <!> <!> <!> <div class="actions svelte-13338y7"><!> <!> <!> <!></div></li>');function Le(i,e){dt(e,!0);let a=Et(e,"editingName",15),r=P(()=>e.instance.status==="running"||e.instance.status==="stopped"||e.instance.status==="error"&&!!e.instance.container_id);var v=Ai(),p=d(v),S=d(p);Gt(S,{get id(){return e.instance.id},get name(){return e.instance.name},interactive:!0});var C=s(S,2);{var w=(f)=>{var x=Pi();Pt(x),se(x,!0),Dt("focus",x,(B)=>B.currentTarget.select()),Dt("blur",x,function(...B){e.oncommitrename?.apply(this,B)}),Q("keydown",x,(B)=>{if(B.key==="Enter")B.currentTarget.blur();else if(B.key==="Escape")e.oncancelrename()}),Tt(x,a),o(f,x)},R=(f)=>{var x=Ti(),B=d(x,!0);l(x),A(()=>Z(B,e.instance.name)),Q("click",x,function(...J){e.onstartrename?.apply(this,J)}),o(f,x)};N(C,(f)=>{if(e.editing)f(w);else f(R,-1)})}var z=s(C,2);{var V=(f)=>{var x=Bi();let B;A(()=>{B=gt(x,1,"attn svelte-13338y7",null,B,{"attn-done":e.instance.attention==="done","attn-waiting":e.instance.attention==="waiting"}),rt(x,"title",e.instance.attention==="waiting"?"Claude is waiting for input":"Claude finished"),rt(x,"aria-label",e.instance.attention==="waiting"?"Claude is waiting for input":"Claude finished")}),o(f,x)};N(z,(f)=>{if(e.instance.attention)f(V)})}var F=s(z,2);Je(F,{get status(){return e.instance.status}}),l(p);var $=s(p,2),E=d($,!0);l($);var u=s($,2);{var D=(f)=>{Me(f,{get ports(){return e.instance.forwarded_ports}})};N(u,(f)=>{if(e.instance.status==="running")f(D)})}var M=s(u,2);{var k=(f)=>{Ce(f,{get branch(){return e.instance.git_branch}})};N(M,(f)=>{if(e.instance.git_branch)f(k)})}var T=s(M,2);{var W=(f)=>{var x=Di(),B=d(x,!0);l(x),A(()=>Z(B,e.instance.error)),o(f,x)};N(T,(f)=>{if(e.instance.status==="error"&&e.instance.error)f(W)})}var Y=s(T,2),O=d(Y);{var et=(f)=>{var x=zi(),B=xt(x);{let nt=P(()=>`/ide/${e.instance.id}`);ft(B,{variant:"primary",size:"sm",get href(){return t(nt)},children:(m,b)=>{X();var it=st("Open IDE");o(m,it)},$$slots:{default:!0}})}var J=s(B,2);ft(J,{size:"sm",onclick:()=>e.onact("stop"),children:(nt,m)=>{X();var b=st("Stop");o(nt,b)},$$slots:{default:!0}}),o(f,x)},St=(f)=>{ft(f,{size:"sm",onclick:()=>e.onact("start"),children:(x,B)=>{X();var J=st("Start");o(x,J)},$$slots:{default:!0}})},wt=(f)=>{{let x=P(()=>`/instances/${e.instance.id}`);ft(f,{size:"sm",get href(){return t(x)},target:"_blank",rel:"noopener noreferrer",children:(B,J)=>{X();var nt=st("View logs");o(B,nt)},$$slots:{default:!0}})}};N(O,(f)=>{if(e.instance.status==="running")f(et);else if(e.instance.status==="stopped"||e.instance.status==="error"&&e.instance.container_id)f(St,1);else if(e.instance.status==="creating")f(wt,2)})}var bt=s(O,2);{var I=(f)=>{ft(f,{size:"sm",title:"Recreate the container and re-run setup (credentials, hooks, port forwards)",onclick:()=>e.onact("rebuild"),children:(x,B)=>{X();var J=st("Rebuild");o(x,J)},$$slots:{default:!0}})};N(bt,(f)=>{if(t(r))f(I)})}var L=s(bt,2);{let f=P(()=>`/instances/${e.instance.id}`);ft(L,{size:"sm",ghost:!0,get href(){return t(f)},target:"_blank",rel:"noopener noreferrer",children:(x,B)=>{X();var J=st("Details");o(x,J)},$$slots:{default:!0}})}var H=s(L,2);ft(H,{variant:"danger",size:"sm",onclick:()=>e.onact("delete"),children:(f,x)=>{X();var B=st("Delete");o(f,B)},$$slots:{default:!0}}),l(Y),l(v),A(()=>{rt($,"title",e.instance.source_path),Z(E,e.instance.source_path)}),o(i,v),ot()}Bt(["keydown","click"]);var Vi=new Set(["$$slots","$$events","$$legacy"]);function fe(i,e){let a=U(e,Vi),r=[["path",{d:"M15.536 11.293a1 1 0 0 0 0 1.414l2.376 2.377a1 1 0 0 0 1.414 0l2.377-2.377a1 1 0 0 0 0-1.414l-2.377-2.377a1 1 0 0 0-1.414 0z"}],["path",{d:"M2.297 11.293a1 1 0 0 0 0 1.414l2.377 2.377a1 1 0 0 0 1.414 0l2.377-2.377a1 1 0 0 0 0-1.414L6.088 8.916a1 1 0 0 0-1.414 0z"}],["path",{d:"M8.916 17.912a1 1 0 0 0 0 1.415l2.377 2.376a1 1 0 0 0 1.414 0l2.377-2.376a1 1 0 0 0 0-1.415l-2.377-2.376a1 1 0 0 0-1.414 0z"}],["path",{d:"M8.916 4.674a1 1 0 0 0 0 1.414l2.377 2.376a1 1 0 0 0 1.414 0l2.377-2.376a1 1 0 0 0 0-1.414l-2.377-2.377a1 1 0 0 0-1.414 0z"}]];q(i,j({name:"component"},()=>a,{get iconNode(){return r}}))}var Fi=new Set(["$$slots","$$events","$$legacy"]);function ce(i,e){let a=U(e,Fi),r=[["path",{d:"M11 21.73a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16V8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73z"}],["path",{d:"M12 22V12"}],["polyline",{points:"3.29 7 12 12 20.71 7"}],["path",{d:"m7.5 4.27 9 5.15"}]];q(i,j({name:"package"},()=>a,{get iconNode(){return r}}))}var ki=c('<a class="brand svelte-94cd8h" href="/"><span class="logo svelte-94cd8h"><!></span><span>Codebay</span><span class="tagline svelte-94cd8h">devcontainer manager</span></a>');function Pe(i){var e=ki(),a=d(e),r=d(a);ce(r,{size:22}),l(a),X(2),l(e),o(i,e)}var Ri=new Set(["$$slots","$$events","$$legacy"]);function Zt(i,e){let a=U(e,Ri),r=[["path",{d:"M9.671 4.136a2.34 2.34 0 0 1 4.659 0 2.34 2.34 0 0 0 3.319 1.915 2.34 2.34 0 0 1 2.33 4.033 2.34 2.34 0 0 0 0 3.831 2.34 2.34 0 0 1-2.33 4.033 2.34 2.34 0 0 0-3.319 1.915 2.34 2.34 0 0 1-4.659 0 2.34 2.34 0 0 0-3.32-1.915 2.34 2.34 0 0 1-2.33-4.033 2.34 2.34 0 0 0 0-3.831A2.34 2.34 0 0 1 6.35 6.051a2.34 2.34 0 0 0 3.319-1.915"}],["circle",{cx:"12",cy:"12",r:"3"}]];q(i,j({name:"settings"},()=>a,{get iconNode(){return r}}))}var _i=c('<a class="cog svelte-1e745g8" href="/settings" aria-label="Settings" title="Settings"><!></a>');function Te(i){var e=_i(),a=d(e);Zt(a,{size:16}),l(e),o(i,e)}var yi=new Set(["$$slots","$$events","$$legacy"]);function me(i,e){let a=U(e,yi),r=[["path",{d:"M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"}],["path",{d:"M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"}]];q(i,j({name:"link"},()=>a,{get iconNode(){return r}}))}var Wi=c('<button type="button" class="cred-row svelte-vongf9" role="menuitem"><span></span> <span class="cred-label"> </span> <span class="cred-state svelte-vongf9"> </span></button>'),Ki=c('<div class="cred-dropdown panel svelte-vongf9" role="menu"></div>'),Qi=c('<div class="cred-menu svelte-vongf9"><button aria-haspopup="menu" aria-label="Credentials" title="Credentials"><!></button> <!></div>');function Be(i,e){dt(e,!0);let a=h(!1),r=P(()=>e.auth.filter(($)=>$.available).length),v=P(()=>t(r)===e.auth.length?"ok":t(r)===0?"error":"warn"),p={ok:me,warn:Qt,error:Yt},S=P(()=>p[t(v)]);function C($){if($.available)Xt.success(`${$.label} credentials come from ${$.source}.`);else{let E=$.hint?` — ${$.hint}`:"";Xt.error(`No ${$.label} credentials found${E}.`)}}$t(()=>{if(!t(a))return;let $=(u)=>{if(!u.target?.closest(".cred-menu"))n(a,!1)},E=(u)=>{if(u.key==="Escape")n(a,!1)};return window.addEventListener("click",$),window.addEventListener("keydown",E),()=>{window.removeEventListener("click",$),window.removeEventListener("keydown",E)}});var w=Qi(),R=d(w),z=d(R);Oe(z,()=>t(S),($,E)=>{E($,{size:16})}),l(R);var V=s(R,2);{var F=($)=>{var E=Ki();mt(E,21,()=>e.auth,(u)=>u.id,(u,D)=>{var M=Wi(),k=d(M),T=s(k,2),W=d(T,!0);l(T);var Y=s(T,2),O=d(Y,!0);l(Y),l(M),A(()=>{rt(M,"title",t(D).available?`Credentials from ${t(D).source}, copied into each new instance.`:`No credentials found on this computer${t(D).hint?` — ${t(D).hint}`:""}.`),gt(k,1,`dot ${t(D).available?"on":"off"}`,"svelte-vongf9"),Z(W,t(D).label),Z(O,t(D).available?"Authorized":"Not found")}),Q("click",M,()=>C(t(D))),o(u,M)}),l(E),o($,E)};N(V,($)=>{if(t(a))$(F)})}l(w),A(()=>{gt(R,1,`cred ${t(v)??""}`,"svelte-vongf9"),rt(R,"aria-expanded",t(a))}),Q("click",R,()=>n(a,!t(a))),o(i,w),ot()}Bt(["click"]);var Zi=c('<header class="topbar svelte-1h259us"><!> <div class="topbar-actions svelte-1h259us"><!> <!> <!> <!> <!></div></header>');function De(i,e){let a=Et(e,"canDelete",3,!1),r=Et(e,"ready",3,!0),v=Et(e,"creating",3,!1);var p=Zi(),S=d(p);Pe(S,{});var C=s(S,2),w=d(C);{var R=(E)=>{ft(E,{variant:"default",size:"sm",get icon(){return fe},href:"/debug",children:(u,D)=>{X();var M=st("Debug");o(u,M)},$$slots:{default:!0}})};N(w,(E)=>{if(Ye)E(R)})}var z=s(w,2);Te(z,{});var V=s(z,2);Be(V,{get auth(){return e.auth}});var F=s(V,2);{let E=P(()=>!a());ft(F,{variant:"danger",size:"sm",get onclick(){return e.onDeleteAll},get disabled(){return t(E)},children:(u,D)=>{X();var M=st("Delete all");o(u,M)},$$slots:{default:!0}})}var $=s(F,2);{let E=P(()=>v()?void 0:$e),u=P(()=>!r()||v());ft($,{variant:"primary",get icon(){return t(E)},get onclick(){return e.onNew},get disabled(){return t(u)},children:(D,M)=>{X();var k=st();A(()=>Z(k,v()?"Creating…":"New instance")),o(D,k)},$$slots:{default:!0}})}l(C),l(p),o(i,p)}var Hi=c("<span>Docker daemon is not reachable.</span>"),Ji=c("<span>The devcontainer CLI is not available.</span>"),Oi=c('<div class="banner error svelte-146pixd"><strong>Setup needed.</strong> <!> <!></div>'),Yi=c('<div class="banner error svelte-146pixd"><strong>Error.</strong> <span> </span></div>'),Gi=c('<div class="empty svelte-146pixd"><p class="empty-sub svelte-146pixd">Loading…</p></div>'),Xi=c('<div class="empty svelte-146pixd"><p class="empty-title svelte-146pixd">No instances yet</p> <p class="empty-sub svelte-146pixd">Pick a project folder to spin up an isolated devcontainer.</p> <!></div>'),Ui=c('<ul class="grid svelte-146pixd"></ul>'),ji=c('<!> <main class="stage svelte-146pixd"><!> <!> <!></main> <!>',1);function ze(i,e){dt(e,!0);let a=h(!1),r=h(!1),v=h(null),p=h(null),S=h(""),C=P(()=>e.preflight.docker&&e.preflight.cli);async function w(I,L){n(a,!1),n(r,!0),n(v,null);try{await zt("/api/instances",{sourcePath:I,branch:L?.branch},"Failed to create instance")}catch(H){n(v,H.message,!0)}finally{n(r,!1)}}async function R(I,L){if(n(v,null),L==="delete"&&!confirm("Delete this instance and its copied files?"))return;if(L==="rebuild"&&!confirm("Recreate this container and re-run setup? The workspace is kept."))return;try{await zt(`/api/instances/${I}/${L}`,void 0,`Failed to ${L}`)}catch(H){n(v,H.message,!0)}}function z(I){n(p,I.id,!0),n(S,I.name,!0)}function V(){n(p,null),n(S,"")}async function F(I){let L=t(S).trim(),H=e.instances.find((f)=>f.id===I)?.name;if(!L||L===H){V();return}V(),n(v,null);try{await zt(`/api/instances/${I}/rename`,{name:L},"Failed to rename")}catch(f){n(v,f.message,!0)}}async function $(){if(n(v,null),!confirm(`Delete all ${e.instances.length} instances and their copied files?`))return;try{await zt("/api/instances/delete-all",void 0,"Failed to delete all")}catch(I){n(v,I.message,!0)}}var E=ji(),u=xt(E);{let I=P(()=>e.instances.length>0);De(u,{get auth(){return e.preflight.auth},get canDelete(){return t(I)},get ready(){return t(C)},get creating(){return t(r)},onNew:()=>n(a,!0),onDeleteAll:$})}var D=s(u,2),M=d(D);{var k=(I)=>{var L=Oi(),H=s(d(L),2);{var f=(J)=>{var nt=Hi();o(J,nt)};N(H,(J)=>{if(!e.preflight.docker)J(f)})}var x=s(H,2);{var B=(J)=>{var nt=Ji();o(J,nt)};N(x,(J)=>{if(!e.preflight.cli)J(B)})}l(L),o(I,L)};N(M,(I)=>{if(!t(C))I(k)})}var T=s(M,2);{var W=(I)=>{var L=Yi(),H=s(d(L),2),f=d(H,!0);l(H),l(L),A(()=>Z(f,t(v))),o(I,L)};N(T,(I)=>{if(t(v))I(W)})}var Y=s(T,2);{var O=(I)=>{var L=Gi();o(I,L)},et=(I)=>{var L=Xi(),H=s(d(L),4);{let f=P(()=>!t(C));ft(H,{variant:"primary",get icon(){return $e},onclick:()=>n(a,!0),get disabled(){return t(f)},children:(x,B)=>{X();var J=st("New instance");o(x,J)},$$slots:{default:!0}})}l(L),o(I,L)},St=(I)=>{var L=Ui();mt(L,21,()=>e.instances,(H)=>H.id,(H,f)=>{{let x=P(()=>t(p)===t(f).id);Le(H,{get instance(){return t(f)},get editing(){return t(x)},onact:(B)=>R(t(f).id,B),onstartrename:()=>z(t(f)),oncommitrename:()=>F(t(f).id),oncancelrename:V,get editingName(){return t(S)},set editingName(B){n(S,B,!0)}})}}),l(L),o(I,L)};N(Y,(I)=>{if(!e.loaded)I(O);else if(e.instances.length===0)I(et,1);else I(St,-1)})}l(D);var wt=s(D,2);{var bt=(I)=>{Ne(I,{onpick:w,onclose:()=>n(a,!1)})};N(wt,(I)=>{if(t(a))I(bt)})}o(i,E),ot()}var qi=c('<div class="tab-label editing svelte-r39acv"><!> <input class="tab-name-edit svelte-r39acv"/></div>'),ta=c('<button type="button" class="tab-label svelte-r39acv"><!> <span class="tab-name svelte-r39acv"> </span></button>'),ea=c("<div><!></div>"),ia=c('<nav class="tabs svelte-r39acv"></nav>'),aa=c('<!> <a class="cog svelte-r39acv" href="/settings" title="Settings" aria-label="Settings"><!></a>',1);function Ae(i,e){dt(e,!0);let a=Et(e,"editingName",15);Ge(i,{children:(r,v)=>{var p=aa(),S=xt(p);{var C=(z)=>{var V=ia();mt(V,21,()=>e.running,(F)=>F.id,(F,$)=>{var E=ea();let u;var D=d(E);{var M=(T)=>{var W=qi(),Y=d(W);Gt(Y,{get id(){return t($).id},get name(){return t($).name},scale:4});var O=s(Y,2);Pt(O),se(O,!0),l(W),Dt("focus",O,(et)=>et.currentTarget.select()),Dt("blur",O,()=>e.oncommitrename(t($).id)),Q("keydown",O,(et)=>{if(et.key==="Enter")et.currentTarget.blur();else if(et.key==="Escape")e.oncancelrename()}),Tt(O,a),o(T,W)},k=(T)=>{var W=ta(),Y=d(W);Gt(Y,{get id(){return t($).id},get name(){return t($).name},scale:4});var O=s(Y,2),et=d(O,!0);l(O),l(W),A(()=>{rt(W,"title",t($).name),Z(et,t($).name)}),Q("click",W,()=>e.onselect(t($).id)),Q("dblclick",W,()=>e.onstartrename(t($))),o(T,W)};N(D,(T)=>{if(e.editingId===t($).id)T(M);else T(k,-1)})}l(E),A(()=>u=gt(E,1,"tab svelte-r39acv",null,u,{active:t($).id===e.active,"attn-done":t($).id!==e.active&&e.attention[t($).id]==="done","attn-waiting":t($).id!==e.active&&e.attention[t($).id]==="waiting"})),o(F,E)}),l(V),o(z,V)};N(S,(z)=>{if(e.running.length>0)z(C)})}var w=s(S,2),R=d(w);Zt(R,{size:18}),l(w),o(r,p)},$$slots:{default:!0}}),ot()}Bt(["keydown","click","dblclick"]);var ra=c('<div class="row svelte-w5e143"> </div>'),na=c('<div class="stalled svelte-w5e143"><p class="svelte-w5e143">Waiting for code-server to answer inside the container.</p> <!></div>'),la=c('<div class="loader svelte-w5e143"><div class="grid svelte-w5e143" aria-hidden="true"></div> <div class="label svelte-w5e143">Loading editor<span class="dot svelte-w5e143">.</span><span class="dot svelte-w5e143">.</span><span class="dot svelte-w5e143">.</span></div> <!></div>');function ge(i,e){dt(e,!0);let a=Et(e,"speed",3,1),r=h(!1);$t(()=>{if(e.stalledAfterMs===void 0)return;let u=setTimeout(()=>n(r,!0),e.stalledAfterMs);return()=>clearTimeout(u)});let v=3,p=22,S=140,C=7,w=P(()=>Math.max(20,S/a())),z=h(Lt((()=>Array.from({length:v},()=>Array.from({length:p},()=>Math.random()<0.5?0:1)))()));$t(()=>{if(window.matchMedia?.("(prefers-reduced-motion: reduce)").matches)return;let u=setInterval(()=>{let D=t(z).map((M)=>M.slice());for(let M=0;M<C;M++){let k=D[Math.floor(Math.random()*v)],T=Math.floor(Math.random()*p);k[T]=k[T]?0:1}n(z,D,!0)},t(w));return()=>clearInterval(u)});var V=la(),F=d(V);mt(F,21,()=>t(z),Xe,(u,D)=>{var M=ra(),k=d(M,!0);l(M),A((T)=>Z(k,T),[()=>t(D).join("")]),o(u,M)}),l(F);var $=s(F,4);{var E=(u)=>{var D=na(),M=s(d(D),2);{var k=(T)=>{ft(T,{size:"sm",get onclick(){return e.onoverride},children:(W,Y)=>{X();var O=st("Open anyway");o(W,O)},$$slots:{default:!0}})};N(M,(T)=>{if(e.onoverride)T(k)})}l(D),o(u,D)};N($,(u)=>{if(t(r))u(E)})}l(V),o(i,V),ot()}var da=c('<iframe class="svelte-1duc7gd"></iframe>'),oa=c("<div><!> <!></div>"),sa=c('<div class="empty svelte-1duc7gd">No running instances.</div>'),fa=c("<div><!> <div><!> <!></div></div> <!>",1);function Ve(i,e){dt(e,!0);let a=h(Lt(e.snapshot)),r=h(Lt(e.preflight)),v=h(e.snapshot.length>0),p=P(()=>t(a).filter((m)=>m.status==="running")),S=h(Lt(Object.fromEntries(e.snapshot.map((m)=>[m.id,m.attention])))),C=h(null),w=h("");function R(m){n(C,m.id,!0),n(w,m.name,!0)}function z(){n(C,null),n(w,"")}async function V(m){let b=t(w).trim(),it=t(a).find((vt)=>vt.id===m)?.name;if(!b||b===it){z();return}z();try{await zt(`/api/instances/${m}/rename`,{name:b},"Failed to rename")}catch(vt){Xt.error(vt.message)}}let F=h(Lt(e.initialPath)),$=P(()=>t(F).startsWith("/ide")),E=P(()=>t(F).startsWith("/ide/")?t(F).slice(5):""),u=P(()=>t($)?t(p).some((m)=>m.id===t(E))?t(E):t(p)[0]?.id??"":"");function D(m){if(m===t(F))return;history.pushState({},"",m),n(F,m,!0)}$t(()=>{function m(b){if(b.defaultPrevented||b.button!==0||b.metaKey||b.ctrlKey||b.shiftKey||b.altKey)return;let it=b.target?.closest?.("a");if(!it)return;let vt=it.getAttribute("href");if(!vt||it.target==="_blank"||it.hasAttribute("download"))return;let pt=new URL(vt,location.href);if(pt.origin!==location.origin)return;if(pt.pathname==="/"||pt.pathname.startsWith("/ide/"))b.preventDefault(),D(pt.pathname)}return document.addEventListener("click",m),()=>document.removeEventListener("click",m)}),$t(()=>{function m(){n(F,location.pathname,!0)}return window.addEventListener("popstate",m),()=>window.removeEventListener("popstate",m)});let M=new Mt;$t(()=>{if(t(u))M.add(t(u))});let k=new Mt,T=new Mt,W=new Mt,Y=(m)=>T.has(m)||W.has(m),O=1e4;$t(()=>{let m=t(p).find((b)=>b.id===t(u));document.title=t($)&&m?`${m.name} — Codebay`:"Codebay"}),$t(()=>{return window.addEventListener("pointerdown",Ut),window.addEventListener("keydown",Ut),()=>{window.removeEventListener("pointerdown",Ut),window.removeEventListener("keydown",Ut)}}),$t(()=>{let m=!1;return ei((b)=>{if(b.type==="preflight"){n(r,{...t(r),docker:b.data.docker,cli:b.data.cli},!0);return}if(b.type==="health"){let _=t(a).find((ht)=>ht.id===b.data.id);if(b.data.health.codeServerAccessible&&_?.status==="running")T.add(b.data.id);return}if(b.type!=="instances")return;let it=b.data,vt=new Set(it.filter((_)=>_.status==="running").map((_)=>_.id));for(let _ of[...T])if(!vt.has(_))T.delete(_);for(let _ of[...W])if(!vt.has(_))W.delete(_);for(let _ of[...k])if(!vt.has(_))k.delete(_);let pt={};for(let _ of it)pt[_.id]=_.attention;if(m)for(let _ in pt){let ht=pt[_];if(ht&&ht!==t(S)[_])if(_===t(u))console.log(`[chime] attention id=${_} state=${ht} — skipped (tab is active/focused)`);else console.log(`[chime] attention id=${_} state=${ht} → playChime`),ti(ht)}else console.log("[chime] first frame after (re)connect — baselining, no chimes");m=!0,n(a,it,!0),n(S,pt,!0),n(v,!0)},()=>{m=!1})}),$t(()=>{if(!t(u)||!t(S)[t(u)])return;let m=()=>{if(document.visibilityState==="visible")zt(`/api/instances/${t(u)}/attention/clear`).catch(()=>{})};return m(),document.addEventListener("visibilitychange",m),()=>document.removeEventListener("visibilitychange",m)});var et=fa(),St=xt(et);let wt;var bt=d(St);{var I=(m)=>{Ae(m,{get running(){return t(p)},get active(){return t(u)},get attention(){return t(S)},get editingId(){return t(C)},onselect:(b)=>D(`/ide/${b}`),onstartrename:R,oncommitrename:V,oncancelrename:z,get editingName(){return t(w)},set editingName(b){n(w,b,!0)}})},L=(m)=>{ze(m,{get preflight(){return t(r)},get instances(){return t(a)},get loaded(){return t(v)}})};N(bt,(m)=>{if(t($))m(I);else m(L,-1)})}var H=s(bt,2);let f;var x=d(H);mt(x,17,()=>t(p),(m)=>m.id,(m,b)=>{var it=oe(),vt=xt(it);{var pt=(ht)=>{var At=oa();let Ht;var g=d(At);{var K=(y)=>{var at=da();A((Nt)=>{rt(at,"src",Nt),rt(at,"title",t(b).name)},[()=>je(t(b))]),Dt("load",at,()=>k.add(t(b).id)),Ue(at),o(y,at)},ut=P(()=>Y(t(b).id));N(g,(y)=>{if(t(ut))y(K)})}var Jt=s(g,2);{var kt=(y)=>{ge(y,{stalledAfterMs:O,onoverride:()=>W.add(t(b).id)})},It=P(()=>!Y(t(b).id)),ct=(y)=>{ge(y,{})},tt=P(()=>!k.has(t(b).id));N(Jt,(y)=>{if(t(It))y(kt);else if(t(tt))y(ct,1)})}l(At),A(()=>Ht=gt(At,1,"pane svelte-1duc7gd",null,Ht,{active:t(b).id===t(u)})),o(ht,At)},_=P(()=>M.has(t(b).id));N(vt,(ht)=>{if(t(_))ht(pt)})}o(m,it)});var B=s(x,2);{var J=(m)=>{var b=sa();o(m,b)};N(B,(m)=>{if(t($)&&t(p).length===0)m(J)})}l(H),l(St);var nt=s(St,2);qe(nt,{toastOptions:{style:"border:1px solid var(--ink); background:var(--bg-card); color:var(--ink); box-shadow:4px 4px 0 var(--ink); font-family:var(--font-mono); font-size:13px;"}}),A(()=>{wt=gt(St,1,"app svelte-1duc7gd",null,wt,{ide:t($)}),f=gt(H,1,"panes svelte-1duc7gd",null,f,{hidden:!t($)})}),o(i,et),ot()}ii("AppShell_2rtnxn6pgp2rh",Ve);