@phenx-inc/ctlsurf 0.1.20 → 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-Cxe23-tB.js → cssMode-D3kH1Kju.js} +3 -3
  6. package/out/renderer/assets/{freemarker2-Be0nj7Oa.js → freemarker2-BCHZUSLb.js} +1 -1
  7. package/out/renderer/assets/{handlebars-C0It7_Nu.js → handlebars-DKx-Fw-H.js} +1 -1
  8. package/out/renderer/assets/{html-BW6LB-7J.js → html-BSCM04uL.js} +1 -1
  9. package/out/renderer/assets/{htmlMode-D_V-1VlE.js → htmlMode-BucU1MUc.js} +3 -3
  10. package/out/renderer/assets/{index-D568SpEt.js → index-BsdOeO0U.js} +240 -94
  11. package/out/renderer/assets/{index-DK9wLFFm.css → index-BzF7I1my.css} +111 -0
  12. package/out/renderer/assets/{javascript-D_LoeNc7.js → javascript-bPY5C4uq.js} +2 -2
  13. package/out/renderer/assets/{jsonMode-K3WSinSE.js → jsonMode-BmJotb6E.js} +3 -3
  14. package/out/renderer/assets/{liquid-BqfOd6m8.js → liquid-Cja_Pzh3.js} +1 -1
  15. package/out/renderer/assets/{lspLanguageFeatures-Bjf28WU6.js → lspLanguageFeatures-hoVZfVKv.js} +1 -1
  16. package/out/renderer/assets/{mdx-BoESjI38.js → mdx-C0s81MOq.js} +1 -1
  17. package/out/renderer/assets/{python-DlafOOgB.js → python-CulkBOJr.js} +1 -1
  18. package/out/renderer/assets/{razor-CB6E9DBD.js → razor-czmzhwVZ.js} +1 -1
  19. package/out/renderer/assets/{tsMode-DYu1z_nn.js → tsMode-B90EqYGx.js} +1 -1
  20. package/out/renderer/assets/{typescript-CDjkh0d5.js → typescript-Ckc6emP2.js} +1 -1
  21. package/out/renderer/assets/{xml-C-XlilKZ.js → xml-CKh-JyGN.js} +1 -1
  22. package/out/renderer/assets/{yaml-BTrtxLEo.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 +113 -48
  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-Cxe23-tB.js","./lspLanguageFeatures-Bjf28WU6.js","./htmlMode-D_V-1VlE.js","./jsonMode-K3WSinSE.js","./javascript-D_LoeNc7.js","./typescript-CDjkh0d5.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,12 +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
- function getOrCreateTerminal(onExit) {
18728
- if (_terminal && _fitAddon) {
18729
- return { terminal: _terminal, fitAddon: _fitAddon };
18724
+ const _terminals = /* @__PURE__ */ new Map();
18725
+ function isAtBottom(terminal) {
18726
+ const buf = terminal.buffer.active;
18727
+ return buf.viewportY >= buf.baseY;
18728
+ }
18729
+ function scrollIfPinned(tabId, terminal) {
18730
+ const state = _terminals.get(tabId);
18731
+ if (state?.pinnedToBottom) {
18732
+ terminal.scrollToBottom();
18733
+ }
18734
+ }
18735
+ function getOrCreateTerminal(tabId, onExit) {
18736
+ const existing = _terminals.get(tabId);
18737
+ if (existing) {
18738
+ return { terminal: existing.terminal, fitAddon: existing.fitAddon };
18730
18739
  }
18731
18740
  const terminal = new xtermExports.Terminal({
18732
18741
  cursorBlink: true,
@@ -18761,26 +18770,51 @@ function getOrCreateTerminal(onExit) {
18761
18770
  const fitAddon = new addonFitExports.FitAddon();
18762
18771
  terminal.loadAddon(fitAddon);
18763
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
+ };
18781
+ terminal.onScroll(() => {
18782
+ state.pinnedToBottom = isAtBottom(terminal);
18783
+ });
18764
18784
  terminal.onData((data) => {
18765
- window.worker.writePty(data);
18785
+ state.pinnedToBottom = true;
18786
+ terminal.scrollToBottom();
18787
+ window.worker.writePty(tabId, data);
18766
18788
  });
18767
- window.worker.onPtyData((data) => {
18768
- terminal.write(data);
18789
+ state.unsubData = window.worker.onPtyData((eventTabId, data) => {
18790
+ if (eventTabId === tabId) {
18791
+ terminal.write(data);
18792
+ scrollIfPinned(tabId, terminal);
18793
+ }
18769
18794
  });
18770
- window.worker.onPtyExit((code) => {
18771
- terminal.writeln(`\r
18795
+ state.unsubExit = window.worker.onPtyExit((eventTabId, code) => {
18796
+ if (eventTabId === tabId) {
18797
+ terminal.writeln(`\r
18772
18798
  \x1B[33m[Process exited with code ${code}]\x1B[0m`);
18773
- onExit();
18799
+ onExit(tabId);
18800
+ }
18774
18801
  });
18775
- _terminal = terminal;
18776
- _fitAddon = fitAddon;
18802
+ _terminals.set(tabId, state);
18777
18803
  return { terminal, fitAddon };
18778
18804
  }
18779
- 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 }) {
18780
18814
  const containerRef = reactExports.useRef(null);
18781
18815
  reactExports.useEffect(() => {
18782
18816
  if (!containerRef.current) return;
18783
- const { terminal, fitAddon } = getOrCreateTerminal(onExit);
18817
+ const { terminal, fitAddon } = getOrCreateTerminal(tabId, onExit);
18784
18818
  const existingParent = terminal.element?.parentElement;
18785
18819
  if (existingParent && existingParent !== containerRef.current) {
18786
18820
  containerRef.current.appendChild(terminal.element);
@@ -18788,16 +18822,17 @@ function TerminalPanel({ agent, onSpawn, onExit }) {
18788
18822
  terminal.open(containerRef.current);
18789
18823
  }
18790
18824
  fitAddon.fit();
18791
- terminal.scrollToBottom();
18825
+ scrollIfPinned(tabId, terminal);
18792
18826
  let resizeTimeout;
18793
18827
  const handleResize = () => {
18794
18828
  clearTimeout(resizeTimeout);
18795
18829
  resizeTimeout = setTimeout(() => {
18796
- if (_fitAddon && _terminal) {
18797
- _fitAddon.fit();
18798
- _terminal.scrollToBottom();
18799
- const { cols, rows } = _terminal;
18800
- 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);
18801
18836
  }
18802
18837
  }, 150);
18803
18838
  };
@@ -18809,22 +18844,36 @@ function TerminalPanel({ agent, onSpawn, onExit }) {
18809
18844
  window.removeEventListener("resize", handleResize);
18810
18845
  observer.disconnect();
18811
18846
  };
18812
- }, [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]);
18813
18867
  reactExports.useEffect(() => {
18814
- if (!agent || !_terminal) return;
18815
- if (_currentAgentId === agent.id) return;
18816
- _currentAgentId = agent.id;
18817
- _terminal.clear();
18818
- onSpawn(agent).then(() => {
18819
- if (_fitAddon && _terminal) {
18820
- _fitAddon.fit();
18821
- _terminal.scrollToBottom();
18822
- const { cols, rows } = _terminal;
18823
- window.worker.resizePty(cols, rows);
18824
- }
18825
- _terminal?.focus();
18826
- });
18827
- }, [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]);
18828
18877
  return /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "terminal-container", ref: containerRef });
18829
18878
  }
18830
18879
  function CtlsurfPanel() {
@@ -206500,7 +206549,7 @@ const lessDefaults = new LanguageServiceDefaultsImpl$3(
206500
206549
  modeConfigurationDefault$2
206501
206550
  );
206502
206551
  function getMode$3() {
206503
- return __vitePreload(() => import("./cssMode-Cxe23-tB.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);
206504
206553
  }
206505
206554
  languages.onLanguage("less", () => {
206506
206555
  getMode$3().then((mode2) => mode2.setupMode(lessDefaults));
@@ -206605,7 +206654,7 @@ const razorLanguageService = registerHTMLLanguageService(
206605
206654
  );
206606
206655
  const razorDefaults = razorLanguageService.defaults;
206607
206656
  function getMode$2() {
206608
- return __vitePreload(() => import("./htmlMode-D_V-1VlE.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);
206609
206658
  }
206610
206659
  function registerHTMLLanguageService(languageId, options = optionsDefault, modeConfiguration = getConfigurationDefault(languageId)) {
206611
206660
  const defaults = new LanguageServiceDefaultsImpl$2(languageId, options, modeConfiguration);
@@ -206689,7 +206738,7 @@ const jsonDefaults = new LanguageServiceDefaultsImpl$1(
206689
206738
  );
206690
206739
  const getWorker$1 = () => getMode$1().then((mode2) => mode2.getWorker());
206691
206740
  function getMode$1() {
206692
- return __vitePreload(() => import("./jsonMode-K3WSinSE.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);
206693
206742
  }
206694
206743
  languages.register({
206695
206744
  id: "json",
@@ -206935,7 +206984,7 @@ const getJavaScriptWorker = () => {
206935
206984
  return getMode().then((mode) => mode.getJavaScriptWorker());
206936
206985
  };
206937
206986
  function getMode() {
206938
- return __vitePreload(() => import("./tsMode-DYu1z_nn.js"), true ? [] : void 0, import.meta.url);
206987
+ return __vitePreload(() => import("./tsMode-B90EqYGx.js"), true ? [] : void 0, import.meta.url);
206939
206988
  }
206940
206989
  languages.onLanguage("typescript", () => {
206941
206990
  return getMode().then((mode) => mode.setupTypeScript(typescriptDefaults));
@@ -207130,49 +207179,49 @@ registerLanguage({
207130
207179
  extensions: [".ftl", ".ftlh", ".ftlx"],
207131
207180
  aliases: ["FreeMarker2", "Apache FreeMarker2"],
207132
207181
  loader: () => {
207133
- return __vitePreload(() => import("./freemarker2-Be0nj7Oa.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);
207134
207183
  }
207135
207184
  });
207136
207185
  registerLanguage({
207137
207186
  id: "freemarker2.tag-angle.interpolation-dollar",
207138
207187
  aliases: ["FreeMarker2 (Angle/Dollar)", "Apache FreeMarker2 (Angle/Dollar)"],
207139
207188
  loader: () => {
207140
- return __vitePreload(() => import("./freemarker2-Be0nj7Oa.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);
207141
207190
  }
207142
207191
  });
207143
207192
  registerLanguage({
207144
207193
  id: "freemarker2.tag-bracket.interpolation-dollar",
207145
207194
  aliases: ["FreeMarker2 (Bracket/Dollar)", "Apache FreeMarker2 (Bracket/Dollar)"],
207146
207195
  loader: () => {
207147
- return __vitePreload(() => import("./freemarker2-Be0nj7Oa.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);
207148
207197
  }
207149
207198
  });
207150
207199
  registerLanguage({
207151
207200
  id: "freemarker2.tag-angle.interpolation-bracket",
207152
207201
  aliases: ["FreeMarker2 (Angle/Bracket)", "Apache FreeMarker2 (Angle/Bracket)"],
207153
207202
  loader: () => {
207154
- return __vitePreload(() => import("./freemarker2-Be0nj7Oa.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);
207155
207204
  }
207156
207205
  });
207157
207206
  registerLanguage({
207158
207207
  id: "freemarker2.tag-bracket.interpolation-bracket",
207159
207208
  aliases: ["FreeMarker2 (Bracket/Bracket)", "Apache FreeMarker2 (Bracket/Bracket)"],
207160
207209
  loader: () => {
207161
- return __vitePreload(() => import("./freemarker2-Be0nj7Oa.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);
207162
207211
  }
207163
207212
  });
207164
207213
  registerLanguage({
207165
207214
  id: "freemarker2.tag-auto.interpolation-dollar",
207166
207215
  aliases: ["FreeMarker2 (Auto/Dollar)", "Apache FreeMarker2 (Auto/Dollar)"],
207167
207216
  loader: () => {
207168
- return __vitePreload(() => import("./freemarker2-Be0nj7Oa.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);
207169
207218
  }
207170
207219
  });
207171
207220
  registerLanguage({
207172
207221
  id: "freemarker2.tag-auto.interpolation-bracket",
207173
207222
  aliases: ["FreeMarker2 (Auto/Bracket)", "Apache FreeMarker2 (Auto/Bracket)"],
207174
207223
  loader: () => {
207175
- return __vitePreload(() => import("./freemarker2-Be0nj7Oa.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);
207176
207225
  }
207177
207226
  });
207178
207227
  registerLanguage({
@@ -207193,7 +207242,7 @@ registerLanguage({
207193
207242
  extensions: [".handlebars", ".hbs"],
207194
207243
  aliases: ["Handlebars", "handlebars", "hbs"],
207195
207244
  mimetypes: ["text/x-handlebars-template"],
207196
- loader: () => __vitePreload(() => import("./handlebars-C0It7_Nu.js"), true ? [] : void 0, import.meta.url)
207245
+ loader: () => __vitePreload(() => import("./handlebars-DKx-Fw-H.js"), true ? [] : void 0, import.meta.url)
207197
207246
  });
207198
207247
  registerLanguage({
207199
207248
  id: "hcl",
@@ -207206,7 +207255,7 @@ registerLanguage({
207206
207255
  extensions: [".html", ".htm", ".shtml", ".xhtml", ".mdoc", ".jsp", ".asp", ".aspx", ".jshtm"],
207207
207256
  aliases: ["HTML", "htm", "html", "xhtml"],
207208
207257
  mimetypes: ["text/html", "text/x-jshtm", "text/template", "text/ng-template"],
207209
- loader: () => __vitePreload(() => import("./html-BW6LB-7J.js"), true ? [] : void 0, import.meta.url)
207258
+ loader: () => __vitePreload(() => import("./html-BSCM04uL.js"), true ? [] : void 0, import.meta.url)
207210
207259
  });
207211
207260
  registerLanguage({
207212
207261
  id: "ini",
@@ -207229,7 +207278,7 @@ registerLanguage({
207229
207278
  filenames: ["jakefile"],
207230
207279
  aliases: ["JavaScript", "javascript", "js"],
207231
207280
  mimetypes: ["text/javascript"],
207232
- loader: () => __vitePreload(() => import("./javascript-D_LoeNc7.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)
207233
207282
  });
207234
207283
  registerLanguage({
207235
207284
  id: "julia",
@@ -207268,7 +207317,7 @@ registerLanguage({
207268
207317
  extensions: [".liquid", ".html.liquid"],
207269
207318
  aliases: ["Liquid", "liquid"],
207270
207319
  mimetypes: ["application/liquid"],
207271
- loader: () => __vitePreload(() => import("./liquid-BqfOd6m8.js"), true ? [] : void 0, import.meta.url)
207320
+ loader: () => __vitePreload(() => import("./liquid-Cja_Pzh3.js"), true ? [] : void 0, import.meta.url)
207272
207321
  });
207273
207322
  registerLanguage({
207274
207323
  id: "m3",
@@ -207286,7 +207335,7 @@ registerLanguage({
207286
207335
  id: "mdx",
207287
207336
  extensions: [".mdx"],
207288
207337
  aliases: ["MDX", "mdx"],
207289
- loader: () => __vitePreload(() => import("./mdx-BoESjI38.js"), true ? [] : void 0, import.meta.url)
207338
+ loader: () => __vitePreload(() => import("./mdx-C0s81MOq.js"), true ? [] : void 0, import.meta.url)
207290
207339
  });
207291
207340
  registerLanguage({
207292
207341
  id: "mips",
@@ -207385,7 +207434,7 @@ registerLanguage({
207385
207434
  extensions: [".py", ".rpy", ".pyw", ".cpy", ".gyp", ".gypi"],
207386
207435
  aliases: ["Python", "py"],
207387
207436
  firstLine: "^#!/.*\\bpython[0-9.-]*\\b",
207388
- loader: () => __vitePreload(() => import("./python-DlafOOgB.js"), true ? [] : void 0, import.meta.url)
207437
+ loader: () => __vitePreload(() => import("./python-CulkBOJr.js"), true ? [] : void 0, import.meta.url)
207389
207438
  });
207390
207439
  registerLanguage({
207391
207440
  id: "qsharp",
@@ -207404,7 +207453,7 @@ registerLanguage({
207404
207453
  extensions: [".cshtml"],
207405
207454
  aliases: ["Razor", "razor"],
207406
207455
  mimetypes: ["text/x-cshtml"],
207407
- loader: () => __vitePreload(() => import("./razor-CB6E9DBD.js"), true ? [] : void 0, import.meta.url)
207456
+ loader: () => __vitePreload(() => import("./razor-czmzhwVZ.js"), true ? [] : void 0, import.meta.url)
207408
207457
  });
207409
207458
  registerLanguage({
207410
207459
  id: "redis",
@@ -207537,7 +207586,7 @@ registerLanguage({
207537
207586
  aliases: ["TypeScript", "ts", "typescript"],
207538
207587
  mimetypes: ["text/typescript"],
207539
207588
  loader: () => {
207540
- return __vitePreload(() => import("./typescript-CDjkh0d5.js"), true ? [] : void 0, import.meta.url);
207589
+ return __vitePreload(() => import("./typescript-Ckc6emP2.js"), true ? [] : void 0, import.meta.url);
207541
207590
  }
207542
207591
  });
207543
207592
  registerLanguage({
@@ -207582,14 +207631,14 @@ registerLanguage({
207582
207631
  firstLine: "(\\<\\?xml.*)|(\\<svg)|(\\<\\!doctype\\s+svg)",
207583
207632
  aliases: ["XML", "xml"],
207584
207633
  mimetypes: ["text/xml", "application/xml", "application/xaml+xml", "application/xml-dtd"],
207585
- loader: () => __vitePreload(() => import("./xml-C-XlilKZ.js"), true ? [] : void 0, import.meta.url)
207634
+ loader: () => __vitePreload(() => import("./xml-CKh-JyGN.js"), true ? [] : void 0, import.meta.url)
207586
207635
  });
207587
207636
  registerLanguage({
207588
207637
  id: "yaml",
207589
207638
  extensions: [".yaml", ".yml"],
207590
207639
  aliases: ["YAML", "yaml", "YML", "yml"],
207591
207640
  mimetypes: ["application/x-yaml", "text/x-yaml"],
207592
- loader: () => __vitePreload(() => import("./yaml-BTrtxLEo.js"), true ? [] : void 0, import.meta.url)
207641
+ loader: () => __vitePreload(() => import("./yaml-B49zLim4.js"), true ? [] : void 0, import.meta.url)
207593
207642
  });
207594
207643
  var __defProp = Object.defineProperty;
207595
207644
  var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
@@ -211621,18 +211670,26 @@ const DEFAULT_LAYOUT = {
211621
211670
  sizes: [50, 50]
211622
211671
  };
211623
211672
  const ALL_PANE_IDS = ["editor", "terminal", "ctlsurf"];
211673
+ let _tabCounter = 0;
211674
+ function nextTabId() {
211675
+ return `tab-${++_tabCounter}`;
211676
+ }
211624
211677
  function App() {
211625
211678
  const [agents, setAgents] = reactExports.useState([]);
211626
- const [selectedAgent, setSelectedAgent] = reactExports.useState(null);
211627
- const [agentStatus, setAgentStatus] = reactExports.useState("idle");
211628
211679
  const [sessionStart, setSessionStart] = reactExports.useState(null);
211629
211680
  const [layout2, setLayout] = reactExports.useState(DEFAULT_LAYOUT);
211630
211681
  const [hiddenPanes, setHiddenPanes] = reactExports.useState(/* @__PURE__ */ new Set());
211631
211682
  const [showSettings, setShowSettings] = reactExports.useState(false);
211632
211683
  const [wsStatus, setWsStatus] = reactExports.useState("disconnected");
211633
211684
  const [cwd2, setCwd] = reactExports.useState(null);
211634
- 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);
211635
211691
  const [showAgentPicker, setShowAgentPicker] = reactExports.useState(true);
211692
+ const visiblePaneIds = findPaneIds(layout2);
211636
211693
  reactExports.useEffect(() => {
211637
211694
  async function init2() {
211638
211695
  const list2 = await window.worker.listAgents();
@@ -211655,41 +211712,78 @@ function App() {
211655
211712
  });
211656
211713
  return unsub;
211657
211714
  }, []);
211658
- const spawnGenRef = reactExports.useRef(0);
211659
211715
  const cwdRef = reactExports.useRef(null);
211660
- const handleSpawn = reactExports.useCallback(async (agent) => {
211661
- spawnGenRef.current += 1;
211662
- setAgentStatus("active");
211716
+ const handleSpawn = reactExports.useCallback(async (tabId, agent) => {
211717
+ setTabs((prev) => prev.map((t) => t.id === tabId ? { ...t, agentStatus: "active" } : t));
211663
211718
  setSessionStart(/* @__PURE__ */ new Date());
211664
211719
  const spawnCwd = cwdRef.current || await window.worker.getCwd().catch(() => window.worker.getHomePath());
211665
211720
  setCwd(spawnCwd);
211666
211721
  cwdRef.current = spawnCwd;
211667
- await window.worker.spawnAgent(agent, spawnCwd);
211722
+ await window.worker.spawnAgent(tabId, agent, spawnCwd);
211668
211723
  }, []);
211669
211724
  const handleAgentChange = reactExports.useCallback(async (agentId) => {
211670
211725
  const agent = agents.find((a) => a.id === agentId);
211671
211726
  if (agent) {
211672
- await window.worker.killPty();
211673
- setSelectedAgent(agent);
211727
+ await window.worker.killPty(activeTabId);
211728
+ setTabs((prev) => prev.map((t) => t.id === activeTabId ? { ...t, agent, agentStatus: "idle" } : t));
211674
211729
  }
211675
- }, [agents]);
211676
- const handleExit = reactExports.useCallback(() => {
211677
- const gen = spawnGenRef.current;
211730
+ }, [agents, activeTabId]);
211731
+ const handleExit = reactExports.useCallback((tabId) => {
211678
211732
  setTimeout(() => {
211679
- if (spawnGenRef.current === gen) setAgentStatus("exited");
211733
+ setTabs((prev) => prev.map((t) => t.id === tabId ? { ...t, agentStatus: "exited" } : t));
211680
211734
  }, 200);
211681
211735
  }, []);
211682
211736
  const handleChangeCwd = reactExports.useCallback(async () => {
211683
211737
  const newCwd = await window.worker.browseCwd();
211684
- if (!newCwd || !selectedAgent) return;
211738
+ const activeTab = tabs.find((t) => t.id === activeTabId);
211739
+ if (!newCwd || !activeTab?.agent) return;
211685
211740
  cwdRef.current = newCwd;
211686
211741
  setCwd(newCwd);
211687
- await window.worker.killPty();
211688
- spawnGenRef.current += 1;
211689
- setAgentStatus("active");
211742
+ await window.worker.killPty(activeTabId);
211743
+ setTabs((prev) => prev.map((t) => t.id === activeTabId ? { ...t, agentStatus: "active" } : t));
211690
211744
  setSessionStart(/* @__PURE__ */ new Date());
211691
- await window.worker.spawnAgent(selectedAgent, newCwd);
211692
- }, [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
+ }, []);
211693
211787
  const togglePane = reactExports.useCallback((id) => {
211694
211788
  if (visiblePaneIds.includes(id)) {
211695
211789
  const newLayout = removePane(layout2, id);
@@ -211757,7 +211851,59 @@ function App() {
211757
211851
  {
211758
211852
  id: "terminal",
211759
211853
  label: "Terminal",
211760
- 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
+ ] })
211761
211907
  },
211762
211908
  { id: "ctlsurf", label: "ctlsurf", content: /* @__PURE__ */ jsxRuntimeExports.jsx(CtlsurfPanel, {}) }
211763
211909
  ];
@@ -211767,16 +211913,19 @@ function App() {
211767
211913
  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "titlebar-controls", children: [
211768
211914
  /* @__PURE__ */ jsxRuntimeExports.jsx("button", { className: "titlebar-btn", onClick: () => setShowSettings(true), title: "Settings", children: "Settings" }),
211769
211915
  /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "titlebar-separator" }),
211770
- agents.map((a) => /* @__PURE__ */ jsxRuntimeExports.jsx(
211771
- "button",
211772
- {
211773
- className: `titlebar-agent-btn ${selectedAgent?.id === a.id ? "active" : ""}`,
211774
- onClick: () => handleAgentChange(a.id),
211775
- title: a.description,
211776
- children: a.name
211777
- },
211778
- a.id
211779
- )),
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
+ }),
211780
211929
  /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "titlebar-separator" }),
211781
211930
  ALL_PANE_IDS.map((id) => /* @__PURE__ */ jsxRuntimeExports.jsx(
211782
211931
  "button",
@@ -211806,10 +211955,7 @@ function App() {
211806
211955
  {
211807
211956
  agents,
211808
211957
  cwd: cwd2 || "",
211809
- onSelect: (agent) => {
211810
- setSelectedAgent(agent);
211811
- setShowAgentPicker(false);
211812
- },
211958
+ onSelect: handlePickerSelect,
211813
211959
  onChangeCwd: async () => {
211814
211960
  const newCwd = await window.worker.browseCwd();
211815
211961
  if (newCwd) {