codebay 0.10.0 → 0.11.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 +193 -167
- package/.mochi/svelte-client/HydratableIsland-dammyce5.js +1 -0
- package/.mochi/svelte-client/_hydrate-AppShell_2rtnxn6pgp2rh-v65ctd99.js +2 -0
- package/.mochi/svelte-client/_hydrate-AvatarsView_257s9yq1wwr4f-htjfv8q9.js +14 -0
- package/.mochi/svelte-client/_hydrate-InstanceView_2ma45l9bybfhl-v07seqge.js +1 -0
- package/.mochi/svelte-client/_hydrate-SettingsView_8hmarwmf8onq-hj9yvqc4.js +38 -0
- package/.mochi/svelte-client/chunk-0zkdsrth.js +2 -0
- package/.mochi/svelte-client/{chunk-bn731rda.js → chunk-566rqq4c.js} +2 -2
- package/.mochi/svelte-client/chunk-79aj59e0.js +2 -0
- package/.mochi/svelte-client/{chunk-wvtkwfsh.js → chunk-czkxd74n.js} +1 -1
- package/.mochi/svelte-client/{chunk-p20tkpde.js → chunk-hxydjtda.js} +1 -1
- package/.mochi/svelte-client/chunk-qx1defbm.js +2 -0
- package/.mochi/svelte-client/chunk-r3wxmmc0.js +2 -0
- package/.mochi/svelte-client/{chunk-j72r8pkk.js → chunk-vs6pd2b4.js} +2 -2
- package/.mochi/svelte-client/{chunk-t0ap7q89.js → chunk-wjagstre.js} +1 -1
- package/.mochi/svelte-client/{chunk-0fjx3z3r.js → chunk-y9yy1004.js} +1 -1
- package/.mochi/svelte-compile/{App-59cdj86f.server.js → App-mzn3dqjm.server.js} +182 -72
- package/.mochi/svelte-compile/{Avatars-fmagfyj2.server.js → Avatars-c0k5jx8q.server.js} +3 -6
- package/.mochi/svelte-compile/{Instance-s1gqwzmx.server.js → Instance-hj76qnha.server.js} +4 -4
- package/.mochi/svelte-compile/{Settings-k447mt0x.server.js → Settings-tvc5yp08.server.js} +39 -28
- package/.mochi/svelte-compile/chunk-ed46m58e.js +22 -0
- package/.mochi/svelte-compile/{chunk-th2dbqvc.js → chunk-gz6hv1h5.js} +5 -1
- package/.mochi/svelte-compile/chunk-zd49axkf.js +65 -0
- package/.mochi/svelte-css/{AppBar-3bxinv4pabv8l.css → AppBar-1gtu2me3fni8e.css} +1 -1
- package/.mochi/svelte-css/AvatarEditor-1mjvec6bwdkv8.css +1 -0
- package/.mochi/svelte-css/{AvatarsView-2llo48w0wt0xn.css → AvatarsView-26ya4ep5n1ze7.css} +1 -1
- package/.mochi/svelte-css/Button-208u50wkms8ya.css +1 -0
- package/.mochi/svelte-css/CoinButton-2727devjtsn10.css +1 -0
- package/.mochi/svelte-css/CredMenu-7qowd1oxujet.css +1 -0
- package/.mochi/svelte-css/DashboardView-17a0b8epjurhb.css +1 -0
- package/.mochi/svelte-css/FolderBrowser-i0uj58dph27f.css +1 -0
- package/.mochi/svelte-css/HealthBox-r0giuhjn2wj4.css +1 -0
- package/.mochi/svelte-css/IdeBar-1mtgemqfuvqzi.css +1 -0
- package/.mochi/svelte-css/InstanceCard-25z7nas7y98zk.css +1 -0
- package/.mochi/svelte-css/InstanceFilter-2vglmyy0yrbbc.css +1 -0
- package/.mochi/svelte-css/InstanceView-oozmmctp8m3p.css +1 -0
- package/.mochi/svelte-css/SettingsCog-1jdeprd3ilczz.css +1 -0
- package/.mochi/svelte-css/{SettingsView-n3oy75uonzp2.css → SettingsView-bccw34agd2bj.css} +1 -1
- package/.mochi/svelte-css/StatusBadge-2eisdtnrsnfdc.css +1 -0
- package/.mochi/svelte-css/TerminalPane-2ywc86rhtmr9l.css +1 -0
- package/.mochi/svelte-css/ThemePicker-3fw4synubier0.css +1 -0
- package/migrations/0008_config_migrated.sql +1 -0
- package/package.json +8 -8
- package/src/components/AppBar.svelte +2 -2
- package/src/components/AppShell.svelte +71 -7
- package/src/components/AvatarEditor.svelte +10 -10
- package/src/components/AvatarsView.svelte +0 -0
- package/src/components/Button.svelte +13 -9
- package/src/components/CoinButton.svelte +2 -2
- package/src/components/CredMenu.svelte +8 -6
- package/src/components/DashboardView.svelte +2 -2
- package/src/components/FolderBrowser.svelte +39 -36
- package/src/components/HealthBox.svelte +5 -4
- package/src/components/IdeBar.svelte +286 -112
- package/src/components/InstanceCard.svelte +7 -7
- package/src/components/InstanceFilter.svelte +6 -6
- package/src/components/InstanceView.svelte +27 -21
- package/src/components/SettingsCog.svelte +4 -3
- package/src/components/SettingsView.svelte +7 -11
- package/src/components/StatusBadge.svelte +8 -6
- package/src/components/TerminalPane.svelte +19 -7
- package/src/components/ThemePicker.svelte +150 -8
- package/src/components/TopBar.svelte +1 -1
- package/src/components/UiShowcase.svelte +300 -64
- package/src/lib/db.server.ts +7 -3
- package/src/lib/devcontainer.server.ts +211 -38
- package/src/lib/docker.server.ts +10 -0
- package/src/lib/git.server.ts +28 -0
- package/src/lib/instances.server.ts +117 -18
- package/src/lib/tab-nav.ts +30 -0
- package/src/routes.ts +12 -0
- package/src/shell.html +56 -23
- package/src/theme.ts +8 -1
- package/src/toast.ts +9 -0
- package/src/types.ts +7 -0
- package/.mochi/svelte-client/HydratableIsland-aebn1fa1.js +0 -1
- package/.mochi/svelte-client/_hydrate-AppShell_2rtnxn6pgp2rh-rx6arrv5.js +0 -2
- package/.mochi/svelte-client/_hydrate-AvatarsView_257s9yq1wwr4f-jpjdmgpe.js +0 -14
- package/.mochi/svelte-client/_hydrate-InstanceView_2ma45l9bybfhl-c9y47dat.js +0 -1
- package/.mochi/svelte-client/_hydrate-SettingsView_8hmarwmf8onq-d61feq89.js +0 -38
- package/.mochi/svelte-client/chunk-8xvr02wh.js +0 -2
- package/.mochi/svelte-client/chunk-9143wy3j.js +0 -2
- package/.mochi/svelte-client/chunk-k37wj1jm.js +0 -2
- package/.mochi/svelte-client/chunk-pc0fm37c.js +0 -2
- package/.mochi/svelte-compile/chunk-3t7v4hk0.js +0 -52
- package/.mochi/svelte-compile/chunk-gkjgybb2.js +0 -15
- package/.mochi/svelte-css/AvatarEditor-2mdq8ss346drw.css +0 -1
- package/.mochi/svelte-css/Button-oharop2xz6am.css +0 -1
- package/.mochi/svelte-css/CoinButton-1rej3sh3tkjud.css +0 -1
- package/.mochi/svelte-css/CredMenu-9hwgeptp7crb.css +0 -1
- package/.mochi/svelte-css/DashboardView-1cy4xpqhja9sx.css +0 -1
- package/.mochi/svelte-css/FolderBrowser-2pxp9z1o7zixk.css +0 -1
- package/.mochi/svelte-css/HealthBox-er2her0jukwl.css +0 -1
- package/.mochi/svelte-css/IdeBar-3bgr3m5z0lpeg.css +0 -1
- package/.mochi/svelte-css/InstanceCard-3vnltxnbxkvay.css +0 -1
- package/.mochi/svelte-css/InstanceFilter-3q6x0jt0hcgpz.css +0 -1
- package/.mochi/svelte-css/InstanceView-1pd7j16bd2b16.css +0 -1
- package/.mochi/svelte-css/SettingsCog-jftyadvo64qo.css +0 -1
- package/.mochi/svelte-css/StatusBadge-3mq0j7z6aq4j.css +0 -1
- package/.mochi/svelte-css/TerminalPane-3bwgk6ulzq6b3.css +0 -1
- package/.mochi/svelte-css/ThemePicker-1ir8jyocm8mvi.css +0 -1
|
@@ -33,6 +33,7 @@ import {
|
|
|
33
33
|
hostPortsInUse,
|
|
34
34
|
isRunning,
|
|
35
35
|
removeContainer,
|
|
36
|
+
removeContainerOnly,
|
|
36
37
|
startContainer,
|
|
37
38
|
stopContainer
|
|
38
39
|
} from './docker.server.ts';
|
|
@@ -43,11 +44,12 @@ import {
|
|
|
43
44
|
INJECTIONS_DONE_FILE,
|
|
44
45
|
launchCommandFor,
|
|
45
46
|
readDeclaredContainerPorts,
|
|
47
|
+
restoreCanonicalConfig,
|
|
46
48
|
TERMINAL_LAUNCHED_MARKER,
|
|
47
49
|
writeOverrideConfig
|
|
48
50
|
} from './devcontainer.server.ts';
|
|
49
51
|
import { writeContainerFile } from './container-files.server.ts';
|
|
50
|
-
import { execInContainer } from './exec.server.ts';
|
|
52
|
+
import { execInContainer, type ExecTarget } from './exec.server.ts';
|
|
51
53
|
import { clearAttention, getAttention } from './bridge.server.ts';
|
|
52
54
|
import { proxyPathFor } from './proxy.server.ts';
|
|
53
55
|
import { resolveInjectionStages } from './injections.server.ts';
|
|
@@ -73,7 +75,8 @@ import {
|
|
|
73
75
|
normalizeMode,
|
|
74
76
|
type Instance,
|
|
75
77
|
type InstanceFilter,
|
|
76
|
-
type InstanceHealth
|
|
78
|
+
type InstanceHealth,
|
|
79
|
+
type Theme
|
|
77
80
|
} from '../types.ts';
|
|
78
81
|
|
|
79
82
|
/** The sprite a row shows: its persisted choice, or the id hash for rows created before avatars were stored. */
|
|
@@ -97,6 +100,27 @@ interface LiveState {
|
|
|
97
100
|
const globalForReg = globalThis as unknown as { __codebayRegistry?: Map<string, LiveState> };
|
|
98
101
|
const registry: Map<string, LiveState> = (globalForReg.__codebayRegistry ??= new Map());
|
|
99
102
|
|
|
103
|
+
/**
|
|
104
|
+
* The ids `provision()` is currently building. A `creating` row is only left alone while its boot
|
|
105
|
+
* is actually in flight — otherwise a server restart mid-boot would strand it there forever, since
|
|
106
|
+
* reconcile skips `creating` and `rebuildInstance` refuses to touch it.
|
|
107
|
+
*/
|
|
108
|
+
const globalForBoots = globalThis as unknown as { __codebayProvisioning?: Set<string> };
|
|
109
|
+
const inFlight: Set<string> = (globalForBoots.__codebayProvisioning ??= new Set());
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Whether reconcile may re-derive a row's status from Docker. A live boot owns its own row until it
|
|
113
|
+
* opens the instance itself; an orphaned `creating` row (the manager restarted mid-boot) must not
|
|
114
|
+
* be left there, since nothing else would ever move it and Rebuild refuses to touch a booting row.
|
|
115
|
+
*/
|
|
116
|
+
export function reconcilesFromDocker(
|
|
117
|
+
row: Pick<InstanceRow, 'id' | 'status'>,
|
|
118
|
+
building: ReadonlySet<string>
|
|
119
|
+
): boolean {
|
|
120
|
+
if (row.status === 'error') return false;
|
|
121
|
+
return row.status !== 'creating' || !building.has(row.id);
|
|
122
|
+
}
|
|
123
|
+
|
|
100
124
|
function live(id: string): LiveState {
|
|
101
125
|
let state = registry.get(id);
|
|
102
126
|
if (!state) {
|
|
@@ -168,7 +192,9 @@ export type StreamEvent =
|
|
|
168
192
|
// The dashboard run-state filter, so a change in one tab propagates to every open client.
|
|
169
193
|
| { type: 'filter'; data: { value: InstanceFilter } }
|
|
170
194
|
// The global default editor surface, so the picker's toggle follows a settings change.
|
|
171
|
-
| { type: 'default-mode'; data: { mode: InstanceMode } }
|
|
195
|
+
| { type: 'default-mode'; data: { mode: InstanceMode } }
|
|
196
|
+
// The colour scheme, so a change in the settings popup repaints the window behind it.
|
|
197
|
+
| { type: 'theme'; data: { value: Theme } };
|
|
172
198
|
|
|
173
199
|
interface StreamHub {
|
|
174
200
|
sockets: Set<ServerWebSocket<unknown>>;
|
|
@@ -229,6 +255,14 @@ export function broadcastDefaultMode(mode: InstanceMode): void {
|
|
|
229
255
|
broadcast({ type: 'default-mode', data: { mode } });
|
|
230
256
|
}
|
|
231
257
|
|
|
258
|
+
/**
|
|
259
|
+
* Same popup problem for the theme — but it lives in a cookie, not `options`, so there's
|
|
260
|
+
* nothing to seed a reconnecting client with: its own cookie already drives the SSR paint.
|
|
261
|
+
*/
|
|
262
|
+
export function broadcastTheme(value: Theme): void {
|
|
263
|
+
broadcast({ type: 'theme', data: { value } });
|
|
264
|
+
}
|
|
265
|
+
|
|
232
266
|
async function reconcileInstances(force = false): Promise<void> {
|
|
233
267
|
const list = await listInstances();
|
|
234
268
|
const listJson = JSON.stringify(list);
|
|
@@ -333,6 +367,9 @@ function failInstance(id: string, err: unknown): void {
|
|
|
333
367
|
}
|
|
334
368
|
|
|
335
369
|
async function boot(row: InstanceRow, opts: { branch?: string } = {}): Promise<void> {
|
|
370
|
+
// Claims the row for the copy/clone phase, which runs ahead of the build; provision() re-claims
|
|
371
|
+
// it and owns the release from there.
|
|
372
|
+
inFlight.add(row.id);
|
|
336
373
|
try {
|
|
337
374
|
const sourceStart = Date.now();
|
|
338
375
|
if (isRepoUrl(row.source_path)) {
|
|
@@ -349,13 +386,14 @@ async function boot(row: InstanceRow, opts: { branch?: string } = {}): Promise<v
|
|
|
349
386
|
}
|
|
350
387
|
await seedDeclaredPorts(row);
|
|
351
388
|
} catch (err) {
|
|
389
|
+
inFlight.delete(row.id);
|
|
352
390
|
failInstance(row.id, err);
|
|
353
391
|
return;
|
|
354
392
|
}
|
|
355
393
|
await provision(row);
|
|
356
394
|
}
|
|
357
395
|
|
|
358
|
-
/**
|
|
396
|
+
/** Reads the project's own `devcontainer.json`, which the config injection never touches. */
|
|
359
397
|
async function seedDeclaredPorts(row: InstanceRow): Promise<void> {
|
|
360
398
|
const existing = new Set(listForwards(row.id).map((f) => f.container_port));
|
|
361
399
|
for (const containerPort of await readDeclaredContainerPorts(row.workspace_path)) {
|
|
@@ -396,7 +434,26 @@ async function rescueHijackedPort(row: InstanceRow): Promise<void> {
|
|
|
396
434
|
|
|
397
435
|
/** Never re-copies the workspace, so in-container edits survive a rebuild. */
|
|
398
436
|
async function provision(row: InstanceRow, opts: { noCache?: boolean } = {}): Promise<void> {
|
|
437
|
+
// Held so the `catch` can release the container-side launcher's wait on a boot that dies.
|
|
438
|
+
let containerId: string | null = null;
|
|
439
|
+
inFlight.add(row.id);
|
|
399
440
|
try {
|
|
441
|
+
// Migrates instances created before the merged config moved to its own file — one-shot per
|
|
442
|
+
// instance, so a later rebuild can never claw back a config the user has since edited.
|
|
443
|
+
if (!row.config_migrated) {
|
|
444
|
+
const migrated = await restoreCanonicalConfig(row.workspace_path);
|
|
445
|
+
if (migrated === 'restored' || migrated === 'deleted') {
|
|
446
|
+
appendLog(
|
|
447
|
+
row.id,
|
|
448
|
+
'Restored the project devcontainer config (Codebay now keeps its merged config in a separate file)\n'
|
|
449
|
+
);
|
|
450
|
+
}
|
|
451
|
+
// 'unknown' means git itself failed to answer; leave the flag unset so the next rebuild retries.
|
|
452
|
+
if (migrated !== 'unknown') {
|
|
453
|
+
updateInstance(row.id, { config_migrated: 1 });
|
|
454
|
+
row.config_migrated = 1;
|
|
455
|
+
}
|
|
456
|
+
}
|
|
400
457
|
// On a rebuild `devcontainer up --remove-existing-container` discards the old container's
|
|
401
458
|
// ~/.claude, so drain it first; a first boot has no container_id and skips straight past.
|
|
402
459
|
if (row.container_id) {
|
|
@@ -410,7 +467,7 @@ async function provision(row: InstanceRow, opts: { noCache?: boolean } = {}): Pr
|
|
|
410
467
|
}));
|
|
411
468
|
appendLog(row.id, `Injecting ${surfaceLabel(row.mode)} (host port ${row.host_port})\n`);
|
|
412
469
|
const defaultImage = getOption('default_image') ?? DEFAULT_IMAGE;
|
|
413
|
-
const { imageSource } = await writeOverrideConfig(
|
|
470
|
+
const { imageSource, configPath } = await writeOverrideConfig(
|
|
414
471
|
row.workspace_path,
|
|
415
472
|
row.host_port,
|
|
416
473
|
forwards,
|
|
@@ -424,10 +481,20 @@ async function provision(row: InstanceRow, opts: { noCache?: boolean } = {}): Pr
|
|
|
424
481
|
const noCache = opts.noCache || getOption('disable_build_cache') === '1';
|
|
425
482
|
if (noCache) appendLog(row.id, `Building without cache (--build-no-cache)\n`);
|
|
426
483
|
|
|
484
|
+
// The CLI's --remove-existing-container matches by the devcontainer.config_file label, which
|
|
485
|
+
// no longer matches containers built from the pre-separate-config path — drop them ourselves.
|
|
486
|
+
if (row.container_id && !(await removeContainerOnly(row.container_id))) {
|
|
487
|
+
appendLog(
|
|
488
|
+
row.id,
|
|
489
|
+
`⚠ Could not remove the previous container (${row.container_id.slice(0, 12)}) — if the boot fails on a busy port, remove it manually\n`
|
|
490
|
+
);
|
|
491
|
+
}
|
|
492
|
+
|
|
427
493
|
appendLog(row.id, `Starting devcontainer…\n`);
|
|
428
494
|
const upStart = Date.now();
|
|
429
495
|
const result = await devcontainerUp(row.workspace_path, (chunk) => appendLog(row.id, chunk), {
|
|
430
|
-
noCache
|
|
496
|
+
noCache,
|
|
497
|
+
configPath
|
|
431
498
|
});
|
|
432
499
|
appendLog(row.id, `⏱ devcontainer up: ${elapsed(upStart)}\n`);
|
|
433
500
|
|
|
@@ -437,11 +504,13 @@ async function provision(row: InstanceRow, opts: { noCache?: boolean } = {}): Pr
|
|
|
437
504
|
);
|
|
438
505
|
}
|
|
439
506
|
|
|
507
|
+
containerId = result.containerId;
|
|
508
|
+
// The row deliberately stays `creating` until the injections below finish: `running` is what
|
|
509
|
+
// opens the IDE/terminal to the user, and a container whose setup is still landing isn't ready.
|
|
440
510
|
updateInstance(row.id, {
|
|
441
511
|
container_id: result.containerId,
|
|
442
512
|
remote_workspace_folder: result.remoteWorkspaceFolder ?? null,
|
|
443
513
|
remote_user: result.remoteUser ?? null,
|
|
444
|
-
status: 'running',
|
|
445
514
|
error: null
|
|
446
515
|
});
|
|
447
516
|
|
|
@@ -450,11 +519,6 @@ async function provision(row: InstanceRow, opts: { noCache?: boolean } = {}): Pr
|
|
|
450
519
|
row.container_id = result.containerId;
|
|
451
520
|
row.remote_workspace_folder = result.remoteWorkspaceFolder ?? null;
|
|
452
521
|
row.remote_user = result.remoteUser ?? null;
|
|
453
|
-
row.status = 'running';
|
|
454
|
-
|
|
455
|
-
// Start the health monitor now so the IDE mounts as soon as code-server answers,
|
|
456
|
-
// instead of after every injection plus a full reconcile/health poll cycle.
|
|
457
|
-
triggerReconcile();
|
|
458
522
|
|
|
459
523
|
const target = {
|
|
460
524
|
containerId: result.containerId,
|
|
@@ -478,22 +542,43 @@ async function provision(row: InstanceRow, opts: { noCache?: boolean } = {}): Pr
|
|
|
478
542
|
appendLog(row.id, `⏱ injections: ${elapsed(injectionsStart)}\n`);
|
|
479
543
|
|
|
480
544
|
// Unblocks the terminal launcher's wait; written even after ⚠s — its timeout is the fallback.
|
|
481
|
-
await
|
|
482
|
-
() => undefined
|
|
483
|
-
);
|
|
545
|
+
await writeInjectionsDone(row.id, target);
|
|
484
546
|
|
|
485
547
|
// postStartCommand ran before the injections above, and its launcher bails when the binary
|
|
486
548
|
// is missing — so a container whose build-time ttyd install failed got it too late to be
|
|
487
549
|
// started. No-ops (one accessibility probe) whenever postStart already brought the port up.
|
|
488
550
|
await relaunchSurface(row);
|
|
489
551
|
|
|
552
|
+
// Everything the instance needs is in place, so open it to the user: this is what lights up
|
|
553
|
+
// Open IDE/terminal, the proxy, and the health and log-capture monitors.
|
|
554
|
+
updateInstance(row.id, { status: 'running' });
|
|
555
|
+
row.status = 'running';
|
|
556
|
+
|
|
490
557
|
appendLog(row.id, `\n✓ Instance running — open it via the proxy at ${proxyPathFor(row.id)}\n`);
|
|
491
558
|
triggerReconcile();
|
|
492
559
|
} catch (err) {
|
|
560
|
+
// The launcher waits minutes for the sentinel, so a boot that will never write it must say so.
|
|
561
|
+
if (containerId)
|
|
562
|
+
await writeInjectionsDone(row.id, { containerId, remoteUser: row.remote_user });
|
|
493
563
|
failInstance(row.id, err);
|
|
564
|
+
} finally {
|
|
565
|
+
inFlight.delete(row.id);
|
|
494
566
|
}
|
|
495
567
|
}
|
|
496
568
|
|
|
569
|
+
/**
|
|
570
|
+
* `writeContainerFile` reports failure by return value rather than throwing, and a sentinel that
|
|
571
|
+
* never lands leaves the launcher waiting out its whole bound — so surface it in the boot log.
|
|
572
|
+
*/
|
|
573
|
+
async function writeInjectionsDone(id: string, target: ExecTarget): Promise<void> {
|
|
574
|
+
const res = await writeContainerFile(
|
|
575
|
+
target,
|
|
576
|
+
{ dir: '$HOME', name: INJECTIONS_DONE_FILE },
|
|
577
|
+
'done\n'
|
|
578
|
+
).catch((err: Error) => ({ ok: false, error: err.message }));
|
|
579
|
+
if (!res.ok) appendLog(id, `⚠ Could not mark setup complete in the container: ${res.error}\n`);
|
|
580
|
+
}
|
|
581
|
+
|
|
497
582
|
/** The first instance keeps the bare name; later collisions get a `#2`, `#3`, … suffix. */
|
|
498
583
|
function uniqueName(desired: string, excludeId?: string): string {
|
|
499
584
|
const taken = new Set(
|
|
@@ -546,7 +631,9 @@ export async function createInstance(
|
|
|
546
631
|
// Kept synchronous through insertInstance so two concurrent creations can't claim the same free sprite.
|
|
547
632
|
avatar: pickUniqueAvatar(id, allInstances().map(effectiveAvatarName)).name,
|
|
548
633
|
mode: opts.mode ?? getDefaultMode(),
|
|
549
|
-
terminal_split: 0
|
|
634
|
+
terminal_split: 0,
|
|
635
|
+
// Born under the separate-config scheme, so there is never a legacy injection to undo.
|
|
636
|
+
config_migrated: 1
|
|
550
637
|
};
|
|
551
638
|
insertInstance(row);
|
|
552
639
|
// Strip the de-dup `#2` suffix so the recent-folders list keeps the base name.
|
|
@@ -563,10 +650,19 @@ export async function listInstances(): Promise<Instance[]> {
|
|
|
563
650
|
const branches = new Map<string, string | null>();
|
|
564
651
|
await Promise.all(
|
|
565
652
|
rows.map(async (row) => {
|
|
566
|
-
if (!row.container_id || row
|
|
653
|
+
if (!row.container_id || !reconcilesFromDocker(row, inFlight)) return;
|
|
567
654
|
const running = await isRunning(row.container_id);
|
|
568
655
|
const next: InstanceStatus = running ? 'running' : 'stopped';
|
|
569
656
|
if (next !== row.status) {
|
|
657
|
+
// Only reachable for a `creating` row whose boot died with the manager, and its
|
|
658
|
+
// injections will never finish — so stop the container-side launcher waiting on them.
|
|
659
|
+
if (row.status === 'creating') {
|
|
660
|
+
appendLog(row.id, `\n⚠ Setup was interrupted — Rebuild to run it again\n`);
|
|
661
|
+
void writeInjectionsDone(row.id, {
|
|
662
|
+
containerId: row.container_id,
|
|
663
|
+
remoteUser: row.remote_user
|
|
664
|
+
});
|
|
665
|
+
}
|
|
570
666
|
updateInstance(row.id, { status: next });
|
|
571
667
|
row.status = next;
|
|
572
668
|
}
|
|
@@ -672,7 +768,10 @@ export function removeForwardedPort(id: string, containerPort: number): Instance
|
|
|
672
768
|
export function rebuildInstance(id: string, opts: { noCache?: boolean } = {}): InstanceRow {
|
|
673
769
|
const row = getInstance(id);
|
|
674
770
|
if (!row) throw new Error('Instance not found');
|
|
675
|
-
if (
|
|
771
|
+
if (inFlight.has(id)) return row; // a build is already in flight
|
|
772
|
+
// Claimed before the broadcast below, which reconciles synchronously: an unclaimed `creating`
|
|
773
|
+
// row reads as orphaned, and reconcile would flip it straight back off `creating`.
|
|
774
|
+
inFlight.add(id);
|
|
676
775
|
updateInstance(id, { status: 'creating', error: null });
|
|
677
776
|
triggerReconcile();
|
|
678
777
|
const fresh = getInstance(id)!;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/** Digit jumps follow the browser convention: 1–8 are absolute, 9 is always the last tab. */
|
|
2
|
+
function digitTarget(digit: number, count: number): number {
|
|
3
|
+
return digit === 9 ? count - 1 : digit - 1;
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Index the tab strip should move to for a key, or `null` to leave the event alone.
|
|
8
|
+
* Pure so the arrow/Home/End/digit math is testable without a DOM.
|
|
9
|
+
*/
|
|
10
|
+
export function nextTabIndex(current: number, key: string, count: number): number | null {
|
|
11
|
+
if (count <= 0) return null;
|
|
12
|
+
// A `current` outside the strip (nothing focused yet) still resolves, since the
|
|
13
|
+
// arrow branches below normalise through a modulo of `count`.
|
|
14
|
+
const from = current < 0 || current >= count ? 0 : current;
|
|
15
|
+
switch (key) {
|
|
16
|
+
case 'ArrowRight':
|
|
17
|
+
return (from + 1) % count;
|
|
18
|
+
case 'ArrowLeft':
|
|
19
|
+
return (from - 1 + count) % count;
|
|
20
|
+
case 'Home':
|
|
21
|
+
return 0;
|
|
22
|
+
case 'End':
|
|
23
|
+
return count - 1;
|
|
24
|
+
default: {
|
|
25
|
+
if (!/^[1-9]$/.test(key)) return null;
|
|
26
|
+
const target = digitTarget(Number(key), count);
|
|
27
|
+
return target < count ? target : null;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
}
|
package/src/routes.ts
CHANGED
|
@@ -35,6 +35,7 @@ import {
|
|
|
35
35
|
broadcastDefaultMode,
|
|
36
36
|
broadcastFilter,
|
|
37
37
|
broadcastPet,
|
|
38
|
+
broadcastTheme,
|
|
38
39
|
createInstance,
|
|
39
40
|
getDefaultMode,
|
|
40
41
|
deleteAllInstances,
|
|
@@ -68,6 +69,7 @@ import { timingSafeEqualStr } from './lib/crypto.server.ts';
|
|
|
68
69
|
import { proxyRoutes } from './lib/proxy.server.ts';
|
|
69
70
|
import {
|
|
70
71
|
isInstanceFilter,
|
|
72
|
+
isTheme,
|
|
71
73
|
normalizeMode,
|
|
72
74
|
normalizePermissionMode,
|
|
73
75
|
normalizeEffortLevel,
|
|
@@ -514,6 +516,16 @@ export const routes: Record<string, MochiRouteValue> = {
|
|
|
514
516
|
return json({ value: body.value });
|
|
515
517
|
}),
|
|
516
518
|
|
|
519
|
+
// The cookie the picker just wrote is already shared browser-wide; this only tells
|
|
520
|
+
// the tabs behind the settings popup to repaint without a reload.
|
|
521
|
+
'/api/settings/theme': Mochi.api(async ({ method, request }) => {
|
|
522
|
+
if (method !== 'POST') return apiError(405, 'Method Not Allowed');
|
|
523
|
+
const body = (await request.json().catch(() => null)) as { value?: string } | null;
|
|
524
|
+
if (!body || !isTheme(body.value)) return apiError(400, 'Invalid theme');
|
|
525
|
+
broadcastTheme(body.value);
|
|
526
|
+
return json({ value: body.value });
|
|
527
|
+
}),
|
|
528
|
+
|
|
517
529
|
'/api/stream': Mochi.ws({
|
|
518
530
|
// Mochi.ws routes bypass the global basicAuth handle, so enforce origin + auth here.
|
|
519
531
|
upgrade: (req) => (wsUpgradeAllowed(req) ? {} : false),
|
package/src/shell.html
CHANGED
|
@@ -8,35 +8,68 @@
|
|
|
8
8
|
/* Each themed variable is defined once as light-dark(light, dark). With no
|
|
9
9
|
data-theme attribute (the "auto" mode) `color-scheme: light dark` lets the
|
|
10
10
|
browser preference pick the value; an explicit choice pins color-scheme
|
|
11
|
-
below, which forces every light-dark() to that side.
|
|
11
|
+
below, which forces every light-dark() to that side.
|
|
12
|
+
|
|
13
|
+
Light is a pale LCD panel; dark is an amber-phosphor CRT. They are not
|
|
14
|
+
inverses of each other, which is why --ink is text ONLY — the structural
|
|
15
|
+
roles it used to double as (border, drop shadow, inverted chip) are the
|
|
16
|
+
four tokens below. Collapsing them again turns every panel bar, active
|
|
17
|
+
tab and drop shadow into a glowing near-white slab in dark mode. */
|
|
12
18
|
:root {
|
|
13
19
|
color-scheme: light dark;
|
|
14
|
-
--bg: light-dark(#d7d8d2, #
|
|
15
|
-
--bg-card: light-dark(#e7e8e2, #
|
|
16
|
-
--ink: light-dark(#14150f, #
|
|
17
|
-
--ink-soft: light-dark(#45463e, #
|
|
18
|
-
--ink-faint: light-dark(#7d7e74, #
|
|
20
|
+
--bg: light-dark(#d7d8d2, #16130d);
|
|
21
|
+
--bg-card: light-dark(#e7e8e2, #211d13);
|
|
22
|
+
--ink: light-dark(#14150f, #e9e0cb);
|
|
23
|
+
--ink-soft: light-dark(#45463e, #b8ac93);
|
|
24
|
+
--ink-faint: light-dark(#7d7e74, #8a806c);
|
|
19
25
|
/* Half-lit avatar LED — a true mid-tone sitting evenly between the off and on cells, so all three levels stay distinct even at tiny sizes. */
|
|
20
|
-
--led-gray: light-dark(#6b6c62, #
|
|
21
|
-
--rule: light-dark(#20211a, #
|
|
22
|
-
--rule-soft: light-dark(#b9bab2, #
|
|
23
|
-
--
|
|
24
|
-
|
|
25
|
-
--
|
|
26
|
+
--led-gray: light-dark(#6b6c62, #8d8875);
|
|
27
|
+
--rule: light-dark(#20211a, #4a4132);
|
|
28
|
+
--rule-soft: light-dark(#b9bab2, #332c1f);
|
|
29
|
+
/* The .panel hairline. Distinct from --ink so it can stay a warm mid-tone
|
|
30
|
+
in dark rather than tracing every card in near-white. */
|
|
31
|
+
--edge: light-dark(#14150f, #645741);
|
|
32
|
+
/* The hard un-blurred offset block. Light casts it darker than the page;
|
|
33
|
+
dark can't — black on near-black is invisible — so there it becomes a
|
|
34
|
+
warm plate that stays a step under --edge, keeping outline-then-plate
|
|
35
|
+
reading order without the near-white glare it had before. */
|
|
36
|
+
--shadow: light-dark(#14150f, #4a3f28);
|
|
37
|
+
/* The inverted chip: active tabs, primary buttons, panel bars, filled
|
|
38
|
+
ticks. In dark this is where the amber lives. */
|
|
39
|
+
--fill: light-dark(#14150f, #d9963a);
|
|
40
|
+
--fill-ink: light-dark(#d7d8d2, #17130a);
|
|
41
|
+
/* Modal scrim. Has to DARKEN whatever it covers, so it can't be derived
|
|
42
|
+
from --ink (near-white in dark) or --shadow (a warm mid-tone in dark). */
|
|
43
|
+
--scrim: light-dark(rgba(20, 21, 15, 0.5), rgba(0, 0, 0, 0.66));
|
|
44
|
+
--warn-bg: light-dark(#e4d98f, #43350f);
|
|
45
|
+
/* Kept yellower than --fill in dark so a warning doesn't read as chrome. */
|
|
46
|
+
--warn-line: light-dark(#9c8729, #cbb45a);
|
|
47
|
+
--warn-ink: light-dark(#463b08, #f3e6ad);
|
|
48
|
+
/* Glint lifting a code chip off --warn-bg — pale in both themes, since
|
|
49
|
+
mixing toward --warn-ink would darken the chip on the light side. */
|
|
50
|
+
--warn-chip: light-dark(rgba(255, 255, 255, 0.35), rgba(243, 230, 173, 0.14));
|
|
26
51
|
--ok-bg: light-dark(#8fbf6e, #23421a);
|
|
27
52
|
--ok-line: light-dark(#4c7a2e, #6fa84a);
|
|
28
53
|
--ok-ink: light-dark(#1c3110, #cdeab8);
|
|
29
54
|
--danger: light-dark(#b23a2e, #e2564a);
|
|
30
55
|
--danger-soft: light-dark(#e3c6c1, #4a231e);
|
|
31
|
-
--screen-bg: #0d0e0a;
|
|
32
|
-
--screen-ink: #d8d9cf;
|
|
33
|
-
--screen-line: rgba(255, 255, 255, 0.04);
|
|
56
|
+
--screen-bg: light-dark(#0d0e0a, #100c04);
|
|
57
|
+
--screen-ink: light-dark(#d8d9cf, #e8b055);
|
|
58
|
+
--screen-line: light-dark(rgba(255, 255, 255, 0.04), rgba(232, 176, 85, 0.05));
|
|
34
59
|
--attn-done: #22c55e;
|
|
35
|
-
--attn-waiting: #f59e0b;
|
|
36
|
-
|
|
37
|
-
--
|
|
60
|
+
--attn-waiting: light-dark(#f59e0b, #ff7a2f);
|
|
61
|
+
/* Softened in dark — a saturated blue is the one hue that fights the warm ground. */
|
|
62
|
+
--info: light-dark(#388bfd, #6c9fd8);
|
|
63
|
+
/* The pixel matrix. 3.5% white over a near-black ground is invisible, so
|
|
64
|
+
dark gets amber at double the alpha to read as a grid rather than noise. */
|
|
65
|
+
--grid-line: light-dark(rgba(0, 0, 0, 0.035), rgba(217, 150, 58, 0.07));
|
|
38
66
|
/* --attn-done at reduced opacity — reads correctly on both themes' track color. */
|
|
39
67
|
--switch-on-bg: rgba(34, 197, 94, 0.32);
|
|
68
|
+
/* The two dim levels, named so they stay consistent. Deliberately not
|
|
69
|
+
themed: at equal alpha, dark disabled text measures higher contrast
|
|
70
|
+
than light, so a dark-only boost would read as "enabled". */
|
|
71
|
+
--dim: 0.4;
|
|
72
|
+
--dim-panel: 0.5;
|
|
40
73
|
--font-display: 'Doto Variable', 'JetBrains Mono Variable', monospace;
|
|
41
74
|
--font-mono:
|
|
42
75
|
'JetBrains Mono Variable', ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
|
|
@@ -66,14 +99,14 @@
|
|
|
66
99
|
rule higher specificity than this global one, so local overrides
|
|
67
100
|
always win regardless of source order. */
|
|
68
101
|
.panel {
|
|
69
|
-
border: 1px solid var(--
|
|
70
|
-
box-shadow: 4px 4px 0 var(--
|
|
102
|
+
border: 1px solid var(--edge);
|
|
103
|
+
box-shadow: 4px 4px 0 var(--shadow);
|
|
71
104
|
}
|
|
72
|
-
/* Shared
|
|
105
|
+
/* Shared header bar — the inverted label strip at the top of a panel. */
|
|
73
106
|
.panel-bar {
|
|
74
107
|
padding: 9px 14px;
|
|
75
|
-
background: var(--
|
|
76
|
-
color: var(--
|
|
108
|
+
background: var(--fill);
|
|
109
|
+
color: var(--fill-ink);
|
|
77
110
|
font-family: var(--font-display);
|
|
78
111
|
font-weight: 700;
|
|
79
112
|
font-size: 12px;
|
package/src/theme.ts
CHANGED
|
@@ -3,8 +3,9 @@
|
|
|
3
3
|
* isomorphic virtual module. Server entry files use `getRequestContext().cookies` instead.
|
|
4
4
|
*/
|
|
5
5
|
import { cookies } from 'mochi-framework';
|
|
6
|
+
import type { Theme } from './types.ts';
|
|
6
7
|
|
|
7
|
-
export type Theme
|
|
8
|
+
export type { Theme };
|
|
8
9
|
|
|
9
10
|
const THEME_KEY = 'theme';
|
|
10
11
|
|
|
@@ -22,3 +23,9 @@ export function applyTheme(theme: Theme): void {
|
|
|
22
23
|
if (theme === 'auto') delete document.documentElement.dataset.theme;
|
|
23
24
|
else document.documentElement.dataset.theme = theme;
|
|
24
25
|
}
|
|
26
|
+
|
|
27
|
+
/** A choice pushed over the stream: persist it here too, so this client's next SSR paint matches. */
|
|
28
|
+
export function syncTheme(theme: Theme): void {
|
|
29
|
+
setTheme(theme);
|
|
30
|
+
applyTheme(theme);
|
|
31
|
+
}
|
package/src/toast.ts
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* svelte-french-toast renders its own chrome, so every mount has to restate the
|
|
3
|
+
* panel look. Shared here because the four mounts (AppShell, Settings, Avatars,
|
|
4
|
+
* the /debug showcase) live on separate pages and silently drifted apart.
|
|
5
|
+
*/
|
|
6
|
+
export const TOAST_STYLE =
|
|
7
|
+
'border:1px solid var(--edge); background:var(--bg-card); color:var(--ink); box-shadow:4px 4px 0 var(--shadow); font-family:var(--font-mono); font-size:13px;';
|
|
8
|
+
|
|
9
|
+
export const TOAST_OPTIONS = { style: TOAST_STYLE };
|
package/src/types.ts
CHANGED
|
@@ -80,6 +80,13 @@ export function isInstanceFilter(v: unknown): v is InstanceFilter {
|
|
|
80
80
|
return v === 'all' || v === 'active' || v === 'stopped';
|
|
81
81
|
}
|
|
82
82
|
|
|
83
|
+
/** Colour-scheme choice; `'auto'` follows the browser's `prefers-color-scheme`. */
|
|
84
|
+
export type Theme = 'light' | 'dark' | 'auto';
|
|
85
|
+
|
|
86
|
+
export function isTheme(v: unknown): v is Theme {
|
|
87
|
+
return v === 'light' || v === 'dark' || v === 'auto';
|
|
88
|
+
}
|
|
89
|
+
|
|
83
90
|
/** Live only — never persisted, so it always reflects the most recent probe. */
|
|
84
91
|
export interface InstanceHealth {
|
|
85
92
|
containerRunning: boolean;
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{eb as a}from"/_mochi/client/chunk-bn731rda.js";import"/_mochi/client/chunk-wvtkwfsh.js";export{a as registerComponent};
|
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
import{a as Zt,b as ze,c as vi,d as Yt,e as hi,g as Li}from"/_mochi/client/chunk-pc0fm37c.js";import{h as tt,i as it,j as Lt,m as dt,n as yi}from"/_mochi/client/chunk-j72r8pkk.js";import{q as ri}from"/_mochi/client/chunk-8xvr02wh.js";import{A as He,B as be,C as Mi,D as ct,E as Ii,z as Ze}from"/_mochi/client/chunk-k37wj1jm.js";import{F as ce,G as ft,H as Ke}from"/_mochi/client/chunk-9143wy3j.js";import{$a as Ci,Aa as Ee,Ba as nt,Ca as c,Da as Y,Ea as M,Ga as bi,Ha as Ie,Ja as Ei,K as $i,Ka as Si,M as f,N as se,Na as oe,Oa as ai,Qa as De,R as te,S as ie,Ta as X,Va as We,Wa as Be,Xa as xi,Y as Ct,Ya as fe,Z as Jt,Za as ne,_ as I,_a as ve,aa as St,ba as w,cb as wi,da as r,ea as $e,eb as Ti,fa as we,ga as n,ha as Se,ia as s,ja as he,ma as F,na as Dt,oa as Wt,pa as qe,qa as ui,ra as e,ua as pi,va as Ae,wa as W,xa as Te,ya as u}from"/_mochi/client/chunk-bn731rda.js";import{fb as Ni}from"/_mochi/client/chunk-wvtkwfsh.js";var ni=!1;class Bt extends Date{#e=w(super.getTime());#t=new Map;#i=Dt;constructor(...i){super(...i);if(!ni)this.#a()}#a(){ni=!0;var i=Bt.prototype,t=Date.prototype,a=Object.getOwnPropertyNames(t);for(let l of a){if(l.startsWith("get")||l.startsWith("to")||l==="valueOf")i[l]=function(...d){if(d.length>0)return e(this.#e),t[l].apply(this,d);var h=this.#t.get(l);if(h===void 0){let o=Dt;Wt(this.#i),h=I(()=>{return e(this.#e),t[l].apply(this,d)}),this.#t.set(l,h),Wt(o)}return e(h)};if(l.startsWith("set"))i[l]=function(...d){var h=t[l].apply(this,d);return r(this.#e,t.getTime.call(this)),h}}}}var Fi=["forEach","isDisjointFrom","isSubsetOf","isSupersetOf"],Ai=["difference","intersection","symmetricDifference","union"],ci=!1;class Ve extends Set{#e=new Map;#t=w(0);#i=w(0);#a=qe||-1;constructor(i){super();if(i){for(var t of i)super.add(t);this.#i.v=super.size}if(!ci)this.#r()}#l(i){return qe===this.#a?w(i):St(i)}#r(){ci=!0;var i=Ve.prototype,t=Set.prototype;for(let a of Fi)i[a]=function(...l){return e(this.#t),t[a].apply(this,l)};for(let a of Ai)i[a]=function(...l){e(this.#t);var d=t[a].apply(this,l);return new Ve(d)}}has(i){var t=super.has(i),a=this.#e,l=a.get(i);if(l===void 0){if(!t)return e(this.#t),!1;l=this.#l(!0),a.set(i,l)}return e(l),t}add(i){if(!super.has(i))super.add(i),r(this.#i,super.size),$e(this.#t);return this}delete(i){var t=super.delete(i),a=this.#e,l=a.get(i);if(l!==void 0)a.delete(i),r(l,!1);if(t)r(this.#i,super.size),$e(this.#t);return t}clear(){if(super.size===0)return;super.clear();var i=this.#e;for(var t of i.values())r(t,!1);i.clear(),r(this.#i,0),$e(this.#t)}keys(){return this.values()}values(){return e(this.#t),super.values()}entries(){return e(this.#t),super.entries()}[Symbol.iterator](){return this.keys()}get size(){return e(this.#i)}}class di extends Map{#e=new Map;#t=w(0);#i=w(0);#a=qe||-1;constructor(i){super();if(i){for(var[t,a]of i)super.set(t,a);this.#i.v=super.size}}#l(i){return qe===this.#a?w(i):St(i)}has(i){var t=this.#e,a=t.get(i);if(a===void 0)if(super.has(i))a=this.#l(0),t.set(i,a);else return e(this.#t),!1;return e(a),!0}forEach(i,t){this.#r(),super.forEach(i,t)}get(i){var t=this.#e,a=t.get(i);if(a===void 0)if(super.has(i))a=this.#l(0),t.set(i,a);else{e(this.#t);return}return e(a),super.get(i)}set(i,t){var a=this.#e,l=a.get(i),d=super.get(i),h=super.set(i,t),o=this.#t;if(l===void 0)l=this.#l(0),a.set(i,l),r(this.#i,super.size),$e(o);else if(d!==t){$e(l);var S=o.reactions===null?null:new Set(o.reactions),b=S===null||!l.reactions?.every((A)=>S.has(A));if(b)$e(o)}return h}delete(i){var t=this.#e,a=t.get(i),l=super.delete(i);if(a!==void 0)t.delete(i),r(a,-1);if(l)r(this.#i,super.size),$e(this.#t);return l}clear(){if(super.size===0)return;super.clear();var i=this.#e;r(this.#i,0);for(var t of i.values())r(t,-1);$e(this.#t),i.clear()}#r(){e(this.#t);var i=this.#e;if(this.#i.v!==i.size){for(var t of super.keys())if(!i.has(t)){var a=this.#l(0);i.set(t,a)}}for([,a]of this.#e)e(a)}keys(){return e(this.#t),super.keys()}values(){return this.#r(),super.values()}entries(){return this.#r(),super.entries()}[Symbol.iterator](){return this.entries()}get size(){return e(this.#i),super.size}}var wt=Symbol("replace");class It extends URLSearchParams{#e=w(0);#t=si();#i=!1;#a(){if(!this.#t||this.#i)return;this.#i=!0;let i=this.toString();this.#t.search=i&&`?${i}`,this.#i=!1}[wt](i){if(this.#i)return;if(i.toString()===super.toString())return;this.#i=!0;for(let t of[...super.keys()])super.delete(t);for(let[t,a]of i)super.append(t,a);$e(this.#e),this.#i=!1}append(i,t){super.append(i,t),this.#a(),$e(this.#e)}delete(i,t){var a=super.has(i,t);if(super.delete(i,t),a)this.#a(),$e(this.#e)}get(i){return e(this.#e),super.get(i)}getAll(i){return e(this.#e),super.getAll(i)}has(i,t){return e(this.#e),super.has(i,t)}keys(){return e(this.#e),super.keys()}forEach(i,t){e(this.#e),super.forEach(i,t)}set(i,t){var a=super.getAll(i);super.set(i,t);var l=super.getAll(i);if(a.length!==l.length||a.some((d,h)=>d!==l[h]))this.#a(),$e(this.#e)}sort(){super.sort(),this.#a(),$e(this.#e)}toString(){return e(this.#e),super.toString()}values(){return e(this.#e),super.values()}entries(){return e(this.#e),super.entries()}[Symbol.iterator](){return this.entries()}get size(){return e(this.#e),super.size}}var Ot=null;function si(){return Ot}class oi extends URL{#e=w(super.protocol);#t=w(super.username);#i=w(super.password);#a=w(super.hostname);#l=w(super.port);#r=w(super.pathname);#f=w(super.hash);#n=w(super.search);#c;constructor(i,t){i=new URL(i,t);super(i);Ot=this,this.#c=new It(i.searchParams),Ot=null}get hash(){return e(this.#f)}set hash(i){super.hash=i,r(this.#f,super.hash)}get host(){return e(this.#a),e(this.#l),super.host}set host(i){super.host=i,r(this.#a,super.hostname),r(this.#l,super.port)}get hostname(){return e(this.#a)}set hostname(i){super.hostname=i,r(this.#a,super.hostname)}get href(){return e(this.#e),e(this.#t),e(this.#i),e(this.#a),e(this.#l),e(this.#r),e(this.#f),e(this.#n),super.href}set href(i){super.href=i,r(this.#e,super.protocol),r(this.#t,super.username),r(this.#i,super.password),r(this.#a,super.hostname),r(this.#l,super.port),r(this.#r,super.pathname),r(this.#f,super.hash),r(this.#n,super.search),this.#c[wt](super.searchParams)}get password(){return e(this.#i)}set password(i){super.password=i,r(this.#i,super.password)}get pathname(){return e(this.#r)}set pathname(i){super.pathname=i,r(this.#r,super.pathname)}get port(){return e(this.#l)}set port(i){super.port=i,r(this.#l,super.port)}get protocol(){return e(this.#e)}set protocol(i){super.protocol=i,r(this.#e,super.protocol)}get search(){return e(this.#n)}set search(i){super.search=i,r(this.#n,super.search),this.#c[wt](super.searchParams)}get username(){return e(this.#t)}set username(i){super.username=i,r(this.#t,super.username)}get origin(){return e(this.#e),e(this.#a),e(this.#l),super.origin}get searchParams(){return this.#c}toString(){return this.href}toJSON(){return this.href}}class mi{#e;#t;constructor(i,t){this.#e=i,this.#t=Jt(t)}get current(){return this.#t(),this.#e()}}var gi=/^[A-Za-z0-9._-]+$/;function ki(i){let t=i.trim();if(!t)return null;let a,l,d=t.match(/^[A-Za-z0-9._-]+@([A-Za-z0-9.-]+):(.+)$/);if(d)a=d[1],l=d[2];else if(/^[a-z][a-z0-9+.-]*:\/\//i.test(t)){let b;try{b=new URL(t)}catch{return null}if(b.protocol!=="http:"&&b.protocol!=="https:"&&b.protocol!=="ssh:")return null;a=b.hostname,l=b.pathname}else{let b=t.match(/^([A-Za-z0-9-]+\.[A-Za-z0-9.-]+)\/(.+)$/);if(!b)return null;a=b[1],l=b[2]}if(!a||!l)return null;let h=l.replace(/\.git$/i,"").split("/").filter(Boolean),[o,S]=h;if(!o||!S||!gi.test(o)||!gi.test(S))return null;return{host:a,owner:o,repo:S,cloneUrl:`https://${a}/${o}/${S}.git`}}function Kt(i){return ki(i)!==null}var Vi=new Set(["$$slots","$$events","$$legacy"]);function bt(i,t){let a=fe(t,Vi),l=[["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"}]];ce(i,ne({name:"folder-clock"},()=>a,{get iconNode(){return l}}))}var Ri=new Set(["$$slots","$$events","$$legacy"]);function _e(i,t){let a=fe(t,Ri),l=[["path",{d:"M15 6a9 9 0 0 0-9 9V3"}],["circle",{cx:"18",cy:"6",r:"3"}],["circle",{cx:"6",cy:"18",r:"3"}]];ce(i,ne({name:"git-branch"},()=>a,{get iconNode(){return l}}))}var Di=new Set(["$$slots","$$events","$$legacy"]);function Nt(i,t){let a=fe(t,Di),l=[["path",{d:"m5 12 7-7 7 7"}],["path",{d:"M12 19V5"}]];ce(i,ne({name:"arrow-up"},()=>a,{get iconNode(){return l}}))}var Wi=new Set(["$$slots","$$events","$$legacy"]);function $t(i,t){let a=fe(t,Wi),l=[["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"}]];ce(i,ne({name:"folder"},()=>a,{get iconNode(){return l}}))}var Bi=new Set(["$$slots","$$events","$$legacy"]);function et(i,t){let a=fe(t,Bi),l=[["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"}]];ce(i,ne({name:"triangle-alert"},()=>a,{get iconNode(){return l}}))}var Oi=u('<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>'),Ji=u('<button class="recent-toggle svelte-oq97c4"> </button>'),Ki=u('<div class="recent svelte-oq97c4"><div class="recent-label svelte-oq97c4">Recent</div> <!> <!></div>'),Zi=u('<div class="muted svelte-oq97c4">Loading…</div>'),Hi=u('<div class="muted err svelte-oq97c4"> </div>'),Qi=u('<div class="row svelte-oq97c4"><button class="nav svelte-oq97c4"><span class="icon svelte-oq97c4"><!></span> <span class="ename svelte-oq97c4">..</span></button></div>'),Yi=u('<div class="muted svelte-oq97c4"> </div>'),Gi=u('<span class="badge svelte-oq97c4">devcontainer</span>'),Ui=u('<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>'),Xi=u("<!> <!> <!>",1),ji=u(`<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>`),qi=u('<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="mode svelte-oq97c4"><div class="mode-label svelte-oq97c4">Editor</div> <div class="mode-toggle svelte-oq97c4" role="group" aria-label="Editor mode"><button type="button"><!> Full IDE</button> <button type="button"><!> Terminal</button></div></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 Ht(i,t){te(t,!0);let a=ve(t,"defaultMode",3,"ide"),l=ve(t,"initialMode",3,null),d=w(we(l())),h=I(()=>e(d)??a()),o=w(null),S=w(!0),b=w(null),A=w(""),V=w(null),O=w(we([])),j=w(!1),L=w(""),R=w(""),P=I(()=>Kt(e(L)));function E(){if(!e(P))return;t.onpick(e(L).trim(),{branch:e(R).trim()||void 0,mode:e(h)})}let G=I(()=>e(o)?e(o).entries.filter((p)=>p.name.toLowerCase().includes(e(A).trim().toLowerCase())):[]),K=I(()=>e(j)?e(O):e(O).slice(0,5));async function Z(){try{let p=await Zt("/api/history");r(O,p.history??[],!0)}catch{}}async function k(p){let ae=e(O);r(O,e(O).filter((ge)=>ge.source_path!==p),!0);try{await vi("/api/history",{sourcePath:p})}catch{r(O,ae,!0)}}async function v(p=null){r(S,!0),r(b,null),r(A,"");try{let ae=p?`/api/browse?path=${encodeURIComponent(p)}`:"/api/browse";r(o,await Zt(ae,void 0,"Could not list folder"),!0)}catch(ae){r(b,ae.message,!0)}finally{r(S,!1)}await ui(),e(V)?.focus()}he(()=>{v(),Z()});var N=qi(),C=n(N),q=n(C),H=s(n(q),2),J=n(H);ft(J,{size:16}),f(H),f(q);var me=s(q,2),Ne=s(n(me),2),z=n(Ne);let B;var _=n(z);it(_,{size:15}),se(),f(z);var g=s(z,2);let y;var Q=n(g);tt(Q,{size:15}),se(),f(g),f(Ne),f(me);var m=s(me,2),T=s(n(m),2),D=n(T);De(D);var U=s(D,2);De(U);var ye=s(U,2);f(T),f(m);var Re=s(m,2),x=n(Re),$=n(x,!0);f(x),f(Re);var ue=s(Re,2);{var Le=(p)=>{var ae=Ki(),ge=s(n(ae),2);Ie(ge,17,()=>e(K),(Pe)=>Pe.source_path,(Pe,Me)=>{var de=Oi(),re=n(de),xe=n(re),Fe=n(xe);{var Ue=(ke)=>{_e(ke,{size:16})},Xe=I(()=>Kt(e(Me).source_path)),rt=(ke)=>{bt(ke,{size:16})};M(Fe,(ke)=>{if(e(Xe))ke(Ue);else ke(rt,-1)})}f(xe);var vt=s(xe,2),Oe=n(vt),Vt=n(Oe,!0);f(Oe);var ht=s(Oe,2),Rt=n(ht,!0);f(ht),f(vt),f(re);var je=s(re,2),Je=n(je);ft(Je,{size:14}),f(je),f(de),F(()=>{Y(Vt,e(Me).name),Y(Rt,e(Me).source_path),X(je,"aria-label",`Remove ${e(Me).name??""} from history`)}),W("click",re,()=>t.onpick(e(Me).source_path,{mode:e(h)})),W("click",je,(ke)=>{ke.stopPropagation(),k(e(Me).source_path)}),c(Pe,de)});var Ye=s(ge,2);{var Ge=(Pe)=>{var Me=Ji(),de=n(Me,!0);f(Me),F(()=>Y(de,e(j)?"Show fewer":`Show all (${e(O).length})`)),W("click",Me,()=>r(j,!e(j))),c(Pe,Me)};M(Ye,(Pe)=>{if(e(O).length>5)Pe(Ge)})}f(ae),c(p,ae)};M(ue,(p)=>{if(e(O).length>0)p(Le)})}var Ce=s(ue,2),ee=n(Ce);De(ee),Be(ee,(p)=>r(V,p),()=>e(V)),f(Ce);var pe=s(Ce,2),Qe=n(pe);{var st=(p)=>{var ae=Zi();c(p,ae)},ot=(p)=>{var ae=Hi(),ge=n(ae,!0);f(ae),F(()=>Y(ge,e(b))),c(p,ae)},zt=(p)=>{var ae=Xi(),ge=Se(ae);{var Ye=(de)=>{var re=Qi(),xe=n(re),Fe=n(xe),Ue=n(Fe);Nt(Ue,{size:16}),f(Fe),se(2),f(xe),f(re),W("click",xe,()=>v(e(o)?.parent??null)),c(de,re)};M(ge,(de)=>{if(e(o).parent&&!e(A))de(Ye)})}var Ge=s(ge,2);{var Pe=(de)=>{var re=Yi(),xe=n(re,!0);f(re),F(()=>Y(xe,e(A)?"No folders match.":"No subfolders here.")),c(de,re)};M(Ge,(de)=>{if(e(G).length===0)de(Pe)})}var Me=s(Ge,2);Ie(Me,19,()=>e(G),(de)=>de.path,(de,re,xe)=>{var Fe=Ui();let Ue;var Xe=n(Fe),rt=n(Xe),vt=n(rt);$t(vt,{size:16}),f(rt);var Oe=s(rt,2),Vt=n(Oe,!0);f(Oe);var ht=s(Oe,2);{var Rt=(Je)=>{var ke=Gi();c(Je,ke)};M(ht,(Je)=>{if(e(re).hasDevcontainer)Je(Rt)})}f(Xe);var je=s(Xe,2);f(Fe),F((Je)=>{Ue=oe(Fe,1,"row svelte-oq97c4",null,Ue,Je),Y(Vt,e(re).name)},[()=>({"first-match":e(A).trim()&&e(xe)===0})]),W("click",Xe,()=>v(e(re).path)),W("click",je,()=>t.onpick(e(re).path,{mode:e(h)})),c(de,Fe)}),c(p,ae)};M(Qe,(p)=>{if(e(S))p(st);else if(e(b))p(ot,1);else if(e(o))p(zt,2)})}f(pe);var mt=s(pe,2);{var kt=(p)=>{var ae=ji(),ge=n(ae);et(ge,{size:15}),se(2),f(ae),c(p,ae)};M(mt,(p)=>{if(e(o)&&!e(o).hasDevcontainer)p(kt)})}var gt=s(mt,2),ut=s(n(gt),2);f(gt),f(C),f(N),F(()=>{B=oe(z,1,"mode-btn svelte-oq97c4",null,B,{active:e(h)==="ide"}),X(z,"aria-pressed",e(h)==="ide"),y=oe(g,1,"mode-btn svelte-oq97c4",null,y,{active:e(h)==="terminal"}),X(g,"aria-pressed",e(h)==="terminal"),ye.disabled=!e(P),Y($,e(o)?.path??"…"),ut.disabled=!e(o)}),W("click",N,function(...p){t.onclose?.apply(this,p)}),W("keydown",N,(p)=>p.key==="Escape"&&t.onclose()),W("click",C,(p)=>p.stopPropagation()),W("keydown",C,()=>{}),W("click",H,function(...p){t.onclose?.apply(this,p)}),W("click",z,()=>r(d,"ide")),W("click",g,()=>r(d,"terminal")),W("keydown",D,(p)=>{if(p.key==="Enter")p.preventDefault(),E()}),We(D,()=>e(L),(p)=>r(L,p)),W("keydown",U,(p)=>{if(p.key==="Enter")p.preventDefault(),E()}),We(U,()=>e(R),(p)=>r(R,p)),W("click",ye,E),W("keydown",ee,(p)=>{let ae=e(G)[0];if(p.key==="Enter"&&ae)p.preventDefault(),v(ae.path)}),We(ee,()=>e(A),(p)=>r(A,p)),W("click",ut,()=>e(o)&&t.onpick(e(o).path,{mode:e(h)})),c(i,N),ie()}Te(["click","keydown"]);var _i=u('<div class="branch svelte-jv8lut" title="Branch checked out in the container"><!><span class="svelte-jv8lut"> </span></div>');function Qt(i,t){var a=_i(),l=n(a);_e(l,{size:12});var d=s(l),h=n(d,!0);f(d),f(a),F(()=>Y(h,t.branch)),c(i,a)}var ea=new Set(["$$slots","$$events","$$legacy"]);function Et(i,t){let a=fe(t,ea),l=[["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"}]];ce(i,ne({name:"cable"},()=>a,{get iconNode(){return l}}))}var ta=u('<a target="_blank" rel="noopener"> </a>'),ia=u('<div class="fports svelte-1uaz383" title="Forwarded ports — click to open"><!> <span class="list svelte-1uaz383"></span></div>');function Gt(i,t){te(t,!0);var a=nt(),l=Se(a);{var d=(h)=>{var o=ia(),S=n(o);Et(S,{size:12});var b=s(S,2);Ie(b,21,()=>t.ports,(A)=>A.container_port,(A,V)=>{var O=ta();let j;var L=n(O,!0);f(O),F((R,P)=>{j=oe(O,1,"fport svelte-1uaz383",null,j,{open:e(V).open}),X(O,"href",R),X(O,"title",P),Y(L,e(V).container_port)},[()=>Yt(e(V).host_port),()=>`container :${e(V).container_port} → ${Yt(e(V).host_port)} ${e(V).open?"(open)":"(not published yet)"}`]),c(A,O)}),f(b),f(o),c(h,o)};M(l,(h)=>{if(t.ports.length)h(d)})}c(i,a),ie()}var aa=u('<div class="busy-overlay svelte-13338y7" aria-live="polite"><span class="busy-label svelte-13338y7"> </span></div>'),la=u('<input class="name-edit svelte-13338y7"/>'),ra=u('<button class="name svelte-13338y7" title="Click to rename"> </button>'),fa=u("<span></span>"),na=u('<div class="card-error svelte-13338y7"> </div>'),ca=u("<!> <!>",1),da=u('<li><!> <div class="card-head svelte-13338y7"><!> <!> <!> <!></div> <div class="path svelte-13338y7"> </div> <!> <!> <!> <div class="actions svelte-13338y7"><!> <!> <!> <!></div></li>');function Ut(i,t){te(t,!0);let a=ve(t,"editingName",15),l=ve(t,"pending",3,null),d=I(()=>t.instance.status==="running"||t.instance.status==="stopped"||t.instance.status==="error"&&!!t.instance.container_id),h={start:"Starting…",stop:"Stopping…",delete:"Deleting…",rebuild:"Rebuilding…"};var o=da();let S;var b=n(o);{var A=(m)=>{var T=aa(),D=n(T),U=n(D,!0);f(D),f(T),F(()=>Y(U,h[l()])),c(m,T)};M(b,(m)=>{if(l())m(A)})}var V=s(b,2),O=n(V);{let m=I(()=>Ze(t.instance.avatar??void 0)??null);He(O,{get name(){return t.instance.name},get art(){return e(m)},interactive:!0})}var j=s(O,2);{var L=(m)=>{var T=la();De(T),Ct(T,!0),Ae("focus",T,(D)=>D.currentTarget.select()),Ae("blur",T,function(...D){t.oncommitrename?.apply(this,D)}),W("keydown",T,(D)=>{if(D.key==="Enter")D.currentTarget.blur();else if(D.key==="Escape")t.oncancelrename()}),We(T,a),c(m,T)},R=(m)=>{var T=ra(),D=n(T,!0);f(T),F(()=>Y(D,t.instance.name)),W("click",T,function(...U){t.onstartrename?.apply(this,U)}),c(m,T)};M(j,(m)=>{if(t.editing)m(L);else m(R,-1)})}var P=s(j,2);{var E=(m)=>{var T=fa();let D;F(()=>{D=oe(T,1,"attn svelte-13338y7",null,D,{"attn-done":t.instance.attention==="done","attn-waiting":t.instance.attention==="waiting"}),X(T,"title",t.instance.attention==="waiting"?"Claude is waiting for input":"Claude finished"),X(T,"aria-label",t.instance.attention==="waiting"?"Claude is waiting for input":"Claude finished")}),c(m,T)};M(P,(m)=>{if(t.instance.attention)m(E)})}var G=s(P,2);hi(G,{get status(){return t.instance.status}}),f(V);var K=s(V,2),Z=n(K,!0);f(K);var k=s(K,2);{var v=(m)=>{Gt(m,{get ports(){return t.instance.forwarded_ports}})};M(k,(m)=>{if(t.instance.status==="running")m(v)})}var N=s(k,2);{var C=(m)=>{Qt(m,{get branch(){return t.instance.git_branch}})};M(N,(m)=>{if(t.instance.git_branch)m(C)})}var q=s(N,2);{var H=(m)=>{var T=na(),D=n(T,!0);f(T),F(()=>Y(D,t.instance.error)),c(m,T)};M(q,(m)=>{if(t.instance.status==="error"&&t.instance.error)m(H)})}var J=s(q,2),me=n(J);{var Ne=(m)=>{var T=ca(),D=Se(T);{let ye=I(()=>`/ide/${t.instance.id}`);be(D,{variant:"primary",size:"sm",get href(){return e(ye)},children:(Re,x)=>{se();var $=Ee();F(()=>Y($,t.instance.mode==="terminal"?"Open terminal":"Open IDE")),c(Re,$)},$$slots:{default:!0}})}var U=s(D,2);be(U,{size:"sm",onclick:()=>t.onact("stop"),children:(ye,Re)=>{se();var x=Ee("Stop");c(ye,x)},$$slots:{default:!0}}),c(m,T)},z=(m)=>{be(m,{size:"sm",onclick:()=>t.onact("start"),children:(T,D)=>{se();var U=Ee("Start");c(T,U)},$$slots:{default:!0}})},B=(m)=>{{let T=I(()=>Ke(`/instances/${t.instance.id}`));be(m,{size:"sm",get href(){return e(T)},target:"_blank",rel:"noopener noreferrer",children:(D,U)=>{se();var ye=Ee("View logs");c(D,ye)},$$slots:{default:!0}})}};M(me,(m)=>{if(t.instance.status==="running")m(Ne);else if(t.instance.status==="stopped"||t.instance.status==="error"&&t.instance.container_id)m(z,1);else if(t.instance.status==="creating")m(B,2)})}var _=s(me,2);{var g=(m)=>{be(m,{size:"sm",title:"Recreate the container and re-run setup (credentials, hooks, port forwards)",onclick:()=>t.onact("rebuild"),children:(T,D)=>{se();var U=Ee("Rebuild");c(T,U)},$$slots:{default:!0}})};M(_,(m)=>{if(e(d))m(g)})}var y=s(_,2);{let m=I(()=>Ke(`/instances/${t.instance.id}`));be(y,{size:"sm",ghost:!0,get href(){return e(m)},target:"_blank",rel:"noopener noreferrer",children:(T,D)=>{se();var U=Ee("Details");c(T,U)},$$slots:{default:!0}})}var Q=s(y,2);be(Q,{variant:"danger",size:"sm",onclick:()=>t.onact("delete"),children:(m,T)=>{se();var D=Ee("Delete");c(m,D)},$$slots:{default:!0}}),f(J),f(o),F(()=>{S=oe(o,1,"card panel svelte-13338y7",null,S,{busy:!!l()}),X(o,"aria-busy",!!l()||void 0),X(K,"title",t.instance.source_path),Y(Z,t.instance.source_path)}),c(i,o),ie()}Te(["keydown","click"]);var sa=new Set(["$$slots","$$events","$$legacy"]);function pt(i,t){let a=fe(t,sa),l=[["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"}]];ce(i,ne({name:"component"},()=>a,{get iconNode(){return l}}))}var oa=new Set(["$$slots","$$events","$$legacy"]);function Mt(i,t){let a=fe(t,oa),l=[["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"}]];ce(i,ne({name:"package"},()=>a,{get iconNode(){return l}}))}var ma=u('<a class="brand svelte-94cd8h" href="/"><span class="logo svelte-94cd8h"><!></span><span class="words svelte-94cd8h"><span>Codebay</span><span class="tagline svelte-94cd8h">devcontainer manager</span></span></a>');function Xt(i,t){te(t,!0);var a=ma(),l=n(a),d=n(l);{var h=(S)=>{He(S,{get art(){return t.pet},get name(){return t.pet.name},scale:4})},o=(S)=>{Mt(S,{size:22})};M(d,(S)=>{if(t.pet)S(h);else S(o,-1)})}f(l),se(),f(a),c(i,a),ie()}var ga=u('<button type="button" role="radio"> </button>'),ua=u('<div class="picker svelte-12yor8r" role="radiogroup" aria-label="Filter instances"></div>');function jt(i,t){te(t,!0);let a=[{value:"all",label:"All"},{value:"active",label:"Active"},{value:"stopped",label:"Stopped"}];var l=ua();Ie(l,21,()=>a,(d)=>d.value,(d,h)=>{var o=ga();let S;var b=n(o,!0);f(o),F(()=>{S=oe(o,1,"segment svelte-12yor8r",null,S,{active:t.value===e(h).value}),X(o,"aria-checked",t.value===e(h).value),Y(b,e(h).label)}),W("click",o,()=>t.onchange(e(h).value)),c(d,o)}),f(l),c(i,l),ie()}Te(["click"]);var va=new Set(["$$slots","$$events","$$legacy"]);function at(i,t){let a=fe(t,va),l=[["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"}]];ce(i,ne({name:"settings"},()=>a,{get iconNode(){return l}}))}var ha=u('<a class="cog svelte-1e745g8" target="_blank" rel="noopener noreferrer" aria-label="Settings" title="Settings"><!></a>');function qt(i,t){te(t,!1),xi();var a=ha(),l=n(a);at(l,{size:16}),f(a),F((d)=>X(a,"href",d),[()=>Ke("/settings")]),c(i,a),ie()}var xa=new Set(["$$slots","$$events","$$legacy"]);function yt(i,t){let a=fe(t,xa),l=[["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"}]];ce(i,ne({name:"link"},()=>a,{get iconNode(){return l}}))}var Sa=u('<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>'),wa=u('<div class="cred-dropdown panel svelte-vongf9" role="menu"></div>'),Ia=u('<div class="cred-menu svelte-vongf9"><button aria-haspopup="menu" aria-label="Credentials" title="Credentials"><!></button> <!></div>');function _t(i,t){te(t,!0);let a=w(!1),l=I(()=>t.auth.filter((L)=>L.available).length),d=I(()=>e(l)===t.auth.length?"ok":e(l)===0?"error":"warn"),h={ok:yt,warn:et,error:ft},o=I(()=>h[e(d)]);function S(L){if(L.available)ct.success(`${L.label} credentials come from ${L.source}.`);else{let R=L.hint?` — ${L.hint}`:"";ct.error(`No ${L.label} credentials found${R}.`)}}he(()=>{if(!e(a))return;let L=(P)=>{if(!P.target?.closest(".cred-menu"))r(a,!1)},R=(P)=>{if(P.key==="Escape")r(a,!1)};return window.addEventListener("click",L),window.addEventListener("keydown",R),()=>{window.removeEventListener("click",L),window.removeEventListener("keydown",R)}});var b=Ia(),A=n(b),V=n(A);Si(V,()=>e(o),(L,R)=>{R(L,{size:16})}),f(A);var O=s(A,2);{var j=(L)=>{var R=wa();Ie(R,21,()=>t.auth,(P)=>P.id,(P,E)=>{var G=Sa(),K=n(G),Z=s(K,2),k=n(Z,!0);f(Z);var v=s(Z,2),N=n(v,!0);f(v),f(G),F(()=>{X(G,"title",e(E).available?`Credentials from ${e(E).source}, copied into each new instance.`:`No credentials found on this computer${e(E).hint?` — ${e(E).hint}`:""}.`),oe(K,1,`dot ${e(E).available?"on":"off"}`,"svelte-vongf9"),Y(k,e(E).label),Y(N,e(E).available?"Authorized":"Not found")}),W("click",G,()=>S(e(E))),c(P,G)}),f(R),c(L,R)};M(O,(L)=>{if(e(a))L(j)})}f(b),F(()=>{oe(A,1,`cred ${e(d)??""}`,"svelte-vongf9"),X(A,"aria-expanded",e(a))}),W("click",A,()=>r(a,!e(a))),c(i,b),ie()}Te(["click"]);var ba=u('<header class="topbar svelte-1h259us"><!> <div class="topbar-actions svelte-1h259us"><!> <!> <!> <!> <!> <div class="new-group svelte-1h259us"><!> <!></div></div></header>');function ei(i,t){te(t,!0);let a=ve(t,"canDelete",3,!1),l=ve(t,"ready",3,!0),d=ve(t,"creating",3,!1),h=ve(t,"defaultMode",3,"ide"),o=I(()=>h()==="terminal"?"ide":"terminal");var S=ba(),b=n(S);Xt(b,{get pet(){return t.pet}});var A=s(b,2),V=n(A);{var O=(k)=>{be(k,{variant:"default",size:"sm",get icon(){return pt},href:"/debug",children:(v,N)=>{se();var C=Ee("Debug");c(v,C)},$$slots:{default:!0}})};M(V,(k)=>{if(wi)k(O)})}var j=s(V,2);{var L=(k)=>{jt(k,{get value(){return t.filter},get onchange(){return t.onFilter}})};M(j,(k)=>{if(t.filter&&t.onFilter)k(L)})}var R=s(j,2);qt(R,{});var P=s(R,2);_t(P,{get auth(){return t.auth}});var E=s(P,2);{let k=I(()=>!a());be(E,{variant:"danger",size:"sm",get onclick(){return t.onDeleteAll},get disabled(){return e(k)},children:(v,N)=>{se();var C=Ee("Delete all");c(v,C)},$$slots:{default:!0}})}var G=s(E,2),K=n(G);{let k=I(()=>d()?void 0:Lt),v=I(()=>!l()||d());be(K,{variant:"primary",size:"sm",get icon(){return e(k)},onclick:()=>t.onNew?.(),get disabled(){return e(v)},children:(N,C)=>{se();var q=Ee();F(()=>Y(q,d()?"Creating…":"New instance")),c(N,q)},$$slots:{default:!0}})}var Z=s(K,2);{let k=I(()=>e(o)==="terminal"?tt:it),v=I(()=>!l()||d()),N=I(()=>e(o)==="terminal"?"New terminal instance":"New full IDE instance"),C=I(()=>e(o)==="terminal"?"New terminal instance":"New full IDE instance");be(Z,{variant:"primary",size:"sm",square:!0,get icon(){return e(k)},iconSize:15,onclick:()=>t.onNew?.(e(o)),get disabled(){return e(v)},get title(){return e(N)},get "aria-label"(){return e(C)}})}f(G),f(A),f(S),c(i,S),ie()}var Na=u("<span>Docker daemon is not reachable.</span>"),$a=u("<span>The devcontainer CLI is not available.</span>"),Ea=u('<div class="banner error svelte-146pixd"><strong>Setup needed.</strong> <!> <!></div>'),Ca=u('<div class="banner error svelte-146pixd"><strong>Error.</strong> <span> </span></div>'),pa=u('<div class="empty svelte-146pixd"><p class="empty-sub svelte-146pixd">Loading…</p></div>'),Ma=u('<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>'),ya=u('<div class="empty svelte-146pixd"><p class="empty-sub svelte-146pixd"> </p></div>'),La=u('<ul class="grid svelte-146pixd"></ul>'),Ta=u('<!> <main class="stage svelte-146pixd"><!> <!> <!></main> <!>',1);function ti(i,t){te(t,!0);let a=w(!1),l=w(null),d=w(!1),h=w(null),o=w(null),S=w(""),b=w(we({})),A=I(()=>t.preflight.docker&&t.preflight.cli),V=I(()=>t.instances.filter((g)=>{if(t.filter==="active")return g.status==="running"||g.status==="creating";if(t.filter==="stopped")return g.status==="stopped"||g.status==="error";return!0}));he(()=>{for(let[g,{since:y}]of Object.entries(e(b))){let Q=t.instances.find((m)=>m.id===g);if(!Q||Q.status!==y)O(g)}});function O(g){let{[g]:y,...Q}=e(b);r(b,Q,!0)}async function j(g,y){r(a,!1),r(d,!0),r(h,null);try{await ze("/api/instances",{sourcePath:g,branch:y?.branch,mode:y?.mode},"Failed to create instance")}catch(Q){r(h,Q.message,!0)}finally{r(d,!1)}}async function L(g,y){if(r(h,null),y==="delete"&&!confirm("Delete this instance and its copied files?"))return;if(y==="rebuild"&&!confirm("Recreate this container and re-run setup? The workspace is kept."))return;let Q=t.instances.find((m)=>m.id===g)?.status;if(Q)r(b,{...e(b),[g]:{action:y,since:Q}},!0);try{await ze(`/api/instances/${g}/${y}`,void 0,`Failed to ${y}`)}catch(m){r(h,m.message,!0),O(g)}}function R(g){r(o,g.id,!0),r(S,g.name,!0)}function P(){r(o,null),r(S,"")}async function E(g){let y=e(S).trim(),Q=t.instances.find((m)=>m.id===g)?.name;if(!y||y===Q){P();return}P(),r(h,null);try{await ze(`/api/instances/${g}/rename`,{name:y},"Failed to rename")}catch(m){r(h,m.message,!0)}}async function G(){if(r(h,null),!confirm(`Delete all ${t.instances.length} instances and their copied files?`))return;try{await ze("/api/instances/delete-all",void 0,"Failed to delete all")}catch(g){r(h,g.message,!0)}}var K=Ta(),Z=Se(K);{let g=I(()=>t.instances.length>0);ei(Z,{get auth(){return t.preflight.auth},get pet(){return t.pet},get canDelete(){return e(g)},get ready(){return e(A)},get creating(){return e(d)},get filter(){return t.filter},get onFilter(){return t.onFilter},get defaultMode(){return t.preflight.defaultMode},onNew:(y)=>{r(l,y??null,!0),r(a,!0)},onDeleteAll:G})}var k=s(Z,2),v=n(k);{var N=(g)=>{var y=Ea(),Q=s(n(y),2);{var m=(U)=>{var ye=Na();c(U,ye)};M(Q,(U)=>{if(!t.preflight.docker)U(m)})}var T=s(Q,2);{var D=(U)=>{var ye=$a();c(U,ye)};M(T,(U)=>{if(!t.preflight.cli)U(D)})}f(y),c(g,y)};M(v,(g)=>{if(!e(A))g(N)})}var C=s(v,2);{var q=(g)=>{var y=Ca(),Q=s(n(y),2),m=n(Q,!0);f(Q),f(y),F(()=>Y(m,e(h))),c(g,y)};M(C,(g)=>{if(e(h))g(q)})}var H=s(C,2);{var J=(g)=>{var y=pa();c(g,y)},me=(g)=>{var y=Ma(),Q=s(n(y),4);{let m=I(()=>!e(A));be(Q,{variant:"primary",get icon(){return Lt},onclick:()=>r(a,!0),get disabled(){return e(m)},children:(T,D)=>{se();var U=Ee("New instance");c(T,U)},$$slots:{default:!0}})}f(y),c(g,y)},Ne=(g)=>{var y=ya(),Q=n(y),m=n(Q);f(Q),f(y),F(()=>Y(m,`No ${t.filter??""} instances.`)),c(g,y)},z=(g)=>{var y=La();Ie(y,21,()=>e(V),(Q)=>Q.id,(Q,m)=>{{let T=I(()=>e(o)===e(m).id),D=I(()=>e(b)[e(m).id]?.action??null);Ut(Q,{get instance(){return e(m)},get editing(){return e(T)},get pending(){return e(D)},onact:(U)=>L(e(m).id,U),onstartrename:()=>R(e(m)),oncommitrename:()=>E(e(m).id),oncancelrename:P,get editingName(){return e(S)},set editingName(U){r(S,U,!0)}})}}),f(y),c(g,y)};M(H,(g)=>{if(!t.loaded)g(J);else if(t.instances.length===0)g(me,1);else if(e(V).length===0)g(Ne,2);else g(z,-1)})}f(k);var B=s(k,2);{var _=(g)=>{Ht(g,{onpick:j,get defaultMode(){return t.preflight.defaultMode},get initialMode(){return e(l)},onclose:()=>r(a,!1)})};M(B,(g)=>{if(e(a))g(_)})}c(i,K),ie()}var Pa=new Set(["$$slots","$$events","$$legacy"]);function lt(i,t){let a=fe(t,Pa),l=[["path",{d:"M21 12a9 9 0 1 1-9-9c2.52 0 4.93 1 6.74 2.74L21 8"}],["path",{d:"M21 3v5h-5"}]];ce(i,ne({name:"rotate-cw"},()=>a,{get iconNode(){return l}}))}var Fa=u('<div class="tab-label editing svelte-r39acv"><!> <input class="tab-name-edit svelte-r39acv"/></div>'),Aa=u('<span class="tab-mode svelte-r39acv" title="Terminal-only instance"><!></span>'),za=u('<span class="tab-mode svelte-r39acv" title="Full IDE instance"><!></span>'),ka=u('<button type="button" class="tab-label svelte-r39acv"><!> <span class="tab-name svelte-r39acv"> </span> <!></button>'),Va=u("<div><!></div>"),Ra=u('<nav class="tabs svelte-r39acv"></nav>'),Da=u('<button type="button" class="reload svelte-r39acv" title="Reload editor" aria-label="Reload editor"><!></button>'),Wa=u('<!> <div class="right svelte-r39acv"><!> <a class="cog svelte-r39acv" target="_blank" rel="noopener noreferrer" title="Settings" aria-label="Settings"><!></a></div>',1);function ii(i,t){te(t,!0);let a=ve(t,"editingName",15);Ii(i,{children:(l,d)=>{var h=Wa(),o=Se(h);{var S=(L)=>{var R=Ra();Ie(R,21,()=>t.running,(P)=>P.id,(P,E)=>{var G=Va();let K;var Z=n(G);{var k=(N)=>{var C=Fa(),q=n(C);{let J=I(()=>Ze(e(E).avatar??void 0)??null);He(q,{get name(){return e(E).name},get art(){return e(J)},scale:4})}var H=s(q,2);De(H),Ct(H,!0),f(C),Ae("focus",H,(J)=>J.currentTarget.select()),Ae("blur",H,()=>t.oncommitrename(e(E).id)),W("keydown",H,(J)=>{if(J.key==="Enter")J.currentTarget.blur();else if(J.key==="Escape")t.oncancelrename()}),We(H,a),c(N,C)},v=(N)=>{var C=ka(),q=n(C);{let B=I(()=>Ze(e(E).avatar??void 0)??null);He(q,{get name(){return e(E).name},get art(){return e(B)},scale:4})}var H=s(q,2),J=n(H,!0);f(H);var me=s(H,2);{var Ne=(B)=>{var _=Aa(),g=n(_);tt(g,{size:13}),f(_),c(B,_)},z=(B)=>{var _=za(),g=n(_);it(g,{size:13}),f(_),c(B,_)};M(me,(B)=>{if(e(E).mode==="terminal")B(Ne);else B(z,-1)})}f(C),F(()=>{X(C,"title",e(E).name),Y(J,e(E).name)}),W("click",C,()=>t.onselect(e(E).id)),W("dblclick",C,()=>t.onstartrename(e(E))),c(N,C)};M(Z,(N)=>{if(t.editingId===e(E).id)N(k);else N(v,-1)})}f(G),F(()=>K=oe(G,1,"tab svelte-r39acv",null,K,{active:e(E).id===t.active,"attn-done":e(E).id!==t.active&&t.attention[e(E).id]==="done","attn-waiting":e(E).id!==t.active&&t.attention[e(E).id]==="waiting"})),c(P,G)}),f(R),c(L,R)};M(o,(L)=>{if(t.running.length>0)L(S)})}var b=s(o,2),A=n(b);{var V=(L)=>{var R=Da(),P=n(R);lt(P,{size:18}),f(R),W("click",R,function(...E){t.onreload?.apply(this,E)}),c(L,R)};M(A,(L)=>{if(t.onreload)L(V)})}var O=s(A,2),j=n(O);at(j,{size:18}),f(O),f(b),F((L)=>X(O,"href",L),[()=>Ke("/settings")]),c(l,h)},$$slots:{default:!0}}),ie()}Te(["keydown","click","dblclick"]);var Ba=u('<div class="row svelte-w5e143"> </div>'),Oa=u('<div class="stalled svelte-w5e143"><p class="svelte-w5e143"> </p> <!></div>'),Ja=u('<div class="loader svelte-w5e143"><div class="grid svelte-w5e143" aria-hidden="true"></div> <div class="label svelte-w5e143"> <span class="dot svelte-w5e143">.</span><span class="dot svelte-w5e143">.</span><span class="dot svelte-w5e143">.</span></div> <!></div>');function Tt(i,t){te(t,!0);let a=ve(t,"speed",3,1),l=ve(t,"mode",3,"ide"),d=I(()=>l()==="terminal"),h=w(!1);he(()=>{if(t.stalledAfterMs===void 0)return;let Z=setTimeout(()=>r(h,!0),t.stalledAfterMs);return()=>clearTimeout(Z)});let o=3,S=22,b=140,A=7,V=I(()=>Math.max(20,b/a())),j=w(we((()=>Array.from({length:o},()=>Array.from({length:S},()=>Math.random()<0.5?0:1)))()));he(()=>{if(window.matchMedia?.("(prefers-reduced-motion: reduce)").matches)return;let Z=setInterval(()=>{let k=e(j).map((v)=>v.slice());for(let v=0;v<A;v++){let N=k[Math.floor(Math.random()*o)],C=Math.floor(Math.random()*S);N[C]=N[C]?0:1}r(j,k,!0)},e(V));return()=>clearInterval(Z)});var L=Ja(),R=n(L);Ie(R,21,()=>e(j),bi,(Z,k)=>{var v=Ba(),N=n(v,!0);f(v),F((C)=>Y(N,C),[()=>e(k).join("")]),c(Z,v)}),f(R);var P=s(R,2),E=n(P);se(3),f(P);var G=s(P,2);{var K=(Z)=>{var k=Oa(),v=n(k),N=n(v);f(v);var C=s(v,2);{var q=(H)=>{be(H,{size:"sm",get onclick(){return t.onoverride},children:(J,me)=>{se();var Ne=Ee("Open anyway");c(J,Ne)},$$slots:{default:!0}})};M(C,(H)=>{if(t.onoverride)H(q)})}f(k),F(()=>Y(N,`Waiting for ${e(d)?"the terminal":"code-server"} to answer inside the container.`)),c(Z,k)};M(G,(Z)=>{if(e(h))Z(K)})}f(L),F(()=>Y(E,`Loading ${e(d)?"terminal":"editor"}`)),c(i,L),ie()}var Ka=new Set(["$$slots","$$events","$$legacy"]);function Pt(i,t){let a=fe(t,Ka),l=[["rect",{width:"18",height:"18",x:"3",y:"3",rx:"2"}],["path",{d:"M15 3v18"}],["path",{d:"m10 15-3-3 3-3"}]];ce(i,ne({name:"panel-right-open"},()=>a,{get iconNode(){return l}}))}var Za=new Set(["$$slots","$$events","$$legacy"]);function Ft(i,t){let a=fe(t,Za),l=[["rect",{width:"18",height:"18",x:"3",y:"3",rx:"2"}],["path",{d:"M15 3v18"}],["path",{d:"m8 9 3 3-3 3"}]];ce(i,ne({name:"panel-right-close"},()=>a,{get iconNode(){return l}}))}var Ha=u('<span class="status svelte-ui3nvu">connecting…</span>'),Qa=u('<div class="term svelte-ui3nvu"></div> <div class="overlay svelte-ui3nvu"><!> <!> <button type="button" title="Reload terminal (reconnects, keeps the session)" aria-label="Reload terminal"><!></button></div>',1);function At(i,t){te(t,!0);let a=ve(t,"focus",3,!0),l,d,h,o,S,b=!1,A=w(!1),V=0,O="0",j="1",L=48,R=new TextEncoder;function P(z){if(o?.readyState===WebSocket.OPEN)o.send(R.encode(z))}function E(z){let B=new Uint8Array(z);if(B.length===0)return;if(B[0]===L)d?.write(B.subarray(1))}function G(){let z=++V,B=location.protocol==="https:"?"wss:":"ws:",_=t.arg?`?arg=${encodeURIComponent(t.arg)}`:"",g=new WebSocket(`${B}//${location.host}/p/${t.id}/ws${_}`,["tty"]);o=g,g.binaryType="arraybuffer",g.onopen=()=>{if(V!==z)return;r(A,!0),P(JSON.stringify({AuthToken:"",columns:d?.cols??80,rows:d?.rows??24}))},g.onmessage=(y)=>{if(V===z)E(y.data)},g.onclose=()=>{if(V!==z||b)return;r(A,!1),S=setTimeout(G,1000)},g.onerror=()=>{try{g.close()}catch{}}}function K(){if(S)clearTimeout(S);V++,r(A,!1),d?.reset();let z=o;o=void 0;let B=!1,_=()=>{if(B||b)return;if(B=!0,Z(),G(),t.active&&a())d?.focus()};if(z&&z.readyState!==WebSocket.CLOSED){z.addEventListener("close",_,{once:!0}),setTimeout(_,1500);try{z.close()}catch{}}else _()}function Z(){if(l?.clientWidth>0&&l?.clientHeight>0)try{h?.fit()}catch{}}function k(){if(!d)return;let z=getComputedStyle(document.documentElement),B=z.getPropertyValue("--bg").trim()||"#1a1a1a",_=z.getPropertyValue("--ink").trim()||"#e6e6e6";d.options.theme={background:B,foreground:_,cursor:_,cursorAccent:B}}Ci(()=>{let z;(async()=>{let[{Terminal:_},{FitAddon:g}]=await Promise.all([import("/_mochi/client/chunk-p20tkpde.js"),import("/_mochi/client/chunk-0fjx3z3r.js")]);if(b)return;if(d=new _({fontFamily:"'JetBrains Mono Variable', ui-monospace, monospace",fontSize:13,cursorBlink:!0,scrollback:1e4,allowProposedApi:!0}),h=new g,d.loadAddon(h),d.open(l),k(),Z(),d.onData((y)=>P(O+y)),d.onResize(({cols:y,rows:Q})=>P(j+JSON.stringify({columns:y,rows:Q}))),z=new MutationObserver(k),z.observe(document.documentElement,{attributes:!0,attributeFilter:["data-theme"]}),G(),t.active&&a())d.focus()})();let B=new ResizeObserver(()=>Z());return B.observe(l),()=>{if(b=!0,B.disconnect(),z?.disconnect(),S)clearTimeout(S);try{o?.close()}catch{}d?.dispose()}}),he(()=>{if(t.active&&d){if(Z(),a())d.focus()}});var v=Qa(),N=Se(v);Be(N,(z)=>l=z,()=>l);var C=s(N,2),q=n(C);{var H=(z)=>{var B=Ha();c(z,B)};M(q,(z)=>{if(!e(A))z(H)})}var J=s(q,2);Ei(J,()=>t.actions??$i);var me=s(J,2),Ne=n(me);lt(Ne,{size:14}),f(me),f(C),W("click",me,K),c(i,v),ie()}Te(["click"]);var Ya=u('<button type="button"><!></button>'),Ga=u('<div role="separator" aria-orientation="vertical" aria-label="Resize terminal panes" tabindex="0"></div> <div><!></div>',1),Ua=u('<div class="split svelte-1ysvu88"><div class="side svelte-1ysvu88"><!></div> <!></div>');function li(i,t){te(t,!0);let a=(v)=>{var N=Ya(),C=n(N);{var q=(J)=>{Ft(J,{size:14})},H=(J)=>{Pt(J,{size:14})};M(C,(J)=>{if(e(d))J(q);else J(H,-1)})}f(N),F(()=>{X(N,"aria-pressed",e(d)),X(N,"title",e(d)?"Hide the shell pane":"Open a shell alongside Claude"),X(N,"aria-label",e(d)?"Hide the shell pane":"Open a shell alongside Claude")}),W("click",N,A),c(v,N)},l=ve(t,"initialOpen",3,!1),d=w(we(l())),h=w(we(l())),o=w(50),S=w("left"),b;function A(){if(r(d,!e(d)),e(d))r(h,!0);r(S,e(d)?"right":"left",!0),ze(`/api/instances/${t.id}/split`,{open:e(d)}).catch(()=>{})}function V(v){return Math.min(80,Math.max(20,v))}function O(v){let N=b.getBoundingClientRect();if(N.width>0)r(o,V((v-N.left)/N.width*100),!0)}function j(v){v.preventDefault(),v.currentTarget.setPointerCapture(v.pointerId)}function L(v){if(v.currentTarget.hasPointerCapture(v.pointerId))O(v.clientX)}function R(v){if(v.key==="ArrowLeft")r(o,V(e(o)-5),!0);else if(v.key==="ArrowRight")r(o,V(e(o)+5),!0);else return;v.preventDefault()}var P=Ua(),E=n(P);let G;var K=n(E);{let v=I(()=>t.active&&e(S)==="left"),N=I(()=>e(d)?void 0:a);At(K,{get id(){return t.id},get active(){return t.active},get focus(){return e(v)},get actions(){return e(N)}})}f(E);var Z=s(E,2);{var k=(v)=>{var N=Ga(),C=Se(N);let q;X(C,"aria-valuemin",20),X(C,"aria-valuemax",80);var H=s(C,2);let J,me;var Ne=n(H);{let z=I(()=>t.active&&e(d)),B=I(()=>t.active&&e(d)&&e(S)==="right"),_=I(()=>e(d)?a:void 0);At(Ne,{get id(){return t.id},arg:"shell",get active(){return e(z)},get focus(){return e(B)},get actions(){return e(_)}})}f(H),F((z)=>{q=oe(C,1,"divider svelte-1ysvu88",null,q,{hidden:!e(d)}),X(C,"aria-valuenow",z),J=oe(H,1,"side svelte-1ysvu88",null,J,{hidden:!e(d)}),me=ai(H,"",me,{"flex-basis":`${100-e(o)}%`})},[()=>Math.round(e(o))]),W("pointerdown",C,j),W("pointermove",C,L),W("dblclick",C,()=>r(o,50)),W("keydown",C,R),Ae("pointerdown",H,()=>r(S,"right"),!0),c(v,N)};M(Z,(v)=>{if(e(h))v(k)})}f(P),Be(P,(v)=>b=v,()=>b),F(()=>G=ai(E,"",G,{"flex-basis":e(d)?`${e(o)}%`:"100%"})),Ae("pointerdown",E,()=>r(S,"left"),!0),c(i,P),ie()}Te(["click","pointerdown","pointermove","dblclick","keydown"]);var Xa=u('<iframe class="svelte-1duc7gd"></iframe>'),ja=u("<div><!> <!></div>"),qa=u('<div class="empty svelte-1duc7gd">No running instances.</div>'),_a=u("<div><!> <div><!> <!></div></div> <!>",1);function fi(i,t){te(t,!0);let a=w(we(t.snapshot)),l=w(we(t.preflight)),d=w(we(t.pet)),h=w(we(t.filter)),o=w(t.snapshot.length>0),S=I(()=>e(a).filter((x)=>x.status==="running")),b=w(we(Object.fromEntries(t.snapshot.map((x)=>[x.id,x.attention])))),A=w(null),V=w("");function O(x){r(A,x.id,!0),r(V,x.name,!0)}function j(){r(A,null),r(V,"")}async function L(x){let $=e(V).trim(),ue=e(a).find((Le)=>Le.id===x)?.name;if(!$||$===ue){j();return}j();try{await ze(`/api/instances/${x}/rename`,{name:$},"Failed to rename")}catch(Le){ct.error(Le.message)}}function R(x){r(h,x,!0),ze("/api/settings/filter",{value:x}).catch(()=>{})}let P=w(we(t.initialPath)),E=I(()=>e(P).startsWith("/ide")),G=I(()=>e(P).startsWith("/ide/")?e(P).slice(5):""),K=I(()=>e(E)?e(S).some((x)=>x.id===e(G))?e(G):e(S)[0]?.id??"":"");function Z(x){if(x===e(P))return;history.pushState({},"",x),r(P,x,!0)}he(()=>{function x($){if($.defaultPrevented||$.button!==0||$.metaKey||$.ctrlKey||$.shiftKey||$.altKey)return;let ue=$.target?.closest?.("a");if(!ue)return;let Le=ue.getAttribute("href");if(!Le||ue.target==="_blank"||ue.hasAttribute("download"))return;let Ce=new URL(Le,location.href);if(Ce.origin!==location.origin)return;if(Ce.pathname==="/"||Ce.pathname.startsWith("/ide/"))$.preventDefault(),Z(Ce.pathname)}return document.addEventListener("click",x),()=>document.removeEventListener("click",x)}),he(()=>{function x(){r(P,location.pathname,!0)}return window.addEventListener("popstate",x),()=>window.removeEventListener("popstate",x)}),he(()=>{if(e(S).length===0)return;function x($){$.preventDefault(),$.returnValue=""}return window.addEventListener("beforeunload",x),()=>window.removeEventListener("beforeunload",x)});let k=new Ve;he(()=>{if(e(K))k.add(e(K))});let v=new Ve,N=new Ve,C=new Ve,q=(x)=>N.has(x)||C.has(x),H=1e4,J=I(()=>e(S).find((x)=>x.id===e(K))),me={};function Ne(){let x=e(J);if(!x||x.mode==="terminal")return;v.delete(x.id),me[x.id]?.contentWindow?.location.replace(ri(x))}he(()=>{document.title=e(E)&&e(J)?`${e(J).name} — Codebay`:"Codebay"}),he(()=>{return window.addEventListener("pointerdown",dt),window.addEventListener("keydown",dt),()=>{window.removeEventListener("pointerdown",dt),window.removeEventListener("keydown",dt)}}),he(()=>{let x=!1;return Li(($)=>{if($.type==="preflight"){r(l,{...e(l),docker:$.data.docker,cli:$.data.cli},!0);return}if($.type==="pet"){r(d,Ze($.data.name??void 0),!0);return}if($.type==="filter"){r(h,$.data.value,!0);return}if($.type==="default-mode"){r(l,{...e(l),defaultMode:$.data.mode},!0);return}if($.type==="health"){let ee=e(a).find((pe)=>pe.id===$.data.id);if($.data.health.codeServerAccessible&&ee?.status==="running")N.add($.data.id);return}if($.type!=="instances")return;let ue=$.data,Le=new Set(ue.filter((ee)=>ee.status==="running").map((ee)=>ee.id));for(let ee of[...N])if(!Le.has(ee))N.delete(ee);for(let ee of[...C])if(!Le.has(ee))C.delete(ee);for(let ee of[...v])if(!Le.has(ee))v.delete(ee);let Ce={};for(let ee of ue)Ce[ee.id]=ee.attention;if(x)for(let ee in Ce){let pe=Ce[ee];if(pe&&pe!==e(b)[ee])if(ee===e(K))console.log(`[chime] attention id=${ee} state=${pe} — skipped (tab is active/focused)`);else console.log(`[chime] attention id=${ee} state=${pe} → playChime`),yi(pe)}else console.log("[chime] first frame after (re)connect — baselining, no chimes");x=!0,r(a,ue,!0),r(b,Ce,!0),r(o,!0)},()=>{x=!1})}),he(()=>{if(!e(K)||!e(b)[e(K)])return;let x=()=>{if(document.visibilityState==="visible")ze(`/api/instances/${e(K)}/attention/clear`).catch(()=>{})};return x(),document.addEventListener("visibilitychange",x),()=>document.removeEventListener("visibilitychange",x)});var z=_a(),B=Se(z);let _;var g=n(B);{var y=(x)=>{{let $=I(()=>e(J)&&e(J).mode!=="terminal"&&q(e(K))?Ne:void 0);ii(x,{get running(){return e(S)},get active(){return e(K)},get attention(){return e(b)},get editingId(){return e(A)},get onreload(){return e($)},onselect:(ue)=>Z(`/ide/${ue}`),onstartrename:O,oncommitrename:L,oncancelrename:j,get editingName(){return e(V)},set editingName(ue){r(V,ue,!0)}})}},Q=(x)=>{ti(x,{get preflight(){return e(l)},get instances(){return e(a)},get loaded(){return e(o)},get pet(){return e(d)},get filter(){return e(h)},onFilter:R})};M(g,(x)=>{if(e(E))x(y);else x(Q,-1)})}var m=s(g,2);let T;var D=n(m);Ie(D,17,()=>e(S),(x)=>x.id,(x,$)=>{var ue=nt(),Le=Se(ue);{var Ce=(pe)=>{var Qe=ja();let st;var ot=n(Qe);{var zt=(ge)=>{var Ye=nt(),Ge=Se(Ye);{var Pe=(de)=>{{let re=I(()=>e($).id===e(K)),xe=I(()=>e($).terminal_split===1);li(de,{get id(){return e($).id},get active(){return e(re)},get initialOpen(){return e(xe)}})}},Me=(de)=>{var re=Xa();Be(re,(xe,Fe)=>me[Fe.id]=xe,(xe)=>me?.[xe.id],()=>[e($)]),F((xe)=>{X(re,"src",xe),X(re,"title",e($).name)},[()=>ri(e($))]),Ae("load",re,()=>v.add(e($).id)),pi(re),c(de,re)};M(Ge,(de)=>{if(e($).mode==="terminal")de(Pe);else de(Me,-1)})}c(ge,Ye)},mt=I(()=>q(e($).id));M(ot,(ge)=>{if(e(mt))ge(zt)})}var kt=s(ot,2);{var gt=(ge)=>{Tt(ge,{get mode(){return e($).mode},stalledAfterMs:H,onoverride:()=>C.add(e($).id)})},ut=I(()=>!q(e($).id)),p=(ge)=>{Tt(ge,{})},ae=I(()=>e($).mode!=="terminal"&&!v.has(e($).id));M(kt,(ge)=>{if(e(ut))ge(gt);else if(e(ae))ge(p,1)})}f(Qe),F(()=>st=oe(Qe,1,"pane svelte-1duc7gd",null,st,{active:e($).id===e(K)})),c(pe,Qe)},ee=I(()=>k.has(e($).id));M(Le,(pe)=>{if(e(ee))pe(Ce)})}c(x,ue)});var U=s(D,2);{var ye=(x)=>{var $=qa();c(x,$)};M(U,(x)=>{if(e(E)&&e(S).length===0)x(ye)})}f(m),f(B);var Re=s(B,2);Mi(Re,{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;"}}),F(()=>{_=oe(B,1,"app svelte-1duc7gd",null,_,{ide:e(E)}),T=oe(m,1,"panes svelte-1duc7gd",null,T,{hidden:!e(E)})}),c(i,z),ie()}Ti("AppShell_2rtnxn6pgp2rh",fi);
|