codebay 0.8.0 → 0.9.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 (79) hide show
  1. package/.mochi/import-css/xterm-1yy1hf1g.css +252 -0
  2. package/.mochi/manifest.json +330 -211
  3. package/.mochi/svelte-client/HydratableIsland-k6q8esj4.js +1 -0
  4. package/.mochi/svelte-client/_hydrate-AppShell_2rtnxn6pgp2rh-sg96rp17.js +2 -0
  5. package/.mochi/svelte-client/_hydrate-AvatarsView_257s9yq1wwr4f-92hepzby.js +14 -0
  6. package/.mochi/svelte-client/_hydrate-InstanceView_2ma45l9bybfhl-p3f649gk.js +1 -0
  7. package/.mochi/svelte-client/_hydrate-SettingsView_8hmarwmf8onq-dzmgmv78.js +29 -0
  8. package/.mochi/svelte-client/chunk-2j95sv83.js +1 -0
  9. package/.mochi/svelte-client/chunk-6rbs0mhx.js +1 -0
  10. package/.mochi/svelte-client/chunk-7wkvn2vx.js +2 -0
  11. package/.mochi/svelte-client/chunk-a2psjmrm.js +2 -0
  12. package/.mochi/svelte-client/chunk-m497q88s.js +2 -0
  13. package/.mochi/svelte-client/{chunk-fqg2qzj8.js → chunk-m4fzsd5b.js} +1 -1
  14. package/.mochi/svelte-client/chunk-mpv3qx28.js +36 -0
  15. package/.mochi/svelte-client/chunk-rs41by6w.js +2 -0
  16. package/.mochi/svelte-client/{chunk-qj7zy2d9.js → chunk-v65n8th6.js} +4 -4
  17. package/.mochi/svelte-compile/{App-6rcf0d74.server.js → App-7vjcp38v.server.js} +368 -37
  18. package/.mochi/svelte-compile/{Avatars-pzyz0tv3.server.js → Avatars-e2cfc95t.server.js} +130 -25
  19. package/.mochi/svelte-compile/{ClientStats-z3tn9ad6.server.js → ClientStats-4cphmrnp.server.js} +1 -1
  20. package/.mochi/svelte-compile/{DefaultError-wh77vebf.server.js → DefaultError-je52k17d.server.js} +1 -1
  21. package/.mochi/svelte-compile/{Instance-49ksrp11.server.js → Instance-h78n2dsv.server.js} +16 -13
  22. package/.mochi/svelte-compile/{Settings-sz5d6qj7.server.js → Settings-tav2asn7.server.js} +153 -127
  23. package/.mochi/svelte-compile/{chunk-fpe16ywq.js → chunk-60mpagr9.js} +17 -7
  24. package/.mochi/svelte-compile/chunk-9nqc2r0y.js +9706 -0
  25. package/.mochi/svelte-compile/{chunk-6ghzacpg.js → chunk-bpqwf1nw.js} +36 -4
  26. package/.mochi/svelte-compile/chunk-jx6h1xzp.js +20 -0
  27. package/.mochi/svelte-compile/{chunk-q8rbesaw.js → chunk-m8ygpyhr.js} +5 -4
  28. package/.mochi/svelte-compile/chunk-rtdne1m8.js +31 -0
  29. package/.mochi/svelte-compile/{chunk-we0ggtws.js → chunk-xpt1a7jm.js} +2 -1
  30. package/.mochi/svelte-css/AvatarEditor-2mdq8ss346drw.css +1 -0
  31. package/.mochi/svelte-css/{AvatarsView-2ughbzc26luyb.css → AvatarsView-2llo48w0wt0xn.css} +1 -1
  32. package/.mochi/svelte-css/FolderBrowser-2pxp9z1o7zixk.css +1 -0
  33. package/.mochi/svelte-css/{IdeBar-2qoqi2ya9zdn3.css → IdeBar-10xodudcx57qr.css} +1 -1
  34. package/.mochi/svelte-css/{SettingsView-3uycxa8z548m4.css → SettingsView-2qfauz68axro1.css} +1 -1
  35. package/.mochi/svelte-css/TerminalPane-3bwgk6ulzq6b3.css +1 -0
  36. package/.mochi/svelte-css/TerminalSplit-2416xfuln89a3.css +1 -0
  37. package/migrations/0005_instance_mode.sql +1 -0
  38. package/migrations/0006_terminal_split.sql +1 -0
  39. package/package.json +3 -1
  40. package/src/avatars/serialize.ts +35 -6
  41. package/src/components/AppShell.svelte +46 -8
  42. package/src/components/Avatar.svelte +3 -2
  43. package/src/components/AvatarEditor.svelte +96 -19
  44. package/src/components/AvatarsView.svelte +0 -0
  45. package/src/components/DashboardView.svelte +22 -7
  46. package/src/components/FolderBrowser.svelte +88 -8
  47. package/src/components/HealthBox.svelte +12 -5
  48. package/src/components/IdeBar.svelte +10 -0
  49. package/src/components/InstanceCard.svelte +3 -1
  50. package/src/components/InstanceView.svelte +1 -0
  51. package/src/components/SettingsView.svelte +108 -0
  52. package/src/components/TerminalPane.svelte +274 -0
  53. package/src/components/TerminalSplit.svelte +154 -0
  54. package/src/container-injections/claude-code-ide-extension.ts +2 -0
  55. package/src/container-injections/ttyd.ts +49 -0
  56. package/src/lib/config.server.ts +3 -0
  57. package/src/lib/db.server.ts +14 -4
  58. package/src/lib/devcontainer.server.ts +136 -22
  59. package/src/lib/health.server.ts +1 -1
  60. package/src/lib/injections.server.ts +15 -5
  61. package/src/lib/instances.server.ts +64 -10
  62. package/src/lib/proxy.server.ts +87 -11
  63. package/src/pages/App.svelte +5 -3
  64. package/src/pages/Settings.svelte +4 -0
  65. package/src/routes.ts +55 -6
  66. package/src/types.ts +18 -0
  67. package/.mochi/svelte-client/HydratableIsland-qyjx1d98.js +0 -1
  68. package/.mochi/svelte-client/_hydrate-AppShell_2rtnxn6pgp2rh-fkna7bj2.js +0 -2
  69. package/.mochi/svelte-client/_hydrate-AvatarsView_257s9yq1wwr4f-89wtkb86.js +0 -13
  70. package/.mochi/svelte-client/_hydrate-InstanceView_2ma45l9bybfhl-eamnbyqk.js +0 -1
  71. package/.mochi/svelte-client/_hydrate-SettingsView_8hmarwmf8onq-kdra4mcb.js +0 -28
  72. package/.mochi/svelte-client/chunk-330mrspw.js +0 -2
  73. package/.mochi/svelte-client/chunk-4jgkak13.js +0 -1
  74. package/.mochi/svelte-client/chunk-k5m4kt20.js +0 -2
  75. package/.mochi/svelte-client/chunk-rpdphch7.js +0 -2
  76. package/.mochi/svelte-compile/chunk-bacb4b0r.js +0 -14
  77. package/.mochi/svelte-css/AvatarEditor-2ewwtejaml4e2.css +0 -1
  78. package/.mochi/svelte-css/FolderBrowser-1x428zb3f2kti.css +0 -1
  79. /package/.mochi/svelte-compile/{chunk-btmcxhqy.js → chunk-brjv9pyd.js} +0 -0
@@ -6,36 +6,38 @@ import {
6
6
  apiPost,
7
7
  forwardedPortUrl,
8
8
  ideUrl
9
- } from "./chunk-btmcxhqy.js";
9
+ } from "./chunk-brjv9pyd.js";
10
10
  import {
11
- Plus
12
- } from "./chunk-6ghzacpg.js";
13
- import {
14
- X
15
- } from "./chunk-bacb4b0r.js";
11
+ Layout_template,
12
+ Plus,
13
+ Terminal
14
+ } from "./chunk-bpqwf1nw.js";
16
15
  import {
17
16
  AppBar,
18
17
  Avatar,
19
18
  Button,
20
19
  Toaster,
21
20
  dist_default
22
- } from "./chunk-q8rbesaw.js";
21
+ } from "./chunk-m8ygpyhr.js";
23
22
  import {
24
23
  HydratableBoundary,
25
24
  Icon,
25
+ X,
26
26
  emitIslandProps,
27
27
  isDev,
28
28
  withPopupMarker
29
- } from "./chunk-fpe16ywq.js";
30
- import"./chunk-we0ggtws.js";
29
+ } from "./chunk-60mpagr9.js";
30
+ import {
31
+ __require
32
+ } from "./chunk-xpt1a7jm.js";
31
33
 
32
34
  // src/pages/App.svelte
33
35
  import"svelte/internal/flags/async";
34
- import * as $24 from "svelte/internal/server";
36
+ import * as $29 from "svelte/internal/server";
35
37
 
36
38
  // src/components/AppShell.svelte
37
39
  import"svelte/internal/flags/async";
38
- import * as $23 from "svelte/internal/server";
40
+ import * as $28 from "svelte/internal/server";
39
41
  import { SvelteSet } from "svelte/reactivity";
40
42
 
41
43
  // src/components/DashboardView.svelte
@@ -165,7 +167,9 @@ function Triangle_alert($$renderer, $$props) {
165
167
  // src/components/FolderBrowser.svelte
166
168
  function FolderBrowser($$renderer, $$props) {
167
169
  $$renderer.component(($$renderer2) => {
168
- let { onpick, onclose } = $$props;
170
+ let { onpick, onclose, defaultMode = "ide" } = $$props;
171
+ let modeOverride = null;
172
+ const mode = $6.derived(() => modeOverride ?? defaultMode);
169
173
  let result = null;
170
174
  let loading = true;
171
175
  let errorMsg = null;
@@ -179,7 +183,7 @@ function FolderBrowser($$renderer, $$props) {
179
183
  function cloneRepoUrl() {
180
184
  if (!repoValid())
181
185
  return;
182
- onpick(repoUrl.trim(), { branch: repoBranch.trim() || undefined });
186
+ onpick(repoUrl.trim(), { branch: repoBranch.trim() || undefined, mode: mode() });
183
187
  }
184
188
  const filtered = $6.derived(() => result ? result.entries.filter((e) => e.name.toLowerCase().includes(query.trim().toLowerCase())) : []);
185
189
  const shownHistory = $6.derived(() => showAll ? history2 : history2.slice(0, 5));
@@ -215,7 +219,11 @@ function FolderBrowser($$renderer, $$props) {
215
219
  }
216
220
  $$renderer2.push(`<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">`);
217
221
  X($$renderer2, { size: 16 });
218
- $$renderer2.push(`<!----></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"${$6.attr("value", repoUrl)} spellcheck="false" autocomplete="off"/> <input class="clone-branch svelte-oq97c4" type="text" placeholder="branch (optional)"${$6.attr("value", repoBranch)} spellcheck="false" autocomplete="off"/> <button class="clone-btn svelte-oq97c4"${$6.attr("disabled", !repoValid(), true)}>Clone</button></div></div> <div class="crumbs svelte-oq97c4"><code class="svelte-oq97c4">${$6.escape(result?.path ?? "\u2026")}</code></div> `);
222
+ $$renderer2.push(`<!----></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"${$6.attr_class("mode-btn svelte-oq97c4", undefined, { active: mode() === "ide" })}${$6.attr("aria-pressed", mode() === "ide")}>`);
223
+ Layout_template($$renderer2, { size: 15 });
224
+ $$renderer2.push(`<!----> Full IDE</button> <button type="button"${$6.attr_class("mode-btn svelte-oq97c4", undefined, { active: mode() === "terminal" })}${$6.attr("aria-pressed", mode() === "terminal")}>`);
225
+ Terminal($$renderer2, { size: 15 });
226
+ $$renderer2.push(`<!----> 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"${$6.attr("value", repoUrl)} spellcheck="false" autocomplete="off"/> <input class="clone-branch svelte-oq97c4" type="text" placeholder="branch (optional)"${$6.attr("value", repoBranch)} spellcheck="false" autocomplete="off"/> <button class="clone-btn svelte-oq97c4"${$6.attr("disabled", !repoValid(), true)}>Clone</button></div></div> <div class="crumbs svelte-oq97c4"><code class="svelte-oq97c4">${$6.escape(result?.path ?? "\u2026")}</code></div> `);
219
227
  if (history2.length > 0) {
220
228
  $$renderer2.push("<!--[0-->");
221
229
  $$renderer2.push(`<div class="recent svelte-oq97c4"><div class="recent-label svelte-oq97c4">Recent</div> <!--[-->`);
@@ -449,7 +457,7 @@ function InstanceCard($$renderer, $$props) {
449
457
  size: "sm",
450
458
  href: `/ide/${instance.id}`,
451
459
  children: ($$renderer3) => {
452
- $$renderer3.push(`<!---->Open IDE`);
460
+ $$renderer3.push(`<!---->${$10.escape(instance.mode === "terminal" ? "Open terminal" : "Open IDE")}`);
453
461
  },
454
462
  $$slots: { default: true }
455
463
  });
@@ -793,9 +801,8 @@ function TopBar($$renderer, $$props) {
793
801
  // src/components/DashboardView.svelte
794
802
  function DashboardView($$renderer, $$props) {
795
803
  $$renderer.component(($$renderer2) => {
796
- let { preflight, instances, loaded, pet } = $$props;
804
+ let { preflight, instances, loaded, pet, filter, onFilter } = $$props;
797
805
  let browserOpen = false;
798
- let filter = "all";
799
806
  let creating = false;
800
807
  let actionError = null;
801
808
  let editingId = null;
@@ -818,7 +825,7 @@ function DashboardView($$renderer, $$props) {
818
825
  creating = true;
819
826
  actionError = null;
820
827
  try {
821
- await apiPost("/api/instances", { sourcePath, branch: opts?.branch }, "Failed to create instance");
828
+ await apiPost("/api/instances", { sourcePath, branch: opts?.branch, mode: opts?.mode }, "Failed to create instance");
822
829
  } catch (err) {
823
830
  actionError = err.message;
824
831
  } finally {
@@ -884,7 +891,7 @@ function DashboardView($$renderer, $$props) {
884
891
  ready: ready(),
885
892
  creating,
886
893
  filter,
887
- onFilter: (v) => filter = v,
894
+ onFilter,
888
895
  onNew: () => browserOpen = true,
889
896
  onDeleteAll: deleteAll
890
897
  });
@@ -965,7 +972,11 @@ function DashboardView($$renderer, $$props) {
965
972
  $$renderer3.push(`<!--]--></main> `);
966
973
  if (browserOpen) {
967
974
  $$renderer3.push("<!--[0-->");
968
- FolderBrowser($$renderer3, { onpick: createFrom, onclose: () => browserOpen = false });
975
+ FolderBrowser($$renderer3, {
976
+ onpick: createFrom,
977
+ defaultMode: preflight.defaultMode,
978
+ onclose: () => browserOpen = false
979
+ });
969
980
  } else {
970
981
  $$renderer3.push("<!--[-1-->");
971
982
  }
@@ -1018,7 +1029,16 @@ function IdeBar($$renderer, $$props) {
1018
1029
  $$renderer3.push("<!--[-1-->");
1019
1030
  $$renderer3.push(`<button type="button" class="tab-label svelte-r39acv"${$21.attr("title", inst.name)}>`);
1020
1031
  Avatar($$renderer3, { id: inst.id, name: inst.name, scale: 4 });
1021
- $$renderer3.push(`<!----> <span class="tab-name svelte-r39acv">${$21.escape(inst.name)}</span></button>`);
1032
+ $$renderer3.push(`<!----> <span class="tab-name svelte-r39acv">${$21.escape(inst.name)}</span> `);
1033
+ if (inst.mode === "terminal") {
1034
+ $$renderer3.push("<!--[0-->");
1035
+ $$renderer3.push(`<span class="tab-mode svelte-r39acv" title="Terminal-only instance">`);
1036
+ Terminal($$renderer3, { size: 13 });
1037
+ $$renderer3.push(`<!----></span>`);
1038
+ } else {
1039
+ $$renderer3.push("<!--[-1-->");
1040
+ }
1041
+ $$renderer3.push(`<!--]--></button>`);
1022
1042
  }
1023
1043
  $$renderer3.push(`<!--]--></div>`);
1024
1044
  }
@@ -1081,15 +1101,304 @@ function IdeLoader($$renderer, $$props) {
1081
1101
  });
1082
1102
  }
1083
1103
 
1104
+ // src/components/TerminalSplit.svelte
1105
+ import"svelte/internal/flags/async";
1106
+ import * as $27 from "svelte/internal/server";
1107
+
1108
+ // node_modules/@lucide/svelte/dist/icons/panel-right-open.svelte
1109
+ import"svelte/internal/flags/async";
1110
+ import * as $23 from "svelte/internal/server";
1111
+ function Panel_right_open($$renderer, $$props) {
1112
+ let { $$slots, $$events, ...props } = $$props;
1113
+ const iconNode = [
1114
+ [
1115
+ "rect",
1116
+ { width: "18", height: "18", x: "3", y: "3", rx: "2" }
1117
+ ],
1118
+ ["path", { d: "M15 3v18" }],
1119
+ ["path", { d: "m10 15-3-3 3-3" }]
1120
+ ];
1121
+ Icon($$renderer, $23.spread_props([{ name: "panel-right-open" }, props, { iconNode }]));
1122
+ }
1123
+ // node_modules/@lucide/svelte/dist/icons/panel-right-close.svelte
1124
+ import"svelte/internal/flags/async";
1125
+ import * as $24 from "svelte/internal/server";
1126
+ function Panel_right_close($$renderer, $$props) {
1127
+ let { $$slots, $$events, ...props } = $$props;
1128
+ const iconNode = [
1129
+ [
1130
+ "rect",
1131
+ { width: "18", height: "18", x: "3", y: "3", rx: "2" }
1132
+ ],
1133
+ ["path", { d: "M15 3v18" }],
1134
+ ["path", { d: "m8 9 3 3-3 3" }]
1135
+ ];
1136
+ Icon($$renderer, $24.spread_props([{ name: "panel-right-close" }, props, { iconNode }]));
1137
+ }
1138
+ // src/components/TerminalPane.svelte
1139
+ import"svelte/internal/flags/async";
1140
+ import * as $26 from "svelte/internal/server";
1141
+ import { onMount } from "svelte";
1142
+ // node_modules/@lucide/svelte/dist/icons/rotate-cw.svelte
1143
+ import"svelte/internal/flags/async";
1144
+ import * as $25 from "svelte/internal/server";
1145
+ function Rotate_cw($$renderer, $$props) {
1146
+ let { $$slots, $$events, ...props } = $$props;
1147
+ const iconNode = [
1148
+ [
1149
+ "path",
1150
+ { d: "M21 12a9 9 0 1 1-9-9c2.52 0 4.93 1 6.74 2.74L21 8" }
1151
+ ],
1152
+ ["path", { d: "M21 3v5h-5" }]
1153
+ ];
1154
+ Icon($$renderer, $25.spread_props([{ name: "rotate-cw" }, props, { iconNode }]));
1155
+ }
1156
+ // src/components/TerminalPane.svelte
1157
+ function TerminalPane($$renderer, $$props) {
1158
+ $$renderer.component(($$renderer2) => {
1159
+ let { id, active, arg, focus = true, actions } = $$props;
1160
+ let el;
1161
+ let term;
1162
+ let fit;
1163
+ let ws;
1164
+ let retry;
1165
+ let disposed = false;
1166
+ let connected = false;
1167
+ let gen = 0;
1168
+ const CMD_INPUT = "0";
1169
+ const CMD_RESIZE = "1";
1170
+ const OUTPUT = 48;
1171
+ const encoder = new TextEncoder;
1172
+ function send(data) {
1173
+ if (ws?.readyState === WebSocket.OPEN)
1174
+ ws.send(encoder.encode(data));
1175
+ }
1176
+ function onFrame(data) {
1177
+ const bytes = new Uint8Array(data);
1178
+ if (bytes.length === 0)
1179
+ return;
1180
+ if (bytes[0] === OUTPUT)
1181
+ term?.write(bytes.subarray(1));
1182
+ }
1183
+ function connect() {
1184
+ const myGen = ++gen;
1185
+ const proto = location.protocol === "https:" ? "wss:" : "ws:";
1186
+ const query = arg ? `?arg=${encodeURIComponent(arg)}` : "";
1187
+ const sock = new WebSocket(`${proto}//${location.host}/p/${id}/ws${query}`, ["tty"]);
1188
+ ws = sock;
1189
+ sock.binaryType = "arraybuffer";
1190
+ sock.onopen = () => {
1191
+ if (gen !== myGen)
1192
+ return;
1193
+ connected = true;
1194
+ send(JSON.stringify({
1195
+ AuthToken: "",
1196
+ columns: term?.cols ?? 80,
1197
+ rows: term?.rows ?? 24
1198
+ }));
1199
+ };
1200
+ sock.onmessage = (e) => {
1201
+ if (gen === myGen)
1202
+ onFrame(e.data);
1203
+ };
1204
+ sock.onclose = () => {
1205
+ if (gen !== myGen || disposed)
1206
+ return;
1207
+ connected = false;
1208
+ retry = setTimeout(connect, 1000);
1209
+ };
1210
+ sock.onerror = () => {
1211
+ try {
1212
+ sock.close();
1213
+ } catch {}
1214
+ };
1215
+ }
1216
+ function reload() {
1217
+ if (retry)
1218
+ clearTimeout(retry);
1219
+ gen++;
1220
+ connected = false;
1221
+ term?.reset();
1222
+ const old = ws;
1223
+ ws = undefined;
1224
+ let started = false;
1225
+ const start = () => {
1226
+ if (started || disposed)
1227
+ return;
1228
+ started = true;
1229
+ fitSafe();
1230
+ connect();
1231
+ if (active && focus)
1232
+ term?.focus();
1233
+ };
1234
+ if (old && old.readyState !== WebSocket.CLOSED) {
1235
+ old.addEventListener("close", start, { once: true });
1236
+ setTimeout(start, 1500);
1237
+ try {
1238
+ old.close();
1239
+ } catch {}
1240
+ } else {
1241
+ start();
1242
+ }
1243
+ }
1244
+ function fitSafe() {
1245
+ if (el?.clientWidth > 0 && el?.clientHeight > 0) {
1246
+ try {
1247
+ fit?.fit();
1248
+ } catch {}
1249
+ }
1250
+ }
1251
+ function applyTheme() {
1252
+ if (!term)
1253
+ return;
1254
+ const cs = getComputedStyle(document.documentElement);
1255
+ const bg = cs.getPropertyValue("--bg").trim() || "#1a1a1a";
1256
+ const fg = cs.getPropertyValue("--ink").trim() || "#e6e6e6";
1257
+ term.options.theme = { background: bg, foreground: fg, cursor: fg, cursorAccent: bg };
1258
+ }
1259
+ onMount(() => {
1260
+ let themeObs;
1261
+ (async () => {
1262
+ const [{ Terminal: Terminal2 }, { FitAddon }] = await Promise.all([import("./chunk-9nqc2r0y.js"), import("./chunk-rtdne1m8.js")]);
1263
+ if (disposed)
1264
+ return;
1265
+ term = new Terminal2({
1266
+ fontFamily: "'JetBrains Mono Variable', ui-monospace, monospace",
1267
+ fontSize: 13,
1268
+ cursorBlink: true,
1269
+ scrollback: 1e4,
1270
+ allowProposedApi: true
1271
+ });
1272
+ fit = new FitAddon;
1273
+ term.loadAddon(fit);
1274
+ term.open(el);
1275
+ applyTheme();
1276
+ fitSafe();
1277
+ term.onData((d) => send(CMD_INPUT + d));
1278
+ term.onResize(({ cols, rows }) => send(CMD_RESIZE + JSON.stringify({ columns: cols, rows })));
1279
+ themeObs = new MutationObserver(applyTheme);
1280
+ themeObs.observe(document.documentElement, { attributes: true, attributeFilter: ["data-theme"] });
1281
+ connect();
1282
+ if (active && focus)
1283
+ term.focus();
1284
+ })();
1285
+ const sizeObs = new ResizeObserver(() => fitSafe());
1286
+ sizeObs.observe(el);
1287
+ return () => {
1288
+ disposed = true;
1289
+ sizeObs.disconnect();
1290
+ themeObs?.disconnect();
1291
+ if (retry)
1292
+ clearTimeout(retry);
1293
+ try {
1294
+ ws?.close();
1295
+ } catch {}
1296
+ term?.dispose();
1297
+ };
1298
+ });
1299
+ $$renderer2.push(`<div class="term svelte-ui3nvu"></div> <div class="overlay svelte-ui3nvu">`);
1300
+ if (!connected) {
1301
+ $$renderer2.push("<!--[0-->");
1302
+ $$renderer2.push(`<span class="status svelte-ui3nvu">connecting\u2026</span>`);
1303
+ } else {
1304
+ $$renderer2.push("<!--[-1-->");
1305
+ }
1306
+ $$renderer2.push(`<!--]--> `);
1307
+ actions?.($$renderer2);
1308
+ $$renderer2.push(`<!----> <button type="button" title="Reload terminal (reconnects, keeps the session)" aria-label="Reload terminal">`);
1309
+ Rotate_cw($$renderer2, { size: 14 });
1310
+ $$renderer2.push(`<!----></button></div>`);
1311
+ });
1312
+ }
1313
+
1314
+ // src/components/TerminalSplit.svelte
1315
+ function TerminalSplit($$renderer, $$props) {
1316
+ $$renderer.component(($$renderer2) => {
1317
+ let { id, active, initialOpen = false } = $$props;
1318
+ let open = initialOpen;
1319
+ let mounted = initialOpen;
1320
+ let ratio = 50;
1321
+ let focusSide = "left";
1322
+ let container;
1323
+ function toggle() {
1324
+ open = !open;
1325
+ if (open)
1326
+ mounted = true;
1327
+ focusSide = open ? "right" : "left";
1328
+ apiPost(`/api/instances/${id}/split`, { open }).catch(() => {});
1329
+ }
1330
+ function clamp(pct) {
1331
+ return Math.min(80, Math.max(20, pct));
1332
+ }
1333
+ function dragTo(clientX) {
1334
+ const rect = container.getBoundingClientRect();
1335
+ if (rect.width > 0)
1336
+ ratio = clamp((clientX - rect.left) / rect.width * 100);
1337
+ }
1338
+ function onDividerDown(e) {
1339
+ e.preventDefault();
1340
+ e.currentTarget.setPointerCapture(e.pointerId);
1341
+ }
1342
+ function onDividerMove(e) {
1343
+ if (e.currentTarget.hasPointerCapture(e.pointerId))
1344
+ dragTo(e.clientX);
1345
+ }
1346
+ function onDividerKey(e) {
1347
+ if (e.key === "ArrowLeft")
1348
+ ratio = clamp(ratio - 5);
1349
+ else if (e.key === "ArrowRight")
1350
+ ratio = clamp(ratio + 5);
1351
+ else
1352
+ return;
1353
+ e.preventDefault();
1354
+ }
1355
+ function splitToggle($$renderer3) {
1356
+ $$renderer3.push(`<button type="button"${$27.attr("aria-pressed", open)}${$27.attr("title", open ? "Hide the shell pane" : "Open a shell alongside Claude")}${$27.attr("aria-label", open ? "Hide the shell pane" : "Open a shell alongside Claude")}>`);
1357
+ if (open) {
1358
+ $$renderer3.push("<!--[0-->");
1359
+ Panel_right_close($$renderer3, { size: 14 });
1360
+ } else {
1361
+ $$renderer3.push("<!--[-1-->");
1362
+ Panel_right_open($$renderer3, { size: 14 });
1363
+ }
1364
+ $$renderer3.push(`<!--]--></button>`);
1365
+ }
1366
+ $$renderer2.push(`<div class="split svelte-1ysvu88"><div class="side svelte-1ysvu88"${$27.attr_style("", { "flex-basis": open ? `${ratio}%` : "100%" })}>`);
1367
+ TerminalPane($$renderer2, {
1368
+ id,
1369
+ active,
1370
+ focus: active && focusSide === "left",
1371
+ actions: open ? undefined : splitToggle
1372
+ });
1373
+ $$renderer2.push(`<!----></div> `);
1374
+ if (mounted) {
1375
+ $$renderer2.push("<!--[0-->");
1376
+ $$renderer2.push(`<div${$27.attr_class("divider svelte-1ysvu88", undefined, { hidden: !open })} role="separator" aria-orientation="vertical" aria-label="Resize terminal panes"${$27.attr("aria-valuenow", Math.round(ratio))}${$27.attr("aria-valuemin", 20)}${$27.attr("aria-valuemax", 80)} tabindex="0"></div> <div${$27.attr_class("side svelte-1ysvu88", undefined, { hidden: !open })}${$27.attr_style("", { "flex-basis": `${$27.stringify(100 - ratio)}%` })}>`);
1377
+ TerminalPane($$renderer2, {
1378
+ id,
1379
+ arg: "shell",
1380
+ active: active && open,
1381
+ focus: active && open && focusSide === "right",
1382
+ actions: open ? splitToggle : undefined
1383
+ });
1384
+ $$renderer2.push(`<!----></div>`);
1385
+ } else {
1386
+ $$renderer2.push("<!--[-1-->");
1387
+ }
1388
+ $$renderer2.push(`<!--]--></div>`);
1389
+ });
1390
+ }
1391
+
1084
1392
  // src/components/AppShell.svelte
1085
1393
  function AppShell($$renderer, $$props) {
1086
1394
  $$renderer.component(($$renderer2) => {
1087
- let { preflight, initialPath, snapshot, pet } = $$props;
1395
+ let { preflight, initialPath, snapshot, pet, filter } = $$props;
1088
1396
  let instances = snapshot;
1089
1397
  let livePreflight = preflight;
1090
1398
  let livePet = pet;
1399
+ let liveFilter = filter;
1091
1400
  let loaded = snapshot.length > 0;
1092
- const running = $23.derived(() => instances.filter((i) => i.status === "running"));
1401
+ const running = $28.derived(() => instances.filter((i) => i.status === "running"));
1093
1402
  let attention = Object.fromEntries(snapshot.map((i) => [i.id, i.attention]));
1094
1403
  let editingId = null;
1095
1404
  let editingName = "";
@@ -1115,10 +1424,14 @@ function AppShell($$renderer, $$props) {
1115
1424
  dist_default.error(err.message);
1116
1425
  }
1117
1426
  }
1427
+ function setFilter(v) {
1428
+ liveFilter = v;
1429
+ apiPost("/api/settings/filter", { value: v }).catch(() => {});
1430
+ }
1118
1431
  let path = initialPath;
1119
- const onIde = $23.derived(() => path.startsWith("/ide"));
1120
- const requestedId = $23.derived(() => path.startsWith("/ide/") ? path.slice("/ide/".length) : "");
1121
- const active = $23.derived(() => onIde() ? running().some((i) => i.id === requestedId()) ? requestedId() : running()[0]?.id ?? "" : "");
1432
+ const onIde = $28.derived(() => path.startsWith("/ide"));
1433
+ const requestedId = $28.derived(() => path.startsWith("/ide/") ? path.slice("/ide/".length) : "");
1434
+ const active = $28.derived(() => onIde() ? running().some((i) => i.id === requestedId()) ? requestedId() : running()[0]?.id ?? "" : "");
1122
1435
  function navigate(to) {
1123
1436
  if (to === path)
1124
1437
  return;
@@ -1134,7 +1447,7 @@ function AppShell($$renderer, $$props) {
1134
1447
  let $$settled = true;
1135
1448
  let $$inner_renderer;
1136
1449
  function $$render_inner($$renderer3) {
1137
- $$renderer3.push(`<div${$23.attr_class("app svelte-1duc7gd", undefined, { ide: onIde() })}>`);
1450
+ $$renderer3.push(`<div${$28.attr_class("app svelte-1duc7gd", undefined, { ide: onIde() })}>`);
1138
1451
  if (onIde()) {
1139
1452
  $$renderer3.push("<!--[0-->");
1140
1453
  IdeBar($$renderer3, {
@@ -1156,18 +1469,36 @@ function AppShell($$renderer, $$props) {
1156
1469
  });
1157
1470
  } else {
1158
1471
  $$renderer3.push("<!--[-1-->");
1159
- DashboardView($$renderer3, { preflight: livePreflight, instances, loaded, pet: livePet });
1472
+ DashboardView($$renderer3, {
1473
+ preflight: livePreflight,
1474
+ instances,
1475
+ loaded,
1476
+ pet: livePet,
1477
+ filter: liveFilter,
1478
+ onFilter: setFilter
1479
+ });
1160
1480
  }
1161
- $$renderer3.push(`<!--]--> <div${$23.attr_class("panes svelte-1duc7gd", undefined, { hidden: !onIde() })}><!--[-->`);
1162
- const each_array = $23.ensure_array_like(running());
1481
+ $$renderer3.push(`<!--]--> <div${$28.attr_class("panes svelte-1duc7gd", undefined, { hidden: !onIde() })}><!--[-->`);
1482
+ const each_array = $28.ensure_array_like(running());
1163
1483
  for (let $$index = 0, $$length = each_array.length;$$index < $$length; $$index++) {
1164
1484
  let inst = each_array[$$index];
1165
1485
  if (visited.has(inst.id)) {
1166
1486
  $$renderer3.push("<!--[0-->");
1167
- $$renderer3.push(`<div${$23.attr_class("pane svelte-1duc7gd", undefined, { active: inst.id === active() })}>`);
1487
+ $$renderer3.push(`<div${$28.attr_class("pane svelte-1duc7gd", undefined, { active: inst.id === active() })}>`);
1168
1488
  if (mountable(inst.id)) {
1169
1489
  $$renderer3.push("<!--[0-->");
1170
- $$renderer3.push(`<iframe${$23.attr("src", ideUrl(inst))}${$23.attr("title", inst.name)} class="svelte-1duc7gd" onload="this.__e=event"></iframe>`);
1490
+ if (inst.mode === "terminal") {
1491
+ $$renderer3.push("<!--[0-->");
1492
+ TerminalSplit($$renderer3, {
1493
+ id: inst.id,
1494
+ active: inst.id === active(),
1495
+ initialOpen: inst.terminal_split === 1
1496
+ });
1497
+ } else {
1498
+ $$renderer3.push("<!--[-1-->");
1499
+ $$renderer3.push(`<iframe${$28.attr("src", ideUrl(inst))}${$28.attr("title", inst.name)} class="svelte-1duc7gd" onload="this.__e=event"></iframe>`);
1500
+ }
1501
+ $$renderer3.push(`<!--]-->`);
1171
1502
  } else {
1172
1503
  $$renderer3.push("<!--[-1-->");
1173
1504
  }
@@ -1178,7 +1509,7 @@ function AppShell($$renderer, $$props) {
1178
1509
  stalledAfterMs: STALLED_AFTER_MS,
1179
1510
  onoverride: () => forced.add(inst.id)
1180
1511
  });
1181
- } else if (!loadedFrames.has(inst.id)) {
1512
+ } else if (inst.mode !== "terminal" && !loadedFrames.has(inst.id)) {
1182
1513
  $$renderer3.push("<!--[1-->");
1183
1514
  IdeLoader($$renderer3, {});
1184
1515
  } else {
@@ -1217,10 +1548,10 @@ function AppShell($$renderer, $$props) {
1217
1548
  // src/pages/App.svelte
1218
1549
  function App($$renderer, $$props) {
1219
1550
  $$renderer.component(($$renderer2) => {
1220
- let { preflight, initialPath, snapshot, pet } = $$props;
1551
+ let { preflight, initialPath, snapshot, pet, filter } = $$props;
1221
1552
  if (true) {
1222
1553
  let failed = function($$renderer3, error) {
1223
- $$renderer3.push(`<mochi-island-failure data-component="AppShell"${$24.attr("data-message", error.message)}></mochi-island-failure>`);
1554
+ $$renderer3.push(`<mochi-island-failure data-component="AppShell"${$29.attr("data-message", error.message)}></mochi-island-failure>`);
1224
1555
  };
1225
1556
  $$renderer2.push("<!--[0-->");
1226
1557
  $$renderer2.boundary({ failed }, ($$renderer3) => {
@@ -1228,10 +1559,10 @@ function App($$renderer, $$props) {
1228
1559
  {
1229
1560
  HydratableBoundary($$renderer3, {
1230
1561
  children: ($$renderer4) => {
1231
- $$renderer4.push(`<mochi-hydratable-island component-name="AppShell_2rtnxn6pgp2rh" component-url="__MOCHI_COMPONENT_URL__AppShell_2rtnxn6pgp2rh__"${$24.attr("props-ref", emitIslandProps({ preflight, initialPath, snapshot, pet }))}>`);
1562
+ $$renderer4.push(`<mochi-hydratable-island component-name="AppShell_2rtnxn6pgp2rh" component-url="__MOCHI_COMPONENT_URL__AppShell_2rtnxn6pgp2rh__"${$29.attr("props-ref", emitIslandProps({ preflight, initialPath, snapshot, pet, filter }))}>`);
1232
1563
  $$renderer4.push(`<!--[-->`);
1233
1564
  {
1234
- AppShell($$renderer4, { preflight, initialPath, snapshot, pet });
1565
+ AppShell($$renderer4, { preflight, initialPath, snapshot, pet, filter });
1235
1566
  }
1236
1567
  $$renderer4.push(`<!--]-->`);
1237
1568
  $$renderer4.push(`</mochi-hydratable-island>`);