@phenx-inc/ctlsurf 0.1.21 → 0.2.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 (31) hide show
  1. package/out/headless/index.mjs +91 -57
  2. package/out/headless/index.mjs.map +2 -2
  3. package/out/main/index.js +145 -63
  4. package/out/preload/index.js +9 -8
  5. package/out/renderer/assets/{cssMode-C6bY9C4O.js → cssMode-D3kH1Kju.js} +3 -3
  6. package/out/renderer/assets/{freemarker2-CkAJiX1K.js → freemarker2-BCHZUSLb.js} +1 -1
  7. package/out/renderer/assets/{handlebars-DnLXVUXp.js → handlebars-DKx-Fw-H.js} +1 -1
  8. package/out/renderer/assets/{html-Ds5-qvDh.js → html-BSCM04uL.js} +1 -1
  9. package/out/renderer/assets/{htmlMode-DYFYy4MK.js → htmlMode-BucU1MUc.js} +3 -3
  10. package/out/renderer/assets/{index-DwSsD_Xm.js → index-BsdOeO0U.js} +230 -101
  11. package/out/renderer/assets/{index-DK9wLFFm.css → index-BzF7I1my.css} +111 -0
  12. package/out/renderer/assets/{javascript-CiHhG2a9.js → javascript-bPY5C4uq.js} +2 -2
  13. package/out/renderer/assets/{jsonMode-DdDRlbXP.js → jsonMode-BmJotb6E.js} +3 -3
  14. package/out/renderer/assets/{liquid-BP5mb-uD.js → liquid-Cja_Pzh3.js} +1 -1
  15. package/out/renderer/assets/{lspLanguageFeatures-Dljhj5Gh.js → lspLanguageFeatures-hoVZfVKv.js} +1 -1
  16. package/out/renderer/assets/{mdx-D4u3N7dt.js → mdx-C0s81MOq.js} +1 -1
  17. package/out/renderer/assets/{python-BQDHXVwp.js → python-CulkBOJr.js} +1 -1
  18. package/out/renderer/assets/{razor-BfXW9cDc.js → razor-czmzhwVZ.js} +1 -1
  19. package/out/renderer/assets/{tsMode-BGTjG8Ow.js → tsMode-B90EqYGx.js} +1 -1
  20. package/out/renderer/assets/{typescript-422MU_YO.js → typescript-Ckc6emP2.js} +1 -1
  21. package/out/renderer/assets/{xml-B6EKhHiy.js → xml-CKh-JyGN.js} +1 -1
  22. package/out/renderer/assets/{yaml-LkO_eGYb.js → yaml-B49zLim4.js} +1 -1
  23. package/out/renderer/index.html +2 -2
  24. package/package.json +1 -1
  25. package/src/main/headless.ts +8 -7
  26. package/src/main/index.ts +87 -13
  27. package/src/main/orchestrator.ts +98 -54
  28. package/src/preload/index.ts +16 -14
  29. package/src/renderer/App.tsx +161 -43
  30. package/src/renderer/components/TerminalPanel.tsx +101 -59
  31. package/src/renderer/styles.css +111 -0
@@ -1,4 +1,4 @@
1
- const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["./cssMode-C6bY9C4O.js","./lspLanguageFeatures-Dljhj5Gh.js","./htmlMode-DYFYy4MK.js","./jsonMode-DdDRlbXP.js","./javascript-CiHhG2a9.js","./typescript-422MU_YO.js"])))=>i.map(i=>d[i]);
1
+ const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["./cssMode-D3kH1Kju.js","./lspLanguageFeatures-hoVZfVKv.js","./htmlMode-BucU1MUc.js","./jsonMode-BmJotb6E.js","./javascript-bPY5C4uq.js","./typescript-Ckc6emP2.js"])))=>i.map(i=>d[i]);
2
2
  function getDefaultExportFromCjs(x) {
3
3
  return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, "default") ? x["default"] : x;
4
4
  }
@@ -18721,22 +18721,21 @@ function requireAddonWebLinks() {
18721
18721
  return addonWebLinks.exports;
18722
18722
  }
18723
18723
  var addonWebLinksExports = requireAddonWebLinks();
18724
- let _terminal = null;
18725
- let _fitAddon = null;
18726
- let _currentAgentId = null;
18727
- let _pinnedToBottom = true;
18724
+ const _terminals = /* @__PURE__ */ new Map();
18728
18725
  function isAtBottom(terminal) {
18729
18726
  const buf = terminal.buffer.active;
18730
18727
  return buf.viewportY >= buf.baseY;
18731
18728
  }
18732
- function scrollIfPinned(terminal) {
18733
- if (_pinnedToBottom) {
18729
+ function scrollIfPinned(tabId, terminal) {
18730
+ const state = _terminals.get(tabId);
18731
+ if (state?.pinnedToBottom) {
18734
18732
  terminal.scrollToBottom();
18735
18733
  }
18736
18734
  }
18737
- function getOrCreateTerminal(onExit) {
18738
- if (_terminal && _fitAddon) {
18739
- return { terminal: _terminal, fitAddon: _fitAddon };
18735
+ function getOrCreateTerminal(tabId, onExit) {
18736
+ const existing = _terminals.get(tabId);
18737
+ if (existing) {
18738
+ return { terminal: existing.terminal, fitAddon: existing.fitAddon };
18740
18739
  }
18741
18740
  const terminal = new xtermExports.Terminal({
18742
18741
  cursorBlink: true,
@@ -18771,32 +18770,51 @@ function getOrCreateTerminal(onExit) {
18771
18770
  const fitAddon = new addonFitExports.FitAddon();
18772
18771
  terminal.loadAddon(fitAddon);
18773
18772
  terminal.loadAddon(new addonWebLinksExports.WebLinksAddon());
18773
+ const state = {
18774
+ terminal,
18775
+ fitAddon,
18776
+ unsubData: null,
18777
+ unsubExit: null,
18778
+ spawnedAgentId: null,
18779
+ pinnedToBottom: true
18780
+ };
18774
18781
  terminal.onScroll(() => {
18775
- _pinnedToBottom = isAtBottom(terminal);
18782
+ state.pinnedToBottom = isAtBottom(terminal);
18776
18783
  });
18777
18784
  terminal.onData((data) => {
18778
- _pinnedToBottom = true;
18785
+ state.pinnedToBottom = true;
18779
18786
  terminal.scrollToBottom();
18780
- window.worker.writePty(data);
18787
+ window.worker.writePty(tabId, data);
18781
18788
  });
18782
- window.worker.onPtyData((data) => {
18783
- terminal.write(data);
18784
- scrollIfPinned(terminal);
18789
+ state.unsubData = window.worker.onPtyData((eventTabId, data) => {
18790
+ if (eventTabId === tabId) {
18791
+ terminal.write(data);
18792
+ scrollIfPinned(tabId, terminal);
18793
+ }
18785
18794
  });
18786
- window.worker.onPtyExit((code) => {
18787
- terminal.writeln(`\r
18795
+ state.unsubExit = window.worker.onPtyExit((eventTabId, code) => {
18796
+ if (eventTabId === tabId) {
18797
+ terminal.writeln(`\r
18788
18798
  \x1B[33m[Process exited with code ${code}]\x1B[0m`);
18789
- onExit();
18799
+ onExit(tabId);
18800
+ }
18790
18801
  });
18791
- _terminal = terminal;
18792
- _fitAddon = fitAddon;
18802
+ _terminals.set(tabId, state);
18793
18803
  return { terminal, fitAddon };
18794
18804
  }
18795
- function TerminalPanel({ agent, onSpawn, onExit }) {
18805
+ function destroyTerminal(tabId) {
18806
+ const state = _terminals.get(tabId);
18807
+ if (!state) return;
18808
+ state.unsubData?.();
18809
+ state.unsubExit?.();
18810
+ state.terminal.dispose();
18811
+ _terminals.delete(tabId);
18812
+ }
18813
+ function TerminalPanel({ tabId, agent, onSpawn, onExit, isActive }) {
18796
18814
  const containerRef = reactExports.useRef(null);
18797
18815
  reactExports.useEffect(() => {
18798
18816
  if (!containerRef.current) return;
18799
- const { terminal, fitAddon } = getOrCreateTerminal(onExit);
18817
+ const { terminal, fitAddon } = getOrCreateTerminal(tabId, onExit);
18800
18818
  const existingParent = terminal.element?.parentElement;
18801
18819
  if (existingParent && existingParent !== containerRef.current) {
18802
18820
  containerRef.current.appendChild(terminal.element);
@@ -18804,16 +18822,17 @@ function TerminalPanel({ agent, onSpawn, onExit }) {
18804
18822
  terminal.open(containerRef.current);
18805
18823
  }
18806
18824
  fitAddon.fit();
18807
- scrollIfPinned(terminal);
18825
+ scrollIfPinned(tabId, terminal);
18808
18826
  let resizeTimeout;
18809
18827
  const handleResize = () => {
18810
18828
  clearTimeout(resizeTimeout);
18811
18829
  resizeTimeout = setTimeout(() => {
18812
- if (_fitAddon && _terminal) {
18813
- _fitAddon.fit();
18814
- scrollIfPinned(_terminal);
18815
- const { cols, rows } = _terminal;
18816
- window.worker.resizePty(cols, rows);
18830
+ const state = _terminals.get(tabId);
18831
+ if (state) {
18832
+ state.fitAddon.fit();
18833
+ scrollIfPinned(tabId, state.terminal);
18834
+ const { cols, rows } = state.terminal;
18835
+ window.worker.resizePty(tabId, cols, rows);
18817
18836
  }
18818
18837
  }, 150);
18819
18838
  };
@@ -18825,23 +18844,36 @@ function TerminalPanel({ agent, onSpawn, onExit }) {
18825
18844
  window.removeEventListener("resize", handleResize);
18826
18845
  observer.disconnect();
18827
18846
  };
18828
- }, [onExit]);
18847
+ }, [tabId, onExit]);
18848
+ reactExports.useEffect(() => {
18849
+ if (!agent) return;
18850
+ const state = _terminals.get(tabId);
18851
+ if (!state) return;
18852
+ if (state.spawnedAgentId === agent.id) return;
18853
+ state.spawnedAgentId = agent.id;
18854
+ state.terminal.clear();
18855
+ onSpawn(tabId, agent).then(() => {
18856
+ const s = _terminals.get(tabId);
18857
+ if (s) {
18858
+ s.fitAddon.fit();
18859
+ s.pinnedToBottom = true;
18860
+ s.terminal.scrollToBottom();
18861
+ const { cols, rows } = s.terminal;
18862
+ window.worker.resizePty(tabId, cols, rows);
18863
+ }
18864
+ state.terminal.focus();
18865
+ });
18866
+ }, [tabId, agent, onSpawn]);
18829
18867
  reactExports.useEffect(() => {
18830
- if (!agent || !_terminal) return;
18831
- if (_currentAgentId === agent.id) return;
18832
- _currentAgentId = agent.id;
18833
- _terminal.clear();
18834
- onSpawn(agent).then(() => {
18835
- if (_fitAddon && _terminal) {
18836
- _fitAddon.fit();
18837
- _pinnedToBottom = true;
18838
- _terminal.scrollToBottom();
18839
- const { cols, rows } = _terminal;
18840
- window.worker.resizePty(cols, rows);
18841
- }
18842
- _terminal?.focus();
18843
- });
18844
- }, [agent, onSpawn]);
18868
+ if (isActive) {
18869
+ const state = _terminals.get(tabId);
18870
+ if (state) {
18871
+ state.fitAddon.fit();
18872
+ state.terminal.focus();
18873
+ }
18874
+ window.worker.setActiveTab(tabId);
18875
+ }
18876
+ }, [isActive, tabId]);
18845
18877
  return /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "terminal-container", ref: containerRef });
18846
18878
  }
18847
18879
  function CtlsurfPanel() {
@@ -206517,7 +206549,7 @@ const lessDefaults = new LanguageServiceDefaultsImpl$3(
206517
206549
  modeConfigurationDefault$2
206518
206550
  );
206519
206551
  function getMode$3() {
206520
- return __vitePreload(() => import("./cssMode-C6bY9C4O.js"), true ? __vite__mapDeps([0,1]) : void 0, import.meta.url);
206552
+ return __vitePreload(() => import("./cssMode-D3kH1Kju.js"), true ? __vite__mapDeps([0,1]) : void 0, import.meta.url);
206521
206553
  }
206522
206554
  languages.onLanguage("less", () => {
206523
206555
  getMode$3().then((mode2) => mode2.setupMode(lessDefaults));
@@ -206622,7 +206654,7 @@ const razorLanguageService = registerHTMLLanguageService(
206622
206654
  );
206623
206655
  const razorDefaults = razorLanguageService.defaults;
206624
206656
  function getMode$2() {
206625
- return __vitePreload(() => import("./htmlMode-DYFYy4MK.js"), true ? __vite__mapDeps([2,1]) : void 0, import.meta.url);
206657
+ return __vitePreload(() => import("./htmlMode-BucU1MUc.js"), true ? __vite__mapDeps([2,1]) : void 0, import.meta.url);
206626
206658
  }
206627
206659
  function registerHTMLLanguageService(languageId, options = optionsDefault, modeConfiguration = getConfigurationDefault(languageId)) {
206628
206660
  const defaults = new LanguageServiceDefaultsImpl$2(languageId, options, modeConfiguration);
@@ -206706,7 +206738,7 @@ const jsonDefaults = new LanguageServiceDefaultsImpl$1(
206706
206738
  );
206707
206739
  const getWorker$1 = () => getMode$1().then((mode2) => mode2.getWorker());
206708
206740
  function getMode$1() {
206709
- return __vitePreload(() => import("./jsonMode-DdDRlbXP.js"), true ? __vite__mapDeps([3,1]) : void 0, import.meta.url);
206741
+ return __vitePreload(() => import("./jsonMode-BmJotb6E.js"), true ? __vite__mapDeps([3,1]) : void 0, import.meta.url);
206710
206742
  }
206711
206743
  languages.register({
206712
206744
  id: "json",
@@ -206952,7 +206984,7 @@ const getJavaScriptWorker = () => {
206952
206984
  return getMode().then((mode) => mode.getJavaScriptWorker());
206953
206985
  };
206954
206986
  function getMode() {
206955
- return __vitePreload(() => import("./tsMode-BGTjG8Ow.js"), true ? [] : void 0, import.meta.url);
206987
+ return __vitePreload(() => import("./tsMode-B90EqYGx.js"), true ? [] : void 0, import.meta.url);
206956
206988
  }
206957
206989
  languages.onLanguage("typescript", () => {
206958
206990
  return getMode().then((mode) => mode.setupTypeScript(typescriptDefaults));
@@ -207147,49 +207179,49 @@ registerLanguage({
207147
207179
  extensions: [".ftl", ".ftlh", ".ftlx"],
207148
207180
  aliases: ["FreeMarker2", "Apache FreeMarker2"],
207149
207181
  loader: () => {
207150
- return __vitePreload(() => import("./freemarker2-CkAJiX1K.js"), true ? [] : void 0, import.meta.url).then((m) => m.TagAutoInterpolationDollar);
207182
+ return __vitePreload(() => import("./freemarker2-BCHZUSLb.js"), true ? [] : void 0, import.meta.url).then((m) => m.TagAutoInterpolationDollar);
207151
207183
  }
207152
207184
  });
207153
207185
  registerLanguage({
207154
207186
  id: "freemarker2.tag-angle.interpolation-dollar",
207155
207187
  aliases: ["FreeMarker2 (Angle/Dollar)", "Apache FreeMarker2 (Angle/Dollar)"],
207156
207188
  loader: () => {
207157
- return __vitePreload(() => import("./freemarker2-CkAJiX1K.js"), true ? [] : void 0, import.meta.url).then((m) => m.TagAngleInterpolationDollar);
207189
+ return __vitePreload(() => import("./freemarker2-BCHZUSLb.js"), true ? [] : void 0, import.meta.url).then((m) => m.TagAngleInterpolationDollar);
207158
207190
  }
207159
207191
  });
207160
207192
  registerLanguage({
207161
207193
  id: "freemarker2.tag-bracket.interpolation-dollar",
207162
207194
  aliases: ["FreeMarker2 (Bracket/Dollar)", "Apache FreeMarker2 (Bracket/Dollar)"],
207163
207195
  loader: () => {
207164
- return __vitePreload(() => import("./freemarker2-CkAJiX1K.js"), true ? [] : void 0, import.meta.url).then((m) => m.TagBracketInterpolationDollar);
207196
+ return __vitePreload(() => import("./freemarker2-BCHZUSLb.js"), true ? [] : void 0, import.meta.url).then((m) => m.TagBracketInterpolationDollar);
207165
207197
  }
207166
207198
  });
207167
207199
  registerLanguage({
207168
207200
  id: "freemarker2.tag-angle.interpolation-bracket",
207169
207201
  aliases: ["FreeMarker2 (Angle/Bracket)", "Apache FreeMarker2 (Angle/Bracket)"],
207170
207202
  loader: () => {
207171
- return __vitePreload(() => import("./freemarker2-CkAJiX1K.js"), true ? [] : void 0, import.meta.url).then((m) => m.TagAngleInterpolationBracket);
207203
+ return __vitePreload(() => import("./freemarker2-BCHZUSLb.js"), true ? [] : void 0, import.meta.url).then((m) => m.TagAngleInterpolationBracket);
207172
207204
  }
207173
207205
  });
207174
207206
  registerLanguage({
207175
207207
  id: "freemarker2.tag-bracket.interpolation-bracket",
207176
207208
  aliases: ["FreeMarker2 (Bracket/Bracket)", "Apache FreeMarker2 (Bracket/Bracket)"],
207177
207209
  loader: () => {
207178
- return __vitePreload(() => import("./freemarker2-CkAJiX1K.js"), true ? [] : void 0, import.meta.url).then((m) => m.TagBracketInterpolationBracket);
207210
+ return __vitePreload(() => import("./freemarker2-BCHZUSLb.js"), true ? [] : void 0, import.meta.url).then((m) => m.TagBracketInterpolationBracket);
207179
207211
  }
207180
207212
  });
207181
207213
  registerLanguage({
207182
207214
  id: "freemarker2.tag-auto.interpolation-dollar",
207183
207215
  aliases: ["FreeMarker2 (Auto/Dollar)", "Apache FreeMarker2 (Auto/Dollar)"],
207184
207216
  loader: () => {
207185
- return __vitePreload(() => import("./freemarker2-CkAJiX1K.js"), true ? [] : void 0, import.meta.url).then((m) => m.TagAutoInterpolationDollar);
207217
+ return __vitePreload(() => import("./freemarker2-BCHZUSLb.js"), true ? [] : void 0, import.meta.url).then((m) => m.TagAutoInterpolationDollar);
207186
207218
  }
207187
207219
  });
207188
207220
  registerLanguage({
207189
207221
  id: "freemarker2.tag-auto.interpolation-bracket",
207190
207222
  aliases: ["FreeMarker2 (Auto/Bracket)", "Apache FreeMarker2 (Auto/Bracket)"],
207191
207223
  loader: () => {
207192
- return __vitePreload(() => import("./freemarker2-CkAJiX1K.js"), true ? [] : void 0, import.meta.url).then((m) => m.TagAutoInterpolationBracket);
207224
+ return __vitePreload(() => import("./freemarker2-BCHZUSLb.js"), true ? [] : void 0, import.meta.url).then((m) => m.TagAutoInterpolationBracket);
207193
207225
  }
207194
207226
  });
207195
207227
  registerLanguage({
@@ -207210,7 +207242,7 @@ registerLanguage({
207210
207242
  extensions: [".handlebars", ".hbs"],
207211
207243
  aliases: ["Handlebars", "handlebars", "hbs"],
207212
207244
  mimetypes: ["text/x-handlebars-template"],
207213
- loader: () => __vitePreload(() => import("./handlebars-DnLXVUXp.js"), true ? [] : void 0, import.meta.url)
207245
+ loader: () => __vitePreload(() => import("./handlebars-DKx-Fw-H.js"), true ? [] : void 0, import.meta.url)
207214
207246
  });
207215
207247
  registerLanguage({
207216
207248
  id: "hcl",
@@ -207223,7 +207255,7 @@ registerLanguage({
207223
207255
  extensions: [".html", ".htm", ".shtml", ".xhtml", ".mdoc", ".jsp", ".asp", ".aspx", ".jshtm"],
207224
207256
  aliases: ["HTML", "htm", "html", "xhtml"],
207225
207257
  mimetypes: ["text/html", "text/x-jshtm", "text/template", "text/ng-template"],
207226
- loader: () => __vitePreload(() => import("./html-Ds5-qvDh.js"), true ? [] : void 0, import.meta.url)
207258
+ loader: () => __vitePreload(() => import("./html-BSCM04uL.js"), true ? [] : void 0, import.meta.url)
207227
207259
  });
207228
207260
  registerLanguage({
207229
207261
  id: "ini",
@@ -207246,7 +207278,7 @@ registerLanguage({
207246
207278
  filenames: ["jakefile"],
207247
207279
  aliases: ["JavaScript", "javascript", "js"],
207248
207280
  mimetypes: ["text/javascript"],
207249
- loader: () => __vitePreload(() => import("./javascript-CiHhG2a9.js"), true ? __vite__mapDeps([4,5]) : void 0, import.meta.url)
207281
+ loader: () => __vitePreload(() => import("./javascript-bPY5C4uq.js"), true ? __vite__mapDeps([4,5]) : void 0, import.meta.url)
207250
207282
  });
207251
207283
  registerLanguage({
207252
207284
  id: "julia",
@@ -207285,7 +207317,7 @@ registerLanguage({
207285
207317
  extensions: [".liquid", ".html.liquid"],
207286
207318
  aliases: ["Liquid", "liquid"],
207287
207319
  mimetypes: ["application/liquid"],
207288
- loader: () => __vitePreload(() => import("./liquid-BP5mb-uD.js"), true ? [] : void 0, import.meta.url)
207320
+ loader: () => __vitePreload(() => import("./liquid-Cja_Pzh3.js"), true ? [] : void 0, import.meta.url)
207289
207321
  });
207290
207322
  registerLanguage({
207291
207323
  id: "m3",
@@ -207303,7 +207335,7 @@ registerLanguage({
207303
207335
  id: "mdx",
207304
207336
  extensions: [".mdx"],
207305
207337
  aliases: ["MDX", "mdx"],
207306
- loader: () => __vitePreload(() => import("./mdx-D4u3N7dt.js"), true ? [] : void 0, import.meta.url)
207338
+ loader: () => __vitePreload(() => import("./mdx-C0s81MOq.js"), true ? [] : void 0, import.meta.url)
207307
207339
  });
207308
207340
  registerLanguage({
207309
207341
  id: "mips",
@@ -207402,7 +207434,7 @@ registerLanguage({
207402
207434
  extensions: [".py", ".rpy", ".pyw", ".cpy", ".gyp", ".gypi"],
207403
207435
  aliases: ["Python", "py"],
207404
207436
  firstLine: "^#!/.*\\bpython[0-9.-]*\\b",
207405
- loader: () => __vitePreload(() => import("./python-BQDHXVwp.js"), true ? [] : void 0, import.meta.url)
207437
+ loader: () => __vitePreload(() => import("./python-CulkBOJr.js"), true ? [] : void 0, import.meta.url)
207406
207438
  });
207407
207439
  registerLanguage({
207408
207440
  id: "qsharp",
@@ -207421,7 +207453,7 @@ registerLanguage({
207421
207453
  extensions: [".cshtml"],
207422
207454
  aliases: ["Razor", "razor"],
207423
207455
  mimetypes: ["text/x-cshtml"],
207424
- loader: () => __vitePreload(() => import("./razor-BfXW9cDc.js"), true ? [] : void 0, import.meta.url)
207456
+ loader: () => __vitePreload(() => import("./razor-czmzhwVZ.js"), true ? [] : void 0, import.meta.url)
207425
207457
  });
207426
207458
  registerLanguage({
207427
207459
  id: "redis",
@@ -207554,7 +207586,7 @@ registerLanguage({
207554
207586
  aliases: ["TypeScript", "ts", "typescript"],
207555
207587
  mimetypes: ["text/typescript"],
207556
207588
  loader: () => {
207557
- return __vitePreload(() => import("./typescript-422MU_YO.js"), true ? [] : void 0, import.meta.url);
207589
+ return __vitePreload(() => import("./typescript-Ckc6emP2.js"), true ? [] : void 0, import.meta.url);
207558
207590
  }
207559
207591
  });
207560
207592
  registerLanguage({
@@ -207599,14 +207631,14 @@ registerLanguage({
207599
207631
  firstLine: "(\\<\\?xml.*)|(\\<svg)|(\\<\\!doctype\\s+svg)",
207600
207632
  aliases: ["XML", "xml"],
207601
207633
  mimetypes: ["text/xml", "application/xml", "application/xaml+xml", "application/xml-dtd"],
207602
- loader: () => __vitePreload(() => import("./xml-B6EKhHiy.js"), true ? [] : void 0, import.meta.url)
207634
+ loader: () => __vitePreload(() => import("./xml-CKh-JyGN.js"), true ? [] : void 0, import.meta.url)
207603
207635
  });
207604
207636
  registerLanguage({
207605
207637
  id: "yaml",
207606
207638
  extensions: [".yaml", ".yml"],
207607
207639
  aliases: ["YAML", "yaml", "YML", "yml"],
207608
207640
  mimetypes: ["application/x-yaml", "text/x-yaml"],
207609
- loader: () => __vitePreload(() => import("./yaml-LkO_eGYb.js"), true ? [] : void 0, import.meta.url)
207641
+ loader: () => __vitePreload(() => import("./yaml-B49zLim4.js"), true ? [] : void 0, import.meta.url)
207610
207642
  });
207611
207643
  var __defProp = Object.defineProperty;
207612
207644
  var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
@@ -211638,18 +211670,26 @@ const DEFAULT_LAYOUT = {
211638
211670
  sizes: [50, 50]
211639
211671
  };
211640
211672
  const ALL_PANE_IDS = ["editor", "terminal", "ctlsurf"];
211673
+ let _tabCounter = 0;
211674
+ function nextTabId() {
211675
+ return `tab-${++_tabCounter}`;
211676
+ }
211641
211677
  function App() {
211642
211678
  const [agents, setAgents] = reactExports.useState([]);
211643
- const [selectedAgent, setSelectedAgent] = reactExports.useState(null);
211644
- const [agentStatus, setAgentStatus] = reactExports.useState("idle");
211645
211679
  const [sessionStart, setSessionStart] = reactExports.useState(null);
211646
211680
  const [layout2, setLayout] = reactExports.useState(DEFAULT_LAYOUT);
211647
211681
  const [hiddenPanes, setHiddenPanes] = reactExports.useState(/* @__PURE__ */ new Set());
211648
211682
  const [showSettings, setShowSettings] = reactExports.useState(false);
211649
211683
  const [wsStatus, setWsStatus] = reactExports.useState("disconnected");
211650
211684
  const [cwd2, setCwd] = reactExports.useState(null);
211651
- const visiblePaneIds = findPaneIds(layout2);
211685
+ const [tabs, setTabs] = reactExports.useState(() => {
211686
+ const id = nextTabId();
211687
+ return [{ id, label: "Terminal 1", agent: null, agentStatus: "idle" }];
211688
+ });
211689
+ const [activeTabId, setActiveTabId] = reactExports.useState(tabs[0].id);
211690
+ const [pickerTargetTabId, setPickerTargetTabId] = reactExports.useState(tabs[0].id);
211652
211691
  const [showAgentPicker, setShowAgentPicker] = reactExports.useState(true);
211692
+ const visiblePaneIds = findPaneIds(layout2);
211653
211693
  reactExports.useEffect(() => {
211654
211694
  async function init2() {
211655
211695
  const list2 = await window.worker.listAgents();
@@ -211672,41 +211712,78 @@ function App() {
211672
211712
  });
211673
211713
  return unsub;
211674
211714
  }, []);
211675
- const spawnGenRef = reactExports.useRef(0);
211676
211715
  const cwdRef = reactExports.useRef(null);
211677
- const handleSpawn = reactExports.useCallback(async (agent) => {
211678
- spawnGenRef.current += 1;
211679
- setAgentStatus("active");
211716
+ const handleSpawn = reactExports.useCallback(async (tabId, agent) => {
211717
+ setTabs((prev) => prev.map((t) => t.id === tabId ? { ...t, agentStatus: "active" } : t));
211680
211718
  setSessionStart(/* @__PURE__ */ new Date());
211681
211719
  const spawnCwd = cwdRef.current || await window.worker.getCwd().catch(() => window.worker.getHomePath());
211682
211720
  setCwd(spawnCwd);
211683
211721
  cwdRef.current = spawnCwd;
211684
- await window.worker.spawnAgent(agent, spawnCwd);
211722
+ await window.worker.spawnAgent(tabId, agent, spawnCwd);
211685
211723
  }, []);
211686
211724
  const handleAgentChange = reactExports.useCallback(async (agentId) => {
211687
211725
  const agent = agents.find((a) => a.id === agentId);
211688
211726
  if (agent) {
211689
- await window.worker.killPty();
211690
- setSelectedAgent(agent);
211727
+ await window.worker.killPty(activeTabId);
211728
+ setTabs((prev) => prev.map((t) => t.id === activeTabId ? { ...t, agent, agentStatus: "idle" } : t));
211691
211729
  }
211692
- }, [agents]);
211693
- const handleExit = reactExports.useCallback(() => {
211694
- const gen = spawnGenRef.current;
211730
+ }, [agents, activeTabId]);
211731
+ const handleExit = reactExports.useCallback((tabId) => {
211695
211732
  setTimeout(() => {
211696
- if (spawnGenRef.current === gen) setAgentStatus("exited");
211733
+ setTabs((prev) => prev.map((t) => t.id === tabId ? { ...t, agentStatus: "exited" } : t));
211697
211734
  }, 200);
211698
211735
  }, []);
211699
211736
  const handleChangeCwd = reactExports.useCallback(async () => {
211700
211737
  const newCwd = await window.worker.browseCwd();
211701
- if (!newCwd || !selectedAgent) return;
211738
+ const activeTab = tabs.find((t) => t.id === activeTabId);
211739
+ if (!newCwd || !activeTab?.agent) return;
211702
211740
  cwdRef.current = newCwd;
211703
211741
  setCwd(newCwd);
211704
- await window.worker.killPty();
211705
- spawnGenRef.current += 1;
211706
- setAgentStatus("active");
211742
+ await window.worker.killPty(activeTabId);
211743
+ setTabs((prev) => prev.map((t) => t.id === activeTabId ? { ...t, agentStatus: "active" } : t));
211707
211744
  setSessionStart(/* @__PURE__ */ new Date());
211708
- await window.worker.spawnAgent(selectedAgent, newCwd);
211709
- }, [selectedAgent]);
211745
+ await window.worker.spawnAgent(activeTabId, activeTab.agent, newCwd);
211746
+ }, [tabs, activeTabId]);
211747
+ const addTab = reactExports.useCallback(() => {
211748
+ const id = nextTabId();
211749
+ const num = _tabCounter;
211750
+ setTabs((prev) => [...prev, { id, label: `Terminal ${num}`, agent: null, agentStatus: "idle" }]);
211751
+ setActiveTabId(id);
211752
+ setPickerTargetTabId(id);
211753
+ setShowAgentPicker(true);
211754
+ }, []);
211755
+ const handlePickerSelect = reactExports.useCallback((agent) => {
211756
+ const tabId = pickerTargetTabId;
211757
+ if (tabId) {
211758
+ setTabs((prev) => prev.map(
211759
+ (t) => t.id === tabId ? { ...t, agent, label: `${agent.name} ${tabs.filter((x) => x.agent?.id === agent.id).length + 1}` } : t
211760
+ ));
211761
+ }
211762
+ setShowAgentPicker(false);
211763
+ setPickerTargetTabId(null);
211764
+ }, [pickerTargetTabId, tabs]);
211765
+ const closeTab = reactExports.useCallback(async (tabId) => {
211766
+ await window.worker.killPty(tabId);
211767
+ destroyTerminal(tabId);
211768
+ setTabs((prev) => {
211769
+ const next = prev.filter((t) => t.id !== tabId);
211770
+ if (tabId === activeTabId && next.length > 0) {
211771
+ setActiveTabId(next[next.length - 1].id);
211772
+ }
211773
+ if (next.length === 0) {
211774
+ const id = nextTabId();
211775
+ const num = _tabCounter;
211776
+ setActiveTabId(id);
211777
+ setPickerTargetTabId(id);
211778
+ setShowAgentPicker(true);
211779
+ return [{ id, label: `Terminal ${num}`, agent: null, agentStatus: "idle" }];
211780
+ }
211781
+ return next;
211782
+ });
211783
+ }, [activeTabId]);
211784
+ const switchTab = reactExports.useCallback((tabId) => {
211785
+ setActiveTabId(tabId);
211786
+ }, []);
211710
211787
  const togglePane = reactExports.useCallback((id) => {
211711
211788
  if (visiblePaneIds.includes(id)) {
211712
211789
  const newLayout = removePane(layout2, id);
@@ -211774,7 +211851,59 @@ function App() {
211774
211851
  {
211775
211852
  id: "terminal",
211776
211853
  label: "Terminal",
211777
- content: /* @__PURE__ */ jsxRuntimeExports.jsx(TerminalPanel, { agent: selectedAgent, onSpawn: handleSpawn, onExit: handleExit })
211854
+ content: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "terminal-tabs-wrapper", children: [
211855
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "terminal-tab-bar", children: [
211856
+ tabs.map((tab) => /* @__PURE__ */ jsxRuntimeExports.jsxs(
211857
+ "div",
211858
+ {
211859
+ className: `terminal-tab ${tab.id === activeTabId ? "active" : ""}`,
211860
+ onClick: () => switchTab(tab.id),
211861
+ children: [
211862
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "terminal-tab-label", children: [
211863
+ tab.agent ? tab.agent.name : tab.label,
211864
+ tab.agentStatus === "active" && /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "terminal-tab-dot active" }),
211865
+ tab.agentStatus === "exited" && /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "terminal-tab-dot exited" })
211866
+ ] }),
211867
+ tabs.length > 1 && /* @__PURE__ */ jsxRuntimeExports.jsx(
211868
+ "button",
211869
+ {
211870
+ className: "terminal-tab-close",
211871
+ onClick: (e) => {
211872
+ e.stopPropagation();
211873
+ closeTab(tab.id);
211874
+ },
211875
+ title: "Close tab",
211876
+ children: "×"
211877
+ }
211878
+ )
211879
+ ]
211880
+ },
211881
+ tab.id
211882
+ )),
211883
+ /* @__PURE__ */ jsxRuntimeExports.jsx("button", { className: "terminal-tab-add", onClick: addTab, title: "New terminal tab", children: "+" })
211884
+ ] }),
211885
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "terminal-tabs-content", children: tabs.map((tab) => /* @__PURE__ */ jsxRuntimeExports.jsx(
211886
+ "div",
211887
+ {
211888
+ className: "terminal-tab-panel",
211889
+ style: {
211890
+ display: tab.id === activeTabId ? "flex" : "none",
211891
+ flex: 1
211892
+ },
211893
+ children: /* @__PURE__ */ jsxRuntimeExports.jsx(
211894
+ TerminalPanel,
211895
+ {
211896
+ tabId: tab.id,
211897
+ agent: tab.agent,
211898
+ onSpawn: handleSpawn,
211899
+ onExit: handleExit,
211900
+ isActive: tab.id === activeTabId
211901
+ }
211902
+ )
211903
+ },
211904
+ tab.id
211905
+ )) })
211906
+ ] })
211778
211907
  },
211779
211908
  { id: "ctlsurf", label: "ctlsurf", content: /* @__PURE__ */ jsxRuntimeExports.jsx(CtlsurfPanel, {}) }
211780
211909
  ];
@@ -211784,16 +211913,19 @@ function App() {
211784
211913
  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "titlebar-controls", children: [
211785
211914
  /* @__PURE__ */ jsxRuntimeExports.jsx("button", { className: "titlebar-btn", onClick: () => setShowSettings(true), title: "Settings", children: "Settings" }),
211786
211915
  /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "titlebar-separator" }),
211787
- agents.map((a) => /* @__PURE__ */ jsxRuntimeExports.jsx(
211788
- "button",
211789
- {
211790
- className: `titlebar-agent-btn ${selectedAgent?.id === a.id ? "active" : ""}`,
211791
- onClick: () => handleAgentChange(a.id),
211792
- title: a.description,
211793
- children: a.name
211794
- },
211795
- a.id
211796
- )),
211916
+ agents.map((a) => {
211917
+ const activeTab = tabs.find((t) => t.id === activeTabId);
211918
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(
211919
+ "button",
211920
+ {
211921
+ className: `titlebar-agent-btn ${activeTab?.agent?.id === a.id ? "active" : ""}`,
211922
+ onClick: () => handleAgentChange(a.id),
211923
+ title: a.description,
211924
+ children: a.name
211925
+ },
211926
+ a.id
211927
+ );
211928
+ }),
211797
211929
  /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "titlebar-separator" }),
211798
211930
  ALL_PANE_IDS.map((id) => /* @__PURE__ */ jsxRuntimeExports.jsx(
211799
211931
  "button",
@@ -211823,10 +211955,7 @@ function App() {
211823
211955
  {
211824
211956
  agents,
211825
211957
  cwd: cwd2 || "",
211826
- onSelect: (agent) => {
211827
- setSelectedAgent(agent);
211828
- setShowAgentPicker(false);
211829
- },
211958
+ onSelect: handlePickerSelect,
211830
211959
  onChangeCwd: async () => {
211831
211960
  const newCwd = await window.worker.browseCwd();
211832
211961
  if (newCwd) {